diff --git a/AUTHORS.TXT b/AUTHORS.TXT
new file mode 100644
index 00000000..c1a289c6
--- /dev/null
+++ b/AUTHORS.TXT
@@ -0,0 +1,38 @@
+SoftEther VPN is developed by SoftEther VPN Project at University of Tsukuba.
+http://www.softether.org/
+
+AUTHORS OF SOFTETHER VPN
+------------------------
+
+PROGRAMMERS:
+
+ - Daiyuu Nobori
+ Computer Science, Graduate School of University of Tsukuba
+ SoftEther Corporation
+ E-mail: daiyuu-nobori [at] softether.org
+
+ - Tetsuo Sugiyama, Ph. D.
+ SoftEther Corporation
+
+ - Junpei Kuwana
+ Risk Engineering, Graduate School of University of Tsukuba
+ SoftEther Corporation
+
+ - Takao Ito
+ Computer Science, Graduate School of University of Tsukuba
+ SoftEther Corporation
+
+ - Christopher Smith
+ College of Information Science, University of Tsukuba
+
+
+WEB-SITE DESIGNER:
+
+ - Genya Hatakeyama
+ College of Information Science, University of Tsukuba
+
+
+Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+Department of Computer Science has dozens of overly-enthusiastic geeks.
+Join us: http://www.tsukuba.ac.jp/english/admission/
+
diff --git a/BUILD_UNIX.TXT b/BUILD_UNIX.TXT
new file mode 100644
index 00000000..f62295dd
--- /dev/null
+++ b/BUILD_UNIX.TXT
@@ -0,0 +1,125 @@
+How to build SoftEther VPN for UNIX
+===================================
+
+
+Requirements
+------------
+
+You need to install the following software to build SoftEther VPN for UNIX.
+
+- Linux, FreeBSD, Solaris or Mac OS X.
+- GNU Compiler Collectipon (gcc) and binary utilities.
+- GNU Make (gmake).
+- GNU C Library (glibc).
+- POSIX Threads (pthread).
+- OpenSSL (crypto, ssl).
+- libiconv.
+- readline.
+- ncurses.
+
+For example, the following commands help you to install the above programs
+on Fedora or CentOS Linux:
+
+$ yum -y groupinstall "Development Tools"
+$ yum -y install readline-devel ncurses-devel openssl-devel
+
+
+How to Build
+------------
+
+To build the programs from the source code, run the following commands:
+
+$ ./configure
+$ make
+
+If any error occurs, please check the above requirements.
+
+
+How to Install SoftEther VPN Server, Bridge or Client
+-----------------------------------------------------
+
+To install the vpnserver, vpnbridge and vpnclient programs into the
+/usr/bin directory, run the following as the root user:
+
+# make install
+
+After the installation will complete successfully:
+
+- Execute 'vpnserver start' to run the SoftEther VPN Server background service.
+- Execute 'vpnbridge start' to run the SoftEther VPN Bridge background service.
+- Execute 'vpnclient start' to run the SoftEther VPN Client background service.
+- Execute 'vpncmd' to run SoftEther VPN Command-Line Utility to configure
+ VPN Server, VPN Bridge or VPN Client.
+
+- You can also use VPN Server/Client Manager GUI Tool on other Windows PC to
+ connect to VPN services remotely.
+ You can download the GUI Tools from http://www.softether-download.com/.
+
+
+How to Run SoftEther VPN Server for Test
+----------------------------------------
+
+To start the SoftEther VPN Server background service, run the following:
+
+$ bin/vpnserver/vpnserver start
+
+To stop the service, run the following:
+
+$ bin/vpnserver/vpnserver stop
+
+To configure the running SoftEther VPN Server service,
+you can use SoftEther VPN Command Line Management Utility as following:
+
+$ bin/vpncmd/vpncmd
+
+Or you can also use VPN Server Manager GUI Tool on other Windows PC to
+connect to the VPN Server remotely. You can download the GUI Tool
+from http://www.softether-download.com/.
+
+
+How to Run SoftEther VPN Bridge for Test
+----------------------------------------
+
+To start the SoftEther VPN Bridge background service, run the following:
+
+$ bin/vpnbridge/vpnbridge start
+
+To stop the service, run the following:
+
+$ bin/vpnbridge/vpnbridge stop
+
+To configure the running SoftEther VPN Bridge service,
+you can use SoftEther VPN Command Line Management Utility as following:
+
+$ bin/vpncmd/vpncmd
+
+Or you can also use VPN Server Manager GUI Tool on other Windows PC to
+connect to the VPN Bridge remotely. You can download the GUI Tool
+from http://www.softether-download.com/.
+
+
+How to Run SoftEther VPN Client for Test
+----------------------------------------
+
+To start the SoftEther VPN Client background service, run the following:
+
+$ bin/vpnclient/vpnclient start
+
+To stop the service, run the following:
+
+$ bin/vpnclient/vpnclient stop
+
+To configure the running SoftEther VPN Client service,
+you can use SoftEther VPN Command Line Management Utility as following:
+
+$ bin/vpncmd/vpncmd
+
+Or you can also use VPN Client Manager GUI Tool on other Windows PC to
+connect to the VPN Client remotely. You can download the GUI Tool
+from http://www.softether-download.com/.
+
+
+************************************
+Thank You Using SoftEther VPN !
+By SoftEther VPN Open-Source Project
+http://www.softether.org/
diff --git a/BUILD_WINDOWS.TXT b/BUILD_WINDOWS.TXT
new file mode 100644
index 00000000..06e64f72
--- /dev/null
+++ b/BUILD_WINDOWS.TXT
@@ -0,0 +1,42 @@
+How to build SoftEther VPN for Windows
+======================================
+
+
+Requirements
+------------
+
+You need to install the following software to build SoftEther VPN for Windows.
+
+- Microsoft Windows XP, Vista, 7, 8 or later.
+- Microsoft Visual Studio 2008.
+
+* Note:
+ Visual Studio 2008 is required to build SoftEther VPN on Windows.
+ Visual Studio 2010, 2012 or 2013 is currently not supported.
+ Visual Studio 2008 Express Edition is not supported.
+ Standard Edition, Professional Edition, Team System or Team Suite is
+ required.
+
+
+Full Build Instructions
+-----------------------
+
+The following steps will build all SoftEther VPN program files, and also build
+the installer packages of SoftEther VPN. It is very easy.
+
+1. Run the "BuildAll.cmd" batch file in the "src" directory.
+2. Wait until the building process will complete.
+3. The built files are stored on the "output" directory.
+
+
+Partly Build, Debug or Development Instructions on Visual Studio 2008
+---------------------------------------------------------------------
+
+If you are a programmer, you can open the SoftEther VPN solution file
+with Visual Studio 2008 to customize. Open "src\SEVPN.sln" and enjoy it.
+
+
+************************************
+Thank You Using SoftEther VPN !
+By SoftEther VPN Open-Source Project
+http://www.softether.org/
diff --git a/LICENSE b/LICENSE
index d7f10513..52c728da 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,339 +1,2350 @@
-GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- {description}
- Copyright (C) {year} {fullname}
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- {signature of Ty Coon}, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
+SoftEther VPN Server, Client and Bridge are free software, and released as
+open-source. You can redistribute them and/or modify them under the terms of
+the GNU General Public License version 2 as published by the Free Software
+Foundation.
+
+Copyright (c) 2012-2014 Daiyuu Nobori.
+Copyright (c) 2012-2014 SoftEther Project at University of Tsukuba, Japan.
+Copyright (c) 2012-2014 SoftEther Corporation.
+All Rights Reserved.
+http://www.softether.org/
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License version 2 as published by the Free
+Software Foundation.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License version 2
+along with this program; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+Neither the name of SoftEther nor the names of its contributors may be used to
+endorse or promote products derived from this software without specific prior
+written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN, UNDER
+JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY, MERGE, PUBLISH,
+DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS SOFTWARE, THAT ANY
+JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS SOFTWARE OR ITS CONTENTS,
+AGAINST US (SOFTETHER PROJECT, SOFTETHER CORPORATION, DAIYUU NOBORI OR OTHER
+SUPPLIERS), OR ANY JURIDICAL DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND
+OF USING, COPYING, MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING,
+AND/OR SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO EXCLUSIVE
+JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO, JAPAN. YOU MUST WAIVE
+ALL DEFENSES OF LACK OF PERSONAL JURISDICTION AND FORUM NON CONVENIENS.
+PROCESS MAY BE SERVED ON EITHER PARTY IN THE MANNER AUTHORIZED BY APPLICABLE
+LAW OR COURT RULE.
+
+USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS SOFTWARE
+INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES PROHIBIT ENCRYPTED
+COMMUNICATIONS. USING THIS SOFTWARE IN OTHER COUNTRIES MIGHT BE RESTRICTED.
+
+THE FOLLOWING GPLV2 CONDITIONS APPLY ON ALL SOFTETHER VPN PROGRAMS WHICH ARE
+DEVELOPED BY SOFTETHER VPN PROJECT.
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your freedom to
+share and change it. By contrast, the GNU General Public License is intended
+to guarantee your freedom to share and change free software--to make sure the
+software is free for all its users. This General Public License applies to
+most of the Free Software Foundation's software and to any other program whose
+authors commit to using it. (Some other Free Software Foundation software is
+covered by the GNU Lesser General Public License instead.) You can apply it
+to your programs, too.
+
+ When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the freedom to
+distribute copies of free software (and charge for this service if you wish),
+that you receive source code or can get it if you want it, that you can change
+the software or use pieces of it in new free programs; and that you know you
+can do these things.
+
+ To protect your rights, we need to make restrictions that forbid anyone to
+deny you these rights or to ask you to surrender the rights. These
+restrictions translate to certain responsibilities for you if you distribute
+copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether gratis or
+for a fee, you must give the recipients all the rights that you have. You
+must make sure that they, too, receive or can get the source code. And you
+must show them these terms so they know their rights.
+
+ We protect your rights with two steps: (1) copyright the software, and (2)
+offer you this license which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain that
+everyone understands that there is no warranty for this free software. If the
+software is modified by someone else and passed on, we want its recipients to
+know that what they have is not the original, so that any problems introduced
+by others will not reflect on the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software patents. We
+wish to avoid the danger that redistributors of a free program will
+individually obtain patent licenses, in effect making the program proprietary.
+To prevent this, we have made it clear that any patent must be licensed for
+everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and modification
+follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains a notice
+placed by the copyright holder saying it may be distributed under the terms of
+this General Public License. The "Program", below, refers to any such program
+or work, and a "work based on the Program" means either the Program or any
+derivative work under copyright law: that is to say, a work containing the
+Program or a portion of it, either verbatim or with modifications and/or
+translated into another language. (Hereinafter, translation is included
+without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not covered
+by this License; they are outside its scope. The act of running the Program
+is not restricted, and the output from the Program is covered only if its
+contents constitute a work based on the Program (independent of having been
+made by running the Program). Whether that is true depends on what the Program
+does.
+
+ 1. You may copy and distribute verbatim copies of the Program's source code
+as you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this License
+and to the absence of any warranty; and give any other recipients of the
+Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you may
+at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion of it,
+thus forming a work based on the Program, and copy and distribute such
+modifications or work under the terms of Section 1 above, provided that you
+also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices stating
+that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in whole
+or in part contains or is derived from the Program or any part thereof, to be
+licensed as a whole at no charge to all third parties under the terms of this
+License.
+
+ c) If the modified program normally reads commands interactively when run,
+you must cause it, when started running for such interactive use in the most
+ordinary way, to print or display an announcement including an appropriate
+copyright notice and a notice that there is no warranty (or else, saying that
+you provide a warranty) and that users may redistribute the program under
+these conditions, and telling the user how to view a copy of this License.
+(Exception: if the Program itself is interactive but does not normally print
+such an announcement, your work based on the Program is not required to print
+an announcement.)
+
+These requirements apply to the modified work as a whole. If identifiable
+sections of that work are not derived from the Program, and can be reasonably
+considered independent and separate works in themselves, then this License,
+and its terms, do not apply to those sections when you distribute them as
+separate works. But when you distribute the same sections as part of a whole
+which is a work based on the Program, the distribution of the whole must be on
+the terms of this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your
+rights to work written entirely by you; rather, the intent is to exercise the
+right to control the distribution of derivative or collective works based on
+the Program.
+
+In addition, mere aggregation of another work not based on the Program with
+the Program (or with a work based on the Program) on a volume of a storage or
+distribution medium does not bring the other work under the scope of this
+License.
+
+ 3. You may copy and distribute the Program (or a work based on it, under
+Section 2) in object code or executable form under the terms of Sections 1 and
+2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable source
+code, which must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three years, to
+give any third party, for a charge no more than your cost of physically
+performing source distribution, a complete machine-readable copy of the
+corresponding source code, to be distributed under the terms of Sections 1 and
+2 above on a medium customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer to
+distribute corresponding source code. (This alternative is allowed only for
+noncommercial distribution and only if you received the program in object code
+or executable form with such an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for making
+modifications to it. For an executable work, complete source code means all
+the source code for all modules it contains, plus any associated interface
+definition files, plus the scripts used to control compilation and
+installation of the executable. However, as a special exception, the source
+code distributed need not include anything that is normally distributed (in
+either source or binary form) with the major components (compiler, kernel, and
+so on) of the operating system on which the executable runs, unless that
+component itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to
+copy from a designated place, then offering equivalent access to copy the
+source code from the same place counts as distribution of the source code,
+even though third parties are not compelled to copy the source along with the
+object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program except as
+expressly provided under this License. Any attempt otherwise to copy, modify,
+sublicense or distribute the Program is void, and will automatically terminate
+your rights under this License. However, parties who have received copies, or
+rights, from you under this License will not have their licenses terminated so
+long as such parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not signed
+it. However, nothing else grants you permission to modify or distribute the
+Program or its derivative works. These actions are prohibited by law if you
+do not accept this License. Therefore, by modifying or distributing the
+Program (or any work based on the Program), you indicate your acceptance of
+this License to do so, and all its terms and conditions for copying,
+distributing or modifying the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the original
+licensor to copy, distribute or modify the Program subject to these terms and
+conditions. You may not impose any further restrictions on the recipients'
+exercise of the rights granted herein. You are not responsible for enforcing
+compliance by third parties to this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or otherwise)
+that contradict the conditions of this License, they do not excuse you from
+the conditions of this License. If you cannot distribute so as to satisfy
+simultaneously your obligations under this License and any other pertinent
+obligations, then as a consequence you may not distribute the Program at all.
+For example, if a patent license would not permit royalty-free redistribution
+of the Program by all those who receive copies directly or indirectly through
+you, then the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply and
+the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or
+other property right claims or to contest validity of any such claims; this
+section has the sole purpose of protecting the integrity of the free software
+distribution system, which is implemented by public license practices. Many
+people have made generous contributions to the wide range of software
+distributed through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing to
+distribute software through any other system and a licensee cannot impose that
+choice.
+
+This section is intended to make thoroughly clear what is believed to be a
+consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in certain
+countries either by patents or by copyrighted interfaces, the original
+copyright holder who places the Program under this License may add an explicit
+geographical distribution limitation excluding those countries, so that
+distribution is permitted only in or among countries not thus excluded. In
+such case, this License incorporates the limitation as if written in the body
+of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions of
+the General Public License from time to time. Such new versions will be
+similar in spirit to the present version, but may differ in detail to address
+new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any later
+version", you have the option of following the terms and conditions either of
+that version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of this License,
+you may choose any version ever published by the Free Software Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free programs
+whose distribution conditions are different, write to the author to ask for
+permission. For software which is copyrighted by the Free Software
+Foundation, write to the Free Software Foundation; we sometimes make
+exceptions for this. Our decision will be guided by the two goals of
+preserving the free status of all derivatives of our free software and of
+promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
+THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
+STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE
+PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
+PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE,
+YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO
+LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR
+THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+Note that the above copyright notices and use conditions do not apply on the
+software components listed in below which are included in this Software. When
+you use or distribute Software with including these libraries, you have to
+follow the conditions of these libraries.
+
+These library's copyright notices and conditions are following;
+
+-------------------
+
+BitVisor(R) VPN Client Module (IPsec Driver):
+Copyright (c) 2007, 2008 University of Tsukuba.
+Copyright (C) 2007, 2008 National Institute of Information and Communications
+Technology.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+3. Neither the name of the University of Tsukuba nor the names of its
+contributors may be used to endorse or promote products derived from this
+software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------
+
+Microsoft(R) C Runtime Library:
+(c) 2007 Microsoft Corporation. All Rights Reserved.
+
+-------------------
+
+RSA Security Inc. PKCS #11 Cryptographic Token Interface (Cryptoki):
+
+License to copy and use this software is granted provided that it is
+identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+(Cryptoki)" in all material mentioning or referencing this software.
+
+License is also granted to make and use derivative works provided that such
+works are identified as "derived from the RSA Security Inc. PKCS #11
+Cryptographic Token Interface (Cryptoki)" in all material mentioning or
+referencing the derived work.
+
+RSA Security Inc. makes no representations concerning either the
+merchantability of this software or the suitability of this software for any
+particular purpose. It is provided "as is" without express or implied warranty
+of any kind.
+
+-------------------
+
+WinPcap:
+Copyright (c) 2001 - 2003 NetGroup, Politecnico di Torino (Italy)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+3. Neither the name of the Politecnico di Torino nor the names of its
+contributors may be used to endorse or promote products derived from this
+software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------
+
+libedit:
+Copyright (c) 1992, 1993 The Regents of the University of California. All
+rights reserved.
+
+This code is derived from software contributed to Berkeley by Christos Zoulas
+of Cornell University.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------
+
+libiconv:
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your freedom to
+share and change it. By contrast, the GNU General Public Licenses are intended
+to guarantee your freedom to share and change free software--to make sure the
+software is free for all its users.
+
+ This license, the Library General Public License, applies to some specially
+designated Free Software Foundation software, and to any other libraries whose
+authors decide to use it. You can use it for your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the freedom to
+distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new free
+programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid anyone to
+deny you these rights or to ask you to surrender the rights. These
+restrictions translate to certain responsibilities for you if you distribute
+copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis or for
+a fee, you must give the recipients all the rights that we gave you. You must
+make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide complete object
+files to the recipients so that they can relink them with the library, after
+making changes to the library and recompiling it. And you must show them these
+terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright the
+library, and (2) offer you this license which gives you legal permission to
+copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain that
+everyone understands that there is no warranty for this free library. If the
+library is modified by someone else and passed on, we want its recipients to
+know that what they have is not the original version, so that any problems
+introduced by others will not reflect on the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software patents. We
+wish to avoid the danger that companies distributing free software will
+individually obtain patent licenses, thus in effect transforming the program
+into proprietary software. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary GNU
+General Public License, which was designed for utility programs. This license,
+the GNU Library General Public License, applies to certain designated
+libraries. This license is quite different from the ordinary one; be sure to
+read it in full, and don't assume that anything in it is the same as in the
+ordinary license.
+
+ The reason we have a separate public license for some libraries is that they
+blur the distinction we usually make between modifying or adding to a program
+and simply using it. Linking a program with a library, without changing the
+library, is in some sense simply using the library, and is analogous to
+running a utility program or application program. However, in a textual and
+legal sense, the linked executable is a combined work, a derivative of the
+original library, and the ordinary General Public License treats it as such.
+
+ Because of this blurred distinction, using the ordinary General Public
+License for libraries did not effectively promote software sharing, because
+most developers did not use the libraries. We concluded that weaker conditions
+might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the users
+of those programs of all benefit from the free status of the libraries
+themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while preserving
+your freedom as a user of such programs to change the free libraries that are
+incorporated in them. (We have not seen how to achieve this as regards changes
+in header files, but we have achieved it as regards changes in the actual
+functions of the Library.) The hope is that this will lead to faster
+development of free libraries.
+
+ The precise terms and conditions for copying, distribution and modification
+follow. Pay close attention to the difference between a "work based on the
+library" and a "work that uses the library". The former contains code derived
+from the library, while the latter only works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary General
+Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which contains a
+notice placed by the copyright holder or other authorized party saying it may
+be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data prepared so
+as to be conveniently linked with application programs (which use some of
+those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work which has
+been distributed under these terms. A "work based on the Library" means either
+the Library or any derivative work under copyright law: that is to say, a work
+containing the Library or a portion of it, either verbatim or with
+modifications and/or translated straightforwardly into another language.
+(Hereinafter, translation is included without limitation in the term
+"modification".)
+
+ "Source code" for a work means the preferred form of the work for making
+modifications to it. For a library, complete source code means all the source
+code for all modules it contains, plus any associated interface definition
+files, plus the scripts used to control compilation and installation of the
+library.
+
+ Activities other than copying, distribution and modification are not covered
+by this License; they are outside its scope. The act of running a program
+using the Library is not restricted, and output from such a program is covered
+only if its contents constitute a work based on the Library (independent of
+the use of the Library in a tool for writing it). Whether that is true depends
+on what the Library does and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's complete
+source code as you receive it, in any medium, provided that you conspicuously
+and appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this License
+and to the absence of any warranty; and distribute a copy of this License
+along with the Library.
+
+ You may charge a fee for the physical act of transferring a copy, and you
+may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Library or any portion of it,
+thus forming a work based on the Library, and copy and distribute such
+modifications or work under the terms of Section 1 above, provided that you
+also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices stating
+that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no charge to all
+third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a table
+of data to be supplied by an application program that uses the facility, other
+than as an argument passed when the facility is invoked, then you must make a
+good faith effort to ensure that, in the event an application does not supply
+such function or table, the facility still operates, and performs whatever
+part of its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has a
+purpose that is entirely well-defined independent of the application.
+Therefore, Subsection 2d requires that any application-supplied function or
+table used by this function must be optional: if the application does not
+supply it, the square root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If identifiable
+sections of that work are not derived from the Library, and can be reasonably
+considered independent and separate works in themselves, then this License,
+and its terms, do not apply to those sections when you distribute them as
+separate works. But when you distribute the same sections as part of a whole
+which is a work based on the Library, the distribution of the whole must be on
+the terms of this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your
+rights to work written entirely by you; rather, the intent is to exercise the
+right to control the distribution of derivative or collective works based on
+the Library.
+
+In addition, mere aggregation of another work not based on the Library with
+the Library (or with a work based on the Library) on a volume of a storage or
+distribution medium does not bring the other work under the scope of this
+License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do this,
+you must alter all the notices that refer to this License, so that they refer
+to the ordinary GNU General Public License, version 2, instead of to this
+License. (If a newer version than version 2 of the ordinary GNU General Public
+License has appeared, then you can specify that version instead if you wish.)
+Do not make any other change in these notices.
+
+ Once this change is made in a given copy, it is irreversible for that copy,
+so the ordinary GNU General Public License applies to all subsequent copies
+and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of the Library
+into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or derivative of
+it, under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you accompany it with the complete
+corresponding machine-readable source code, which must be distributed under
+the terms of Sections 1 and 2 above on a medium customarily used for software
+interchange.
+
+ If distribution of object code is made by offering access to copy from a
+designated place, then offering equivalent access to copy the source code from
+the same place satisfies the requirement to distribute the source code, even
+though third parties are not compelled to copy the source along with the
+object code.
+
+ 5. A program that contains no derivative of any portion of the Library, but
+is designed to work with the Library by being compiled or linked with it, is
+called a "work that uses the Library". Such a work, in isolation, is not a
+derivative work of the Library, and therefore falls outside the scope of this
+License.
+
+ However, linking a "work that uses the Library" with the Library creates an
+executable that is a derivative of the Library (because it contains portions
+of the Library), rather than a "work that uses the library". The executable is
+therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file that is
+part of the Library, the object code for the work may be a derivative work of
+the Library even though the source code is not.
+Whether this is true is especially significant if the work can be linked
+without the Library, or if the work is itself a library. The threshold for
+this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data structure
+layouts and accessors, and small macros and small inline functions (ten lines
+or less in length), then the use of the object file is unrestricted,
+regardless of whether it is legally a derivative work. (Executables containing
+this object code plus portions of the Library will still fall under Section
+6.)
+
+ Otherwise, if the work is a derivative of the Library, you may distribute
+the object code for the work under the terms of Section 6. Any executables
+containing that work also fall under Section 6, whether or not they are linked
+directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or link a
+"work that uses the Library" with the Library to produce a work containing
+portions of the Library, and distribute that work under terms of your choice,
+provided that the terms permit modification of the work for the customer's own
+use and reverse engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the Library
+is used in it and that the Library and its use are covered by this License.
+You must supply a copy of this License. If the work during execution displays
+copyright notices, you must include the copyright notice for the Library among
+them, as well as a reference directing the user to the copy of this License.
+Also, you must do one of these things:
+
+ a) Accompany the work with the complete corresponding machine-readable
+source code for the Library including whatever changes were used in the work
+(which must be distributed under Sections 1 and 2 above) ; and, if the work is
+an executable linked with the Library, with the complete machine-readable
+"work that uses the Library", as object code and/or source code, so that the
+user can modify the Library and then relink to produce a modified executable
+containing the modified Library. (It is understood that the user who changes
+the contents of definitions files in the Library will not necessarily be able
+to recompile the application to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at least three
+years, to give the same user the materials specified in Subsection 6a, above,
+for a charge no more than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy from a
+designated place, offer equivalent access to copy the above specified
+materials from the same place.
+
+ d) Verify that the user has already received a copy of these materials or
+that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the Library"
+must include any data and utility programs needed for reproducing the
+executable from it. However, as a special exception, the source code
+distributed need not include anything that is normally distributed (in either
+source or binary form) with the major components (compiler, kernel, and so on)
+of the operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+ It may happen that this requirement contradicts the license restrictions of
+other proprietary libraries that do not normally accompany the operating
+system. Such a contradiction means you cannot use both them and the Library
+together in an executable that you distribute.
+
+ 7. You may place library facilities that are a work based on the Library
+side-by-side in a single library together with other library facilities not
+covered by this License, and distribute such a combined library, provided that
+the separate distribution of the work based on the Library and of the other
+library facilities is otherwise permitted, and provided that you do these two
+things:
+
+ a) Accompany the combined library with a copy of the same work based on
+the Library, uncombined with any other library facilities. This must be
+distributed under the terms of the Sections above.
+
+ b) Give prominent notice with the combined library of the fact that part
+of it is a work based on the Library, and explaining where to find the
+accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute the
+Library except as expressly provided under this License. Any attempt otherwise
+to copy, modify, sublicense, link with, or distribute the Library is void, and
+will automatically terminate your rights under this License. However, parties
+who have received copies, or rights, from you under this License will not have
+their licenses terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not signed
+it. However, nothing else grants you permission to modify or distribute the
+Library or its derivative works. These actions are prohibited by law if you do
+not accept this License. Therefore, by modifying or distributing the Library
+(or any work based on the Library), you indicate your acceptance of this
+License to do so, and all its terms and conditions for copying, distributing
+or modifying the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the original
+licensor to copy, distribute, link with or modify the Library subject to these
+terms and conditions. You may not impose any further restrictions on the
+recipients' exercise of the rights granted herein. You are not responsible for
+enforcing compliance by third parties to this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or otherwise)
+that contradict the conditions of this License, they do not excuse you from
+the conditions of this License. If you cannot distribute so as to satisfy
+simultaneously your obligations under this License and any other pertinent
+obligations, then as a consequence you may not distribute the Library at all.
+For example, if a patent license would not permit royalty-free redistribution
+of the Library by all those who receive copies directly or indirectly through
+you, then the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply, and
+the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or
+other property right claims or to contest validity of any such claims; this
+section has the sole purpose of protecting the integrity of the free software
+distribution system which is implemented by public license practices. Many
+people have made generous contributions to the wide range of software
+distributed through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing to
+distribute software through any other system and a licensee cannot impose that
+choice.
+
+This section is intended to make thoroughly clear what is believed to be a
+consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in certain
+countries either by patents or by copyrighted interfaces, the original
+copyright holder who places the Library under this License may add an explicit
+geographical distribution limitation excluding those countries, so that
+distribution is permitted only in or among countries not thus excluded. In
+such case, this License incorporates the limitation as if written in the body
+of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new versions of
+the Library General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and "any later
+version", you have the option of following the terms and conditions either of
+that version or of any later version published by the Free Software
+Foundation. If the Library does not specify a license version number, you may
+choose any version ever published by the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free programs
+whose distribution conditions are incompatible with these, write to the author
+to ask for permission. For software which is copyrighted by the Free Software
+Foundation, write to the Free Software Foundation; we sometimes make
+exceptions for this. Our decision will be guided by the two goals of
+preserving the free status of all derivatives of our free software and of
+promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
+THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
+STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE
+LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
+PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE,
+YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO
+LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR
+THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+-------------------
+
+ncurses:
+Copyright (c) 1998-2005,2006 Free Software Foundation, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, distribute with
+modifications, sublicense, and/or sell copies of the Software, and to permit
+persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name(s) of the above copyright holders
+shall not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization.
+
+-------------------
+
+OpenSSL:
+OpenSSL License
+Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+3. All advertising materials mentioning features or use of this software must
+display the following acknowledgment: "This product includes software
+developed by the OpenSSL Project for use in the OpenSSL Toolkit.
+(http://www.openssl.org/)"
+
+4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+endorse or promote products derived from this software without prior written
+permission. For written permission, please contact openssl-core@openssl.org.
+
+5. Products derived from this software may not be called "OpenSSL" nor may
+"OpenSSL" appear in their names without prior written permission of the
+OpenSSL Project.
+
+6. Redistributions of any form whatsoever must retain the following
+acknowledgment: "This product includes software developed by the OpenSSL
+Project for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+
+THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY EXPRESSED
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE OpenSSL PROJECT OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+This product includes cryptographic software written by Eric Young
+(eay@cryptsoft.com). This product includes software written by Tim Hudson
+(tjh@cryptsoft.com).
+
+Original SSLeay License
+Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) All rights reserved.
+
+This package is an SSL implementation written by Eric Young
+(eay@cryptsoft.com). The implementation was written so as to conform with
+Netscapes SSL.
+
+This library is free for commercial and non-commercial use as long as the
+following conditions are aheared to. The following conditions apply to all
+code found in this distribution, be it the RC4, RSA, lhash, DES, etc., code;
+not just the SSL code. The SSL documentation included with this distribution
+is covered by the same copyright terms except that the holder is Tim Hudson
+(tjh@cryptsoft.com).
+
+Copyright remains Eric Young's, and as such any Copyright notices in the code
+are not to be removed. If this package is used in a product, Eric Young should
+be given attribution as the author of the parts of the library used. This can
+be in the form of a textual message at program startup or in documentation
+(online or textual) provided with the package.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the copyright notice, this list
+of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software must
+display the following acknowledgement: "This product includes cryptographic
+software written by Eric Young (eay@cryptsoft.com)" The word 'cryptographic'
+can be left out if the rouines from the library being used are not
+cryptographic related :-).
+4. If you include any Windows specific code (or a derivative thereof) from the
+apps directory (application code) you must include an acknowledgement: "This
+product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+
+THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The licence and distribution terms for any publically available version or
+derivative of this code cannot be changed. i.e. this code cannot simply be
+copied and put under another distribution licence [including the GNU Public
+Licence.]
+
+-------------------
+
+zlib:
+Acknowledgments:
+ The deflate format used by zlib was defined by Phil Katz. The deflate and
+zlib specifications were written by L. Peter Deutsch. Thanks to all the people
+who reported problems and suggested various improvements in zlib; they are too
+numerous to cite here.
+
+Copyright notice:
+ (C) 1995-2004 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the
+use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+claim that you wrote the original software. If you use this software in a
+product, an acknowledgment in the product documentation would be appreciated
+but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+If you use the zlib library in a product, we would appreciate *not* receiving
+lengthy legal documents to sign. The sources are provided for free but without
+warranty of any kind. The library has been entirely written by Jean-loup
+Gailly and Mark Adler; it does not include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include in
+the file ChangeLog history information documenting your changes. Please read
+the FAQ for more information on the distribution of modified source versions.
+
+-------------------
+
+Intel AESNI Sample Library:
+
+Copyright (c) 2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+* Neither the name of Intel Corporation nor the names of its contributors may
+be used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Issue Date: Aug 6, 2010
+
+-------------------
+
+NOTES
+
+SoftEther provides source codes of some GPL/LGPL/other libraries listed above
+on its web server. Anyone can download, use and re-distribute them under
+individual licenses which are contained on each archive file, available from
+the following URL:
+http://uploader.softether.co.jp/src/
+
+
+
+BitVisor(R) VPN Client Module (IPsec Driver):
+Copyright (c) 2007, 2008 University of Tsukuba.
+Copyright (C) 2007, 2008 National Institute of Information and Communications
+Technology.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+3. Neither the name of the University of Tsukuba nor the names of its
+contributors may be used to endorse or promote products derived from this
+software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------
+
+Microsoft(R) C Runtime Library:
+(c) 2007 Microsoft Corporation. All Rights Reserved.
+
+-------------------
+
+RSA Security Inc. PKCS #11 Cryptographic Token Interface (Cryptoki):
+
+License to copy and use this software is granted provided that it is
+identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+(Cryptoki)" in all material mentioning or referencing this software.
+
+License is also granted to make and use derivative works provided that such
+works are identified as "derived from the RSA Security Inc. PKCS #11
+Cryptographic Token Interface (Cryptoki)" in all material mentioning or
+referencing the derived work.
+
+RSA Security Inc. makes no representations concerning either the
+merchantability of this software or the suitability of this software for any
+particular purpose. It is provided "as is" without express or implied warranty
+of any kind.
+
+-------------------
+
+WinPcap:
+Copyright (c) 2001 - 2003 NetGroup, Politecnico di Torino (Italy)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+3. Neither the name of the Politecnico di Torino nor the names of its
+contributors may be used to endorse or promote products derived from this
+software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------
+
+libedit:
+Copyright (c) 1992, 1993 The Regents of the University of California. All
+rights reserved.
+
+This code is derived from software contributed to Berkeley by Christos Zoulas
+of Cornell University.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------
+
+libiconv:
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your freedom to
+share and change it. By contrast, the GNU General Public Licenses are intended
+to guarantee your freedom to share and change free software--to make sure the
+software is free for all its users.
+
+ This license, the Library General Public License, applies to some specially
+designated Free Software Foundation software, and to any other libraries whose
+authors decide to use it. You can use it for your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the freedom to
+distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new free
+programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid anyone to
+deny you these rights or to ask you to surrender the rights. These
+restrictions translate to certain responsibilities for you if you distribute
+copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis or for
+a fee, you must give the recipients all the rights that we gave you. You must
+make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide complete object
+files to the recipients so that they can relink them with the library, after
+making changes to the library and recompiling it. And you must show them these
+terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright the
+library, and (2) offer you this license which gives you legal permission to
+copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain that
+everyone understands that there is no warranty for this free library. If the
+library is modified by someone else and passed on, we want its recipients to
+know that what they have is not the original version, so that any problems
+introduced by others will not reflect on the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software patents. We
+wish to avoid the danger that companies distributing free software will
+individually obtain patent licenses, thus in effect transforming the program
+into proprietary software. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary GNU
+General Public License, which was designed for utility programs. This license,
+the GNU Library General Public License, applies to certain designated
+libraries. This license is quite different from the ordinary one; be sure to
+read it in full, and don't assume that anything in it is the same as in the
+ordinary license.
+
+ The reason we have a separate public license for some libraries is that they
+blur the distinction we usually make between modifying or adding to a program
+and simply using it. Linking a program with a library, without changing the
+library, is in some sense simply using the library, and is analogous to
+running a utility program or application program. However, in a textual and
+legal sense, the linked executable is a combined work, a derivative of the
+original library, and the ordinary General Public License treats it as such.
+
+ Because of this blurred distinction, using the ordinary General Public
+License for libraries did not effectively promote software sharing, because
+most developers did not use the libraries. We concluded that weaker conditions
+might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the users
+of those programs of all benefit from the free status of the libraries
+themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while preserving
+your freedom as a user of such programs to change the free libraries that are
+incorporated in them. (We have not seen how to achieve this as regards changes
+in header files, but we have achieved it as regards changes in the actual
+functions of the Library.) The hope is that this will lead to faster
+development of free libraries.
+
+ The precise terms and conditions for copying, distribution and modification
+follow. Pay close attention to the difference between a "work based on the
+library" and a "work that uses the library". The former contains code derived
+from the library, while the latter only works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary General
+Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which contains a
+notice placed by the copyright holder or other authorized party saying it may
+be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data prepared so
+as to be conveniently linked with application programs (which use some of
+those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work which has
+been distributed under these terms. A "work based on the Library" means either
+the Library or any derivative work under copyright law: that is to say, a work
+containing the Library or a portion of it, either verbatim or with
+modifications and/or translated straightforwardly into another language.
+(Hereinafter, translation is included without limitation in the term
+"modification".)
+
+ "Source code" for a work means the preferred form of the work for making
+modifications to it. For a library, complete source code means all the source
+code for all modules it contains, plus any associated interface definition
+files, plus the scripts used to control compilation and installation of the
+library.
+
+ Activities other than copying, distribution and modification are not covered
+by this License; they are outside its scope. The act of running a program
+using the Library is not restricted, and output from such a program is covered
+only if its contents constitute a work based on the Library (independent of
+the use of the Library in a tool for writing it). Whether that is true depends
+on what the Library does and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's complete
+source code as you receive it, in any medium, provided that you conspicuously
+and appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this License
+and to the absence of any warranty; and distribute a copy of this License
+along with the Library.
+
+ You may charge a fee for the physical act of transferring a copy, and you
+may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Library or any portion of it,
+thus forming a work based on the Library, and copy and distribute such
+modifications or work under the terms of Section 1 above, provided that you
+also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices stating
+that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no charge to all
+third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a table
+of data to be supplied by an application program that uses the facility, other
+than as an argument passed when the facility is invoked, then you must make a
+good faith effort to ensure that, in the event an application does not supply
+such function or table, the facility still operates, and performs whatever
+part of its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has a
+purpose that is entirely well-defined independent of the application.
+Therefore, Subsection 2d requires that any application-supplied function or
+table used by this function must be optional: if the application does not
+supply it, the square root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If identifiable
+sections of that work are not derived from the Library, and can be reasonably
+considered independent and separate works in themselves, then this License,
+and its terms, do not apply to those sections when you distribute them as
+separate works. But when you distribute the same sections as part of a whole
+which is a work based on the Library, the distribution of the whole must be on
+the terms of this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your
+rights to work written entirely by you; rather, the intent is to exercise the
+right to control the distribution of derivative or collective works based on
+the Library.
+
+In addition, mere aggregation of another work not based on the Library with
+the Library (or with a work based on the Library) on a volume of a storage or
+distribution medium does not bring the other work under the scope of this
+License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do this,
+you must alter all the notices that refer to this License, so that they refer
+to the ordinary GNU General Public License, version 2, instead of to this
+License. (If a newer version than version 2 of the ordinary GNU General Public
+License has appeared, then you can specify that version instead if you wish.)
+Do not make any other change in these notices.
+
+ Once this change is made in a given copy, it is irreversible for that copy,
+so the ordinary GNU General Public License applies to all subsequent copies
+and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of the Library
+into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or derivative of
+it, under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you accompany it with the complete
+corresponding machine-readable source code, which must be distributed under
+the terms of Sections 1 and 2 above on a medium customarily used for software
+interchange.
+
+ If distribution of object code is made by offering access to copy from a
+designated place, then offering equivalent access to copy the source code from
+the same place satisfies the requirement to distribute the source code, even
+though third parties are not compelled to copy the source along with the
+object code.
+
+ 5. A program that contains no derivative of any portion of the Library, but
+is designed to work with the Library by being compiled or linked with it, is
+called a "work that uses the Library". Such a work, in isolation, is not a
+derivative work of the Library, and therefore falls outside the scope of this
+License.
+
+ However, linking a "work that uses the Library" with the Library creates an
+executable that is a derivative of the Library (because it contains portions
+of the Library), rather than a "work that uses the library". The executable is
+therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file that is
+part of the Library, the object code for the work may be a derivative work of
+the Library even though the source code is not.
+Whether this is true is especially significant if the work can be linked
+without the Library, or if the work is itself a library. The threshold for
+this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data structure
+layouts and accessors, and small macros and small inline functions (ten lines
+or less in length), then the use of the object file is unrestricted,
+regardless of whether it is legally a derivative work. (Executables containing
+this object code plus portions of the Library will still fall under Section
+6.)
+
+ Otherwise, if the work is a derivative of the Library, you may distribute
+the object code for the work under the terms of Section 6. Any executables
+containing that work also fall under Section 6, whether or not they are linked
+directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or link a
+"work that uses the Library" with the Library to produce a work containing
+portions of the Library, and distribute that work under terms of your choice,
+provided that the terms permit modification of the work for the customer's own
+use and reverse engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the Library
+is used in it and that the Library and its use are covered by this License.
+You must supply a copy of this License. If the work during execution displays
+copyright notices, you must include the copyright notice for the Library among
+them, as well as a reference directing the user to the copy of this License.
+Also, you must do one of these things:
+
+ a) Accompany the work with the complete corresponding machine-readable
+source code for the Library including whatever changes were used in the work
+(which must be distributed under Sections 1 and 2 above) ; and, if the work is
+an executable linked with the Library, with the complete machine-readable
+"work that uses the Library", as object code and/or source code, so that the
+user can modify the Library and then relink to produce a modified executable
+containing the modified Library. (It is understood that the user who changes
+the contents of definitions files in the Library will not necessarily be able
+to recompile the application to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at least three
+years, to give the same user the materials specified in Subsection 6a, above,
+for a charge no more than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy from a
+designated place, offer equivalent access to copy the above specified
+materials from the same place.
+
+ d) Verify that the user has already received a copy of these materials or
+that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the Library"
+must include any data and utility programs needed for reproducing the
+executable from it. However, as a special exception, the source code
+distributed need not include anything that is normally distributed (in either
+source or binary form) with the major components (compiler, kernel, and so on)
+of the operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+ It may happen that this requirement contradicts the license restrictions of
+other proprietary libraries that do not normally accompany the operating
+system. Such a contradiction means you cannot use both them and the Library
+together in an executable that you distribute.
+
+ 7. You may place library facilities that are a work based on the Library
+side-by-side in a single library together with other library facilities not
+covered by this License, and distribute such a combined library, provided that
+the separate distribution of the work based on the Library and of the other
+library facilities is otherwise permitted, and provided that you do these two
+things:
+
+ a) Accompany the combined library with a copy of the same work based on
+the Library, uncombined with any other library facilities. This must be
+distributed under the terms of the Sections above.
+
+ b) Give prominent notice with the combined library of the fact that part
+of it is a work based on the Library, and explaining where to find the
+accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute the
+Library except as expressly provided under this License. Any attempt otherwise
+to copy, modify, sublicense, link with, or distribute the Library is void, and
+will automatically terminate your rights under this License. However, parties
+who have received copies, or rights, from you under this License will not have
+their licenses terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not signed
+it. However, nothing else grants you permission to modify or distribute the
+Library or its derivative works. These actions are prohibited by law if you do
+not accept this License. Therefore, by modifying or distributing the Library
+(or any work based on the Library), you indicate your acceptance of this
+License to do so, and all its terms and conditions for copying, distributing
+or modifying the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the original
+licensor to copy, distribute, link with or modify the Library subject to these
+terms and conditions. You may not impose any further restrictions on the
+recipients' exercise of the rights granted herein. You are not responsible for
+enforcing compliance by third parties to this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or otherwise)
+that contradict the conditions of this License, they do not excuse you from
+the conditions of this License. If you cannot distribute so as to satisfy
+simultaneously your obligations under this License and any other pertinent
+obligations, then as a consequence you may not distribute the Library at all.
+For example, if a patent license would not permit royalty-free redistribution
+of the Library by all those who receive copies directly or indirectly through
+you, then the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply, and
+the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or
+other property right claims or to contest validity of any such claims; this
+section has the sole purpose of protecting the integrity of the free software
+distribution system which is implemented by public license practices. Many
+people have made generous contributions to the wide range of software
+distributed through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing to
+distribute software through any other system and a licensee cannot impose that
+choice.
+
+This section is intended to make thoroughly clear what is believed to be a
+consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in certain
+countries either by patents or by copyrighted interfaces, the original
+copyright holder who places the Library under this License may add an explicit
+geographical distribution limitation excluding those countries, so that
+distribution is permitted only in or among countries not thus excluded. In
+such case, this License incorporates the limitation as if written in the body
+of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new versions of
+the Library General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and "any later
+version", you have the option of following the terms and conditions either of
+that version or of any later version published by the Free Software
+Foundation. If the Library does not specify a license version number, you may
+choose any version ever published by the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free programs
+whose distribution conditions are incompatible with these, write to the author
+to ask for permission. For software which is copyrighted by the Free Software
+Foundation, write to the Free Software Foundation; we sometimes make
+exceptions for this. Our decision will be guided by the two goals of
+preserving the free status of all derivatives of our free software and of
+promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
+THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
+STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE
+LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
+PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE,
+YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO
+LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR
+THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+-------------------
+
+ncurses:
+Copyright (c) 1998-2005,2006 Free Software Foundation, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, distribute with
+modifications, sublicense, and/or sell copies of the Software, and to permit
+persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name(s) of the above copyright holders
+shall not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization.
+
+-------------------
+
+OpenSSL:
+OpenSSL License
+Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+3. All advertising materials mentioning features or use of this software must
+display the following acknowledgment: "This product includes software
+developed by the OpenSSL Project for use in the OpenSSL Toolkit.
+(http://www.openssl.org/)"
+
+4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+endorse or promote products derived from this software without prior written
+permission. For written permission, please contact openssl-core@openssl.org.
+
+5. Products derived from this software may not be called "OpenSSL" nor may
+"OpenSSL" appear in their names without prior written permission of the
+OpenSSL Project.
+
+6. Redistributions of any form whatsoever must retain the following
+acknowledgment: "This product includes software developed by the OpenSSL
+Project for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+
+THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY EXPRESSED
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE OpenSSL PROJECT OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+This product includes cryptographic software written by Eric Young
+(eay@cryptsoft.com). This product includes software written by Tim Hudson
+(tjh@cryptsoft.com).
+
+Original SSLeay License
+Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) All rights reserved.
+
+This package is an SSL implementation written by Eric Young
+(eay@cryptsoft.com). The implementation was written so as to conform with
+Netscapes SSL.
+
+This library is free for commercial and non-commercial use as long as the
+following conditions are aheared to. The following conditions apply to all
+code found in this distribution, be it the RC4, RSA, lhash, DES, etc., code;
+not just the SSL code. The SSL documentation included with this distribution
+is covered by the same copyright terms except that the holder is Tim Hudson
+(tjh@cryptsoft.com).
+
+Copyright remains Eric Young's, and as such any Copyright notices in the code
+are not to be removed. If this package is used in a product, Eric Young should
+be given attribution as the author of the parts of the library used. This can
+be in the form of a textual message at program startup or in documentation
+(online or textual) provided with the package.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the copyright notice, this list
+of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software must
+display the following acknowledgement: "This product includes cryptographic
+software written by Eric Young (eay@cryptsoft.com)" The word 'cryptographic'
+can be left out if the rouines from the library being used are not
+cryptographic related :-).
+4. If you include any Windows specific code (or a derivative thereof) from the
+apps directory (application code) you must include an acknowledgement: "This
+product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+
+THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The licence and distribution terms for any publically available version or
+derivative of this code cannot be changed. i.e. this code cannot simply be
+copied and put under another distribution licence [including the GNU Public
+Licence.]
+
+-------------------
+
+zlib:
+Acknowledgments:
+ The deflate format used by zlib was defined by Phil Katz. The deflate and
+zlib specifications were written by L. Peter Deutsch. Thanks to all the people
+who reported problems and suggested various improvements in zlib; they are too
+numerous to cite here.
+
+Copyright notice:
+ (C) 1995-2004 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the
+use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+claim that you wrote the original software. If you use this software in a
+product, an acknowledgment in the product documentation would be appreciated
+but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+If you use the zlib library in a product, we would appreciate *not* receiving
+lengthy legal documents to sign. The sources are provided for free but without
+warranty of any kind. The library has been entirely written by Jean-loup
+Gailly and Mark Adler; it does not include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include in
+the file ChangeLog history information documenting your changes. Please read
+the FAQ for more information on the distribution of modified source versions.
+
+-------------------
+
+Intel AESNI Sample Library:
+
+Copyright (c) 2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+* Neither the name of Intel Corporation nor the names of its contributors may
+be used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Issue Date: Aug 6, 2010
+
+-------------------
+
+NOTES WRITTEN BY SOFTETHER CORPORATION
+
+Note for users of non-Windows version of PacketiX VPN: The enumerated bundle
+of License Agreements above are copies of original License Agreements of each
+library programs which PacketiX VPN uses. PacketiX VPN is not a delivered work
+from these libraries. PacketiX VPN is a separated work from the libraries, but
+it may call functions of the libraries (whether or not PacketiX VPN calls such
+functions are depended on the user's intention to link them or not on user's
+side computer). While some libraries indicate GPL or LGPL as a condition to
+re-distribute, PacketiX VPN is not license under GPL nor LGPL. Therefore, we
+took special care not to make PacketiX VPN become delivered works of any GPL
+or LGPL libraries. In order to achieve that, both PacketiX VPN and GPL/LGPL
+libraries are distributed with isolated forms (means that any program files of
+PacketiX VPN are not bound nor linked to any GPL/LGPL libraries). If a user of
+PacketiX VPN wants to link GPL/LGPL libraries by their own decisions,
+operations and responsibilities, he may do that on his computer. However, if a
+delivered work under copyright law is created as a result of such an
+operation, such a delivered work must not re-distributed to other people,
+because it may violate GPL/LGPL libraries' conditions.
+
+Note for users of Windows version of PacketiX VPN: For technical reason, the
+above texts are exactly same as a file which is also contained on the
+non-Windows version of PacketiX VPN. Actually, the Windows version of PacketiX
+VPN has no relations to any GPL/LGPL libraries enumerated above.
+
+SoftEther Corporation provides source codes of some GPL/LGPL/other libraries
+listed above on its web server. Anyone can download, use and re-distribute
+them under individual licenses which are contained on each archive file,
+available from the following URL:
+http://uploader.softether.co.jp/src/
+
+
+
+THE IMPORTANT NOTICES ABOUT SOFTETHER VPN
+
+FUNCTIONS OF VPN COMMUNICATIONS EMBEDDED ON THIS SOFTWARE ARE VERY POWERFUL
+THAN EVER. THIS STRONG VPN ABILITY WILL BRING YOU HUGE BENEFITS. HOWEVER, IF
+YOU MISUSE THIS SOFTWARE, IT MIGHT DAMAGES YOURSELF. IN ORDER TO AVOID SUCH
+RISKS, THIS DOCUMENT ACCOUNTS IMPORTANT NOTICES FOR CUSTOMERS WHO ARE WILLING
+TO USE THIS SOFTWARE. THE FOLLOWING INSTRUCTIONS ARE VERY IMPORTANT. READ AND
+UNDERSTAND IT CAREFULLY. ADDITIONALLY, IF YOU ARE PLANNING TO USE THE DYNAMIC
+DNS, THE NAT TRAVERSAL OR THE VPN AZURE FUNCTIONS, READ THE SECTION 3.5
+CAREFULLY. THESE FUNCTIONS ARE FREE SERVICES PROVIDED VIA THE INTERNET, ARE
+NOT GUARANTEED, AND ARE NOT INTENDED TO BE USED FOR BUSINESS OR COMMERCIAL
+USE. DO NOT USE THESE SERVICES FOR YOUR BUSINESS OR COMMERCIAL USE.
+
+
+1. VPN Communication Protocols
+1.1. SoftEther VPN Protocol
+SoftEther VPN can perform VPN communication. Unlike traditional VPN protocols,
+SoftEther VPN has an implementation of the newly-designed "SoftEther VPN
+Protocol (SE-VPN Protocol)" . SE-VPN protocol encapsulates any Ethernet
+packets into a HTTPS (HTTP over SSL) connection. Therefore SE-VPN protocol can
+communicate beyond firewalls even if the firewall is configured to block
+traditional VPN packets by network administrator. SE-VPN protocol is designed
+and implemented to comply TLS 1.0 (RFC 5246) and HTTPS (RFC 2818). However, it
+sometimes have different behavior to RFCs. If you are a network administrator
+and want to block SE-VPN protocols on the firewall, you can adopt a
+"white-list" policy on the firewall to filter any TCP or UDP packets on the
+border except explicitly allowed packets towards specific web sites and
+servers.
+
+1.2. NAT Traversal Function
+Generally, if you use traditional VPN systems you have to request a network
+administrator to make the NAT or firewall to "open" or "relay" specific TCP or
+UDP ports. However, there are demands somehow to eliminate such working costs
+on network administrators. In order to satisfy such demands, SoftEther VPN has
+the newly-implemented "NAT Traversal" function. NAT Traversal is enabled by
+default. A SoftEther VPN Server running on the computer behind NAT or firewall
+can accept VPN connections from the Internet, without any special
+configurations on firewalls or NATs. If you want to disable the NAT Traversal
+function, modify the "DisableNatTraversal" to "true" on the configuration file
+of SoftEther VPN Server. In order to disable it on the client-side, append
+"/tcp" suffix on the destination hostname.
+
+1.3. Dynamic DNS Function
+Traditional legacy VPN system requires a static global IP address on the VPN
+server. In consideration of shortage of global IP addresses, SoftEther
+Corporation implements the "Dynamic DNS Function" on SoftEther VPN Server.
+Dynamic DNS is enabled by default. Dynamic DNS function notify the current
+global IP address of the PC to the Dynamic DNS Servers which are operated by
+SoftEther Corporation. A globally-unique hostname (FQDN) such as
+"abc.softether.net" ( "abc" varies as unique per a user) will be assigned on
+the VPN Server. If you tell this unique hostname to a VPN user, the user can
+specify it as the destination VPN Sever hostname on the VPN Client and will be
+able to connect the VPN Server. No IP addresses are required to know
+beforehand. If the IP address of the VPN Server varies, the registered IP
+address related to the hostname of Dynamic DNS service will be changed
+automatically. By this mechanism, no longer need a static global IP address
+which costs monthly to ISPs. You can use consumer-level inexpensive Internet
+connection with dynamic IP address in order to operate an enterprise-level VPN
+system. If you want to disable Dynamic DNS, specify "true" on the "Disabled"
+items of the "DDnsClient" directive on the SoftEther VPN Server configuration
+file. * Note for residents in People's Republic of China: If your VPN Server
+is running on the People's Republic of China, the DNS suffix will be replaced
+to "sedns.cn" domain. The "sedns.cn" domain is the service possessed and
+operated by "Beijing Daiyuu SoftEther Technology Co., Ltd" which is a
+Chinese-local enterprise.
+
+1.4. VPN over ICMP / VPN over DNS functions
+If you want to make a VPN connection between SoftEther VPN Client / Bridge and
+SoftEther VPN Server, but if TCP and UDP packets are prohibited by the
+firewall, then you can encapsulates payloads into "ICMP" (as known as Ping) or
+"DNS" packets. This function can realize a VPN connection by using ICMP or DNS
+even if the firewall or router blocks every TCP or UDP connections. VPN over
+ICMP / VPN over DNS functions are designed to comply standard ICMP and DNS
+specifications as possible, however it sometimes has a behavior not to fully
+comply them. Therefore, few poor-quality routers may be caused a
+memory-overflow or something troubles when a lot of ICMP or DNS packets are
+passed, and such routers sometimes freezes or reboots. It might affects other
+users on the same network. To avoid such risks, append the suffix "/tcp" on
+the destination hostname which is specified on the VPN-client side to disable
+VPN over ICMP / DNS functions.
+
+1.5. VPN Azure Cloud Service
+If your SoftEther VPN Server is placed behind the NAT or firwall, and by some
+reason you cannot use NAT Traversal function, Dynamic DNS function or VPN over
+ICMP/DNS function, you can use VPN Azure Clouse Service. SoftEther Corporation
+operates VPN Azure Cloud on Internet. After the VPN Server makes a connection
+to the VPN Azure Cloud, the hostname "abc.vpnazure.net" ( "abc" is a unique
+hostname) can be specified to connect to the VPN Server via the VPN Azure
+Cloud. Practically, such a hostname is pointing a global IP address of one of
+cloud servers which are operated by SoftEther Corporation. If A VPN Client
+connects to such a VPN Azure host, then the VPN Azure host will relay all
+traffics between the VPN Client and the VPN Server. VPN Azure is disabled by
+default. You can activate it easily by using VPN Server Configuration Tool.
+
+1.6. UDP Acceleration
+SoftEther VPN has the UDP Acceleration Function. If a VPN consists of two
+sites detects that UDP channel can be established, UDP will be automatically
+used. By this function, throughput of UDP increases. If direct UDP channel can
+be established, direct UDP packets will be used. However, if there is
+something obstacles such as firewalls or NATs, the "UDP Hole Punching"
+technology will be used, instead. The "UDP Hole Punching" uses the cloud
+servers which SoftEther Corporation operates on Internet. UDP Acceleration can
+be disabled anytime by setting up so on the VPN-client side.
+
+
+2. VPN Software
+2.1. SoftEther VPN Client
+If you use SoftEther VPN Client on Windows, the Virtual Network Adapter device
+driver will be installed on Windows. The Virtual Network Adapter is
+implemented as a kernel-mode driver for Windows. The driver is
+digitally-signed by a certificate issued by VeriSign, Inc. and also sub-signed
+by Symantec Corporation. A message to ask you want to sure install the driver
+might be popped up on the screen. SoftEther VPN Client may response the
+message if possible. SoftEther VPN Client also optimizes the configuration of
+MMCSS (Multimedia Class Scheduler Service) on Windows. You can undo the
+optimizations of MMCSS afterwards.
+
+2.2. SoftEther VPN Server / Bridge
+If you use SoftEther VPN Server / Bridge on Windows with "Local Bridge"
+functions, you have to install the low-level Ethernet packet processing driver
+on the computer. The driver is digitally-signed by a certificate issued by
+VeriSign, Inc. and also sub-signed by Symantec Corporation. SoftEther VPN
+Server / Bridge may disable the TCP/IP offloading features on the physical
+network adapter for Local Bridge function. In Windows Vista / 2008 or greater
+version, VPN Server may inject a packet-filter driver which complies Windows
+Filter Platform (WPF) specification into the kernel in order to provide IPsec
+function. The packet-filter driver will be loaded available only if IPsec
+function is enabled. Once you enables IPsec function of SoftEther VPN Server,
+the built-in IPsec function of Windows will be disabled. After you disabled
+IPsec function of SoftEther VPN Server, then the built-in IPsec function of
+Windows will revive. In order to provide the Local Bridge function, SoftEther
+VPN Server / Bridge disables the TCP/IP offloading function on the operating
+system.
+
+2.3. User-mode Installation
+You can install SoftEther VPN Server and SoftEther VPN Bridge as "User-mode"
+on Windows. In other words, even if you don't have Windows system
+administrator's privileges, you can install SoftEther VPN as a normal user.
+User-mode install will disable a few functions, however other most functions
+work well. Therefore, for example, an employee can install SoftEther VPN
+Server on the computer in the office network, and he will be able to connect
+to the server from his home. In order to realize such a system by user-self,
+no system administrative privileges are required in the view-point of
+technical. However, breaking rules of the company to install software on the
+computer without authority might be regarded as an unfavorable behavior. If
+you are an employee and belong to the company, and the company-policy
+prohibits installing software or making communications towards Internet
+without permission, you have to obtain a permission from the network
+administrator or the executive officer of your company in advance to install
+SoftEther VPN. If you install VPN Server / Bridge as User-mode, an icon will
+be appeared on the Windows task-tray. If you feel that the icon disturbs you,
+you can hide it by your operation. However, you must not exploit this hiding
+function to install VPN Server on other person's computer as a spyware. Such
+behavior might be an offence against the criminal law.
+
+2.4. Keep Alive Function
+SoftEther VPN Server and SoftEther VPN Bridge has Keep Alive Function by
+default. The purpose of this function is to sustain the Internet line active.
+The function transmits UDP packets with a random-byte-array-payload
+periodically. This function is useful to avoid automatic disconnection on
+mobile or dial-up connections. You can disable Keep Alive Function anytime.
+
+2.5. Uninstallation
+The uninstallation process of SoftEther VPN software will delete all program
+files. However, non-program files (such as files and data which are generated
+by running of programs) ) will not be deleted. For technical reason, the exe
+and resource files of uninstaller might remain. Such remaining files never
+affects to use the computer, however you can delete it manually. Kernel-mode
+drivers might not be deleted, however such drivers will not be loaded after
+the next boot of Windows. You can use "sc" command of Windows to delete
+kernel-mode drivers manually.
+
+2.6. Security
+You should set the administrator's password on SoftEther VPN Server / Bridge
+after installation. If you neglect to do it, another person can access to
+SoftEther VPN Server / Bridge and can set the password without your
+permission. This caution might be also applied on SoftEther VPN Client for
+Linux.
+
+2.7. Automatic Update Notification
+SoftEther VPN software for Windows has an automatic update notification
+function. It accesses to the SoftEther Update server periodically to check
+whether or not the latest version of software is released. If the latest
+version is released, the notification message will be popped up on the screen.
+In order to achieve this purpose, the version, language settings, the unique
+identifier, the IP address of your computer and the hostname of VPN Server
+which is connected to will be sent to the SoftEther Update server. No personal
+information will be sent. Automatic Update Notification is enabled by default,
+however you can disable it on the configuration screen. The setting whether
+turned on or turned off will be saved individually corresponding to each
+destination VPN server, by VPN Server Manager.
+
+2.8. Virtual NAT Function
+A Virtual Hub on SoftEther VPN Server / Bridge has "Virtual NAT Function" .
+Virtual NAT Function can share a single IP address on the physical network by
+multiple private IP address of VPN Clients. There are two operation mode of
+Virtual NAT: User-mode and Kernel-mode. In the user-mode operation, Virtual
+NAT shares an IP address which is assigned on the host operating system.
+Unlike user-mode, the kernel-mode operation attempts to find DHCP servers on
+the physical network. If there are two or more physical networks, a DHCP
+server will be sought automatically for each segments serially. If a DHCP
+server found, and an IP address is acquired, the IP address will be used by
+the Virtual NAT. In this case, an IP entry as a DHCP client will be registered
+on the IP pool of the physical DHCP Server. The physical default gateway and
+the DNS server will be used by the Virtual NAT in order to communicate with
+hosts in Internet. In kernel-mode operation, a Virtual Hub has a virtual MAC
+address which is operating on the physical Ethernet segment. In order to check
+the connectivity to Internet, SoftEther VPN periodically sends DNS query
+packet to resolve the IP address of host "www.yahoo.com" or "www.baidu.com" ,
+and attempts to connect to the TCP port 80 of such a resulted IP address for
+connectivity check.
+
+2.9. Unattended Installation of Kernel-mode Components
+When SoftEther VPN will detect a necessity to install the kernel-mode
+components on Windows, a confirmation message will be appeared by Windows
+system. In this occasion, SoftEther VPN software will switch to the Unattended
+Installation mode in order to respond "Yes" to Windows. This is a solution to
+prevent dead-locks when a remote-administration is performed from remote
+place.
+
+2.10. Windows Firewall
+SoftEther VPN software will register itself as a safe-program. Such an entry
+will be remain after the uninstallation. You can remove it manually from the
+Control Panel of Windows.
+
+
+3. Internet Services
+3.1. Internet Services which are provided by SoftEther Corporation
+SoftEther Corporation provides Dynamic DNS, NAT Traversal and VPN Azure server
+services on the Internet. These services are free of charge. Customers can
+access to the services by using SoftEther VPN software, via Internet. These
+service will be planned to be available from Open-Source version of "SoftEther
+VPN" which will be released in the future.
+
+3.2. Sent Information and Privacy Protection
+SoftEther VPN software may send an IP address, hostname, the version of VPN
+software on the customer's computer to the cloud service operated by SoftEther
+Corporation, in order to use the above services. These sending of information
+are minimal necessary to use the services. No personal information will be
+sent. SoftEther Corporation records log files of the cloud service servers for
+90 days at least with the received information. Such logs will be used for
+troubleshooting and other legitimate activities. SoftEther Corporation may
+provide logs to a public servant of Japanese government who are belonging to
+courts, police stations and the prosecutor's office, in order to comply such
+authorities' order. (Every Japanese public servants are liable by law to keep
+the information close.) Moreover, the IP addresses or other information will
+be processed statistically and provided to the public, not to expose the each
+concrete IP address, in order to release the release of research activities.
+
+3.3. Communication Data via VPN Azure Service
+Regardless of the above 3.2 rule, if the customer sends or receives VPN
+packets using VPN Azure Cloud Service, the actual payloads will stored and
+forwarded via the volatile memory of the servers for very short period. Such a
+behavior is naturally needed to provide the "VPN relay service" . No payloads
+will be recorded on "fixed" storages such as hard-drives. However, the
+"Wiretapping for Criminals Procedures Act" (The 137th legislation ruled on
+August 18, 1999 in Japan) requires telecommunication companies to allow the
+Japanese government authority to conduct a wire-tapping on the line. VPN Azure
+Servers which are physically placed on Japan are subjects of this law.
+
+3.4. Comply to Japanese Telecommunication Laws
+SoftEther Corporation complies with Japanese Telecommunication Laws as
+necessary to provide online services via Internet.
+
+3.5. Free and Academic Experiment Services
+SoftEther provides Dynamic DNS, NAT Traversal and VPN Azure as academic
+experiment services. Therefore, there services can be used for free of charge.
+These services are not parts of "SoftEther VPN Software Products" . These
+services are provided without any warranty. The services may be suspended or
+discontinued by technical or operational matters. In such occasions, users
+will not be able to use the services. A user have to understand such risks,
+and to acknowledge that such risks are borne by a user-self. SoftEther will
+never be liable to results or damages of use or unable-to-use of the service.
+Even if the user has already paid the license-fee of the commercial version of
+SoftEther VPN, such paid fees don't include any fees of these services.
+Therefore, if the online services will stop or be discontinued, no refunds or
+recoveries of damages will be provided by SoftEther Corporation.
+
+3.6. DNS Proxy Cloud Servers
+In some regions, when a user uses Internet, a DNS query sometimes broken or
+lost when it is passing through the ISP line. If SoftEther VPN Server, Client
+or Bridge detects a possibility that the accessing to the actual VPN server
+might be unstable, then DNS queries will be also transferred to the DNS proxy
+cloud servers which are operated by SoftEther Corporation. A DNS proxy cloud
+server will respond DNS queries with answering correct a IP address.
+
+
+4. General Cautions
+4.1. Needs an Approval from Network Administrator
+SoftEther VPN has powerful functions which don't require special settings by
+network administrators. For example, you need not to ask the administrator to
+configure the existing firewall in order to "open" a TCP/UDP port. Such
+characteristic features are for the purpose to eliminate working times and
+costs of network administrators, and avoid misconfiguration-risks around the
+tasks to open specific exception ports on the firewall. However, any employees
+belong to the company have to obtain an approval from the network
+administrator before installs SoftEther VPN. If your network administrator
+neglects to provide such an approval, you can consider to take an approval
+from an upper authority. (For example, executive officer of the company.) If
+you use SoftEther VPN without any approvals from the authority of your
+company, you might have disadvantage. SoftEther Corporation will be never
+liable for results or damages of using SoftEther VPN.
+
+4.2. Observe Laws of Your Country
+If your country's law prohibits the use of encryption, you have to disable the
+encryption function of SoftEther VPN by yourself. Similarly, in some countries
+or regions, some functions of SoftEther VPN might be prohibited to use by
+laws. Other countries' laws are none of SoftEther Corporation's concern
+because SoftEther Corporation is an enterprise which is located and registered
+in Japan physically. For example, there might be a risk that a part of
+SoftEther VPN conflicts an existing patent which is valid only on the specific
+region. SoftEther Corporation has no interests in such specific region outside
+Japan's territory. Therefore, if you want to use SoftEther VPN in regions
+outside Japan, you have to be careful not to violate third-person's rights.
+You have to verify the legitimacy of the use of SoftEther VPN in the specific
+region before you actually use it in such region. By nature, there are almost
+200 countries in the World, and each country's law is different each other. It
+is practically impossible to verify every countries' laws and regulations and
+make the software comply with all countries' laws in advance to release the
+software. Therefore SoftEther Corporation has verified the legitimacy of
+SoftEther VPN against the laws and regulations of only Japan. If a user uses
+SoftEther VPN in a specific country, and damaged by public servants of the
+government authority, SoftEther Corporation will never be liable to recover or
+compensate such damages or criminal responsibilities.
+
+
+5. VPN Gate Academic Experiment Project
+(This chapter applies only on SoftEther VPN software package which contains
+the extension plug-in for VPN Gate Academic Experiment Project.)
+5.1. About VPN Gate Academic Experiment Project
+VPN Gate Academic Experiment Project is an online service operated for just
+the academic research purpose at the graduate school of University of Tsukuba,
+Japan. The purpose of this research is to expend our knowledge about the
+"Global Distributed Public VPN Relay Server" (GDPVRS) technology. For details,
+please visit http://www.vpngate.net/.
+
+5.2. About VPN Gate Service
+SoftEther VPN Server and SoftEther VPN Client may contain "VPN Gate Service"
+program. However, VPN Gate Service is disabled by default.
+VPN Gate Service should be activated and enabled by the voluntary intention of
+the owner of the computer which SoftEther VPN Server or SoftEther VPN Client
+is installed on. After you activate VPN Gate Service, the computer will be
+start to serve as a part of the Global Distributed Public VPN Relay Servers.
+The IP address, hostname and related information of the computer will be sent
+and registered to the directory server of VPN Gate Academic Experiment
+Project, and they will be published and disclosed to the public. This
+mechanism will allow any VPN Gate Client software's user to connect to the VPN
+Gate Service running on your computer. While the VPN session between a VPN
+Gate Client and your VPN Gate Service is established, the VPN Gate Client's
+user can send/receive any IP packets towards the Internet via the VPN Gate
+Service. The global IP address of the VPN Gate Service's hosing computer will
+be used as the source IP address of such communications which a VPN Gate
+Client initiates.
+VPN Gate Service will send some information to the VPN Gate Academic
+Experiment Service Directory Server. The information includes the operator's
+information which described in section 5.5, logging settings, uptime,
+operating system version, type of protocol, port numbers, quality information,
+statistical information, VPN Gate clients' log history data (includes dates,
+IP addresses, version numbers and IDs) and the version of the software. These
+information will be exposed on the directory. VPN Gate Service also receives a
+key for encoding which is described on the chapter 5.9 from the directory
+server.
+
+5.3. Details of VPN Gate Service's Behavior
+If you enable VPN Gate Service manually, which is disabled by default, the
+"VPNGATE" Virtual Hub will be created on the SoftEther VPN Server. If you are
+using SoftEther VPN Client and attempt to active VPN Gate Service on it, an
+equivalent program to SoftEther VPN Server will be invoked on the same process
+of SoftEther VPN Client, and the "VPNGATE" Virtual Hub will be created. The
+"VPNGATE" Virtual Hub contains a user named "VPN" by default which permits
+anyone on the Internet to make a VPN connection to the Virtual Hub. Once a VPN
+Client connects to the "VPNGATE" Virtual Hub, any communication between the
+user and the Internet will pass through the Virtual Hub, and
+transmitted/received using the physical network interface on the computer
+which SoftEther VPN Server (or SoftEther VPN Client) is running on. This will
+cause the result that a destination host specified by the VPN Client will
+identify that the source of the communication has initiated from the VPN Gate
+Service's hosting computer's IP address. However, for safety, any packets
+which destinations are within 192.168.0.0/255.255.0.0, 172.16.0.0/255.240.0.0
+or 10.0.0.0/255.0.0.0 will be blocked by the "VPNGATE" Virtual Hub in order to
+protect your local network. Therefore, if you run VPN Gate Service on your
+corporate network or private network, it is safe because anonymous VPN Client
+users will not be permitted to access such private networks. VPN Gate Service
+also serves as relay for accessing to the VPN Gate Directory Server.
+In order to make VPN Gate Service familiar with firewalls and NATs, it opens
+an UDP port by using the NAT Traversal function which is described on the
+section 1.2. It also opens and listens on some TCP ports, and some TCP and UDP
+ports will be specified as the target port of Universal Plug and Play (UPnP)
+Port Transfer entries which are requested to your local routers. UPnP request
+packets will be sent periodically. Some routers keep such an opened TCP/UDP
+port permanently on the device. If you wish to close them, do it manually.
+VPN Gate Service also provides the mirror-site function for www.vpngate.net.
+This is a mechanism that a copy of the latest contents from www.vpngate.net
+will be hosted by the mirror-site tiny HTTP server which is running on the VPN
+Gate Service program. It will register itself on the mirror-sites list in
+www.vpngate.net. However, it never relays any other communications which are
+not towards www.vpngate.net.
+
+5.4. Communication between Internet via VPN Gate Service
+VPN Gate Service provides a routing between users and the Internet, by using
+the Virtual NAT Function which is described on the section 2.8. VPN Gate
+Service sends polling Ping packets to the server which is located on
+University of Tsukuba, and the Google Public DNS Server which is identified as
+8.8.8.8, in order to check the latest quality of your Internet line. VPN Gate
+Service also sends and receives a lot of random packets to/from the Speed Test
+Server on University of Tsukuba. These quality data will be reported to VPN
+Gate Directory Server, automatically and periodically. The result will be
+saved and disclosed to the public. These periodical polling communication are
+adjusted not to occupy the Internet line, however in some circumstances they
+might occupy the line.
+
+5.5. Operator's Information of VPN Gate Service
+If you activate VPN Gate Service on your computer, the computer will be a part
+of the Global Distributed Public VPN Relay Servers. Therefore, the Operator's
+administrative information of your VPN Gate Service should be reported and
+registered on the VPN Gate Service Directory. Operator's information contains
+the name of the operator and the abuse-reporting contact e-mail address. These
+information can be inputted on the screen if the VPN Gate configuration.
+Inputted information will be transmitted to the VPN Gate Directory Server,
+stored and disclosed to the public. So you have to be careful to input
+information. By the way, until you specify something as the operator's
+information, the computer's hostname will be used automatically as the field
+of the name of the operator, by appending the "'s owner" string after the
+hostname.
+
+5.6. Observe Laws to Operate VPN Gate Service
+In some countries or regions, a user who is planning to activate and operate
+VPN Gate Service, he are mandated to obtain a license or register a service
+from/to the government. If your region has such a regulation, you must fulfill
+mandated process before activating VPN Gate Service in advance. Neither the
+developers nor operators of the VPN Gate Academic Experiment Project will be
+liable for legal/criminal responsibilities or damages which are occurred from
+failure to comply your local laws.
+
+5.7. Protect Privacy of Communication
+Most of countries have a law which requires communication service's operators,
+including VPN Gate Service operators, to protect the privacy of communication
+of third-persons. When you operate VPN Gate Service, you must always protect
+user's privacy.
+
+5.8. Packet Logs
+The packet logging function is implemented on VPN Gate Service. It records
+essential headers of major TCP/IP packets which are transmitted via the
+Virtual Hub. This function will be helpful to investigate the "original IP
+address" of the initiator of communication who was a connected user of your
+VPN Gate Service, by checking the packet logs and the connection logs. The
+packet logs are recorded only for such legitimate investigates purpose. Do not
+peek nor leak packet logs except the rightful purpose. Such act will be
+violate the section 5.7.
+
+5.9. Packet Logs Automatic Archiving and Encoding Function
+The VPN Gate Academic Experiment Service is operated and running under the
+Japanese constitution and laws. The Japanese constitution laws demand strictly
+protection over the privacy of communication. Because this service is under
+Japanese rules, the program of VPN Gate Service implements this "Automatic Log
+File Encoding" protection mechanism, and enabled by default.
+The VPN Gate Service is currently configured to encode packet log files which
+has passed two or more weeks automatically, by default. In order to protect
+privacy of communication, if a packet log file is once encoded, even the
+administrator of the local computer cannot censor the packet log file. This
+mechanism protects privacy of end-users of VPN Gate Service.
+You can change the VPN Gate Service setting to disable this automatic encoding
+function. Then packet log files will never be encoded even after two weeks
+passed. In such a configuration, all packet logs will remain as plain-text on
+the disk. Therefore you have to take care not to violate user's privacy.
+If you are liable to decode an encoded packet log files (for example: a VPN
+Gate Service's user illegally abused your VPN Gate Service and you have to
+decode the packet logs in order to comply the laws), contact the administrator
+of the VPN Gate Academic Experiment Service at Graduate School of University
+of Tsukuba, Japan. You can find the contact address at
+http://www.vpngate.net/. The administrator of VPN Gate Service will respond to
+decode the packet logs if there is an appropriate and legal request from court
+or other judicial authorities, according to laws.
+
+5.10. Caution if You Operate VPN Gate Service in the Japan's Territories
+When a user operates VPN Gate Service in the Japan's territories, such an act
+may be regulated under the Japanese Telecommunication Laws if the operation is
+a subject to the law. However, in such a circumstance, according to the
+"Japanese Telecommunication Business Compete Manual [supplemental version]" ,
+non- profitable operations of communications are not identified as a
+"telecommunication business" . So usual operators of VPN Gate Service are not
+subjects to "telecommunication business operators" , and not be mandated to
+register to the government. Even so, legalities to protect the privacy of
+communication still imposed. As a conclusion, if you operate VPN Gate Service
+in the Japan's Territories, you must not leak the secrets of communications
+which are transmitted via your operating VPN Gate Service.
+
+5.11. VPN Gate Client
+If SoftEther VPN Client contains the VPN Gate Client plug-in, you can use it
+to obtain the list of current operating VPN Gate Service servers in the
+Internet, and make a VPN connection to a specific server on the list.
+VPN Gate Client always keeps the latest list of the VPN Gate Services
+periodically. Be careful if you are using a pay-per-use Internet line.
+When you start the VPN Gate Client software, the screen which asks you
+activate or not VPN Gate Service will be appeared. For details of VPN Gate
+Service, read the above sections.
+
+5.12. Caution before Joining or Exploiting VPN Gate Academic Experiment
+Project
+The VPN Gate Academic Experiment Service is operated as a research project at
+the graduate school on University of Tsukuba, Japan. The service is governed
+under the Japanese laws. Other countries' laws are none of our concerns nor
+responsibilities.
+By nature, there are almost 200 countries in the World, with different laws.
+It is impossible to verify every countries' laws and regulations and make the
+software comply with all countries' laws in advance to release the software.
+If a user uses VPN Gate service in a specific country, and damaged by public
+servants of the authority, the developer of either the service or software
+will never be liable to recover or compensate such damages or criminal
+responsibilities.
+By using this software and service, the user must observe all concerned laws
+and rules with user's own responsibility. The user will be completely liable
+to any damages and responsibilities which are results of using this software
+and service, regardless of either inside or outside of Japan's territory.
+If you don't agree nor understand the above warnings, do not use any of VPN
+Gate Academic Experiment Service functions.
+VPN Gate is a research project for just academic purpose only. VPN Gate was
+developed as a plug-in for SoftEther VPN and UT-VPN. However, all parts of VPN
+Gate were developed on this research project at University of Tsukuba. Any
+parts of VPN Gate are not developed by SoftEther Corporation. The VPN Gate
+Research Project is not a subject to be led, operated, promoted nor guaranteed
+by SoftEther Corporation.
+
+
diff --git a/LICENSE.TXT b/LICENSE.TXT
new file mode 100644
index 00000000..52c728da
--- /dev/null
+++ b/LICENSE.TXT
@@ -0,0 +1,2350 @@
+SoftEther VPN Server, Client and Bridge are free software, and released as
+open-source. You can redistribute them and/or modify them under the terms of
+the GNU General Public License version 2 as published by the Free Software
+Foundation.
+
+Copyright (c) 2012-2014 Daiyuu Nobori.
+Copyright (c) 2012-2014 SoftEther Project at University of Tsukuba, Japan.
+Copyright (c) 2012-2014 SoftEther Corporation.
+All Rights Reserved.
+http://www.softether.org/
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License version 2 as published by the Free
+Software Foundation.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License version 2
+along with this program; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+Neither the name of SoftEther nor the names of its contributors may be used to
+endorse or promote products derived from this software without specific prior
+written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN, UNDER
+JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY, MERGE, PUBLISH,
+DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS SOFTWARE, THAT ANY
+JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS SOFTWARE OR ITS CONTENTS,
+AGAINST US (SOFTETHER PROJECT, SOFTETHER CORPORATION, DAIYUU NOBORI OR OTHER
+SUPPLIERS), OR ANY JURIDICAL DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND
+OF USING, COPYING, MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING,
+AND/OR SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO EXCLUSIVE
+JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO, JAPAN. YOU MUST WAIVE
+ALL DEFENSES OF LACK OF PERSONAL JURISDICTION AND FORUM NON CONVENIENS.
+PROCESS MAY BE SERVED ON EITHER PARTY IN THE MANNER AUTHORIZED BY APPLICABLE
+LAW OR COURT RULE.
+
+USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS SOFTWARE
+INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES PROHIBIT ENCRYPTED
+COMMUNICATIONS. USING THIS SOFTWARE IN OTHER COUNTRIES MIGHT BE RESTRICTED.
+
+THE FOLLOWING GPLV2 CONDITIONS APPLY ON ALL SOFTETHER VPN PROGRAMS WHICH ARE
+DEVELOPED BY SOFTETHER VPN PROJECT.
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your freedom to
+share and change it. By contrast, the GNU General Public License is intended
+to guarantee your freedom to share and change free software--to make sure the
+software is free for all its users. This General Public License applies to
+most of the Free Software Foundation's software and to any other program whose
+authors commit to using it. (Some other Free Software Foundation software is
+covered by the GNU Lesser General Public License instead.) You can apply it
+to your programs, too.
+
+ When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the freedom to
+distribute copies of free software (and charge for this service if you wish),
+that you receive source code or can get it if you want it, that you can change
+the software or use pieces of it in new free programs; and that you know you
+can do these things.
+
+ To protect your rights, we need to make restrictions that forbid anyone to
+deny you these rights or to ask you to surrender the rights. These
+restrictions translate to certain responsibilities for you if you distribute
+copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether gratis or
+for a fee, you must give the recipients all the rights that you have. You
+must make sure that they, too, receive or can get the source code. And you
+must show them these terms so they know their rights.
+
+ We protect your rights with two steps: (1) copyright the software, and (2)
+offer you this license which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain that
+everyone understands that there is no warranty for this free software. If the
+software is modified by someone else and passed on, we want its recipients to
+know that what they have is not the original, so that any problems introduced
+by others will not reflect on the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software patents. We
+wish to avoid the danger that redistributors of a free program will
+individually obtain patent licenses, in effect making the program proprietary.
+To prevent this, we have made it clear that any patent must be licensed for
+everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and modification
+follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains a notice
+placed by the copyright holder saying it may be distributed under the terms of
+this General Public License. The "Program", below, refers to any such program
+or work, and a "work based on the Program" means either the Program or any
+derivative work under copyright law: that is to say, a work containing the
+Program or a portion of it, either verbatim or with modifications and/or
+translated into another language. (Hereinafter, translation is included
+without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not covered
+by this License; they are outside its scope. The act of running the Program
+is not restricted, and the output from the Program is covered only if its
+contents constitute a work based on the Program (independent of having been
+made by running the Program). Whether that is true depends on what the Program
+does.
+
+ 1. You may copy and distribute verbatim copies of the Program's source code
+as you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this License
+and to the absence of any warranty; and give any other recipients of the
+Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you may
+at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion of it,
+thus forming a work based on the Program, and copy and distribute such
+modifications or work under the terms of Section 1 above, provided that you
+also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices stating
+that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in whole
+or in part contains or is derived from the Program or any part thereof, to be
+licensed as a whole at no charge to all third parties under the terms of this
+License.
+
+ c) If the modified program normally reads commands interactively when run,
+you must cause it, when started running for such interactive use in the most
+ordinary way, to print or display an announcement including an appropriate
+copyright notice and a notice that there is no warranty (or else, saying that
+you provide a warranty) and that users may redistribute the program under
+these conditions, and telling the user how to view a copy of this License.
+(Exception: if the Program itself is interactive but does not normally print
+such an announcement, your work based on the Program is not required to print
+an announcement.)
+
+These requirements apply to the modified work as a whole. If identifiable
+sections of that work are not derived from the Program, and can be reasonably
+considered independent and separate works in themselves, then this License,
+and its terms, do not apply to those sections when you distribute them as
+separate works. But when you distribute the same sections as part of a whole
+which is a work based on the Program, the distribution of the whole must be on
+the terms of this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your
+rights to work written entirely by you; rather, the intent is to exercise the
+right to control the distribution of derivative or collective works based on
+the Program.
+
+In addition, mere aggregation of another work not based on the Program with
+the Program (or with a work based on the Program) on a volume of a storage or
+distribution medium does not bring the other work under the scope of this
+License.
+
+ 3. You may copy and distribute the Program (or a work based on it, under
+Section 2) in object code or executable form under the terms of Sections 1 and
+2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable source
+code, which must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three years, to
+give any third party, for a charge no more than your cost of physically
+performing source distribution, a complete machine-readable copy of the
+corresponding source code, to be distributed under the terms of Sections 1 and
+2 above on a medium customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer to
+distribute corresponding source code. (This alternative is allowed only for
+noncommercial distribution and only if you received the program in object code
+or executable form with such an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for making
+modifications to it. For an executable work, complete source code means all
+the source code for all modules it contains, plus any associated interface
+definition files, plus the scripts used to control compilation and
+installation of the executable. However, as a special exception, the source
+code distributed need not include anything that is normally distributed (in
+either source or binary form) with the major components (compiler, kernel, and
+so on) of the operating system on which the executable runs, unless that
+component itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to
+copy from a designated place, then offering equivalent access to copy the
+source code from the same place counts as distribution of the source code,
+even though third parties are not compelled to copy the source along with the
+object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program except as
+expressly provided under this License. Any attempt otherwise to copy, modify,
+sublicense or distribute the Program is void, and will automatically terminate
+your rights under this License. However, parties who have received copies, or
+rights, from you under this License will not have their licenses terminated so
+long as such parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not signed
+it. However, nothing else grants you permission to modify or distribute the
+Program or its derivative works. These actions are prohibited by law if you
+do not accept this License. Therefore, by modifying or distributing the
+Program (or any work based on the Program), you indicate your acceptance of
+this License to do so, and all its terms and conditions for copying,
+distributing or modifying the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the original
+licensor to copy, distribute or modify the Program subject to these terms and
+conditions. You may not impose any further restrictions on the recipients'
+exercise of the rights granted herein. You are not responsible for enforcing
+compliance by third parties to this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or otherwise)
+that contradict the conditions of this License, they do not excuse you from
+the conditions of this License. If you cannot distribute so as to satisfy
+simultaneously your obligations under this License and any other pertinent
+obligations, then as a consequence you may not distribute the Program at all.
+For example, if a patent license would not permit royalty-free redistribution
+of the Program by all those who receive copies directly or indirectly through
+you, then the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply and
+the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or
+other property right claims or to contest validity of any such claims; this
+section has the sole purpose of protecting the integrity of the free software
+distribution system, which is implemented by public license practices. Many
+people have made generous contributions to the wide range of software
+distributed through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing to
+distribute software through any other system and a licensee cannot impose that
+choice.
+
+This section is intended to make thoroughly clear what is believed to be a
+consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in certain
+countries either by patents or by copyrighted interfaces, the original
+copyright holder who places the Program under this License may add an explicit
+geographical distribution limitation excluding those countries, so that
+distribution is permitted only in or among countries not thus excluded. In
+such case, this License incorporates the limitation as if written in the body
+of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions of
+the General Public License from time to time. Such new versions will be
+similar in spirit to the present version, but may differ in detail to address
+new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any later
+version", you have the option of following the terms and conditions either of
+that version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of this License,
+you may choose any version ever published by the Free Software Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free programs
+whose distribution conditions are different, write to the author to ask for
+permission. For software which is copyrighted by the Free Software
+Foundation, write to the Free Software Foundation; we sometimes make
+exceptions for this. Our decision will be guided by the two goals of
+preserving the free status of all derivatives of our free software and of
+promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
+THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
+STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE
+PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
+PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE,
+YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO
+LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR
+THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+Note that the above copyright notices and use conditions do not apply on the
+software components listed in below which are included in this Software. When
+you use or distribute Software with including these libraries, you have to
+follow the conditions of these libraries.
+
+These library's copyright notices and conditions are following;
+
+-------------------
+
+BitVisor(R) VPN Client Module (IPsec Driver):
+Copyright (c) 2007, 2008 University of Tsukuba.
+Copyright (C) 2007, 2008 National Institute of Information and Communications
+Technology.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+3. Neither the name of the University of Tsukuba nor the names of its
+contributors may be used to endorse or promote products derived from this
+software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------
+
+Microsoft(R) C Runtime Library:
+(c) 2007 Microsoft Corporation. All Rights Reserved.
+
+-------------------
+
+RSA Security Inc. PKCS #11 Cryptographic Token Interface (Cryptoki):
+
+License to copy and use this software is granted provided that it is
+identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+(Cryptoki)" in all material mentioning or referencing this software.
+
+License is also granted to make and use derivative works provided that such
+works are identified as "derived from the RSA Security Inc. PKCS #11
+Cryptographic Token Interface (Cryptoki)" in all material mentioning or
+referencing the derived work.
+
+RSA Security Inc. makes no representations concerning either the
+merchantability of this software or the suitability of this software for any
+particular purpose. It is provided "as is" without express or implied warranty
+of any kind.
+
+-------------------
+
+WinPcap:
+Copyright (c) 2001 - 2003 NetGroup, Politecnico di Torino (Italy)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+3. Neither the name of the Politecnico di Torino nor the names of its
+contributors may be used to endorse or promote products derived from this
+software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------
+
+libedit:
+Copyright (c) 1992, 1993 The Regents of the University of California. All
+rights reserved.
+
+This code is derived from software contributed to Berkeley by Christos Zoulas
+of Cornell University.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------
+
+libiconv:
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your freedom to
+share and change it. By contrast, the GNU General Public Licenses are intended
+to guarantee your freedom to share and change free software--to make sure the
+software is free for all its users.
+
+ This license, the Library General Public License, applies to some specially
+designated Free Software Foundation software, and to any other libraries whose
+authors decide to use it. You can use it for your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the freedom to
+distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new free
+programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid anyone to
+deny you these rights or to ask you to surrender the rights. These
+restrictions translate to certain responsibilities for you if you distribute
+copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis or for
+a fee, you must give the recipients all the rights that we gave you. You must
+make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide complete object
+files to the recipients so that they can relink them with the library, after
+making changes to the library and recompiling it. And you must show them these
+terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright the
+library, and (2) offer you this license which gives you legal permission to
+copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain that
+everyone understands that there is no warranty for this free library. If the
+library is modified by someone else and passed on, we want its recipients to
+know that what they have is not the original version, so that any problems
+introduced by others will not reflect on the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software patents. We
+wish to avoid the danger that companies distributing free software will
+individually obtain patent licenses, thus in effect transforming the program
+into proprietary software. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary GNU
+General Public License, which was designed for utility programs. This license,
+the GNU Library General Public License, applies to certain designated
+libraries. This license is quite different from the ordinary one; be sure to
+read it in full, and don't assume that anything in it is the same as in the
+ordinary license.
+
+ The reason we have a separate public license for some libraries is that they
+blur the distinction we usually make between modifying or adding to a program
+and simply using it. Linking a program with a library, without changing the
+library, is in some sense simply using the library, and is analogous to
+running a utility program or application program. However, in a textual and
+legal sense, the linked executable is a combined work, a derivative of the
+original library, and the ordinary General Public License treats it as such.
+
+ Because of this blurred distinction, using the ordinary General Public
+License for libraries did not effectively promote software sharing, because
+most developers did not use the libraries. We concluded that weaker conditions
+might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the users
+of those programs of all benefit from the free status of the libraries
+themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while preserving
+your freedom as a user of such programs to change the free libraries that are
+incorporated in them. (We have not seen how to achieve this as regards changes
+in header files, but we have achieved it as regards changes in the actual
+functions of the Library.) The hope is that this will lead to faster
+development of free libraries.
+
+ The precise terms and conditions for copying, distribution and modification
+follow. Pay close attention to the difference between a "work based on the
+library" and a "work that uses the library". The former contains code derived
+from the library, while the latter only works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary General
+Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which contains a
+notice placed by the copyright holder or other authorized party saying it may
+be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data prepared so
+as to be conveniently linked with application programs (which use some of
+those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work which has
+been distributed under these terms. A "work based on the Library" means either
+the Library or any derivative work under copyright law: that is to say, a work
+containing the Library or a portion of it, either verbatim or with
+modifications and/or translated straightforwardly into another language.
+(Hereinafter, translation is included without limitation in the term
+"modification".)
+
+ "Source code" for a work means the preferred form of the work for making
+modifications to it. For a library, complete source code means all the source
+code for all modules it contains, plus any associated interface definition
+files, plus the scripts used to control compilation and installation of the
+library.
+
+ Activities other than copying, distribution and modification are not covered
+by this License; they are outside its scope. The act of running a program
+using the Library is not restricted, and output from such a program is covered
+only if its contents constitute a work based on the Library (independent of
+the use of the Library in a tool for writing it). Whether that is true depends
+on what the Library does and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's complete
+source code as you receive it, in any medium, provided that you conspicuously
+and appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this License
+and to the absence of any warranty; and distribute a copy of this License
+along with the Library.
+
+ You may charge a fee for the physical act of transferring a copy, and you
+may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Library or any portion of it,
+thus forming a work based on the Library, and copy and distribute such
+modifications or work under the terms of Section 1 above, provided that you
+also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices stating
+that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no charge to all
+third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a table
+of data to be supplied by an application program that uses the facility, other
+than as an argument passed when the facility is invoked, then you must make a
+good faith effort to ensure that, in the event an application does not supply
+such function or table, the facility still operates, and performs whatever
+part of its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has a
+purpose that is entirely well-defined independent of the application.
+Therefore, Subsection 2d requires that any application-supplied function or
+table used by this function must be optional: if the application does not
+supply it, the square root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If identifiable
+sections of that work are not derived from the Library, and can be reasonably
+considered independent and separate works in themselves, then this License,
+and its terms, do not apply to those sections when you distribute them as
+separate works. But when you distribute the same sections as part of a whole
+which is a work based on the Library, the distribution of the whole must be on
+the terms of this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your
+rights to work written entirely by you; rather, the intent is to exercise the
+right to control the distribution of derivative or collective works based on
+the Library.
+
+In addition, mere aggregation of another work not based on the Library with
+the Library (or with a work based on the Library) on a volume of a storage or
+distribution medium does not bring the other work under the scope of this
+License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do this,
+you must alter all the notices that refer to this License, so that they refer
+to the ordinary GNU General Public License, version 2, instead of to this
+License. (If a newer version than version 2 of the ordinary GNU General Public
+License has appeared, then you can specify that version instead if you wish.)
+Do not make any other change in these notices.
+
+ Once this change is made in a given copy, it is irreversible for that copy,
+so the ordinary GNU General Public License applies to all subsequent copies
+and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of the Library
+into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or derivative of
+it, under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you accompany it with the complete
+corresponding machine-readable source code, which must be distributed under
+the terms of Sections 1 and 2 above on a medium customarily used for software
+interchange.
+
+ If distribution of object code is made by offering access to copy from a
+designated place, then offering equivalent access to copy the source code from
+the same place satisfies the requirement to distribute the source code, even
+though third parties are not compelled to copy the source along with the
+object code.
+
+ 5. A program that contains no derivative of any portion of the Library, but
+is designed to work with the Library by being compiled or linked with it, is
+called a "work that uses the Library". Such a work, in isolation, is not a
+derivative work of the Library, and therefore falls outside the scope of this
+License.
+
+ However, linking a "work that uses the Library" with the Library creates an
+executable that is a derivative of the Library (because it contains portions
+of the Library), rather than a "work that uses the library". The executable is
+therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file that is
+part of the Library, the object code for the work may be a derivative work of
+the Library even though the source code is not.
+Whether this is true is especially significant if the work can be linked
+without the Library, or if the work is itself a library. The threshold for
+this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data structure
+layouts and accessors, and small macros and small inline functions (ten lines
+or less in length), then the use of the object file is unrestricted,
+regardless of whether it is legally a derivative work. (Executables containing
+this object code plus portions of the Library will still fall under Section
+6.)
+
+ Otherwise, if the work is a derivative of the Library, you may distribute
+the object code for the work under the terms of Section 6. Any executables
+containing that work also fall under Section 6, whether or not they are linked
+directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or link a
+"work that uses the Library" with the Library to produce a work containing
+portions of the Library, and distribute that work under terms of your choice,
+provided that the terms permit modification of the work for the customer's own
+use and reverse engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the Library
+is used in it and that the Library and its use are covered by this License.
+You must supply a copy of this License. If the work during execution displays
+copyright notices, you must include the copyright notice for the Library among
+them, as well as a reference directing the user to the copy of this License.
+Also, you must do one of these things:
+
+ a) Accompany the work with the complete corresponding machine-readable
+source code for the Library including whatever changes were used in the work
+(which must be distributed under Sections 1 and 2 above) ; and, if the work is
+an executable linked with the Library, with the complete machine-readable
+"work that uses the Library", as object code and/or source code, so that the
+user can modify the Library and then relink to produce a modified executable
+containing the modified Library. (It is understood that the user who changes
+the contents of definitions files in the Library will not necessarily be able
+to recompile the application to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at least three
+years, to give the same user the materials specified in Subsection 6a, above,
+for a charge no more than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy from a
+designated place, offer equivalent access to copy the above specified
+materials from the same place.
+
+ d) Verify that the user has already received a copy of these materials or
+that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the Library"
+must include any data and utility programs needed for reproducing the
+executable from it. However, as a special exception, the source code
+distributed need not include anything that is normally distributed (in either
+source or binary form) with the major components (compiler, kernel, and so on)
+of the operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+ It may happen that this requirement contradicts the license restrictions of
+other proprietary libraries that do not normally accompany the operating
+system. Such a contradiction means you cannot use both them and the Library
+together in an executable that you distribute.
+
+ 7. You may place library facilities that are a work based on the Library
+side-by-side in a single library together with other library facilities not
+covered by this License, and distribute such a combined library, provided that
+the separate distribution of the work based on the Library and of the other
+library facilities is otherwise permitted, and provided that you do these two
+things:
+
+ a) Accompany the combined library with a copy of the same work based on
+the Library, uncombined with any other library facilities. This must be
+distributed under the terms of the Sections above.
+
+ b) Give prominent notice with the combined library of the fact that part
+of it is a work based on the Library, and explaining where to find the
+accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute the
+Library except as expressly provided under this License. Any attempt otherwise
+to copy, modify, sublicense, link with, or distribute the Library is void, and
+will automatically terminate your rights under this License. However, parties
+who have received copies, or rights, from you under this License will not have
+their licenses terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not signed
+it. However, nothing else grants you permission to modify or distribute the
+Library or its derivative works. These actions are prohibited by law if you do
+not accept this License. Therefore, by modifying or distributing the Library
+(or any work based on the Library), you indicate your acceptance of this
+License to do so, and all its terms and conditions for copying, distributing
+or modifying the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the original
+licensor to copy, distribute, link with or modify the Library subject to these
+terms and conditions. You may not impose any further restrictions on the
+recipients' exercise of the rights granted herein. You are not responsible for
+enforcing compliance by third parties to this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or otherwise)
+that contradict the conditions of this License, they do not excuse you from
+the conditions of this License. If you cannot distribute so as to satisfy
+simultaneously your obligations under this License and any other pertinent
+obligations, then as a consequence you may not distribute the Library at all.
+For example, if a patent license would not permit royalty-free redistribution
+of the Library by all those who receive copies directly or indirectly through
+you, then the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply, and
+the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or
+other property right claims or to contest validity of any such claims; this
+section has the sole purpose of protecting the integrity of the free software
+distribution system which is implemented by public license practices. Many
+people have made generous contributions to the wide range of software
+distributed through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing to
+distribute software through any other system and a licensee cannot impose that
+choice.
+
+This section is intended to make thoroughly clear what is believed to be a
+consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in certain
+countries either by patents or by copyrighted interfaces, the original
+copyright holder who places the Library under this License may add an explicit
+geographical distribution limitation excluding those countries, so that
+distribution is permitted only in or among countries not thus excluded. In
+such case, this License incorporates the limitation as if written in the body
+of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new versions of
+the Library General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and "any later
+version", you have the option of following the terms and conditions either of
+that version or of any later version published by the Free Software
+Foundation. If the Library does not specify a license version number, you may
+choose any version ever published by the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free programs
+whose distribution conditions are incompatible with these, write to the author
+to ask for permission. For software which is copyrighted by the Free Software
+Foundation, write to the Free Software Foundation; we sometimes make
+exceptions for this. Our decision will be guided by the two goals of
+preserving the free status of all derivatives of our free software and of
+promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
+THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
+STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE
+LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
+PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE,
+YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO
+LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR
+THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+-------------------
+
+ncurses:
+Copyright (c) 1998-2005,2006 Free Software Foundation, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, distribute with
+modifications, sublicense, and/or sell copies of the Software, and to permit
+persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name(s) of the above copyright holders
+shall not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization.
+
+-------------------
+
+OpenSSL:
+OpenSSL License
+Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+3. All advertising materials mentioning features or use of this software must
+display the following acknowledgment: "This product includes software
+developed by the OpenSSL Project for use in the OpenSSL Toolkit.
+(http://www.openssl.org/)"
+
+4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+endorse or promote products derived from this software without prior written
+permission. For written permission, please contact openssl-core@openssl.org.
+
+5. Products derived from this software may not be called "OpenSSL" nor may
+"OpenSSL" appear in their names without prior written permission of the
+OpenSSL Project.
+
+6. Redistributions of any form whatsoever must retain the following
+acknowledgment: "This product includes software developed by the OpenSSL
+Project for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+
+THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY EXPRESSED
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE OpenSSL PROJECT OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+This product includes cryptographic software written by Eric Young
+(eay@cryptsoft.com). This product includes software written by Tim Hudson
+(tjh@cryptsoft.com).
+
+Original SSLeay License
+Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) All rights reserved.
+
+This package is an SSL implementation written by Eric Young
+(eay@cryptsoft.com). The implementation was written so as to conform with
+Netscapes SSL.
+
+This library is free for commercial and non-commercial use as long as the
+following conditions are aheared to. The following conditions apply to all
+code found in this distribution, be it the RC4, RSA, lhash, DES, etc., code;
+not just the SSL code. The SSL documentation included with this distribution
+is covered by the same copyright terms except that the holder is Tim Hudson
+(tjh@cryptsoft.com).
+
+Copyright remains Eric Young's, and as such any Copyright notices in the code
+are not to be removed. If this package is used in a product, Eric Young should
+be given attribution as the author of the parts of the library used. This can
+be in the form of a textual message at program startup or in documentation
+(online or textual) provided with the package.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the copyright notice, this list
+of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software must
+display the following acknowledgement: "This product includes cryptographic
+software written by Eric Young (eay@cryptsoft.com)" The word 'cryptographic'
+can be left out if the rouines from the library being used are not
+cryptographic related :-).
+4. If you include any Windows specific code (or a derivative thereof) from the
+apps directory (application code) you must include an acknowledgement: "This
+product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+
+THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The licence and distribution terms for any publically available version or
+derivative of this code cannot be changed. i.e. this code cannot simply be
+copied and put under another distribution licence [including the GNU Public
+Licence.]
+
+-------------------
+
+zlib:
+Acknowledgments:
+ The deflate format used by zlib was defined by Phil Katz. The deflate and
+zlib specifications were written by L. Peter Deutsch. Thanks to all the people
+who reported problems and suggested various improvements in zlib; they are too
+numerous to cite here.
+
+Copyright notice:
+ (C) 1995-2004 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the
+use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+claim that you wrote the original software. If you use this software in a
+product, an acknowledgment in the product documentation would be appreciated
+but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+If you use the zlib library in a product, we would appreciate *not* receiving
+lengthy legal documents to sign. The sources are provided for free but without
+warranty of any kind. The library has been entirely written by Jean-loup
+Gailly and Mark Adler; it does not include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include in
+the file ChangeLog history information documenting your changes. Please read
+the FAQ for more information on the distribution of modified source versions.
+
+-------------------
+
+Intel AESNI Sample Library:
+
+Copyright (c) 2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+* Neither the name of Intel Corporation nor the names of its contributors may
+be used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Issue Date: Aug 6, 2010
+
+-------------------
+
+NOTES
+
+SoftEther provides source codes of some GPL/LGPL/other libraries listed above
+on its web server. Anyone can download, use and re-distribute them under
+individual licenses which are contained on each archive file, available from
+the following URL:
+http://uploader.softether.co.jp/src/
+
+
+
+BitVisor(R) VPN Client Module (IPsec Driver):
+Copyright (c) 2007, 2008 University of Tsukuba.
+Copyright (C) 2007, 2008 National Institute of Information and Communications
+Technology.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+3. Neither the name of the University of Tsukuba nor the names of its
+contributors may be used to endorse or promote products derived from this
+software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------
+
+Microsoft(R) C Runtime Library:
+(c) 2007 Microsoft Corporation. All Rights Reserved.
+
+-------------------
+
+RSA Security Inc. PKCS #11 Cryptographic Token Interface (Cryptoki):
+
+License to copy and use this software is granted provided that it is
+identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+(Cryptoki)" in all material mentioning or referencing this software.
+
+License is also granted to make and use derivative works provided that such
+works are identified as "derived from the RSA Security Inc. PKCS #11
+Cryptographic Token Interface (Cryptoki)" in all material mentioning or
+referencing the derived work.
+
+RSA Security Inc. makes no representations concerning either the
+merchantability of this software or the suitability of this software for any
+particular purpose. It is provided "as is" without express or implied warranty
+of any kind.
+
+-------------------
+
+WinPcap:
+Copyright (c) 2001 - 2003 NetGroup, Politecnico di Torino (Italy)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+3. Neither the name of the Politecnico di Torino nor the names of its
+contributors may be used to endorse or promote products derived from this
+software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------
+
+libedit:
+Copyright (c) 1992, 1993 The Regents of the University of California. All
+rights reserved.
+
+This code is derived from software contributed to Berkeley by Christos Zoulas
+of Cornell University.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------
+
+libiconv:
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your freedom to
+share and change it. By contrast, the GNU General Public Licenses are intended
+to guarantee your freedom to share and change free software--to make sure the
+software is free for all its users.
+
+ This license, the Library General Public License, applies to some specially
+designated Free Software Foundation software, and to any other libraries whose
+authors decide to use it. You can use it for your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the freedom to
+distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new free
+programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid anyone to
+deny you these rights or to ask you to surrender the rights. These
+restrictions translate to certain responsibilities for you if you distribute
+copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis or for
+a fee, you must give the recipients all the rights that we gave you. You must
+make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide complete object
+files to the recipients so that they can relink them with the library, after
+making changes to the library and recompiling it. And you must show them these
+terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright the
+library, and (2) offer you this license which gives you legal permission to
+copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain that
+everyone understands that there is no warranty for this free library. If the
+library is modified by someone else and passed on, we want its recipients to
+know that what they have is not the original version, so that any problems
+introduced by others will not reflect on the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software patents. We
+wish to avoid the danger that companies distributing free software will
+individually obtain patent licenses, thus in effect transforming the program
+into proprietary software. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary GNU
+General Public License, which was designed for utility programs. This license,
+the GNU Library General Public License, applies to certain designated
+libraries. This license is quite different from the ordinary one; be sure to
+read it in full, and don't assume that anything in it is the same as in the
+ordinary license.
+
+ The reason we have a separate public license for some libraries is that they
+blur the distinction we usually make between modifying or adding to a program
+and simply using it. Linking a program with a library, without changing the
+library, is in some sense simply using the library, and is analogous to
+running a utility program or application program. However, in a textual and
+legal sense, the linked executable is a combined work, a derivative of the
+original library, and the ordinary General Public License treats it as such.
+
+ Because of this blurred distinction, using the ordinary General Public
+License for libraries did not effectively promote software sharing, because
+most developers did not use the libraries. We concluded that weaker conditions
+might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the users
+of those programs of all benefit from the free status of the libraries
+themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while preserving
+your freedom as a user of such programs to change the free libraries that are
+incorporated in them. (We have not seen how to achieve this as regards changes
+in header files, but we have achieved it as regards changes in the actual
+functions of the Library.) The hope is that this will lead to faster
+development of free libraries.
+
+ The precise terms and conditions for copying, distribution and modification
+follow. Pay close attention to the difference between a "work based on the
+library" and a "work that uses the library". The former contains code derived
+from the library, while the latter only works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary General
+Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which contains a
+notice placed by the copyright holder or other authorized party saying it may
+be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data prepared so
+as to be conveniently linked with application programs (which use some of
+those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work which has
+been distributed under these terms. A "work based on the Library" means either
+the Library or any derivative work under copyright law: that is to say, a work
+containing the Library or a portion of it, either verbatim or with
+modifications and/or translated straightforwardly into another language.
+(Hereinafter, translation is included without limitation in the term
+"modification".)
+
+ "Source code" for a work means the preferred form of the work for making
+modifications to it. For a library, complete source code means all the source
+code for all modules it contains, plus any associated interface definition
+files, plus the scripts used to control compilation and installation of the
+library.
+
+ Activities other than copying, distribution and modification are not covered
+by this License; they are outside its scope. The act of running a program
+using the Library is not restricted, and output from such a program is covered
+only if its contents constitute a work based on the Library (independent of
+the use of the Library in a tool for writing it). Whether that is true depends
+on what the Library does and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's complete
+source code as you receive it, in any medium, provided that you conspicuously
+and appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this License
+and to the absence of any warranty; and distribute a copy of this License
+along with the Library.
+
+ You may charge a fee for the physical act of transferring a copy, and you
+may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Library or any portion of it,
+thus forming a work based on the Library, and copy and distribute such
+modifications or work under the terms of Section 1 above, provided that you
+also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices stating
+that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no charge to all
+third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a table
+of data to be supplied by an application program that uses the facility, other
+than as an argument passed when the facility is invoked, then you must make a
+good faith effort to ensure that, in the event an application does not supply
+such function or table, the facility still operates, and performs whatever
+part of its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has a
+purpose that is entirely well-defined independent of the application.
+Therefore, Subsection 2d requires that any application-supplied function or
+table used by this function must be optional: if the application does not
+supply it, the square root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If identifiable
+sections of that work are not derived from the Library, and can be reasonably
+considered independent and separate works in themselves, then this License,
+and its terms, do not apply to those sections when you distribute them as
+separate works. But when you distribute the same sections as part of a whole
+which is a work based on the Library, the distribution of the whole must be on
+the terms of this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your
+rights to work written entirely by you; rather, the intent is to exercise the
+right to control the distribution of derivative or collective works based on
+the Library.
+
+In addition, mere aggregation of another work not based on the Library with
+the Library (or with a work based on the Library) on a volume of a storage or
+distribution medium does not bring the other work under the scope of this
+License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do this,
+you must alter all the notices that refer to this License, so that they refer
+to the ordinary GNU General Public License, version 2, instead of to this
+License. (If a newer version than version 2 of the ordinary GNU General Public
+License has appeared, then you can specify that version instead if you wish.)
+Do not make any other change in these notices.
+
+ Once this change is made in a given copy, it is irreversible for that copy,
+so the ordinary GNU General Public License applies to all subsequent copies
+and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of the Library
+into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or derivative of
+it, under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you accompany it with the complete
+corresponding machine-readable source code, which must be distributed under
+the terms of Sections 1 and 2 above on a medium customarily used for software
+interchange.
+
+ If distribution of object code is made by offering access to copy from a
+designated place, then offering equivalent access to copy the source code from
+the same place satisfies the requirement to distribute the source code, even
+though third parties are not compelled to copy the source along with the
+object code.
+
+ 5. A program that contains no derivative of any portion of the Library, but
+is designed to work with the Library by being compiled or linked with it, is
+called a "work that uses the Library". Such a work, in isolation, is not a
+derivative work of the Library, and therefore falls outside the scope of this
+License.
+
+ However, linking a "work that uses the Library" with the Library creates an
+executable that is a derivative of the Library (because it contains portions
+of the Library), rather than a "work that uses the library". The executable is
+therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file that is
+part of the Library, the object code for the work may be a derivative work of
+the Library even though the source code is not.
+Whether this is true is especially significant if the work can be linked
+without the Library, or if the work is itself a library. The threshold for
+this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data structure
+layouts and accessors, and small macros and small inline functions (ten lines
+or less in length), then the use of the object file is unrestricted,
+regardless of whether it is legally a derivative work. (Executables containing
+this object code plus portions of the Library will still fall under Section
+6.)
+
+ Otherwise, if the work is a derivative of the Library, you may distribute
+the object code for the work under the terms of Section 6. Any executables
+containing that work also fall under Section 6, whether or not they are linked
+directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or link a
+"work that uses the Library" with the Library to produce a work containing
+portions of the Library, and distribute that work under terms of your choice,
+provided that the terms permit modification of the work for the customer's own
+use and reverse engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the Library
+is used in it and that the Library and its use are covered by this License.
+You must supply a copy of this License. If the work during execution displays
+copyright notices, you must include the copyright notice for the Library among
+them, as well as a reference directing the user to the copy of this License.
+Also, you must do one of these things:
+
+ a) Accompany the work with the complete corresponding machine-readable
+source code for the Library including whatever changes were used in the work
+(which must be distributed under Sections 1 and 2 above) ; and, if the work is
+an executable linked with the Library, with the complete machine-readable
+"work that uses the Library", as object code and/or source code, so that the
+user can modify the Library and then relink to produce a modified executable
+containing the modified Library. (It is understood that the user who changes
+the contents of definitions files in the Library will not necessarily be able
+to recompile the application to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at least three
+years, to give the same user the materials specified in Subsection 6a, above,
+for a charge no more than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy from a
+designated place, offer equivalent access to copy the above specified
+materials from the same place.
+
+ d) Verify that the user has already received a copy of these materials or
+that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the Library"
+must include any data and utility programs needed for reproducing the
+executable from it. However, as a special exception, the source code
+distributed need not include anything that is normally distributed (in either
+source or binary form) with the major components (compiler, kernel, and so on)
+of the operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+ It may happen that this requirement contradicts the license restrictions of
+other proprietary libraries that do not normally accompany the operating
+system. Such a contradiction means you cannot use both them and the Library
+together in an executable that you distribute.
+
+ 7. You may place library facilities that are a work based on the Library
+side-by-side in a single library together with other library facilities not
+covered by this License, and distribute such a combined library, provided that
+the separate distribution of the work based on the Library and of the other
+library facilities is otherwise permitted, and provided that you do these two
+things:
+
+ a) Accompany the combined library with a copy of the same work based on
+the Library, uncombined with any other library facilities. This must be
+distributed under the terms of the Sections above.
+
+ b) Give prominent notice with the combined library of the fact that part
+of it is a work based on the Library, and explaining where to find the
+accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute the
+Library except as expressly provided under this License. Any attempt otherwise
+to copy, modify, sublicense, link with, or distribute the Library is void, and
+will automatically terminate your rights under this License. However, parties
+who have received copies, or rights, from you under this License will not have
+their licenses terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not signed
+it. However, nothing else grants you permission to modify or distribute the
+Library or its derivative works. These actions are prohibited by law if you do
+not accept this License. Therefore, by modifying or distributing the Library
+(or any work based on the Library), you indicate your acceptance of this
+License to do so, and all its terms and conditions for copying, distributing
+or modifying the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the original
+licensor to copy, distribute, link with or modify the Library subject to these
+terms and conditions. You may not impose any further restrictions on the
+recipients' exercise of the rights granted herein. You are not responsible for
+enforcing compliance by third parties to this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or otherwise)
+that contradict the conditions of this License, they do not excuse you from
+the conditions of this License. If you cannot distribute so as to satisfy
+simultaneously your obligations under this License and any other pertinent
+obligations, then as a consequence you may not distribute the Library at all.
+For example, if a patent license would not permit royalty-free redistribution
+of the Library by all those who receive copies directly or indirectly through
+you, then the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply, and
+the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or
+other property right claims or to contest validity of any such claims; this
+section has the sole purpose of protecting the integrity of the free software
+distribution system which is implemented by public license practices. Many
+people have made generous contributions to the wide range of software
+distributed through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing to
+distribute software through any other system and a licensee cannot impose that
+choice.
+
+This section is intended to make thoroughly clear what is believed to be a
+consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in certain
+countries either by patents or by copyrighted interfaces, the original
+copyright holder who places the Library under this License may add an explicit
+geographical distribution limitation excluding those countries, so that
+distribution is permitted only in or among countries not thus excluded. In
+such case, this License incorporates the limitation as if written in the body
+of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new versions of
+the Library General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and "any later
+version", you have the option of following the terms and conditions either of
+that version or of any later version published by the Free Software
+Foundation. If the Library does not specify a license version number, you may
+choose any version ever published by the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free programs
+whose distribution conditions are incompatible with these, write to the author
+to ask for permission. For software which is copyrighted by the Free Software
+Foundation, write to the Free Software Foundation; we sometimes make
+exceptions for this. Our decision will be guided by the two goals of
+preserving the free status of all derivatives of our free software and of
+promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
+THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
+STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE
+LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
+PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE,
+YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO
+LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR
+THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+-------------------
+
+ncurses:
+Copyright (c) 1998-2005,2006 Free Software Foundation, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, distribute with
+modifications, sublicense, and/or sell copies of the Software, and to permit
+persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name(s) of the above copyright holders
+shall not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization.
+
+-------------------
+
+OpenSSL:
+OpenSSL License
+Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+3. All advertising materials mentioning features or use of this software must
+display the following acknowledgment: "This product includes software
+developed by the OpenSSL Project for use in the OpenSSL Toolkit.
+(http://www.openssl.org/)"
+
+4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+endorse or promote products derived from this software without prior written
+permission. For written permission, please contact openssl-core@openssl.org.
+
+5. Products derived from this software may not be called "OpenSSL" nor may
+"OpenSSL" appear in their names without prior written permission of the
+OpenSSL Project.
+
+6. Redistributions of any form whatsoever must retain the following
+acknowledgment: "This product includes software developed by the OpenSSL
+Project for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+
+THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY EXPRESSED
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE OpenSSL PROJECT OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+This product includes cryptographic software written by Eric Young
+(eay@cryptsoft.com). This product includes software written by Tim Hudson
+(tjh@cryptsoft.com).
+
+Original SSLeay License
+Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) All rights reserved.
+
+This package is an SSL implementation written by Eric Young
+(eay@cryptsoft.com). The implementation was written so as to conform with
+Netscapes SSL.
+
+This library is free for commercial and non-commercial use as long as the
+following conditions are aheared to. The following conditions apply to all
+code found in this distribution, be it the RC4, RSA, lhash, DES, etc., code;
+not just the SSL code. The SSL documentation included with this distribution
+is covered by the same copyright terms except that the holder is Tim Hudson
+(tjh@cryptsoft.com).
+
+Copyright remains Eric Young's, and as such any Copyright notices in the code
+are not to be removed. If this package is used in a product, Eric Young should
+be given attribution as the author of the parts of the library used. This can
+be in the form of a textual message at program startup or in documentation
+(online or textual) provided with the package.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the copyright notice, this list
+of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software must
+display the following acknowledgement: "This product includes cryptographic
+software written by Eric Young (eay@cryptsoft.com)" The word 'cryptographic'
+can be left out if the rouines from the library being used are not
+cryptographic related :-).
+4. If you include any Windows specific code (or a derivative thereof) from the
+apps directory (application code) you must include an acknowledgement: "This
+product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+
+THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The licence and distribution terms for any publically available version or
+derivative of this code cannot be changed. i.e. this code cannot simply be
+copied and put under another distribution licence [including the GNU Public
+Licence.]
+
+-------------------
+
+zlib:
+Acknowledgments:
+ The deflate format used by zlib was defined by Phil Katz. The deflate and
+zlib specifications were written by L. Peter Deutsch. Thanks to all the people
+who reported problems and suggested various improvements in zlib; they are too
+numerous to cite here.
+
+Copyright notice:
+ (C) 1995-2004 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the
+use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+claim that you wrote the original software. If you use this software in a
+product, an acknowledgment in the product documentation would be appreciated
+but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+If you use the zlib library in a product, we would appreciate *not* receiving
+lengthy legal documents to sign. The sources are provided for free but without
+warranty of any kind. The library has been entirely written by Jean-loup
+Gailly and Mark Adler; it does not include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include in
+the file ChangeLog history information documenting your changes. Please read
+the FAQ for more information on the distribution of modified source versions.
+
+-------------------
+
+Intel AESNI Sample Library:
+
+Copyright (c) 2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+* Neither the name of Intel Corporation nor the names of its contributors may
+be used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Issue Date: Aug 6, 2010
+
+-------------------
+
+NOTES WRITTEN BY SOFTETHER CORPORATION
+
+Note for users of non-Windows version of PacketiX VPN: The enumerated bundle
+of License Agreements above are copies of original License Agreements of each
+library programs which PacketiX VPN uses. PacketiX VPN is not a delivered work
+from these libraries. PacketiX VPN is a separated work from the libraries, but
+it may call functions of the libraries (whether or not PacketiX VPN calls such
+functions are depended on the user's intention to link them or not on user's
+side computer). While some libraries indicate GPL or LGPL as a condition to
+re-distribute, PacketiX VPN is not license under GPL nor LGPL. Therefore, we
+took special care not to make PacketiX VPN become delivered works of any GPL
+or LGPL libraries. In order to achieve that, both PacketiX VPN and GPL/LGPL
+libraries are distributed with isolated forms (means that any program files of
+PacketiX VPN are not bound nor linked to any GPL/LGPL libraries). If a user of
+PacketiX VPN wants to link GPL/LGPL libraries by their own decisions,
+operations and responsibilities, he may do that on his computer. However, if a
+delivered work under copyright law is created as a result of such an
+operation, such a delivered work must not re-distributed to other people,
+because it may violate GPL/LGPL libraries' conditions.
+
+Note for users of Windows version of PacketiX VPN: For technical reason, the
+above texts are exactly same as a file which is also contained on the
+non-Windows version of PacketiX VPN. Actually, the Windows version of PacketiX
+VPN has no relations to any GPL/LGPL libraries enumerated above.
+
+SoftEther Corporation provides source codes of some GPL/LGPL/other libraries
+listed above on its web server. Anyone can download, use and re-distribute
+them under individual licenses which are contained on each archive file,
+available from the following URL:
+http://uploader.softether.co.jp/src/
+
+
+
+THE IMPORTANT NOTICES ABOUT SOFTETHER VPN
+
+FUNCTIONS OF VPN COMMUNICATIONS EMBEDDED ON THIS SOFTWARE ARE VERY POWERFUL
+THAN EVER. THIS STRONG VPN ABILITY WILL BRING YOU HUGE BENEFITS. HOWEVER, IF
+YOU MISUSE THIS SOFTWARE, IT MIGHT DAMAGES YOURSELF. IN ORDER TO AVOID SUCH
+RISKS, THIS DOCUMENT ACCOUNTS IMPORTANT NOTICES FOR CUSTOMERS WHO ARE WILLING
+TO USE THIS SOFTWARE. THE FOLLOWING INSTRUCTIONS ARE VERY IMPORTANT. READ AND
+UNDERSTAND IT CAREFULLY. ADDITIONALLY, IF YOU ARE PLANNING TO USE THE DYNAMIC
+DNS, THE NAT TRAVERSAL OR THE VPN AZURE FUNCTIONS, READ THE SECTION 3.5
+CAREFULLY. THESE FUNCTIONS ARE FREE SERVICES PROVIDED VIA THE INTERNET, ARE
+NOT GUARANTEED, AND ARE NOT INTENDED TO BE USED FOR BUSINESS OR COMMERCIAL
+USE. DO NOT USE THESE SERVICES FOR YOUR BUSINESS OR COMMERCIAL USE.
+
+
+1. VPN Communication Protocols
+1.1. SoftEther VPN Protocol
+SoftEther VPN can perform VPN communication. Unlike traditional VPN protocols,
+SoftEther VPN has an implementation of the newly-designed "SoftEther VPN
+Protocol (SE-VPN Protocol)" . SE-VPN protocol encapsulates any Ethernet
+packets into a HTTPS (HTTP over SSL) connection. Therefore SE-VPN protocol can
+communicate beyond firewalls even if the firewall is configured to block
+traditional VPN packets by network administrator. SE-VPN protocol is designed
+and implemented to comply TLS 1.0 (RFC 5246) and HTTPS (RFC 2818). However, it
+sometimes have different behavior to RFCs. If you are a network administrator
+and want to block SE-VPN protocols on the firewall, you can adopt a
+"white-list" policy on the firewall to filter any TCP or UDP packets on the
+border except explicitly allowed packets towards specific web sites and
+servers.
+
+1.2. NAT Traversal Function
+Generally, if you use traditional VPN systems you have to request a network
+administrator to make the NAT or firewall to "open" or "relay" specific TCP or
+UDP ports. However, there are demands somehow to eliminate such working costs
+on network administrators. In order to satisfy such demands, SoftEther VPN has
+the newly-implemented "NAT Traversal" function. NAT Traversal is enabled by
+default. A SoftEther VPN Server running on the computer behind NAT or firewall
+can accept VPN connections from the Internet, without any special
+configurations on firewalls or NATs. If you want to disable the NAT Traversal
+function, modify the "DisableNatTraversal" to "true" on the configuration file
+of SoftEther VPN Server. In order to disable it on the client-side, append
+"/tcp" suffix on the destination hostname.
+
+1.3. Dynamic DNS Function
+Traditional legacy VPN system requires a static global IP address on the VPN
+server. In consideration of shortage of global IP addresses, SoftEther
+Corporation implements the "Dynamic DNS Function" on SoftEther VPN Server.
+Dynamic DNS is enabled by default. Dynamic DNS function notify the current
+global IP address of the PC to the Dynamic DNS Servers which are operated by
+SoftEther Corporation. A globally-unique hostname (FQDN) such as
+"abc.softether.net" ( "abc" varies as unique per a user) will be assigned on
+the VPN Server. If you tell this unique hostname to a VPN user, the user can
+specify it as the destination VPN Sever hostname on the VPN Client and will be
+able to connect the VPN Server. No IP addresses are required to know
+beforehand. If the IP address of the VPN Server varies, the registered IP
+address related to the hostname of Dynamic DNS service will be changed
+automatically. By this mechanism, no longer need a static global IP address
+which costs monthly to ISPs. You can use consumer-level inexpensive Internet
+connection with dynamic IP address in order to operate an enterprise-level VPN
+system. If you want to disable Dynamic DNS, specify "true" on the "Disabled"
+items of the "DDnsClient" directive on the SoftEther VPN Server configuration
+file. * Note for residents in People's Republic of China: If your VPN Server
+is running on the People's Republic of China, the DNS suffix will be replaced
+to "sedns.cn" domain. The "sedns.cn" domain is the service possessed and
+operated by "Beijing Daiyuu SoftEther Technology Co., Ltd" which is a
+Chinese-local enterprise.
+
+1.4. VPN over ICMP / VPN over DNS functions
+If you want to make a VPN connection between SoftEther VPN Client / Bridge and
+SoftEther VPN Server, but if TCP and UDP packets are prohibited by the
+firewall, then you can encapsulates payloads into "ICMP" (as known as Ping) or
+"DNS" packets. This function can realize a VPN connection by using ICMP or DNS
+even if the firewall or router blocks every TCP or UDP connections. VPN over
+ICMP / VPN over DNS functions are designed to comply standard ICMP and DNS
+specifications as possible, however it sometimes has a behavior not to fully
+comply them. Therefore, few poor-quality routers may be caused a
+memory-overflow or something troubles when a lot of ICMP or DNS packets are
+passed, and such routers sometimes freezes or reboots. It might affects other
+users on the same network. To avoid such risks, append the suffix "/tcp" on
+the destination hostname which is specified on the VPN-client side to disable
+VPN over ICMP / DNS functions.
+
+1.5. VPN Azure Cloud Service
+If your SoftEther VPN Server is placed behind the NAT or firwall, and by some
+reason you cannot use NAT Traversal function, Dynamic DNS function or VPN over
+ICMP/DNS function, you can use VPN Azure Clouse Service. SoftEther Corporation
+operates VPN Azure Cloud on Internet. After the VPN Server makes a connection
+to the VPN Azure Cloud, the hostname "abc.vpnazure.net" ( "abc" is a unique
+hostname) can be specified to connect to the VPN Server via the VPN Azure
+Cloud. Practically, such a hostname is pointing a global IP address of one of
+cloud servers which are operated by SoftEther Corporation. If A VPN Client
+connects to such a VPN Azure host, then the VPN Azure host will relay all
+traffics between the VPN Client and the VPN Server. VPN Azure is disabled by
+default. You can activate it easily by using VPN Server Configuration Tool.
+
+1.6. UDP Acceleration
+SoftEther VPN has the UDP Acceleration Function. If a VPN consists of two
+sites detects that UDP channel can be established, UDP will be automatically
+used. By this function, throughput of UDP increases. If direct UDP channel can
+be established, direct UDP packets will be used. However, if there is
+something obstacles such as firewalls or NATs, the "UDP Hole Punching"
+technology will be used, instead. The "UDP Hole Punching" uses the cloud
+servers which SoftEther Corporation operates on Internet. UDP Acceleration can
+be disabled anytime by setting up so on the VPN-client side.
+
+
+2. VPN Software
+2.1. SoftEther VPN Client
+If you use SoftEther VPN Client on Windows, the Virtual Network Adapter device
+driver will be installed on Windows. The Virtual Network Adapter is
+implemented as a kernel-mode driver for Windows. The driver is
+digitally-signed by a certificate issued by VeriSign, Inc. and also sub-signed
+by Symantec Corporation. A message to ask you want to sure install the driver
+might be popped up on the screen. SoftEther VPN Client may response the
+message if possible. SoftEther VPN Client also optimizes the configuration of
+MMCSS (Multimedia Class Scheduler Service) on Windows. You can undo the
+optimizations of MMCSS afterwards.
+
+2.2. SoftEther VPN Server / Bridge
+If you use SoftEther VPN Server / Bridge on Windows with "Local Bridge"
+functions, you have to install the low-level Ethernet packet processing driver
+on the computer. The driver is digitally-signed by a certificate issued by
+VeriSign, Inc. and also sub-signed by Symantec Corporation. SoftEther VPN
+Server / Bridge may disable the TCP/IP offloading features on the physical
+network adapter for Local Bridge function. In Windows Vista / 2008 or greater
+version, VPN Server may inject a packet-filter driver which complies Windows
+Filter Platform (WPF) specification into the kernel in order to provide IPsec
+function. The packet-filter driver will be loaded available only if IPsec
+function is enabled. Once you enables IPsec function of SoftEther VPN Server,
+the built-in IPsec function of Windows will be disabled. After you disabled
+IPsec function of SoftEther VPN Server, then the built-in IPsec function of
+Windows will revive. In order to provide the Local Bridge function, SoftEther
+VPN Server / Bridge disables the TCP/IP offloading function on the operating
+system.
+
+2.3. User-mode Installation
+You can install SoftEther VPN Server and SoftEther VPN Bridge as "User-mode"
+on Windows. In other words, even if you don't have Windows system
+administrator's privileges, you can install SoftEther VPN as a normal user.
+User-mode install will disable a few functions, however other most functions
+work well. Therefore, for example, an employee can install SoftEther VPN
+Server on the computer in the office network, and he will be able to connect
+to the server from his home. In order to realize such a system by user-self,
+no system administrative privileges are required in the view-point of
+technical. However, breaking rules of the company to install software on the
+computer without authority might be regarded as an unfavorable behavior. If
+you are an employee and belong to the company, and the company-policy
+prohibits installing software or making communications towards Internet
+without permission, you have to obtain a permission from the network
+administrator or the executive officer of your company in advance to install
+SoftEther VPN. If you install VPN Server / Bridge as User-mode, an icon will
+be appeared on the Windows task-tray. If you feel that the icon disturbs you,
+you can hide it by your operation. However, you must not exploit this hiding
+function to install VPN Server on other person's computer as a spyware. Such
+behavior might be an offence against the criminal law.
+
+2.4. Keep Alive Function
+SoftEther VPN Server and SoftEther VPN Bridge has Keep Alive Function by
+default. The purpose of this function is to sustain the Internet line active.
+The function transmits UDP packets with a random-byte-array-payload
+periodically. This function is useful to avoid automatic disconnection on
+mobile or dial-up connections. You can disable Keep Alive Function anytime.
+
+2.5. Uninstallation
+The uninstallation process of SoftEther VPN software will delete all program
+files. However, non-program files (such as files and data which are generated
+by running of programs) ) will not be deleted. For technical reason, the exe
+and resource files of uninstaller might remain. Such remaining files never
+affects to use the computer, however you can delete it manually. Kernel-mode
+drivers might not be deleted, however such drivers will not be loaded after
+the next boot of Windows. You can use "sc" command of Windows to delete
+kernel-mode drivers manually.
+
+2.6. Security
+You should set the administrator's password on SoftEther VPN Server / Bridge
+after installation. If you neglect to do it, another person can access to
+SoftEther VPN Server / Bridge and can set the password without your
+permission. This caution might be also applied on SoftEther VPN Client for
+Linux.
+
+2.7. Automatic Update Notification
+SoftEther VPN software for Windows has an automatic update notification
+function. It accesses to the SoftEther Update server periodically to check
+whether or not the latest version of software is released. If the latest
+version is released, the notification message will be popped up on the screen.
+In order to achieve this purpose, the version, language settings, the unique
+identifier, the IP address of your computer and the hostname of VPN Server
+which is connected to will be sent to the SoftEther Update server. No personal
+information will be sent. Automatic Update Notification is enabled by default,
+however you can disable it on the configuration screen. The setting whether
+turned on or turned off will be saved individually corresponding to each
+destination VPN server, by VPN Server Manager.
+
+2.8. Virtual NAT Function
+A Virtual Hub on SoftEther VPN Server / Bridge has "Virtual NAT Function" .
+Virtual NAT Function can share a single IP address on the physical network by
+multiple private IP address of VPN Clients. There are two operation mode of
+Virtual NAT: User-mode and Kernel-mode. In the user-mode operation, Virtual
+NAT shares an IP address which is assigned on the host operating system.
+Unlike user-mode, the kernel-mode operation attempts to find DHCP servers on
+the physical network. If there are two or more physical networks, a DHCP
+server will be sought automatically for each segments serially. If a DHCP
+server found, and an IP address is acquired, the IP address will be used by
+the Virtual NAT. In this case, an IP entry as a DHCP client will be registered
+on the IP pool of the physical DHCP Server. The physical default gateway and
+the DNS server will be used by the Virtual NAT in order to communicate with
+hosts in Internet. In kernel-mode operation, a Virtual Hub has a virtual MAC
+address which is operating on the physical Ethernet segment. In order to check
+the connectivity to Internet, SoftEther VPN periodically sends DNS query
+packet to resolve the IP address of host "www.yahoo.com" or "www.baidu.com" ,
+and attempts to connect to the TCP port 80 of such a resulted IP address for
+connectivity check.
+
+2.9. Unattended Installation of Kernel-mode Components
+When SoftEther VPN will detect a necessity to install the kernel-mode
+components on Windows, a confirmation message will be appeared by Windows
+system. In this occasion, SoftEther VPN software will switch to the Unattended
+Installation mode in order to respond "Yes" to Windows. This is a solution to
+prevent dead-locks when a remote-administration is performed from remote
+place.
+
+2.10. Windows Firewall
+SoftEther VPN software will register itself as a safe-program. Such an entry
+will be remain after the uninstallation. You can remove it manually from the
+Control Panel of Windows.
+
+
+3. Internet Services
+3.1. Internet Services which are provided by SoftEther Corporation
+SoftEther Corporation provides Dynamic DNS, NAT Traversal and VPN Azure server
+services on the Internet. These services are free of charge. Customers can
+access to the services by using SoftEther VPN software, via Internet. These
+service will be planned to be available from Open-Source version of "SoftEther
+VPN" which will be released in the future.
+
+3.2. Sent Information and Privacy Protection
+SoftEther VPN software may send an IP address, hostname, the version of VPN
+software on the customer's computer to the cloud service operated by SoftEther
+Corporation, in order to use the above services. These sending of information
+are minimal necessary to use the services. No personal information will be
+sent. SoftEther Corporation records log files of the cloud service servers for
+90 days at least with the received information. Such logs will be used for
+troubleshooting and other legitimate activities. SoftEther Corporation may
+provide logs to a public servant of Japanese government who are belonging to
+courts, police stations and the prosecutor's office, in order to comply such
+authorities' order. (Every Japanese public servants are liable by law to keep
+the information close.) Moreover, the IP addresses or other information will
+be processed statistically and provided to the public, not to expose the each
+concrete IP address, in order to release the release of research activities.
+
+3.3. Communication Data via VPN Azure Service
+Regardless of the above 3.2 rule, if the customer sends or receives VPN
+packets using VPN Azure Cloud Service, the actual payloads will stored and
+forwarded via the volatile memory of the servers for very short period. Such a
+behavior is naturally needed to provide the "VPN relay service" . No payloads
+will be recorded on "fixed" storages such as hard-drives. However, the
+"Wiretapping for Criminals Procedures Act" (The 137th legislation ruled on
+August 18, 1999 in Japan) requires telecommunication companies to allow the
+Japanese government authority to conduct a wire-tapping on the line. VPN Azure
+Servers which are physically placed on Japan are subjects of this law.
+
+3.4. Comply to Japanese Telecommunication Laws
+SoftEther Corporation complies with Japanese Telecommunication Laws as
+necessary to provide online services via Internet.
+
+3.5. Free and Academic Experiment Services
+SoftEther provides Dynamic DNS, NAT Traversal and VPN Azure as academic
+experiment services. Therefore, there services can be used for free of charge.
+These services are not parts of "SoftEther VPN Software Products" . These
+services are provided without any warranty. The services may be suspended or
+discontinued by technical or operational matters. In such occasions, users
+will not be able to use the services. A user have to understand such risks,
+and to acknowledge that such risks are borne by a user-self. SoftEther will
+never be liable to results or damages of use or unable-to-use of the service.
+Even if the user has already paid the license-fee of the commercial version of
+SoftEther VPN, such paid fees don't include any fees of these services.
+Therefore, if the online services will stop or be discontinued, no refunds or
+recoveries of damages will be provided by SoftEther Corporation.
+
+3.6. DNS Proxy Cloud Servers
+In some regions, when a user uses Internet, a DNS query sometimes broken or
+lost when it is passing through the ISP line. If SoftEther VPN Server, Client
+or Bridge detects a possibility that the accessing to the actual VPN server
+might be unstable, then DNS queries will be also transferred to the DNS proxy
+cloud servers which are operated by SoftEther Corporation. A DNS proxy cloud
+server will respond DNS queries with answering correct a IP address.
+
+
+4. General Cautions
+4.1. Needs an Approval from Network Administrator
+SoftEther VPN has powerful functions which don't require special settings by
+network administrators. For example, you need not to ask the administrator to
+configure the existing firewall in order to "open" a TCP/UDP port. Such
+characteristic features are for the purpose to eliminate working times and
+costs of network administrators, and avoid misconfiguration-risks around the
+tasks to open specific exception ports on the firewall. However, any employees
+belong to the company have to obtain an approval from the network
+administrator before installs SoftEther VPN. If your network administrator
+neglects to provide such an approval, you can consider to take an approval
+from an upper authority. (For example, executive officer of the company.) If
+you use SoftEther VPN without any approvals from the authority of your
+company, you might have disadvantage. SoftEther Corporation will be never
+liable for results or damages of using SoftEther VPN.
+
+4.2. Observe Laws of Your Country
+If your country's law prohibits the use of encryption, you have to disable the
+encryption function of SoftEther VPN by yourself. Similarly, in some countries
+or regions, some functions of SoftEther VPN might be prohibited to use by
+laws. Other countries' laws are none of SoftEther Corporation's concern
+because SoftEther Corporation is an enterprise which is located and registered
+in Japan physically. For example, there might be a risk that a part of
+SoftEther VPN conflicts an existing patent which is valid only on the specific
+region. SoftEther Corporation has no interests in such specific region outside
+Japan's territory. Therefore, if you want to use SoftEther VPN in regions
+outside Japan, you have to be careful not to violate third-person's rights.
+You have to verify the legitimacy of the use of SoftEther VPN in the specific
+region before you actually use it in such region. By nature, there are almost
+200 countries in the World, and each country's law is different each other. It
+is practically impossible to verify every countries' laws and regulations and
+make the software comply with all countries' laws in advance to release the
+software. Therefore SoftEther Corporation has verified the legitimacy of
+SoftEther VPN against the laws and regulations of only Japan. If a user uses
+SoftEther VPN in a specific country, and damaged by public servants of the
+government authority, SoftEther Corporation will never be liable to recover or
+compensate such damages or criminal responsibilities.
+
+
+5. VPN Gate Academic Experiment Project
+(This chapter applies only on SoftEther VPN software package which contains
+the extension plug-in for VPN Gate Academic Experiment Project.)
+5.1. About VPN Gate Academic Experiment Project
+VPN Gate Academic Experiment Project is an online service operated for just
+the academic research purpose at the graduate school of University of Tsukuba,
+Japan. The purpose of this research is to expend our knowledge about the
+"Global Distributed Public VPN Relay Server" (GDPVRS) technology. For details,
+please visit http://www.vpngate.net/.
+
+5.2. About VPN Gate Service
+SoftEther VPN Server and SoftEther VPN Client may contain "VPN Gate Service"
+program. However, VPN Gate Service is disabled by default.
+VPN Gate Service should be activated and enabled by the voluntary intention of
+the owner of the computer which SoftEther VPN Server or SoftEther VPN Client
+is installed on. After you activate VPN Gate Service, the computer will be
+start to serve as a part of the Global Distributed Public VPN Relay Servers.
+The IP address, hostname and related information of the computer will be sent
+and registered to the directory server of VPN Gate Academic Experiment
+Project, and they will be published and disclosed to the public. This
+mechanism will allow any VPN Gate Client software's user to connect to the VPN
+Gate Service running on your computer. While the VPN session between a VPN
+Gate Client and your VPN Gate Service is established, the VPN Gate Client's
+user can send/receive any IP packets towards the Internet via the VPN Gate
+Service. The global IP address of the VPN Gate Service's hosing computer will
+be used as the source IP address of such communications which a VPN Gate
+Client initiates.
+VPN Gate Service will send some information to the VPN Gate Academic
+Experiment Service Directory Server. The information includes the operator's
+information which described in section 5.5, logging settings, uptime,
+operating system version, type of protocol, port numbers, quality information,
+statistical information, VPN Gate clients' log history data (includes dates,
+IP addresses, version numbers and IDs) and the version of the software. These
+information will be exposed on the directory. VPN Gate Service also receives a
+key for encoding which is described on the chapter 5.9 from the directory
+server.
+
+5.3. Details of VPN Gate Service's Behavior
+If you enable VPN Gate Service manually, which is disabled by default, the
+"VPNGATE" Virtual Hub will be created on the SoftEther VPN Server. If you are
+using SoftEther VPN Client and attempt to active VPN Gate Service on it, an
+equivalent program to SoftEther VPN Server will be invoked on the same process
+of SoftEther VPN Client, and the "VPNGATE" Virtual Hub will be created. The
+"VPNGATE" Virtual Hub contains a user named "VPN" by default which permits
+anyone on the Internet to make a VPN connection to the Virtual Hub. Once a VPN
+Client connects to the "VPNGATE" Virtual Hub, any communication between the
+user and the Internet will pass through the Virtual Hub, and
+transmitted/received using the physical network interface on the computer
+which SoftEther VPN Server (or SoftEther VPN Client) is running on. This will
+cause the result that a destination host specified by the VPN Client will
+identify that the source of the communication has initiated from the VPN Gate
+Service's hosting computer's IP address. However, for safety, any packets
+which destinations are within 192.168.0.0/255.255.0.0, 172.16.0.0/255.240.0.0
+or 10.0.0.0/255.0.0.0 will be blocked by the "VPNGATE" Virtual Hub in order to
+protect your local network. Therefore, if you run VPN Gate Service on your
+corporate network or private network, it is safe because anonymous VPN Client
+users will not be permitted to access such private networks. VPN Gate Service
+also serves as relay for accessing to the VPN Gate Directory Server.
+In order to make VPN Gate Service familiar with firewalls and NATs, it opens
+an UDP port by using the NAT Traversal function which is described on the
+section 1.2. It also opens and listens on some TCP ports, and some TCP and UDP
+ports will be specified as the target port of Universal Plug and Play (UPnP)
+Port Transfer entries which are requested to your local routers. UPnP request
+packets will be sent periodically. Some routers keep such an opened TCP/UDP
+port permanently on the device. If you wish to close them, do it manually.
+VPN Gate Service also provides the mirror-site function for www.vpngate.net.
+This is a mechanism that a copy of the latest contents from www.vpngate.net
+will be hosted by the mirror-site tiny HTTP server which is running on the VPN
+Gate Service program. It will register itself on the mirror-sites list in
+www.vpngate.net. However, it never relays any other communications which are
+not towards www.vpngate.net.
+
+5.4. Communication between Internet via VPN Gate Service
+VPN Gate Service provides a routing between users and the Internet, by using
+the Virtual NAT Function which is described on the section 2.8. VPN Gate
+Service sends polling Ping packets to the server which is located on
+University of Tsukuba, and the Google Public DNS Server which is identified as
+8.8.8.8, in order to check the latest quality of your Internet line. VPN Gate
+Service also sends and receives a lot of random packets to/from the Speed Test
+Server on University of Tsukuba. These quality data will be reported to VPN
+Gate Directory Server, automatically and periodically. The result will be
+saved and disclosed to the public. These periodical polling communication are
+adjusted not to occupy the Internet line, however in some circumstances they
+might occupy the line.
+
+5.5. Operator's Information of VPN Gate Service
+If you activate VPN Gate Service on your computer, the computer will be a part
+of the Global Distributed Public VPN Relay Servers. Therefore, the Operator's
+administrative information of your VPN Gate Service should be reported and
+registered on the VPN Gate Service Directory. Operator's information contains
+the name of the operator and the abuse-reporting contact e-mail address. These
+information can be inputted on the screen if the VPN Gate configuration.
+Inputted information will be transmitted to the VPN Gate Directory Server,
+stored and disclosed to the public. So you have to be careful to input
+information. By the way, until you specify something as the operator's
+information, the computer's hostname will be used automatically as the field
+of the name of the operator, by appending the "'s owner" string after the
+hostname.
+
+5.6. Observe Laws to Operate VPN Gate Service
+In some countries or regions, a user who is planning to activate and operate
+VPN Gate Service, he are mandated to obtain a license or register a service
+from/to the government. If your region has such a regulation, you must fulfill
+mandated process before activating VPN Gate Service in advance. Neither the
+developers nor operators of the VPN Gate Academic Experiment Project will be
+liable for legal/criminal responsibilities or damages which are occurred from
+failure to comply your local laws.
+
+5.7. Protect Privacy of Communication
+Most of countries have a law which requires communication service's operators,
+including VPN Gate Service operators, to protect the privacy of communication
+of third-persons. When you operate VPN Gate Service, you must always protect
+user's privacy.
+
+5.8. Packet Logs
+The packet logging function is implemented on VPN Gate Service. It records
+essential headers of major TCP/IP packets which are transmitted via the
+Virtual Hub. This function will be helpful to investigate the "original IP
+address" of the initiator of communication who was a connected user of your
+VPN Gate Service, by checking the packet logs and the connection logs. The
+packet logs are recorded only for such legitimate investigates purpose. Do not
+peek nor leak packet logs except the rightful purpose. Such act will be
+violate the section 5.7.
+
+5.9. Packet Logs Automatic Archiving and Encoding Function
+The VPN Gate Academic Experiment Service is operated and running under the
+Japanese constitution and laws. The Japanese constitution laws demand strictly
+protection over the privacy of communication. Because this service is under
+Japanese rules, the program of VPN Gate Service implements this "Automatic Log
+File Encoding" protection mechanism, and enabled by default.
+The VPN Gate Service is currently configured to encode packet log files which
+has passed two or more weeks automatically, by default. In order to protect
+privacy of communication, if a packet log file is once encoded, even the
+administrator of the local computer cannot censor the packet log file. This
+mechanism protects privacy of end-users of VPN Gate Service.
+You can change the VPN Gate Service setting to disable this automatic encoding
+function. Then packet log files will never be encoded even after two weeks
+passed. In such a configuration, all packet logs will remain as plain-text on
+the disk. Therefore you have to take care not to violate user's privacy.
+If you are liable to decode an encoded packet log files (for example: a VPN
+Gate Service's user illegally abused your VPN Gate Service and you have to
+decode the packet logs in order to comply the laws), contact the administrator
+of the VPN Gate Academic Experiment Service at Graduate School of University
+of Tsukuba, Japan. You can find the contact address at
+http://www.vpngate.net/. The administrator of VPN Gate Service will respond to
+decode the packet logs if there is an appropriate and legal request from court
+or other judicial authorities, according to laws.
+
+5.10. Caution if You Operate VPN Gate Service in the Japan's Territories
+When a user operates VPN Gate Service in the Japan's territories, such an act
+may be regulated under the Japanese Telecommunication Laws if the operation is
+a subject to the law. However, in such a circumstance, according to the
+"Japanese Telecommunication Business Compete Manual [supplemental version]" ,
+non- profitable operations of communications are not identified as a
+"telecommunication business" . So usual operators of VPN Gate Service are not
+subjects to "telecommunication business operators" , and not be mandated to
+register to the government. Even so, legalities to protect the privacy of
+communication still imposed. As a conclusion, if you operate VPN Gate Service
+in the Japan's Territories, you must not leak the secrets of communications
+which are transmitted via your operating VPN Gate Service.
+
+5.11. VPN Gate Client
+If SoftEther VPN Client contains the VPN Gate Client plug-in, you can use it
+to obtain the list of current operating VPN Gate Service servers in the
+Internet, and make a VPN connection to a specific server on the list.
+VPN Gate Client always keeps the latest list of the VPN Gate Services
+periodically. Be careful if you are using a pay-per-use Internet line.
+When you start the VPN Gate Client software, the screen which asks you
+activate or not VPN Gate Service will be appeared. For details of VPN Gate
+Service, read the above sections.
+
+5.12. Caution before Joining or Exploiting VPN Gate Academic Experiment
+Project
+The VPN Gate Academic Experiment Service is operated as a research project at
+the graduate school on University of Tsukuba, Japan. The service is governed
+under the Japanese laws. Other countries' laws are none of our concerns nor
+responsibilities.
+By nature, there are almost 200 countries in the World, with different laws.
+It is impossible to verify every countries' laws and regulations and make the
+software comply with all countries' laws in advance to release the software.
+If a user uses VPN Gate service in a specific country, and damaged by public
+servants of the authority, the developer of either the service or software
+will never be liable to recover or compensate such damages or criminal
+responsibilities.
+By using this software and service, the user must observe all concerned laws
+and rules with user's own responsibility. The user will be completely liable
+to any damages and responsibilities which are results of using this software
+and service, regardless of either inside or outside of Japan's territory.
+If you don't agree nor understand the above warnings, do not use any of VPN
+Gate Academic Experiment Service functions.
+VPN Gate is a research project for just academic purpose only. VPN Gate was
+developed as a plug-in for SoftEther VPN and UT-VPN. However, all parts of VPN
+Gate were developed on this research project at University of Tsukuba. Any
+parts of VPN Gate are not developed by SoftEther Corporation. The VPN Gate
+Research Project is not a subject to be led, operated, promoted nor guaranteed
+by SoftEther Corporation.
+
+
diff --git a/README b/README
new file mode 100644
index 00000000..df623ce6
--- /dev/null
+++ b/README
@@ -0,0 +1,189 @@
+SoftEther VPN - An Open-Source Cross-platform Multi-protocol VPN Program
+http://www.softether.org/
+
+We use GitHub as the primary official SoftEther VPN repository:
+https://github.com/SoftEtherVPN/SoftEtherVPN/
+
+Source code packages (.zip and .tar.gz) and binary files are also available:
+http://www.softether-download.com/
+
+Copyright (c) 2012-2014 SoftEther Project at University of Tsukuba, Japan.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2
+as published by the Free Software Foundation.
+
+SoftEther VPN ("SoftEther" means "Software Ethernet") is one of the
+world's most powerful and easy-to-use multi-protocol VPN software.
+
+SoftEther VPN runs on Windows, Linux, Mac, FreeBSD and Solaris.
+
+SoftEther VPN supports most of widely-used VPN protocols
+including SSL-VPN, OpenVPN, IPsec, L2TP, MS-SSTP, L2TPv3 and EtherIP
+by the single SoftEther VPN Server program.
+
+More details on http://www.softether.org/.
+
+
+SOFTETHER VPN ADVANTAGES
+------------------------
+
+- Supporting all popular VPN protocols by the single VPN server:
+ SSL-VPN (HTTPS)
+ OpenVPN
+ IPsec
+ L2TP
+ MS-SSTP
+ L2TPv3
+ EtherIP
+- Free and open-source software.
+- Easy to establish both remote-access and site-to-site VPN.
+- SSL-VPN Tunneling on HTTPS to pass through NATs and firewalls.
+- Revolutionary VPN over ICMP and VPN over DNS features.
+- Resistance to highly-restricted firewall.
+- Ethernet-bridging (L2) and IP-routing (L3) over VPN.
+- Embedded dynamic-DNS and NAT-traversal so that no static nor
+ fixed IP address is required.
+- AES 256-bit and RSA 4096-bit encryptions.
+- Sufficient security features such as logging and firewall inner
+ VPN tunnel.
+- 1Gbps-class high-speed throughput performance with low memory and
+ CPU usage.
+- Windows, Linux, Mac, Android, iPhone, iPad and Windows Phone are
+ supported.
+- The OpenVPN clone function supports legacy OpenVPN clients.
+- IPv4 / IPv6 dual-stack.
+- The VPN server runs on Windows, Linux, FreeBSD, Solaris and Mac OS X.
+- Configure All settings on GUI.
+- Multi-languages (English, Japanese and Simplified-Chinese).
+- More details at http://www.softether.org/.
+
+
+GETTING STARTED
+---------------
+
+Visit the SoftEther VPN Project official web site at first:
+ http://www.softether.org/
+
+If you are not a developer, it is recommended to download the binary
+installers from:
+ http://www.softether-download.com/
+
+To build from the source,
+see "BUILD_UNIX.TXT" or "BUILD_WINDOWS.TXT" files.
+
+
+HOW TO DOWNLOAD THE LATEST SOURCE CODE PACKAGE
+----------------------------------------------
+
+Go to http://www.softether-download.com/ and you can find the latest
+source-code package file in both .ZIP and .TAR.GZ format.
+
+This is the easiest way to obtain the source code of SoftEther VPN.
+
+
+HOW TO GET THE LATEST SOURCE CODE TREE FOR DEVELOPERS
+-----------------------------------------------------
+
+If you are an open-source developer, visit our GitHub repository:
+https://github.com/SoftEtherVPN/SoftEtherVPN/
+
+You can download the up-to-date source-code tree of SoftEther VPN
+from GitHub. You may make your own fork project from our project.
+
+The download and build instruction is following:
+
+$ git clone https://github.com/SoftEtherVPN/SoftEtherVPN.git
+$ cd SoftEtherVPN
+$ make
+$ make install
+
+
+TO CIRCUMVENT YOUR GOVERNMENT'S FIREWALL RESTRICTION
+----------------------------------------------------
+
+Because SoftEther VPN is overly strong tool to build a VPN tunnel,
+some censorship governments want to block your access to the source code
+of SoftEther VPN, by abusing their censorship firewalls.
+
+To circumvent your censor's unjust restriction,
+SoftEther VPN Project distributes the up-to-date source-code
+on all the following open-source repositories:
+
+ - GitHub
+ https://github.com/SoftEtherVPN/SoftEtherVPN/
+
+ - SourceForge
+ https://sourceforge.net/projects/softethervpn/
+
+ - Google Code
+ https://code.google.com/p/softether/
+
+
+To fetch the source code from GitHub:
+$ git clone https://github.com/SoftEtherVPN/SoftEtherVPN.git
+
+To fetch the source code from SourceForge:
+$ git clone http://git.code.sf.net/p/softethervpn/code
+ - or -
+$ git clone git://git.code.sf.net/p/softethervpn/code
+
+To fetch the source code from Google Code:
+$ git clone https://code.google.com/p/softether/
+
+We hope that you can reach one of the above URLs at least!
+
+
+DEAR SECURITY EXPERTS
+---------------------
+
+If you find a bug or a security vulnerability please kindly inform us
+about the problem immediately so that we can fix the security problem
+to protect a lot of users around the world as soon as possible.
+
+Our e-mail address for security reports is:
+softether-vpn-security [at] softether.org
+
+Please note that the above e-mail address is not a technical support
+inquiry address. If you need technical assistance, please visit
+http://www.softether.org/ and ask your question on the users forum.
+
+
+DISCLAIMER
+----------
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+
+USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+COUNTRIES MIGHT BE RESTRICTED.
+
+
+ADVERTISEMENT
+-------------
+
+SoftEther VPN is developed by SoftEther VPN Project at University of Tsukuba.
+Department of Computer Science has dozens of overly-enthusiastic geeks.
+Join us: http://www.tsukuba.ac.jp/english/admission/
+
diff --git a/README.TXT b/README.TXT
new file mode 100644
index 00000000..df623ce6
--- /dev/null
+++ b/README.TXT
@@ -0,0 +1,189 @@
+SoftEther VPN - An Open-Source Cross-platform Multi-protocol VPN Program
+http://www.softether.org/
+
+We use GitHub as the primary official SoftEther VPN repository:
+https://github.com/SoftEtherVPN/SoftEtherVPN/
+
+Source code packages (.zip and .tar.gz) and binary files are also available:
+http://www.softether-download.com/
+
+Copyright (c) 2012-2014 SoftEther Project at University of Tsukuba, Japan.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2
+as published by the Free Software Foundation.
+
+SoftEther VPN ("SoftEther" means "Software Ethernet") is one of the
+world's most powerful and easy-to-use multi-protocol VPN software.
+
+SoftEther VPN runs on Windows, Linux, Mac, FreeBSD and Solaris.
+
+SoftEther VPN supports most of widely-used VPN protocols
+including SSL-VPN, OpenVPN, IPsec, L2TP, MS-SSTP, L2TPv3 and EtherIP
+by the single SoftEther VPN Server program.
+
+More details on http://www.softether.org/.
+
+
+SOFTETHER VPN ADVANTAGES
+------------------------
+
+- Supporting all popular VPN protocols by the single VPN server:
+ SSL-VPN (HTTPS)
+ OpenVPN
+ IPsec
+ L2TP
+ MS-SSTP
+ L2TPv3
+ EtherIP
+- Free and open-source software.
+- Easy to establish both remote-access and site-to-site VPN.
+- SSL-VPN Tunneling on HTTPS to pass through NATs and firewalls.
+- Revolutionary VPN over ICMP and VPN over DNS features.
+- Resistance to highly-restricted firewall.
+- Ethernet-bridging (L2) and IP-routing (L3) over VPN.
+- Embedded dynamic-DNS and NAT-traversal so that no static nor
+ fixed IP address is required.
+- AES 256-bit and RSA 4096-bit encryptions.
+- Sufficient security features such as logging and firewall inner
+ VPN tunnel.
+- 1Gbps-class high-speed throughput performance with low memory and
+ CPU usage.
+- Windows, Linux, Mac, Android, iPhone, iPad and Windows Phone are
+ supported.
+- The OpenVPN clone function supports legacy OpenVPN clients.
+- IPv4 / IPv6 dual-stack.
+- The VPN server runs on Windows, Linux, FreeBSD, Solaris and Mac OS X.
+- Configure All settings on GUI.
+- Multi-languages (English, Japanese and Simplified-Chinese).
+- More details at http://www.softether.org/.
+
+
+GETTING STARTED
+---------------
+
+Visit the SoftEther VPN Project official web site at first:
+ http://www.softether.org/
+
+If you are not a developer, it is recommended to download the binary
+installers from:
+ http://www.softether-download.com/
+
+To build from the source,
+see "BUILD_UNIX.TXT" or "BUILD_WINDOWS.TXT" files.
+
+
+HOW TO DOWNLOAD THE LATEST SOURCE CODE PACKAGE
+----------------------------------------------
+
+Go to http://www.softether-download.com/ and you can find the latest
+source-code package file in both .ZIP and .TAR.GZ format.
+
+This is the easiest way to obtain the source code of SoftEther VPN.
+
+
+HOW TO GET THE LATEST SOURCE CODE TREE FOR DEVELOPERS
+-----------------------------------------------------
+
+If you are an open-source developer, visit our GitHub repository:
+https://github.com/SoftEtherVPN/SoftEtherVPN/
+
+You can download the up-to-date source-code tree of SoftEther VPN
+from GitHub. You may make your own fork project from our project.
+
+The download and build instruction is following:
+
+$ git clone https://github.com/SoftEtherVPN/SoftEtherVPN.git
+$ cd SoftEtherVPN
+$ make
+$ make install
+
+
+TO CIRCUMVENT YOUR GOVERNMENT'S FIREWALL RESTRICTION
+----------------------------------------------------
+
+Because SoftEther VPN is overly strong tool to build a VPN tunnel,
+some censorship governments want to block your access to the source code
+of SoftEther VPN, by abusing their censorship firewalls.
+
+To circumvent your censor's unjust restriction,
+SoftEther VPN Project distributes the up-to-date source-code
+on all the following open-source repositories:
+
+ - GitHub
+ https://github.com/SoftEtherVPN/SoftEtherVPN/
+
+ - SourceForge
+ https://sourceforge.net/projects/softethervpn/
+
+ - Google Code
+ https://code.google.com/p/softether/
+
+
+To fetch the source code from GitHub:
+$ git clone https://github.com/SoftEtherVPN/SoftEtherVPN.git
+
+To fetch the source code from SourceForge:
+$ git clone http://git.code.sf.net/p/softethervpn/code
+ - or -
+$ git clone git://git.code.sf.net/p/softethervpn/code
+
+To fetch the source code from Google Code:
+$ git clone https://code.google.com/p/softether/
+
+We hope that you can reach one of the above URLs at least!
+
+
+DEAR SECURITY EXPERTS
+---------------------
+
+If you find a bug or a security vulnerability please kindly inform us
+about the problem immediately so that we can fix the security problem
+to protect a lot of users around the world as soon as possible.
+
+Our e-mail address for security reports is:
+softether-vpn-security [at] softether.org
+
+Please note that the above e-mail address is not a technical support
+inquiry address. If you need technical assistance, please visit
+http://www.softether.org/ and ask your question on the users forum.
+
+
+DISCLAIMER
+----------
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+
+USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+COUNTRIES MIGHT BE RESTRICTED.
+
+
+ADVERTISEMENT
+-------------
+
+SoftEther VPN is developed by SoftEther VPN Project at University of Tsukuba.
+Department of Computer Science has dozens of overly-enthusiastic geeks.
+Join us: http://www.tsukuba.ac.jp/english/admission/
+
diff --git a/configure b/configure
new file mode 100755
index 00000000..7b7c249e
--- /dev/null
+++ b/configure
@@ -0,0 +1,76 @@
+#!/bin/sh
+
+echo '---------------------------------------------------------------------'
+echo 'SoftEther VPN for Unix'
+echo
+echo 'Copyright (c) SoftEther VPN Project at University of Tsukuba, Japan.'
+echo 'Copyright (c) Daiyuu Nobori. All Rights Reserved.'
+echo
+echo 'This program is free software; you can redistribute it and/or'
+echo 'modify it under the terms of the GNU General Public License'
+echo 'version 2 as published by the Free Software Foundation.'
+echo '---------------------------------------------------------------------'
+echo
+
+echo 'Welcome to the corner-cutting configure script !'
+echo
+echo 'Select your operating system below:'
+echo ' 1: Linux'
+echo ' 2: FreeBSD'
+echo ' 3: Solaris'
+echo ' 4: Mac OS X'
+echo
+echo -n 'Which is your operating system (1 - 4) ? : '
+read TMP
+echo
+OS=""
+if test "$TMP" = "1"
+then
+ OS="linux"
+fi
+if test "$TMP" = "2"
+then
+ OS="freebsd"
+fi
+if test "$TMP" = "3"
+then
+ OS="solaris"
+fi
+if test "$TMP" = "4"
+then
+ OS="macos"
+fi
+
+if test "$OS" = ""
+then
+ echo "Wrong number."
+ exit 1
+fi
+
+echo 'Select your CPU bits below:'
+echo ' 1: 32-bit'
+echo ' 2: 64-bit'
+echo
+echo -n 'Which is the type of your CPU (1 - 2) ? : '
+read TMP
+echo
+CPU=""
+if test "$TMP" = "1"
+then
+ CPU="32bit"
+fi
+if test "$TMP" = "2"
+then
+ CPU="64bit"
+fi
+
+if test "$CPU" = ""
+then
+ echo "Wrong number."
+ exit 1
+fi
+
+cp src/makefiles/${OS}_${CPU}.mak Makefile
+
+echo "The Makefile is generated. Run 'make' to build SoftEther VPN."
+
diff --git a/src/BUILD_UNIX.TXT b/src/BUILD_UNIX.TXT
new file mode 100644
index 00000000..f62295dd
--- /dev/null
+++ b/src/BUILD_UNIX.TXT
@@ -0,0 +1,125 @@
+How to build SoftEther VPN for UNIX
+===================================
+
+
+Requirements
+------------
+
+You need to install the following software to build SoftEther VPN for UNIX.
+
+- Linux, FreeBSD, Solaris or Mac OS X.
+- GNU Compiler Collectipon (gcc) and binary utilities.
+- GNU Make (gmake).
+- GNU C Library (glibc).
+- POSIX Threads (pthread).
+- OpenSSL (crypto, ssl).
+- libiconv.
+- readline.
+- ncurses.
+
+For example, the following commands help you to install the above programs
+on Fedora or CentOS Linux:
+
+$ yum -y groupinstall "Development Tools"
+$ yum -y install readline-devel ncurses-devel openssl-devel
+
+
+How to Build
+------------
+
+To build the programs from the source code, run the following commands:
+
+$ ./configure
+$ make
+
+If any error occurs, please check the above requirements.
+
+
+How to Install SoftEther VPN Server, Bridge or Client
+-----------------------------------------------------
+
+To install the vpnserver, vpnbridge and vpnclient programs into the
+/usr/bin directory, run the following as the root user:
+
+# make install
+
+After the installation will complete successfully:
+
+- Execute 'vpnserver start' to run the SoftEther VPN Server background service.
+- Execute 'vpnbridge start' to run the SoftEther VPN Bridge background service.
+- Execute 'vpnclient start' to run the SoftEther VPN Client background service.
+- Execute 'vpncmd' to run SoftEther VPN Command-Line Utility to configure
+ VPN Server, VPN Bridge or VPN Client.
+
+- You can also use VPN Server/Client Manager GUI Tool on other Windows PC to
+ connect to VPN services remotely.
+ You can download the GUI Tools from http://www.softether-download.com/.
+
+
+How to Run SoftEther VPN Server for Test
+----------------------------------------
+
+To start the SoftEther VPN Server background service, run the following:
+
+$ bin/vpnserver/vpnserver start
+
+To stop the service, run the following:
+
+$ bin/vpnserver/vpnserver stop
+
+To configure the running SoftEther VPN Server service,
+you can use SoftEther VPN Command Line Management Utility as following:
+
+$ bin/vpncmd/vpncmd
+
+Or you can also use VPN Server Manager GUI Tool on other Windows PC to
+connect to the VPN Server remotely. You can download the GUI Tool
+from http://www.softether-download.com/.
+
+
+How to Run SoftEther VPN Bridge for Test
+----------------------------------------
+
+To start the SoftEther VPN Bridge background service, run the following:
+
+$ bin/vpnbridge/vpnbridge start
+
+To stop the service, run the following:
+
+$ bin/vpnbridge/vpnbridge stop
+
+To configure the running SoftEther VPN Bridge service,
+you can use SoftEther VPN Command Line Management Utility as following:
+
+$ bin/vpncmd/vpncmd
+
+Or you can also use VPN Server Manager GUI Tool on other Windows PC to
+connect to the VPN Bridge remotely. You can download the GUI Tool
+from http://www.softether-download.com/.
+
+
+How to Run SoftEther VPN Client for Test
+----------------------------------------
+
+To start the SoftEther VPN Client background service, run the following:
+
+$ bin/vpnclient/vpnclient start
+
+To stop the service, run the following:
+
+$ bin/vpnclient/vpnclient stop
+
+To configure the running SoftEther VPN Client service,
+you can use SoftEther VPN Command Line Management Utility as following:
+
+$ bin/vpncmd/vpncmd
+
+Or you can also use VPN Client Manager GUI Tool on other Windows PC to
+connect to the VPN Client remotely. You can download the GUI Tool
+from http://www.softether-download.com/.
+
+
+************************************
+Thank You Using SoftEther VPN !
+By SoftEther VPN Open-Source Project
+http://www.softether.org/
diff --git a/src/BUILD_WINDOWS.TXT b/src/BUILD_WINDOWS.TXT
new file mode 100644
index 00000000..06e64f72
--- /dev/null
+++ b/src/BUILD_WINDOWS.TXT
@@ -0,0 +1,42 @@
+How to build SoftEther VPN for Windows
+======================================
+
+
+Requirements
+------------
+
+You need to install the following software to build SoftEther VPN for Windows.
+
+- Microsoft Windows XP, Vista, 7, 8 or later.
+- Microsoft Visual Studio 2008.
+
+* Note:
+ Visual Studio 2008 is required to build SoftEther VPN on Windows.
+ Visual Studio 2010, 2012 or 2013 is currently not supported.
+ Visual Studio 2008 Express Edition is not supported.
+ Standard Edition, Professional Edition, Team System or Team Suite is
+ required.
+
+
+Full Build Instructions
+-----------------------
+
+The following steps will build all SoftEther VPN program files, and also build
+the installer packages of SoftEther VPN. It is very easy.
+
+1. Run the "BuildAll.cmd" batch file in the "src" directory.
+2. Wait until the building process will complete.
+3. The built files are stored on the "output" directory.
+
+
+Partly Build, Debug or Development Instructions on Visual Studio 2008
+---------------------------------------------------------------------
+
+If you are a programmer, you can open the SoftEther VPN solution file
+with Visual Studio 2008 to customize. Open "src\SEVPN.sln" and enjoy it.
+
+
+************************************
+Thank You Using SoftEther VPN !
+By SoftEther VPN Open-Source Project
+http://www.softether.org/
diff --git a/src/BuildAll.cmd b/src/BuildAll.cmd
new file mode 100644
index 00000000..5c96ea50
--- /dev/null
+++ b/src/BuildAll.cmd
@@ -0,0 +1,19 @@
+SETLOCAL
+SET BATCH_FILE_NAME=%0
+SET BATCH_DIR_NAME=%0\..
+SET NOW_TMP=%time:~0,2%
+SET NOW=%date:~0,4%%date:~5,2%%date:~8,2%_%NOW_TMP: =0%%time:~3,2%%time:~6,2%
+
+call "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"
+call "C:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"
+echo on
+
+del %BATCH_DIR_NAME%\bin\BuildUtil.exe
+
+C:\windows\Microsoft.NET\Framework\v3.5\MSBuild.exe /toolsversion:3.5 /verbosity:detailed /target:Clean /property:Configuration=Debug "%BATCH_DIR_NAME%\BuildUtil\BuildUtil.csproj"
+
+C:\windows\Microsoft.NET\Framework\v3.5\MSBuild.exe /toolsversion:3.5 /verbosity:detailed /target:Rebuild /property:Configuration=Debug "%BATCH_DIR_NAME%\BuildUtil\BuildUtil.csproj"
+
+cmd /k "%BATCH_DIR_NAME%\bin\BuildUtil.exe /CMD:All"
+
+
diff --git a/src/BuildFiles/Library/Win32_Debug/libeay32.lib b/src/BuildFiles/Library/Win32_Debug/libeay32.lib
new file mode 100644
index 00000000..d0540ea2
Binary files /dev/null and b/src/BuildFiles/Library/Win32_Debug/libeay32.lib differ
diff --git a/src/BuildFiles/Library/Win32_Debug/libintelaes.lib b/src/BuildFiles/Library/Win32_Debug/libintelaes.lib
new file mode 100644
index 00000000..cb2bf4c5
Binary files /dev/null and b/src/BuildFiles/Library/Win32_Debug/libintelaes.lib differ
diff --git a/src/BuildFiles/Library/Win32_Debug/ssleay32.lib b/src/BuildFiles/Library/Win32_Debug/ssleay32.lib
new file mode 100644
index 00000000..e6b41878
Binary files /dev/null and b/src/BuildFiles/Library/Win32_Debug/ssleay32.lib differ
diff --git a/src/BuildFiles/Library/Win32_Debug/zlib.lib b/src/BuildFiles/Library/Win32_Debug/zlib.lib
new file mode 100644
index 00000000..cdda429c
Binary files /dev/null and b/src/BuildFiles/Library/Win32_Debug/zlib.lib differ
diff --git a/src/BuildFiles/Library/Win32_Release/libeay32.lib b/src/BuildFiles/Library/Win32_Release/libeay32.lib
new file mode 100644
index 00000000..3366d3aa
Binary files /dev/null and b/src/BuildFiles/Library/Win32_Release/libeay32.lib differ
diff --git a/src/BuildFiles/Library/Win32_Release/libintelaes.lib b/src/BuildFiles/Library/Win32_Release/libintelaes.lib
new file mode 100644
index 00000000..cb2bf4c5
Binary files /dev/null and b/src/BuildFiles/Library/Win32_Release/libintelaes.lib differ
diff --git a/src/BuildFiles/Library/Win32_Release/ssleay32.lib b/src/BuildFiles/Library/Win32_Release/ssleay32.lib
new file mode 100644
index 00000000..d2645535
Binary files /dev/null and b/src/BuildFiles/Library/Win32_Release/ssleay32.lib differ
diff --git a/src/BuildFiles/Library/Win32_Release/zlib.lib b/src/BuildFiles/Library/Win32_Release/zlib.lib
new file mode 100644
index 00000000..36f89247
Binary files /dev/null and b/src/BuildFiles/Library/Win32_Release/zlib.lib differ
diff --git a/src/BuildFiles/Library/x64_Debug/libeay32.lib b/src/BuildFiles/Library/x64_Debug/libeay32.lib
new file mode 100644
index 00000000..13a87803
Binary files /dev/null and b/src/BuildFiles/Library/x64_Debug/libeay32.lib differ
diff --git a/src/BuildFiles/Library/x64_Debug/libintelaes.lib b/src/BuildFiles/Library/x64_Debug/libintelaes.lib
new file mode 100644
index 00000000..c00ae06b
Binary files /dev/null and b/src/BuildFiles/Library/x64_Debug/libintelaes.lib differ
diff --git a/src/BuildFiles/Library/x64_Debug/ssleay32.lib b/src/BuildFiles/Library/x64_Debug/ssleay32.lib
new file mode 100644
index 00000000..d7f7e49e
Binary files /dev/null and b/src/BuildFiles/Library/x64_Debug/ssleay32.lib differ
diff --git a/src/BuildFiles/Library/x64_Debug/zlib.lib b/src/BuildFiles/Library/x64_Debug/zlib.lib
new file mode 100644
index 00000000..da852576
Binary files /dev/null and b/src/BuildFiles/Library/x64_Debug/zlib.lib differ
diff --git a/src/BuildFiles/Library/x64_Release/libeay32.lib b/src/BuildFiles/Library/x64_Release/libeay32.lib
new file mode 100644
index 00000000..afbe0c2e
Binary files /dev/null and b/src/BuildFiles/Library/x64_Release/libeay32.lib differ
diff --git a/src/BuildFiles/Library/x64_Release/libintelaes.lib b/src/BuildFiles/Library/x64_Release/libintelaes.lib
new file mode 100644
index 00000000..c00ae06b
Binary files /dev/null and b/src/BuildFiles/Library/x64_Release/libintelaes.lib differ
diff --git a/src/BuildFiles/Library/x64_Release/ssleay32.lib b/src/BuildFiles/Library/x64_Release/ssleay32.lib
new file mode 100644
index 00000000..bf7f3acc
Binary files /dev/null and b/src/BuildFiles/Library/x64_Release/ssleay32.lib differ
diff --git a/src/BuildFiles/Library/x64_Release/zlib.lib b/src/BuildFiles/Library/x64_Release/zlib.lib
new file mode 100644
index 00000000..9be4c609
Binary files /dev/null and b/src/BuildFiles/Library/x64_Release/zlib.lib differ
diff --git a/src/BuildFiles/Manifests/x64_admin.manifest b/src/BuildFiles/Manifests/x64_admin.manifest
new file mode 100644
index 00000000..0fcdb4d9
--- /dev/null
+++ b/src/BuildFiles/Manifests/x64_admin.manifest
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
diff --git a/src/BuildFiles/Manifests/x64_user.manifest b/src/BuildFiles/Manifests/x64_user.manifest
new file mode 100644
index 00000000..21e1e78a
--- /dev/null
+++ b/src/BuildFiles/Manifests/x64_user.manifest
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
diff --git a/src/BuildFiles/Manifests/x86_admin.manifest b/src/BuildFiles/Manifests/x86_admin.manifest
new file mode 100644
index 00000000..0129bc30
--- /dev/null
+++ b/src/BuildFiles/Manifests/x86_admin.manifest
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
diff --git a/src/BuildFiles/Manifests/x86_user.manifest b/src/BuildFiles/Manifests/x86_user.manifest
new file mode 100644
index 00000000..4a3d6fb4
--- /dev/null
+++ b/src/BuildFiles/Manifests/x86_user.manifest
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
diff --git a/src/BuildFiles/OcxCabInf/vpnweb.inf b/src/BuildFiles/OcxCabInf/vpnweb.inf
new file mode 100644
index 00000000..9a7c46dd
--- /dev/null
+++ b/src/BuildFiles/OcxCabInf/vpnweb.inf
@@ -0,0 +1,18 @@
+; VPN Client Web Installer Inf File
+;
+; Copyright (c) SoftEther Project at University of Tsukuba, Japan.
+; All Rights Reserved.
+
+[version]
+signature="$CHICAGO$"
+AdvancedINF=2.0
+
+[Add.Code]
+vpnweb.ocx=vpnweb.ocx
+
+[vpnweb.ocx]
+file-win32-x86=thiscab
+clsid={64F1A16B-C3EE-484C-B551-35338A9BB6D2}
+FileVersion=$CAB_VERSION$
+RegisterServer=yes
+
diff --git a/src/BuildFiles/Utility/cabarc.exe b/src/BuildFiles/Utility/cabarc.exe
new file mode 100644
index 00000000..11f437d9
Binary files /dev/null and b/src/BuildFiles/Utility/cabarc.exe differ
diff --git a/src/BuildFiles/Utility/cabarc_redist.txt b/src/BuildFiles/Utility/cabarc_redist.txt
new file mode 100644
index 00000000..9241359f
--- /dev/null
+++ b/src/BuildFiles/Utility/cabarc_redist.txt
@@ -0,0 +1,74 @@
+
+MICROSOFT CABINET SOFTWARE DEVELOPMENT KIT
+
+END-USER LICENSE AGREEMENT FOR MICROSOFT SOFTWARE
+
+IMPORTANT-READ CAREFULLY: This Microsoft End-User License Agreement ("EULA") is a legal agreement between you (either an individual or a single entity) and Microsoft Corporation for the Microsoft software product identified above, which includes computer software and associated media and printed materials, and may include "online" or electronic documentation ("SOFTWARE PRODUCT" or "SOFTWARE"). By installing, copying, or otherwise using the SOFTWARE PRODUCT, you agree to be bound by the terms of this EULA. If you do not agree to the terms of this EULA; promptly return the unused SOFTWARE PRODUCT to the place from which you obtained it for a full refund; or if you received the SOFTWARE PRODUCT as part of a subscription or other service from Microsoft, you may cancel the subscription and receive a pro rata portion of the subscription price.
+
+SOFTWARE PRODUCT LICENSE
+
+The SOFTWARE PRODUCT is protected by copyright laws and international copyright treaties, as well as other intellectual property laws and treaties. The SOFTWARE PRODUCT is licensed, not sold.
+
+1. GRANT OF LICENSE. This EULA grants you the following limited, non-exclusive rights:
+
+Software Product. You may install and use the SOFTWARE PRODUCT on a single computer solely for the purpose of developing applications which create, extract or manipulate files that are compatible with Microsoft CAB file format ("Application"). You may not use the SOFTWARE PRODUCT to create files which are not compatible with the Microsoft CAB file format.
+
+Microsoft Developer Network Subscriber. If you acquired the SOFTWARE PRODUCT through a subscription to the Microsoft Developer Network, and you are either an individual developer or an individual designated within a single entity, you are granted the following additional rights with respect to the SOFTWARE PRODUCT: (a) you may make and use copies of the SOFTWARE PRODUCT on up to ten (10) separate computers, provided that you are the only individual using the SOFTWARE PRODUCT on each such computer, and (b) if you are a single entity, you may designate one individual within your organization to have the right to use the SOFTWARE PRODUCT in the manner described herein.
+
+Sample Code. You may modify the sample source code located in the SOFTWARE PRODUCT's "SAMPLES" directory ("Sample Code") to design, develop, and test your Application. You may also reproduce and distribute the Sample Code in object code form along with any modifications you make to the Sample Code, provided that the modifications do not create files which are not compatible with Microsoft CAB file format and that you comply with the Distribution Requirements described below. For purposes of this section, "modifications" shall mean changes to the functionality of the Sample Code.
+
+Redistributable Code. Portions of the SOFTWARE PRODUCT in the "BIN" and "LIB" directories are designated as "Redistributable Code." You may reproduce and distribute the Redistributable Code provided you comply with the Distribution Requirements described below.
+
+Distribution Requirements. You may copy and redistribute the Sample Code and/or Redistributable Code (collectively "REDISTRIBUTABLE COMPONENTS") as described above, provided that (a) you distribute the REDISTRIBUTABLE COMPONENTS only in conjunction with, and as a part of, your Application; (b) your Application adds significant and primary functionality to the REDISTRIBUTABLE COMPONENTS; (c) the Application does not allow the use of the REDISTRIBUTABLE COMPONENTS for files which are not compatible with the Microsoft CAB files; (d) the executable code in the BIN directory may be redistributed unmodified in conjunction with your Application provided that your Application adds significant and primary functionality to the REDISTRIBUTABLE COMPONENTS; (e) the library code in the LIB directory may only be redistributed when linked into your Application; (f) you do not use Microsoft's name, logo, or trademarks to market your Application; (g) you include a valid copyright notice on your Application; and (h) you agree to indemnify, hold harmless, and defend Microsoft from and against any claims or lawsuits, including attorneys' fees, that arise or result from the use or distribution of your Application. Contact Microsoft for the applicable royalties due and other licensing terms for all other uses and/or distribution of the REDISTRIBUTABLE COMPONENTS.
+
+Microsoft reserves all rights not expressly granted to you.
+
+2. COPYRIGHT. All rights, title, and copyrights in and to the SOFTWARE PRODUCT (including, but not limited to, any images, photographs, animations, video, audio, music, text, and "applets" incorporated into the SOFTWARE PRODUCT) and any copies of the SOFTWARE PRODUCT are owned by Microsoft or its suppliers. The SOFTWARE PRODUCT is protected by copyright laws and international treaty provisions. Therefore, you must treat the SOFTWARE PRODUCT like any other copyrighted material, except that you may either (a) make one copy of the SOFTWARE PRODUCT solely for backup or archival purposes, or (b) install the SOFTWARE PRODUCT on a single computer, provided you keep the original solely for backup or archival purposes. You may not copy the printed materials accompanying the SOFTWARE PRODUCT.
+
+3. PRERELEASE CODE. The SOFTWARE PRODUCT may contain PRERELEASE CODE that is not at the level of performance and compatibility of the final, generally available, product offering. These portions of the SOFTWARE PRODUCT may not operate correctly and may be substantially modified prior to first commercial shipment. Microsoft is not obligated to make this or any later version of the SOFTWARE PRODUCT commercially available. Microsoft grants you the right to distribute test versions of your Application created using the PRERELEASE CODE provided you comply with the Distribution Requirements described in Section 1 and the following additional provisions: (a) you must mark the test version of your Application "BETA" and (b) you are solely responsible for updating your customers with versions of your Application that operate satisfactorily with the final commercial release of the PRERELEASE CODE.
+
+4. DESCRIPTION OF OTHER RIGHTS AND LIMITATIONS.
+
+Limitations on Reverse-Engineering, Decompilation, and Disassembly. You may not reverse- engineer, decompile, or disassemble the SOFTWARE PRODUCT, except and only to the extent that such activity is expressly permitted by applicable law notwithstanding this limitation.
+
+Rental. You may not rent or lease the SOFTWARE PRODUCT.
+
+Software Transfer. You may permanently transfer all of your rights under this EULA, provided you retain no copies, you transfer all of the SOFTWARE PRODUCT (including all component parts, the media and printed materials, any upgrades, this EULA, and, if applicable, the Certificate of Authenticity), and the recipient agrees to the terms of this EULA. If the SOFTWARE PRODUCT is an upgrade, any transfer must include all prior versions of the SOFTWARE PRODUCT.
+
+Termination. Without prejudice to any other rights, Microsoft may terminate this EULA if you fail to comply with the terms and conditions of this EULA. In such event, you must destroy all copies of the SOFTWARE PRODUCT and all of its component parts.
+
+5. EXPORT RESTRICTIONS. You agree that neither you nor your customers intend to or will, directly or indirectly, export or transmit (a) the SOFTWARE PRODUCT or related documentation and technical data, or (b) your Application as described in Section 1 of this EULA (or any part thereof), or process, or service that is the direct product of the SOFTWARE PRODUCT to any country to which such export or transmission is restricted by any applicable U.S. regulation or statute, without the prior written consent, if required, of the Bureau of Export Administration of the U.S. Department of Commerce, or such other governmental entity as may have jurisdiction over such export or transmission.
+
+6. U.S. GOVERNMENT RESTRICTED RIGHTS. The SOFTWARE PRODUCT and documentation are provided with RESTRICTED RIGHTS. Use, duplication, or disclosure by the Government is subject to restrictions as set forth in subparagraph (c)(1)(ii) of The Rights in Technical Data and Computer Software clause at DFARS 252.227-7013 or subparagraphs (c)(1) and (2) of the Commercial Computer Software - Restricted Rights at 48 CFR 52.227-19, as applicable. Manufacturer is Microsoft Corporation/One Microsoft Way/Redmond, WA 98052-6399.
+
+MISCELLANEOUS
+
+If you acquired this product in the United States, this EULA is governed by the laws of the State of Washington.
+
+If you acquired this product in Canada, this EULA is governed by the laws of the Province of Ontario, Canada. Each of the parties hereto irrevocably attorns to the jurisdiction of the courts of the Province of Ontario and further agrees to commence any litigation that may arise hereunder in the courts located in the Judicial District of York, Province of Ontario.
+
+If this product was acquired outside the United States, local law may apply.
+
+Should you have any questions concerning this EULA, or if you desire to contact Microsoft for any reason, please contact the Microsoft subsidiary serving your country, or write: Microsoft Customer Sales and Service/One Microsoft Way/Redmond, WA 98052-6399.
+
+NO WARRANTIES. To the maximum extent permitted by applicable law, Microsoft expressly disclaims any warranty for the SOFTWARE PRODUCT. The SOFTWARE PRODUCT and any related documentation are provided "as is" without warranty of any kind, either express or implied, including, without limitation, the implied warranties of merchantability or fitness for a particular purpose. The entire risk arising out of use or performance of the SOFTWARE PRODUCT remains with you.
+
+LIMITATION OF LIABILITY. Microsoft's entire liability and your exclusive remedy under this EULA shall not exceed five dollars (US$5.00).
+
+NO LIABILITY FOR CONSEQUENTIAL DAMAGES. To the maximum extent permitted by applicable law, in no event shall Microsoft or its suppliers be liable for any damages whatsoever (including, without limitation, damages for loss of business profit, business interruption, loss of business information, or any other pecuniary loss) arising out of the use of, or inability to use, this Microsoft product, even if Microsoft has been advised of the possibility of such damages. Because some states/jurisdictions do not allow the exclusion or limitation of liability for consequential or incidental damages, the above limitation may not apply to you.
+
+
+Si vous avez acquis votre produit Microsoft au CANADA, la garantie limitée suivante vous concerne:
+
+GARANTIE LIMITÉE
+
+EXCLUSION DE GARANTIES. Microsoft renonce entièrement à toute garantie pour le LOGICIEL. Le LOGICIEL et toute autre documentation s'y rapportant sont fournis « comme tels » sans aucune garantie quelle qu'elle soit, expresse ou implicite, y compris, mais ne se limitant pas aux garanties implicites de la qualité marchande ou un usage particulier. Le risque total découlant de l'utilisation ou de la performance du LOGICIEL est entre vos mains.
+
+RESPONSABILITÉ LIMITÉE. La seule obligation de Microsoft et votre recours exclusif concernant ce contrat n'excèderont pas cinq dollars (US$5.00).
+
+ABSENCE DE RESPONSABILITÉ POUR LES DOMMAGES INDIRECTS. Microsoft ou ses
+fournisseurs ne pourront être tenus responsables en aucune circonstance de tout dommage quel qu'il soit (y compris mais non de façon limitative les dommages directs ou indirects causés par la perte de bénéfices commerciaux, l'interruption des affaires, la perte d'information commerciale ou toute autre perte pécuniaire) résultant de l'utilisation ou de l'impossibilité d'utilisation de ce produit, et ce, même si la société Microsoft a été avisée de l'éventualité de tels dommages. Certains états/juridictions ne permettent pas l'exclusion ou la limitation de responsabilité relative aux dommages indirects ou consécutifs, et la limitation ci-dessus peut ne pas s'appliquer à votre égard.
+La présente Convention est régie par les lois de la province d'Ontario, Canada. Chacune des parties à la Convention reconnaît irrévocablement la compétence des tribunaux de la province d'Ontario et consent à instituer tout litige qui pourrait découler de la Convention auprès des tribunaux situés dans le district judiciaire de York, province d'Ontario.
+Au cas où vous auriez des questions concernant cette licence ou que vous désiriez vous mettre en rapport avec Microsoft pour quelque raison que ce soit, veuillez contacter la succursale Microsoft desservant votre pays, dont l'adresse est fournie dans ce produit, ou écrire à: Microsoft Customer Sales and Service, One Microsoft Way, Redmond, Washington 98052-6399.
+
+3/27/97 10:39 AM 970860004
\ No newline at end of file
diff --git a/src/BuildFiles/VerScript/ver.rc b/src/BuildFiles/VerScript/ver.rc
new file mode 100644
index 00000000..1d937b5e
--- /dev/null
+++ b/src/BuildFiles/VerScript/ver.rc
@@ -0,0 +1,30 @@
+#pragma code_page(932)
+
+1 VERSIONINFO
+ FILEVERSION $VER_MAJOR$,$VER_MINOR$,0,$VER_BUILD$
+ PRODUCTVERSION $VER_MAJOR$,$VER_MINOR$,0,$VER_BUILD$
+ FILEFLAGSMASK 0x17L
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "041104b0"
+ BEGIN
+ VALUE "CompanyName", "SoftEther VPN Project at University of Tsukuba, Japan. (Open-source Customized Build)"
+ VALUE "FileDescription", "$PRODUCTNAME$ (Open-source Customized Build)"
+ VALUE "FileVersion", "$VER_MAJOR$, $VER_MINOR$, 0, $VER_BUILD$"
+ VALUE "InternalName", "$INTERNALNAME$ (Open-source Customized Build)"
+ VALUE "LegalCopyright", "Copyright (C) 2012-$YEAR$ SoftEther VPN Project. All Rights Reserved. (Open-source Customized Build)"
+ VALUE "LegalTrademarks", "SoftEther(R) is a registered trademark of SoftEther Corporation in Japan, United Status and People's Republic of China. SoftEther Corporation is a company founded at University of Tsukuba, Japan."
+ VALUE "OriginalFilename", "$FILENAME$"
+ VALUE "ProductName", "$PRODUCTNAME$ (Open-source Customized Build)"
+ VALUE "ProductVersion", "$VER_MAJOR$, $VER_MINOR$, 0, $VER_BUILD$"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x411, 1200
+ END
+END
diff --git a/src/BuildFiles/VerScript/ver_vg.rc b/src/BuildFiles/VerScript/ver_vg.rc
new file mode 100644
index 00000000..b185c5d5
--- /dev/null
+++ b/src/BuildFiles/VerScript/ver_vg.rc
@@ -0,0 +1,30 @@
+#pragma code_page(932)
+
+1 VERSIONINFO
+ FILEVERSION $VER_MAJOR$,$VER_MINOR$,0,$VER_BUILD$
+ PRODUCTVERSION $VER_MAJOR$,$VER_MINOR$,0,$VER_BUILD$
+ FILEFLAGSMASK 0x17L
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "041104b0"
+ BEGIN
+ VALUE "CompanyName", "University of Tsukuba"
+ VALUE "FileDescription", "VPN Gate Plug-in DLL for SoftEther VPN"
+ VALUE "FileVersion", "$VER_MAJOR$, $VER_MINOR$, 0, $VER_BUILD$"
+ VALUE "InternalName", "$INTERNALNAME$"
+ VALUE "LegalCopyright", "Copyright (C) 2012-$YEAR$ VPN Gate Project at University of Tsukuba. All Rights Reserved."
+ VALUE "LegalTrademarks", ""
+ VALUE "OriginalFilename", "$FILENAME$"
+ VALUE "ProductName", "VPN Gate Software"
+ VALUE "ProductVersion", "$VER_MAJOR$, $VER_MINOR$, 0, $VER_BUILD$"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x411, 1200
+ END
+END
diff --git a/src/BuildUtil/BuildUtil.csproj b/src/BuildUtil/BuildUtil.csproj
new file mode 100644
index 00000000..effc6d26
--- /dev/null
+++ b/src/BuildUtil/BuildUtil.csproj
@@ -0,0 +1,181 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {384815C3-333C-4CEC-9DCD-B6AB2602EBB9}
+ Exe
+ Properties
+ BuildUtil
+ BuildUtilTmp
+ v2.0
+ 512
+ BuildUtilIcon.ico
+ false
+ BuildUtil.BuildUtilMain
+ true
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ true
+
+
+ true
+ full
+ false
+ ..\bin\
+ TRACE;DEBUG;BU_SOFTETHER;BU_OSS
+ prompt
+ 4
+ x86
+
+
+ false
+
+
+
+ False
+ .\CoreUtil.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ Settings.settings
+
+
+
+
+
+
+
+ True
+ True
+ Reference.map
+
+
+ True
+ True
+ Reference.map
+
+
+
+
+
+
+
+
+
+ Dynamic
+ Web References\SignService\
+ http://dv/Sign/Sign.asmx
+
+
+
+
+ Settings
+ BuildUtil_SignService_Sign
+
+
+ Dynamic
+ Web References\HvSignService\
+ http://hvsigncode/Sign.asmx
+
+
+
+
+ Settings
+ BuildUtilTmp_HvSignService_Sign
+
+
+
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+
+ MSDiscoCodeGenerator
+ Reference.cs
+
+
+
+
+
+
+
+ MSDiscoCodeGenerator
+ Reference.cs
+
+
+
+
+
+ False
+ .NET Framework Client Profile
+ false
+
+
+ False
+ .NET Framework 2.0 %28x86%29
+ true
+
+
+ False
+ .NET Framework 3.0 %28x86%29
+ false
+
+
+ False
+ .NET Framework 3.5
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+
+
+
+ $(ProjectDir)CopyBuildUtil.cmd
+
+
\ No newline at end of file
diff --git a/src/BuildUtil/BuildUtilCommands.cs b/src/BuildUtil/BuildUtilCommands.cs
new file mode 100644
index 00000000..9d78477c
--- /dev/null
+++ b/src/BuildUtil/BuildUtilCommands.cs
@@ -0,0 +1,1245 @@
+// SoftEther VPN Source Code
+// Build Utility
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+using System;
+using System.Threading;
+using System.Text;
+using System.Configuration;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Security.Cryptography;
+using System.Web;
+using System.Web.Security;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+using System.Web.UI.WebControls.WebParts;
+using System.Web.UI.HtmlControls;
+using System.IO;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Drawing.Drawing2D;
+using System.Diagnostics;
+using System.Net;
+using System.Net.Security;
+using System.Security.Cryptography.X509Certificates;
+using CoreUtil;
+
+namespace BuildUtil
+{
+ public static class BuildUtilCommands
+ {
+ // Perform all
+ [ConsoleCommandMethod(
+ "Builds all sources and releases all packages.",
+ "All [yes|no] [/NORMALIZESRC:yes|no] [/IGNOREERROR:yes|no] [/DEBUG:yes|no] [/SERIAL:yes|no]",
+ "Builds all sources and releases all packages.",
+ "[yes|no]:Specify 'yes' if you'd like to increment the build number.",
+ "NORMALIZESRC:Specity 'yes' if you'd like to normalize the build infomations in the source codes and resource scripts.",
+ "IGNOREERROR:Specify yes if you'd like to ignore the child process to show the error message.",
+ "SERIAL:Specify yes not to use parallel mode.",
+ "DEBUG:Specity yes to enable debug mode. (UNIX only)"
+#if !BU_SOFTETHER
+ , "SEVPN:Build SoftEther VPN Automatically After PacketiX VPN Build"
+#endif
+ )]
+ static int All(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+#if !BU_SOFTETHER
+ new ConsoleParam("[yes|no]", ConsoleService.Prompt, "Increments build number (y/n) ? ", ConsoleService.EvalNotEmpty, null),
+ new ConsoleParam("SEVPN", ConsoleService.Prompt, "Build SoftEther VPN automatically after PacketiX VPN Build (y/n) ? ", ConsoleService.EvalNotEmpty, null),
+#else
+ new ConsoleParam("[yes|no]"),
+#endif
+ new ConsoleParam("IGNOREERROR"),
+ new ConsoleParam("DEBUG"),
+ new ConsoleParam("SERIAL"),
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ DateTime start = Time.NowDateTime;
+
+ Win32BuildUtil.ExecCommand(Env.ExeFileName, string.Format("/CMD:BuildWin32 {0} /NORMALIZESRC:{1}",
+ vl["[yes|no]"].BoolValue ? "yes" : "no",
+ "yes"));
+
+ Win32BuildUtil.ExecCommand(Env.ExeFileName, string.Format("/CMD:ReleaseWin32 all /IGNOREERROR:{0} /SERIAL:{1}",
+ vl["IGNOREERROR"].BoolValue ? "yes" : "no",
+ vl["SERIAL"].BoolValue ? "yes" : "no"));
+
+#if !BU_OSS
+ Win32BuildUtil.ExecCommand(Env.ExeFileName, string.Format("/CMD:ReleaseUnix all /IGNOREERROR:{0} /DEBUG:{1} /SERIAL:{2}",
+ vl["IGNOREERROR"].BoolValue ? "yes" : "no",
+ vl["DEBUG"].BoolValue ? "yes" : "no",
+ vl["SERIAL"].BoolValue ? "yes" : "no"));
+#endif
+
+ Win32BuildUtil.ExecCommand(Env.ExeFileName, string.Format("/CMD:CopyRelease"));
+
+#if !BU_SOFTETHER
+ Win32BuildUtil.ExecCommand(Env.ExeFileName, string.Format("/CMD:MakeOpenSource"));
+
+ Win32BuildUtil.ExecCommand(Env.ExeFileName, string.Format("/CMD:MakeSoftEtherDir"));
+
+ if (vl["SEVPN"].BoolValue)
+ {
+ // Build SEVPN
+ Win32BuildUtil.ExecCommand(Paths.CmdFileName, string.Format("/C \"{0}\"", Path.Combine(Paths.SoftEtherBuildDir, @"Main\BuildAll.cmd")));
+ }
+#endif
+
+ DateTime end = Time.NowDateTime;
+
+ Con.WriteLine("Taken time: {0}.", (end - start));
+
+ return 0;
+ }
+
+#if !BU_SOFTETHER
+ // Create SoftEther Edition source
+ [ConsoleCommandMethod(
+ "Make MakeSoftEtherDir Source Dir.",
+ "MakeSoftEtherDir",
+ "Make MakeSoftEtherDir Source Dir."
+ )]
+ static int MakeSoftEtherDir(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ OpenSourceUtil.MakeSoftEtherDir();
+
+ return 0;
+ }
+
+ // Create an open source version of source
+ [ConsoleCommandMethod(
+ "Make MakeOpenSource Source Dir.",
+ "MakeOpenSource",
+ "Make MakeOpenSource Source Dir."
+ )]
+ static int MakeOpenSource(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ OpenSourceUtil.MakeOpenSource();
+
+ return 0;
+ }
+#endif
+
+ // Copy the released files
+ [ConsoleCommandMethod(
+ "Copies all release files.",
+ "CopyRelease",
+ "Copies all release files."
+ )]
+ static int CopyRelease(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ int build, version;
+ string name;
+ DateTime date;
+ Win32BuildUtil.ReadBuildInfoFromTextFile(out build, out version, out name, out date);
+
+ string baseName = string.Format("v{0}-{1}-{2}-{3:D4}.{4:D2}.{5:D2}",
+ BuildHelper.VersionIntToString(version),
+ build,
+ name,
+ date.Year, date.Month, date.Day);
+
+#if !BU_OSS
+ string destDirName = Path.Combine(Paths.ReleaseDestDir,
+ string.Format(@"{0}-{1}-{2}-{3}",
+ Str.DateToStrShort(BuildSoftwareList.ListCreatedDateTime),
+ baseName,
+ Env.MachineName, Env.UserName));
+#else // !BU_OSS
+ string destDirName = Path.Combine(Paths.ReleaseDestDir,
+ string.Format(@"{1}",
+ Str.DateToStrShort(BuildSoftwareList.ListCreatedDateTime),
+ baseName,
+ Env.MachineName, Env.UserName));
+#endif
+
+#if !BU_OSS
+ string publicDir = Path.Combine(destDirName, "Public");
+#else // !BU_OSS
+ string publicDir = destDirName;
+#endif
+
+#if !BU_OSS
+ string filesReleaseDir = Path.Combine(publicDir, baseName);
+#else // !BU_OSS
+ string filesReleaseDir = publicDir;
+#endif
+
+ string autorunReleaseSrcDir = Path.Combine(publicDir, "autorun");
+
+ IO.CopyDir(Paths.ReleaseDir, filesReleaseDir, null, false, true);
+
+#if !BU_OSS
+ IO.CopyDir(Paths.ReleaseSrckitDir, Path.Combine(destDirName, "Private"), null, false, true);
+ IO.CopyDir(Path.Combine(Paths.BaseDirName, @"tmp\lib"), Path.Combine(destDirName, @"Private\lib"), null, false, true);
+#endif
+
+ //IO.MakeDir(autorunReleaseSrcDir);
+
+ /*
+ File.Copy(Path.Combine(Paths.AutorunSrcDir, "Project1.exe"),
+ Path.Combine(autorunReleaseSrcDir, "autorun.exe"), true);
+
+ File.Copy(Path.Combine(Paths.AutorunSrcDir, "autorun.inf"),
+ Path.Combine(autorunReleaseSrcDir, "autorun.inf"), true);
+
+ File.Copy(Path.Combine(Paths.AutorunSrcDir, "packetix.ico"),
+ Path.Combine(autorunReleaseSrcDir, "autorun.ico"), true);*/
+
+ // Create a batch file
+ string batchFileName = Path.Combine(publicDir, "MakeCD.cmd");
+#if !BU_OSS
+ StreamWriter w = new StreamWriter(batchFileName);
+#else // !BU_OSS
+ StringWriter w = new StringWriter();
+#endif
+ w.WriteLine(@"SETLOCAL");
+ w.WriteLine(@"SET BATCH_FILE_NAME=%0");
+ w.WriteLine(@"SET BATCH_DIR_NAME=%0\..");
+ w.WriteLine(@"SET NOW_TMP=%time:~0,2%");
+ w.WriteLine(@"SET NOW=%date:~0,4%%date:~5,2%%date:~8,2%_%NOW_TMP: =0%%time:~3,2%%time:~6,2%");
+ w.WriteLine();
+ w.WriteLine();
+
+ string[] files = Directory.GetFiles(filesReleaseDir, "*", SearchOption.AllDirectories);
+
+ string cddir = "CD";
+ /*string.Format("CD-v{0}.{1}-{2}-{3}-{4:D4}.{5:D2}.{6:D2}",
+ version / 100, version % 100, build, name,
+ date.Year, date.Month, date.Day);*/
+
+ StringWriter txt = new StringWriter();
+
+ foreach (string filename in files)
+ {
+ string file = filename;
+
+ BuildSoftware s = new BuildSoftware(file);
+
+ // Software\Windows\PacketiX VPN Server 4.0\32bit (Intel x86)\filename.exe
+ string cpustr = string.Format("{0} - {1}", CPUBitsUtil.CPUBitsToString(s.Cpu.Bits), s.Cpu.Title).Replace("/", "or");
+ string cpustr2 = cpustr;
+
+ if (s.Cpu == CpuList.intel)
+ {
+ cpustr2 = "";
+ cpustr = "Intel";
+ }
+
+ string tmp = string.Format(@"{1}\{2}\{3}\{5}{4}",
+ 0,
+ s.Os.Title,
+ BuildHelper.GetSoftwareTitle(s.Software),
+ cpustr2,
+ Path.GetFileName(file),
+ ""
+ );
+
+ tmp = Str.ReplaceStr(tmp, "\\\\", "\\");
+
+ w.WriteLine("mkdir \"{1}\\{0}\"", Path.GetDirectoryName(tmp), cddir);
+ w.WriteLine("copy /b /y \"{2}\\{0}\" \"{3}\\{1}\"", IO.GetRelativeFileName(file, filesReleaseDir), tmp, baseName, cddir);
+ w.WriteLine();
+
+ string txt_filename = tmp;
+ txt_filename = Str.ReplaceStr(txt_filename, "\\", "/");
+
+ string txt_description = BuildHelper.GetSoftwareTitle(s.Software);
+
+ string txt_products = BuildHelper.GetSoftwareProductList(s.Software);
+
+ string txt_os = s.Os.Title;
+
+ string txt_cpu = s.Cpu.Title;
+ if (s.Cpu.Bits != CPUBits.Both)
+ {
+ txt_cpu += " (" + CPUBitsUtil.CPUBitsToString(s.Cpu.Bits) + ")";
+ }
+ else
+ {
+ txt_cpu += " (x86 and x64)";
+ }
+
+ string txt_version = BuildHelper.VersionIntToString(version);
+
+ string txt_build = build.ToString();
+
+ string txt_verstr = name;
+
+ string txt_date = Str.DateTimeToStrShortWithMilliSecs(date);
+
+ string txt_lang = "English, Japanese, Simplified Chinese";
+
+ string txt_category = "PacketiX VPN (Commercial)";
+
+#if BU_SOFTETHER
+ txt_category = "SoftEther VPN (Freeware)";
+#endif
+
+ txt.WriteLine("FILENAME\t" + txt_filename);
+ txt.WriteLine("DESCRIPTION\t" + txt_description);
+ txt.WriteLine("CATEGORY\t" + txt_category);
+ txt.WriteLine("PRODUCT\t" + txt_products);
+ txt.WriteLine("OS\t" + txt_os);
+ txt.WriteLine("OSLIST\t" + s.Os.OSSimpleList);
+ txt.WriteLine("CPU\t" + txt_cpu);
+ txt.WriteLine("VERSION\t" + txt_version);
+ txt.WriteLine("BUILD\t" + txt_build);
+ txt.WriteLine("VERSTR\t" + txt_verstr);
+ txt.WriteLine("DATE\t" + txt_date);
+ txt.WriteLine("LANGUAGE\t" + txt_lang);
+ txt.WriteLine("*");
+ txt.WriteLine();
+ }
+
+#if BU_OSS
+ Con.WriteLine("Installer packages are built on '{0}'. Enjoy it !!", publicDir);
+
+ return 0;
+#endif // BU_OSS
+
+ /*
+ w.WriteLine("mkdir \"{0}\\autorun\"", cddir);
+ w.WriteLine("copy /b /y autorun\\autorun.ico \"{0}\\autorun\"", cddir);
+ w.WriteLine("copy /b /y autorun\\autorun.exe \"{0}\\autorun\"", cddir);
+ w.WriteLine("copy /b /y autorun\\autorun.inf \"{0}\\autorun.inf\"", cddir);
+ * */
+
+ string zipFileName = string.Format("VPN-CD-v{0}.{1:D2}-{2}-{3}-{4:D4}.{5:D2}.{6:D2}.zip",
+ version / 100, version % 100, build, name,
+ date.Year, date.Month, date.Day);
+ w.WriteLine("del {0}", zipFileName);
+ w.WriteLine("CD {0}", cddir);
+ w.WriteLine("zip -r -0 ../{0} *", zipFileName);
+ w.WriteLine("cd ..");
+ w.WriteLine("move {0} CD\\", zipFileName);
+ w.WriteLine("rename CD {0}-tree", baseName);
+ w.WriteLine();
+
+ w.Close();
+
+ // Copy of fastcopy
+ string fastcopy_dest = Path.Combine(destDirName, @"Private\fastcopy_bin");
+ IO.MakeDirIfNotExists(fastcopy_dest);
+ File.Copy(Path.Combine(Paths.UtilityDirName, "FastCopy.exe"), Path.Combine(fastcopy_dest, "FastCopy.exe"), true);
+ File.Copy(Path.Combine(Paths.UtilityDirName, "FastEx64.dll"), Path.Combine(fastcopy_dest, "FastEx64.dll"), true);
+ File.Copy(Path.Combine(Paths.UtilityDirName, "FastExt1.dll"), Path.Combine(fastcopy_dest, "FastExt1.dll"), true);
+
+ string fastcopy_exe = @"..\Private\fastcopy_bin\FastCopy.exe";
+
+ // Create a upload batch
+ string uploadBatchFileName = Path.Combine(publicDir, "UploadNow.cmd");
+#if !BU_OSS
+ w = new StreamWriter(uploadBatchFileName);
+#endif // !BU_OSS
+
+ string folder_name = "packetix";
+#if BU_SOFTETHER
+ folder_name = "softether";
+#endif
+ w.WriteLine(@"mkdir \\download\FILES\{1}\{0}-tree", baseName, folder_name);
+ w.WriteLine(@"{0} /cmd=force_copy /exclude={3} /auto_close /force_start /estimate /open_window /error_stop=TRUE /bufsize=128 /disk_mode=diff /speed=full /verify {1}-tree /to=\\download\FILES\{2}\{1}-tree", fastcopy_exe, baseName, folder_name,
+ "\"*files.txt*\"");
+
+ w.WriteLine();
+ /*
+ w.WriteLine(@"mkdir \\downloadjp\FILES\{1}\{0}-tree", baseName, folder_name);
+ w.WriteLine(@"{0} /cmd=force_copy /exclude={3} /auto_close /force_start /estimate /open_window /error_stop=TRUE /bufsize=128 /disk_mode=diff /speed=full /verify {1}-tree /to=\\downloadjp\FILES\{2}\{1}-tree", fastcopy_exe, baseName, folder_name,
+ "\"*files.txt*\"");
+
+ w.WriteLine();*/
+
+ w.WriteLine(@"copy /y /b {0}-tree\files.txt \\download\FILES\{1}\{0}-tree\files.txt", baseName, folder_name);
+ //w.WriteLine(@"copy /y /b {0}-tree\files.txt \\downloadjp\FILES\{1}\{0}-tree\files.txt", baseName, folder_name);
+
+
+ w.WriteLine();
+ w.WriteLine(@"pause");
+ w.WriteLine();
+
+ w.Close();
+
+
+ txt.WriteLine("FILENAME\t" + zipFileName);
+#if BU_SOFTETHER
+ txt.WriteLine("DESCRIPTION\t" + "ZIP CD-ROM Image Package of SoftEther VPN (for Admins)");
+ txt.WriteLine("CATEGORY\t" + "SoftEther VPN (Freeware)");
+ txt.WriteLine("PRODUCT\t" + "ZIP CD-ROM Image Package of SoftEther VPN");
+#else // BU_SOFTETHER
+ txt.WriteLine("DESCRIPTION\t" + "ZIP CD-ROM Image Package of PacketiX VPN (for Admins)");
+ txt.WriteLine("CATEGORY\t" + "PacketiX VPN (Commercial)");
+ txt.WriteLine("PRODUCT\t" + "ZIP CD-ROM Image Package of PacketiX VPN");
+#endif // BU_SOFTETHER
+ txt.WriteLine("OS\t" + "Any");
+ txt.WriteLine("OSLIST\t" + "Any");
+ txt.WriteLine("CPU\t" + "CD-ROM");
+ txt.WriteLine("VERSION\t" + BuildHelper.VersionIntToString(version));
+ txt.WriteLine("BUILD\t" + build.ToString());
+ txt.WriteLine("VERSTR\t" + name);
+ txt.WriteLine("DATE\t" + Str.DateTimeToStrShortWithMilliSecs(date));
+ txt.WriteLine("LANGUAGE\t" + "English, Japanese, Simplified Chinese");
+ txt.WriteLine("*");
+ txt.WriteLine();
+
+ IO.MakeDirIfNotExists(Path.Combine(publicDir, cddir));
+ File.WriteAllText(Path.Combine(Path.Combine(publicDir, cddir), "files.txt"), txt.ToString(), Str.Utf8Encoding);
+
+ // Execution of batch file
+ string old_cd = Environment.CurrentDirectory;
+
+ try
+ {
+ Environment.CurrentDirectory = Path.GetDirectoryName(batchFileName);
+ }
+ catch
+ {
+ }
+
+ Win32BuildUtil.ExecCommand(Paths.CmdFileName, string.Format("/C \"{0}\"", batchFileName));
+
+ try
+ {
+ Environment.CurrentDirectory = old_cd;
+ }
+ catch
+ {
+ }
+
+ Con.WriteLine();
+ Con.WriteLine("'{0}' ã«å‡ºåŠ›ã•ã‚Œã¾ã—ãŸã€‚", destDirName);
+
+ return 0;
+ }
+
+ // UNIX release
+ [ConsoleCommandMethod(
+ "Builds UNIX installer package files.",
+ "ReleaseUnix [id] [/IGNOREERROR:yes|no] [/DEBUG:yes|no] [/SERIAL:yes|no]",
+ "Builds Unix installer package files.",
+ "[id]:Specify target package ID which you'd like to build. If you'd like to erase and rebuild all packages, specify 'all'. Specify 'clean' to delete all release files.",
+ "IGNOREERROR:Specify yes if you'd like to ignore the child process to show the error message.",
+ "SERIAL:Specify yes not to use parallel mode.",
+ "DEBUG:Specity yes to enable debug mode."
+ )]
+ static int ReleaseUnix(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ new ConsoleParam("[id]"),
+ new ConsoleParam("IGNOREERROR"),
+ new ConsoleParam("DEBUG"),
+ new ConsoleParam("SERIAL"),
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ int version, build;
+ string name;
+ DateTime date;
+ Win32BuildUtil.ReadBuildInfoFromTextFile(out build, out version, out name, out date);
+ BuildSoftware[] softs = BuildSoftwareList.List;
+ bool serial = vl["SERIAL"].BoolValue;
+
+ if (Str.IsEmptyStr(vl.DefaultParam.StrValue))
+ {
+ Con.WriteLine("IDs:");
+ foreach (BuildSoftware soft in softs)
+ {
+ if (soft.Os.IsWindows == false)
+ {
+ soft.SetBuildNumberVersionName(build, version, name, date);
+ Con.WriteLine(" {0}", soft.IDString);
+ Con.WriteLine(" - \"{0}\"", soft.OutputFileName);
+ }
+ }
+ }
+ else
+ {
+ string key = vl.DefaultParam.StrValue;
+ bool all = false;
+
+ if ("all".StartsWith(key, StringComparison.InvariantCultureIgnoreCase))
+ {
+ all = true;
+ }
+
+ if ("clean".StartsWith(key, StringComparison.InvariantCultureIgnoreCase))
+ {
+ // Delete the release directory
+ Paths.DeleteAllReleaseTarGz();
+ Con.WriteLine("Clean completed.");
+ return 0;
+ }
+
+ List o = new List();
+
+ foreach (BuildSoftware soft in softs)
+ {
+ soft.SetBuildNumberVersionName(build, version, name, date);
+
+ if (soft.Os.IsWindows == false)
+ {
+ if (all || soft.IDString.IndexOf(key, StringComparison.InvariantCultureIgnoreCase) != -1)
+ {
+ o.Add(soft);
+ }
+ }
+ }
+
+ if (o.Count == 0)
+ {
+ throw new ApplicationException(string.Format("Software ID '{0}' not found.", key));
+ }
+ else
+ {
+ if (all)
+ {
+ // Delete the release directory
+ Paths.DeleteAllReleaseTarGz();
+ }
+ else
+ {
+ IO.MakeDir(Paths.ReleaseDir);
+ }
+
+ if (serial)
+ {
+ // Build in series
+ int i;
+ for (i = 0; i < o.Count; i++)
+ {
+ Con.WriteLine("{0} / {1}: Executing for '{2}'...",
+ i + 1, o.Count, o[i].IDString);
+
+ BuildHelper.BuildMain(o[i], vl["DEBUG"].BoolValue);
+ }
+ }
+ else if (o.Count == 1)
+ {
+ // To build
+ BuildHelper.BuildMain(o[0], vl["DEBUG"].BoolValue);
+ }
+ else
+ {
+ // Make a child process build
+ Process[] procs = new Process[o.Count];
+
+ int i;
+
+ for (i = 0; i < o.Count; i++)
+ {
+ Con.WriteLine("{0} / {1}: Executing for '{2}'...",
+ i + 1, o.Count, o[i].IDString);
+
+ procs[i] = Kernel.Run(Env.ExeFileName,
+ string.Format("/PAUSEIFERROR:{1} /DT:{2} /CMD:ReleaseUnix /DEBUG:{3} {0}",
+ o[i].IDString, vl["IGNOREERROR"].BoolValue ? "no" : "yes", Str.DateTimeToStrShort(BuildSoftwareList.ListCreatedDateTime), vl["DEBUG"].BoolValue ? "yes" : "no")
+ );
+ }
+
+ Con.WriteLine("Waiting child processes...");
+
+ int numError = 0;
+
+ for (i = 0; i < o.Count; i++)
+ {
+ procs[i].WaitForExit();
+
+ bool ok = procs[i].ExitCode == 0;
+
+ if (ok == false)
+ {
+ numError++;
+ }
+
+ Con.WriteLine("{0} / {1} ({2}):", i + 1, o.Count, o[i].IDString);
+ Con.WriteLine(" {0}", ok ? "Success" : "* Error *");
+ }
+
+ Con.WriteLine();
+ if (numError != 0)
+ {
+ throw new ApplicationException(string.Format("{0} Errors.", numError));
+ }
+ Con.WriteLine("No Errors.");
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ // Win32 Release
+ [ConsoleCommandMethod(
+ "Builds Win32 installer package files.",
+ "ReleaseWin32 [id] [/IGNOREERROR:yes|no] [/SERIAL:yes|no]",
+ "Builds Win32 installer package files.",
+ "[id]:Specify target package ID which you'd like to build. If you'd like to erase and rebuild all packages, specify 'all'. Specify 'clean' to delete all release files.",
+ "SERIAL:Specify yes not to use parallel mode.",
+ "IGNOREERROR:Specify yes if you'd like to ignore the child process to show the error message."
+ )]
+ static int ReleaseWin32(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ new ConsoleParam("[id]"),
+ new ConsoleParam("IGNOREERROR"),
+ new ConsoleParam("SERIAL"),
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ bool serial = vl["SERIAL"].BoolValue;
+ int version, build;
+ string name;
+ DateTime date;
+ Win32BuildUtil.ReadBuildInfoFromTextFile(out build, out version, out name, out date);
+ BuildSoftware[] softs = BuildSoftwareList.List;
+
+ if (Str.IsEmptyStr(vl.DefaultParam.StrValue))
+ {
+ Con.WriteLine("IDs:");
+ foreach (BuildSoftware soft in softs)
+ {
+ if (soft.Os.IsWindows)
+ {
+ soft.SetBuildNumberVersionName(build, version, name, date);
+ Con.WriteLine(" {0}", soft.IDString);
+ Con.WriteLine(" - \"{0}\"", soft.OutputFileName);
+ }
+ }
+ }
+ else
+ {
+ string key = vl.DefaultParam.StrValue;
+ bool all = false;
+
+ if ("all".StartsWith(key, StringComparison.InvariantCultureIgnoreCase))
+ {
+ all = true;
+ }
+
+ if ("clean".StartsWith(key, StringComparison.InvariantCultureIgnoreCase))
+ {
+ // Delete the release directory
+ Paths.DeleteAllReleaseExe();
+ Con.WriteLine("Clean completed.");
+ return 0;
+ }
+
+ List o = new List();
+
+ foreach (BuildSoftware soft in softs)
+ {
+ soft.SetBuildNumberVersionName(build, version, name, date);
+
+ if (soft.Os.IsWindows)
+ {
+ if (all || soft.IDString.IndexOf(key, StringComparison.InvariantCultureIgnoreCase) != -1)
+ {
+ o.Add(soft);
+ }
+ }
+ }
+
+ if (o.Count == 0)
+ {
+ throw new ApplicationException(string.Format("Software ID '{0}' not found.", key));
+ }
+ else
+ {
+ if (all)
+ {
+ // Delete the release directory
+ Paths.DeleteAllReleaseExe();
+ }
+ else
+ {
+ IO.MakeDir(Paths.ReleaseDir);
+ }
+
+ if (serial)
+ {
+ // Build in series
+ int i;
+ for (i = 0; i < o.Count; i++)
+ {
+ Con.WriteLine("{0} / {1}: Executing for '{2}'...",
+ i + 1, o.Count, o[i].IDString);
+
+ BuildHelper.BuildMain(o[i], false);
+ }
+ }
+ else if (o.Count == 1)
+ {
+ // To build
+ BuildHelper.BuildMain(o[0], false);
+ }
+ else
+ {
+ // Make a child process build
+ Process[] procs = new Process[o.Count];
+
+ int i;
+
+ for (i = 0; i < o.Count; i++)
+ {
+ Con.WriteLine("{0} / {1}: Executing for '{2}'...",
+ i + 1, o.Count, o[i].IDString);
+
+ procs[i] = Kernel.Run(Env.ExeFileName,
+ string.Format("/PAUSEIFERROR:{1} /CMD:ReleaseWin32 {0}",
+ o[i].IDString, vl["IGNOREERROR"].BoolValue ? "no" : "yes"));
+ }
+
+ Con.WriteLine("Waiting child processes...");
+
+ int numError = 0;
+
+ for (i = 0; i < o.Count; i++)
+ {
+ procs[i].WaitForExit();
+
+ bool ok = procs[i].ExitCode == 0;
+
+ if (ok == false)
+ {
+ numError++;
+ }
+
+ Con.WriteLine("{0} / {1} ({2}):", i + 1, o.Count, o[i].IDString);
+ Con.WriteLine(" {0}", ok ? "Success" : "* Error *");
+ }
+
+ Con.WriteLine();
+ if (numError != 0)
+ {
+ throw new ApplicationException(string.Format("{0} Errors.", numError));
+ }
+ Con.WriteLine("No Errors.");
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ // Copy the Unix source
+ [ConsoleCommandMethod(
+ "Copies source codes for Unix.",
+ "CopyUnixSrc [destdir]",
+ "Copies source codes for Unix.",
+ "[destdir]:Specify the destination directory."
+ )]
+ static int CopyUnixSrc(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ new ConsoleParam("[destdir]", ConsoleService.Prompt, "Destination directory : ", ConsoleService.EvalNotEmpty, null),
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ ((BuildSoftwareUnix)BuildSoftwareList.vpnbridge_linux_x86_ja).CopyUnixSrc(vl.DefaultParam.StrValue);
+
+ return 0;
+ }
+
+ // Win32 build
+ [ConsoleCommandMethod(
+ "Builds all executable files for win32 and HamCore for all OS.",
+ "BuildWin32 [yes|no] [/NORMALIZESRC:yes|no]",
+ "Builds all executable files for win32 and HamCore for all OS.",
+ "[yes|no]:Specify 'yes' if you'd like to increment the build number.",
+ "NORMALIZESRC:Specity 'yes' if you'd like to normalize the build infomations in the source codes and resource scripts."
+ )]
+ static int BuildWin32(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ new ConsoleParam("[yes|no]", ConsoleService.Prompt, "Increments build number (y/n) ? ", ConsoleService.EvalNotEmpty, null),
+ new ConsoleParam("NORMALIZESRC", ConsoleService.Prompt, "Normalizes source codes (y/n) ? ", ConsoleService.EvalNotEmpty, null)
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ if (vl.DefaultParam.BoolValue)
+ {
+ Win32BuildUtil.IncrementBuildNumber();
+ }
+ if (vl.DefaultParam.BoolValue || vl["NORMALIZESRC"].BoolValue)
+ {
+ Win32BuildUtil.NormalizeBuildInfo();
+ }
+
+ Paths.DeleteAllReleaseTarGz();
+ Paths.DeleteAllReleaseExe();
+ Paths.DeleteAllReleaseManuals();
+ Paths.DeleteAllReleaseAdminKits();
+
+ Win32BuildUtil.BuildMain();
+ Win32BuildUtil.SignAllBinaryFiles();
+ HamCoreBuildUtil.BuildHamcore();
+ Win32BuildUtil.CopyDebugSnapshot();
+
+ return 0;
+ }
+
+ // Process of post-build
+ [ConsoleCommandMethod(
+ "Process necessary tasks after building.",
+ "PostBuild",
+ "Process necessary tasks after building."
+ )]
+ static int PostBuild(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ Win32BuildUtil.SignAllBinaryFiles();
+ HamCoreBuildUtil.BuildHamcore();
+
+ return 0;
+ }
+
+ // Increment the build number
+ [ConsoleCommandMethod(
+ "Increments the build number.",
+ "IncrementBuildNumber",
+ "Increments the build number written in 'CurrentBuild.txt' text file."
+ )]
+ static int IncrementBuildNumber(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ Win32BuildUtil.IncrementBuildNumber();
+
+ return 0;
+ }
+
+
+ // Test processing
+ [ConsoleCommandMethod(
+ "Run Test Procedure.",
+ "Test",
+ "Run Test Procedure."
+ )]
+ static int Test(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ TestClass.Test();
+
+ return 0;
+ }
+
+ // Build a HamCore
+ [ConsoleCommandMethod(
+ "Builds a HamCore file.",
+ "BuildHamCore",
+ "Builds a HamCore file."
+ )]
+ static int BuildHamCore(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ HamCoreBuildUtil.BuildHamcore();
+
+ return 0;
+ }
+
+ // Sign a binary file
+ [ConsoleCommandMethod(
+ "Sign all binary files.",
+ "SignAll",
+ "Sign all binary files."
+ )]
+ static int SignAll(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ Win32BuildUtil.SignAllBinaryFiles();
+
+ return 0;
+ }
+
+ // Create and sign a Inf file of SeLow for Windows 8
+ [ConsoleCommandMethod(
+ "Generate INF files for SeLow.",
+ "SignSeLowInfFiles",
+ "Generate INF files for SeLow."
+ )]
+ static int SignSeLowInfFiles(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ new ConsoleParam("[cpu]", ConsoleService.Prompt, "x86 / x64: ", ConsoleService.EvalNotEmpty, null)
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+#if !BU_OSS
+
+ Win32BuildUtil.SignSeLowInfFiles(vl.DefaultParam.StrValue);
+
+#endif
+
+ return 0;
+ }
+
+ // Create Inf file for Windows 8
+ [ConsoleCommandMethod(
+ "Generate INF files for Windows 8.",
+ "GenerateWin8InfFiles",
+ "Generate INF files for Windows 8."
+ )]
+ static int GenerateWin8InfFiles(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ new ConsoleParam("[cpu]", ConsoleService.Prompt, "x86 / x64: ", ConsoleService.EvalNotEmpty, null)
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+#if !BU_OSS
+
+ Win32BuildUtil.GenerateINFFilesForWindows8(vl.DefaultParam.StrValue);
+
+#endif
+
+ return 0;
+ }
+
+ // Set the version of the PE to 4
+ [ConsoleCommandMethod(
+ "Set the version of the PE file to 4.",
+ "SetPE4 [filename]",
+ "Set the version of the PE file to 4.",
+ "[filename]:Specify the target filename."
+ )]
+ static int SetPE4(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ new ConsoleParam("[filename]", ConsoleService.Prompt, "Filename: ", ConsoleService.EvalNotEmpty, null)
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ PEUtil.SetPEVersionTo4(vl.DefaultParam.StrValue);
+
+ return 0;
+ }
+
+ // Set the Manifest
+ [ConsoleCommandMethod(
+ "Set the manifest to the executable file.",
+ "SetManifest [filename] [/MANIFEST:manifest_file_name]",
+ "Set the manifest to the executable file.",
+ "[filename]:Specify the target executable filename.",
+ "MANIFEST:Specify the manifest XML file."
+ )]
+ static int SetManifest(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ new ConsoleParam("[filename]", ConsoleService.Prompt, "Target Filename: ", ConsoleService.EvalNotEmpty, null),
+ new ConsoleParam("MANIFEST", ConsoleService.Prompt, "Manifest Filename: ", ConsoleService.EvalNotEmpty, null),
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ PEUtil.SetManifest(vl.DefaultParam.StrValue, vl["MANIFEST"].StrValue);
+
+ return 0;
+ }
+
+ // Generate a version information resource
+ [ConsoleCommandMethod(
+ "Generate a Version Information Resource File.",
+ "GenerateVersionResource [targetFileName] [/OUT:destFileName]",
+ "Generate a Version Information Resource File.",
+ "[targetFileName]:Specify the target exe/dll file name.",
+ "OUT:Specify the output .res file.",
+ "RC:Specify a template RC file name.")]
+ static int GenerateVersionResource(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ new ConsoleParam("[targetFileName]", ConsoleService.Prompt, "Target Filename: ", ConsoleService.EvalNotEmpty, null),
+ new ConsoleParam("OUT", ConsoleService.Prompt, "Dst Filename: ", ConsoleService.EvalNotEmpty, null),
+ new ConsoleParam("RC"),
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ string targetFilename = vl.DefaultParam.StrValue;
+ string outFilename = vl["OUT"].StrValue;
+
+ Win32BuildUtil.GenerateVersionInfoResource(targetFilename, outFilename, vl["RC"].StrValue);
+
+ return 0;
+ }
+
+ // Measure the number of lines of code
+ [ConsoleCommandMethod(
+ "Count the number of lines of the sources.",
+ "Count [DIR]",
+ "Count the number of lines of the sources.",
+ "[DIR]:dir name.")]
+ static int Count(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ new ConsoleParam("[DIR]", null, null, null, null),
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ string dir = vl.DefaultParam.StrValue;
+ if (Str.IsEmptyStr(dir))
+ {
+ dir = Paths.BaseDirName;
+ }
+
+ string[] files = Directory.GetFiles(dir, "*", SearchOption.AllDirectories);
+
+ int numLines = 0;
+ int numBytes = 0;
+ int numComments = 0;
+ int totalLetters = 0;
+
+ Dictionary commentsDict = new Dictionary();
+
+ foreach (string file in files)
+ {
+ string ext = Path.GetExtension(file);
+
+ if (Str.StrCmpi(ext, ".c") || Str.StrCmpi(ext, ".cpp") || Str.StrCmpi(ext, ".h") ||
+ Str.StrCmpi(ext, ".rc") || Str.StrCmpi(ext, ".stb") || Str.StrCmpi(ext, ".cs")
+ || Str.StrCmpi(ext, ".fx") || Str.StrCmpi(ext, ".hlsl"))
+ {
+ if (Str.InStr(file, "\\.svn\\") == false && Str.InStr(file, "\\seedll\\") == false && Str.InStr(file, "\\see\\") == false && Str.InStr(file, "\\openssl\\") == false)
+ {
+ string[] lines = File.ReadAllLines(file);
+
+ numLines += lines.Length;
+ numBytes += (int)new FileInfo(file).Length;
+
+ foreach (string line in lines)
+ {
+ if (Str.InStr(line, "//") && Str.InStr(line, "// Validate arguments") == false)
+ {
+ if (commentsDict.ContainsKey(line) == false)
+ {
+ commentsDict.Add(line, 1);
+ }
+ numComments++;
+
+ totalLetters += line.Trim().Length - 3;
+ }
+ }
+ }
+ }
+ }
+
+ Con.WriteLine("{0} Lines, {1} Bytes. {2} Comments ({3} distinct, aver: {4})", Str.ToStr3(numLines), Str.ToStr3(numBytes),
+ Str.ToStr3(numComments), commentsDict.Count, totalLetters / numComments);
+
+ return 0;
+ }
+
+ // Add to Cab by compressing OCX
+ [ConsoleCommandMethod(
+ "Compress a OCX and Generate a Cab file.",
+ "GenerateVpnWebOcxCab [src] [/DEST:dest]",
+ "Compress a OCX and Generate a Cab file.",
+ "[src]:Specify the ocx file.",
+ "DEST:Specify the destination cab file.")]
+ static int GenerateVpnWebOcxCab(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ new ConsoleParam("[src]", ConsoleService.Prompt, "Src Filename: ", ConsoleService.EvalNotEmpty, null),
+ new ConsoleParam("DEST", ConsoleService.Prompt, "Dst Filename: ", ConsoleService.EvalNotEmpty, null),
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+#if !BU_OSS
+ string destFileName = vl["DEST"].StrValue;
+ string srcFileName = vl.DefaultParam.StrValue;
+
+ Win32BuildUtil.GenerateVpnWebOcxCab(destFileName, srcFileName);
+#endif
+
+ return 0;
+ }
+
+
+ // Copy the file
+ [ConsoleCommandMethod(
+ "Copy a File.",
+ "FileCopy [src] [/DEST:dest]",
+ "Copy a File.",
+ "[src]:Specify the source file.",
+ "DEST:Specify the destination file.")]
+ static int FileCopy(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ new ConsoleParam("[src]", ConsoleService.Prompt, "Src Filename: ", ConsoleService.EvalNotEmpty, null),
+ new ConsoleParam("DEST", ConsoleService.Prompt, "Dst Filename: ", ConsoleService.EvalNotEmpty, null),
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ string destFileName = vl["DEST"].StrValue;
+ string srcFileName = vl.DefaultParam.StrValue;
+
+ IO.FileCopy(srcFileName, destFileName, true, false);
+
+ return 0;
+ }
+
+ // Sign the file
+ [ConsoleCommandMethod(
+ "Sign files using Authenticode certificates.",
+ "SignCode [filename] [/DEST:destfilename] [/COMMENT:comment] [/KERNEL:yes|no]",
+ "Sign files using Authenticode certificates.",
+ "[filename]:Specify the target filename.",
+ "DEST:Specify the destination filename. If this parameter is not specified, the target file will be overwritten.",
+ "COMMENT:Provide a description of the signed content.",
+ "KERNEL:Specify \"yes\" if Windows Vista / 7 Kernel Mode Driver Signing is needed."
+ )]
+ static int SignCode(ConsoleService c, string cmdName, string str)
+ {
+ ConsoleParam[] args =
+ {
+ new ConsoleParam("[filename]", ConsoleService.Prompt, "Filename: ", ConsoleService.EvalNotEmpty, null),
+ new ConsoleParam("DEST"),
+ new ConsoleParam("COMMENT", ConsoleService.Prompt, "Comment: ", ConsoleService.EvalNotEmpty, null),
+ new ConsoleParam("KERNEL"),
+ };
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ string destFileName = vl["DEST"].StrValue;
+ string srcFileName = vl.DefaultParam.StrValue;
+ if (Str.IsEmptyStr(destFileName))
+ {
+ destFileName = srcFileName;
+ }
+ string comment = vl["COMMENT"].StrValue;
+ bool kernel = vl["KERNEL"].BoolValue;
+
+ CodeSign.SignFile(destFileName, srcFileName, comment, kernel);
+
+ return 0;
+ }
+ }
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/BuildUtil/BuildUtilIcon.ico b/src/BuildUtil/BuildUtilIcon.ico
new file mode 100644
index 00000000..75d3c4aa
Binary files /dev/null and b/src/BuildUtil/BuildUtilIcon.ico differ
diff --git a/src/BuildUtil/BuildUtilMain.cs b/src/BuildUtil/BuildUtilMain.cs
new file mode 100644
index 00000000..a8f2918b
--- /dev/null
+++ b/src/BuildUtil/BuildUtilMain.cs
@@ -0,0 +1,193 @@
+// SoftEther VPN Source Code
+// Build Utility
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+using System;
+using System.Threading;
+using System.Text;
+using System.Configuration;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Security.Cryptography;
+using System.Web;
+using System.Web.Security;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+using System.Web.UI.WebControls.WebParts;
+using System.Web.UI.HtmlControls;
+using System.IO;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Drawing.Drawing2D;
+using System.Diagnostics;
+using System.Net;
+using System.Net.Security;
+using System.Security.Cryptography.X509Certificates;
+using CoreUtil;
+
+namespace BuildUtil
+{
+ public class BuildUtilMain
+ {
+ public static bool pause = false;
+
+ // Main function
+ public static int Main(string[] args)
+ {
+ string errMsg = "";
+
+ int ret = 0;
+
+ ret = ConsoleService.EntryPoint("BuildUtil " + Env.CommandLine, "BuildUtil", typeof(BuildUtilMain), out errMsg);
+
+ if (ret != 0)
+ {
+ Con.WriteLine("{0}: fatal error C0001: {1}", Path.GetFileNameWithoutExtension(Env.ExeFileName), errMsg);
+
+ if (pause)
+ {
+ Console.Write("Press any key to exit...");
+ Console.ReadKey();
+ }
+
+ Environment.Exit(1);
+ }
+
+ return ret;
+ }
+
+ // Command execution
+ [ConsoleCommandMethod(
+ "VPN Build Utility",
+ "[/IN:infile] [/OUT:outfile] [/CSV] [/PAUSEIFERROR:yes|no] [/CMD command_line...]",
+ "VPN Build Utility",
+ "IN:This will specify the text file 'infile' that contains the list of commands that are automatically executed after the connection is completed. If the /IN parameter is specified, the vpncmd program will terminate automatically after the execution of all commands in the file are finished. If the file contains multiple-byte characters, the encoding must be Unicode (UTF-8). This cannot be specified together with /CMD (if /CMD is specified, /IN will be ignored).",
+ "OUT:You can specify the text file 'outfile' to write all strings such as onscreen prompts, message, error and execution results. Note that if the specified file already exists, the contents of the existing file will be overwritten. Output strings will be recorded using Unicode (UTF-8) encoding.",
+ "CMD:If the optional command 'command_line...' is included after /CMD, that command will be executed after the connection is complete and the vpncmd program will terminate after that. This cannot be specified together with /IN (if specified together with /IN, /IN will be ignored). Specify the /CMD parameter after all other vpncmd parameters.",
+ "CSV:Enable CSV Mode.",
+ "PAUSEIFERROR:Specify yes if you'd like to pause before exiting the process if there are any errors."
+ )]
+ public static int BuildUtil(ConsoleService c, string cmdName, string str)
+ {
+ Con.WriteLine("");
+ Con.WriteLine("Copyright (c) SoftEther Corporation. All Rights Reserved.");
+ Con.WriteLine("");
+
+ ConsoleParam[] args =
+ {
+ new ConsoleParam("IN", null, null, null, null),
+ new ConsoleParam("OUT", null, null, null, null),
+ new ConsoleParam("CMD", null, null, null, null),
+ new ConsoleParam("CSV", null, null, null, null),
+ new ConsoleParam("PAUSEIFERROR", null, null, null, null),
+ new ConsoleParam("DT", null, null, null, null),
+ };
+
+ ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args);
+
+ pause = vl["PAUSEIFERROR"].BoolValue;
+
+ string cmdline = vl["CMD"].StrValue;
+
+ if (vl["DT"].IsEmpty == false)
+ {
+ BuildSoftwareList.ListCreatedDateTime = Str.StrToDateTime(vl["DT"].StrValue);
+ }
+
+ ConsoleService cs = c;
+
+ while (cs.DispatchCommand(cmdline, "BuildUtil>", typeof(BuildUtilCommands), null))
+ {
+ if (Str.IsEmptyStr(cmdline) == false)
+ {
+ break;
+ }
+ }
+
+ return cs.RetCode;
+ }
+ }
+}
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/BuildUtil/CodeSign.cs b/src/BuildUtil/CodeSign.cs
new file mode 100644
index 00000000..d699716e
--- /dev/null
+++ b/src/BuildUtil/CodeSign.cs
@@ -0,0 +1,263 @@
+// SoftEther VPN Source Code
+// Build Utility
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+using System;
+using System.Threading;
+using System.Text;
+using System.Configuration;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Security.Cryptography;
+using System.Web;
+using System.Web.Security;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+using System.Web.UI.WebControls.WebParts;
+using System.Web.UI.HtmlControls;
+using System.IO;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Drawing.Drawing2D;
+using System.Diagnostics;
+using System.Net;
+using System.Net.Security;
+using System.Security.Cryptography.X509Certificates;
+using CoreUtil;
+using BuildUtil.HvSignService;
+
+namespace BuildUtil
+{
+ public static class CodeSign
+ {
+ public const int NumRetries = 1;
+ public const int RetryIntervals = 200;
+
+ public const int NumRetriesForCopy = 50;
+ public const int RetryIntervalsForCopy = 10;
+
+ const string in_dir = @"\\hvsigncode\SIGN\IN";
+ const string out_dir = @"\\hvsigncode\SIGN\OUT";
+
+#if !BU_SOFTETHER
+ public static int UsingCertId = 1;
+#else
+ public static int UsingCertId = 2;
+#endif
+
+ static object lockObj = new object();
+
+ // Digital-sign the data on the memory
+ public static byte[] SignMemory(byte[] srcData, string comment, bool kernelModeDriver, int cert_id)
+ {
+#if !BU_OSS
+ int i;
+ string out_filename = null;
+ byte[] ret = null;
+
+ string in_tmp_filename = Path.Combine(in_dir,
+ Str.DateTimeToStrShortWithMilliSecs(DateTime.Now) + "_" +
+ Env.MachineName + "_" +
+ Secure.Rand63i().ToString() + ".dat");
+
+ IO.SaveFile(in_tmp_filename, srcData);
+
+ for (i = 0; i < NumRetries; i++)
+ {
+ Sign sign = new Sign();
+ sign.Proxy = new WebProxy();
+
+ try
+ {
+ out_filename = sign.ExecSign(Path.GetFileName(in_tmp_filename),
+ kernelModeDriver,
+ comment,
+ cert_id);
+ break;
+ }
+ catch (Exception ex)
+ {
+ if (i != (NumRetries - 1))
+ {
+ Kernel.SleepThread(RetryIntervals);
+ }
+ else
+ {
+ throw ex;
+ }
+ }
+ }
+
+ for (i = 0; i < NumRetriesForCopy; i++)
+ {
+ try
+ {
+ ret = IO.ReadFile(Path.Combine(out_dir, out_filename));
+ }
+ catch (Exception ex)
+ {
+ if (i != (NumRetriesForCopy - 1))
+ {
+ Kernel.SleepThread(RetryIntervalsForCopy);
+ }
+ else
+ {
+ throw ex;
+ }
+ }
+ }
+
+ string tmpFileName = IO.CreateTempFileNameByExt(".exe");
+ try
+ {
+ File.Delete(tmpFileName);
+ }
+ catch
+ {
+ }
+ File.WriteAllBytes(tmpFileName, ret);
+
+ lock (lockObj)
+ {
+ if (ExeSignChecker.CheckFileDigitalSignature(tmpFileName) == false)
+ {
+ throw new ApplicationException("CheckFileDigitalSignature failed.");
+ }
+
+ if (kernelModeDriver)
+ {
+ if (ExeSignChecker.IsKernelModeSignedFile(tmpFileName) == false)
+ {
+ throw new ApplicationException("IsKernelModeSignedFile failed.");
+ }
+ }
+ }
+
+ try
+ {
+ }
+ catch
+ {
+ File.Delete(tmpFileName);
+ }
+
+ return ret;
+#else // BU_OSS
+ return srcData;
+#endif // BU_OSS
+ }
+
+ // Digital-sign the data on the file
+ public static void SignFile(string destFileName, string srcFileName, string comment, bool kernelModeDriver)
+ {
+ int cert_id = UsingCertId;
+
+ SignFile(destFileName, srcFileName, comment, kernelModeDriver, cert_id);
+ }
+ public static void SignFile(string destFileName, string srcFileName, string comment, bool kernelModeDriver, int cert_id)
+ {
+#if !BU_OSS
+ Con.WriteLine("Signing for '{0}'...", Path.GetFileName(destFileName));
+ byte[] srcData = File.ReadAllBytes(srcFileName);
+
+ byte[] destData = SignMemory(srcData, comment, kernelModeDriver, cert_id);
+
+ try
+ {
+ File.Delete(destFileName);
+ }
+ catch
+ {
+ }
+
+ File.WriteAllBytes(destFileName, destData);
+
+ Con.WriteLine("Done.");
+#else // BU_OSS
+ Con.WriteLine("Skipping the code signing for '{0}' in the build process. You can insert your own authenticode sign process here.", srcFileName);
+#endif // BU_OSS
+ }
+ }
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/BuildUtil/CopyBuildUtil.cmd b/src/BuildUtil/CopyBuildUtil.cmd
new file mode 100644
index 00000000..18c4d9c5
--- /dev/null
+++ b/src/BuildUtil/CopyBuildUtil.cmd
@@ -0,0 +1,2 @@
+copy %0\..\..\bin\BuildUtilTmp.exe %0\..\..\bin\BuildUtil.exe
+exit /b 0
diff --git a/src/BuildUtil/CoreUtil.dll b/src/BuildUtil/CoreUtil.dll
new file mode 100644
index 00000000..c2da4954
Binary files /dev/null and b/src/BuildUtil/CoreUtil.dll differ
diff --git a/src/BuildUtil/PEUtil.cs b/src/BuildUtil/PEUtil.cs
new file mode 100644
index 00000000..59b71daa
--- /dev/null
+++ b/src/BuildUtil/PEUtil.cs
@@ -0,0 +1,231 @@
+// SoftEther VPN Source Code
+// Build Utility
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+using System;
+using System.Threading;
+using System.Text;
+using System.Configuration;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Security.Cryptography;
+using System.Web;
+using System.Web.Security;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+using System.Web.UI.WebControls.WebParts;
+using System.Web.UI.HtmlControls;
+using System.IO;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Drawing.Drawing2D;
+using System.Diagnostics;
+using System.Net;
+using System.Net.Security;
+using System.Security.Cryptography.X509Certificates;
+using CoreUtil;
+
+namespace BuildUtil
+{
+ public static class PEUtil
+ {
+ public const int NumRetries = 5;
+ public const int RetryIntervals = 200;
+ public const string MutexName = "peutil_setmanifest_mutex";
+
+ // Set the version of the PE header to 4 (to work in Windows 98, etc.)
+ public static void SetPEVersionTo4(byte[] srcData)
+ {
+ int offset = 0x140 + (int)((uint)srcData[0x3c] + ((uint)srcData[0x3d] * 256)) - 0xf8;
+
+ if (!((srcData[offset] == 0x04 || srcData[offset] == 0x05) && srcData[offset + 1] == 0x00))
+ {
+ throw new ApplicationException("The specified file is not PE file.");
+ }
+
+ srcData[offset] = 0x04;
+ }
+ public static void SetPEVersionTo4(string fileName)
+ {
+ FileInfo fi = new FileInfo(fileName);
+
+ byte[] data = File.ReadAllBytes(fileName);
+ SetPEVersionTo4(data);
+
+ int i;
+ for (i = 0;; i++)
+ {
+ try
+ {
+ File.WriteAllBytes(fileName, data);
+ break;
+ }
+ catch (Exception ex)
+ {
+ if (i >= (NumRetries - 1))
+ {
+ throw ex;
+ }
+
+ Kernel.SleepThread(RetryIntervals);
+ }
+ }
+
+ File.SetCreationTime(fileName, fi.CreationTime);
+ File.SetLastAccessTime(fileName, fi.LastAccessTime);
+ File.SetLastWriteTime(fileName, fi.LastWriteTime);
+ }
+
+ public static void SetManifest(string exe, string manifestName)
+ {
+ Mutex x = new Mutex(false, MutexName);
+
+ x.WaitOne();
+
+ try
+ {
+ // Manifest file name
+ string filename = Path.Combine(Paths.ManifestsDir, manifestName);
+ if (File.Exists(filename) == false)
+ {
+ throw new FileNotFoundException(filename);
+ }
+
+ FileInfo fi = new FileInfo(exe);
+
+ // Copy exe file to a temporary directory
+ string exeTmp = IO.CreateTempFileNameByExt(".exe");
+ IO.FileCopy(exe, exeTmp);
+
+ // Create a batch file
+ string batFileName = Path.Combine(Paths.TmpDirName, "exec_mt.cmd");
+ StreamWriter bat = new StreamWriter(batFileName, false, Str.ShiftJisEncoding);
+ bat.WriteLine("call \"{0}\"", Paths.VisualStudioVCBatchFileName);
+ bat.WriteLine("echo on");
+ bat.WriteLine("mt.exe -manifest \"{0}\" -outputresource:\"{1}\";1", filename, exeTmp);
+ bat.WriteLine("EXIT /B %ERRORLEVEL%");
+ bat.Close();
+
+ Exception ex = null;
+
+ int i;
+ // Repeated 20 times in order to avoid locking the file by the anti-virus software
+ for (i = 0; i < 20; i++)
+ {
+ try
+ {
+ // Execute
+ Win32BuildUtil.ExecCommand(Paths.CmdFileName, string.Format("/C \"{0}\"", batFileName), true);
+ ex = null;
+
+ break;
+ }
+ catch (Exception ex2)
+ {
+ ex = ex2;
+ }
+
+ ThreadObj.Sleep(Secure.Rand31i() % 50);
+ }
+
+ if (ex != null)
+ {
+ throw new ApplicationException("mt.exe Manifest Processing for '" + exe + "' Failed.");
+ }
+
+ // Revert to the original file
+ IO.FileCopy(exeTmp, exe);
+
+ // Restore the date and time
+ File.SetCreationTime(exe, fi.CreationTime);
+ File.SetLastAccessTime(exe, fi.LastAccessTime);
+ File.SetLastWriteTime(exe, fi.LastWriteTime);
+ }
+ finally
+ {
+ x.ReleaseMutex();
+ }
+ }
+ }
+}
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/BuildUtil/Properties/AssemblyInfo.cs b/src/BuildUtil/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..2cff91e2
--- /dev/null
+++ b/src/BuildUtil/Properties/AssemblyInfo.cs
@@ -0,0 +1,18 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("PacketiX VPN / SoftEther VPN Build Utility")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("SoftEther Corporation")]
+[assembly: AssemblyProduct("PacketiX VPN / SoftEther VPN Build Utility")]
+[assembly: AssemblyCopyright("Copyright (c) SoftEther Corporation. All Rights Reserved.")]
+[assembly: AssemblyTrademark("PacketiX(R) and SoftEther(R) is a registered trademark of SoftEther Corporation.")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+
+[assembly: Guid("5bf63a11-27da-4ca4-ba9d-a60a0f8e1fd7")]
+
+[assembly: AssemblyVersion("1.0.*")]
diff --git a/src/BuildUtil/Properties/Settings.Designer.cs b/src/BuildUtil/Properties/Settings.Designer.cs
new file mode 100644
index 00000000..5715f13d
--- /dev/null
+++ b/src/BuildUtil/Properties/Settings.Designer.cs
@@ -0,0 +1,115 @@
+//------------------------------------------------------------------------------
+//
+// ã“ã®ã‚³ãƒ¼ãƒ‰ã¯ãƒ„ールã«ã‚ˆã£ã¦ç”Ÿæˆã•ã‚Œã¾ã—ãŸã€‚
+// ランタイムãƒãƒ¼ã‚¸ãƒ§ãƒ³:2.0.50727.5466
+//
+// ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã¸ã®å¤‰æ›´ã¯ã€ä»¥ä¸‹ã®çŠ¶æ³ä¸‹ã§ä¸æ£ãªå‹•ä½œã®åŽŸå› ã«ãªã£ãŸã‚Šã€
+// コードãŒå†ç”Ÿæˆã•ã‚Œã‚‹ã¨ãã«æ失ã—ãŸã‚Šã—ã¾ã™ã€‚
+//
+//------------------------------------------------------------------------------
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+namespace BuildUtil.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+
+ [global::System.Configuration.ApplicationScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.SpecialSettingAttribute(global::System.Configuration.SpecialSetting.WebServiceUrl)]
+ [global::System.Configuration.DefaultSettingValueAttribute("http://dv/Sign/Sign.asmx")]
+ public string BuildUtil_SignService_Sign {
+ get {
+ return ((string)(this["BuildUtil_SignService_Sign"]));
+ }
+ }
+
+ [global::System.Configuration.ApplicationScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.SpecialSettingAttribute(global::System.Configuration.SpecialSetting.WebServiceUrl)]
+ [global::System.Configuration.DefaultSettingValueAttribute("http://hvsigncode/Sign.asmx")]
+ public string BuildUtilTmp_HvSignService_Sign {
+ get {
+ return ((string)(this["BuildUtilTmp_HvSignService_Sign"]));
+ }
+ }
+ }
+}
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/BuildUtil/Properties/Settings.settings b/src/BuildUtil/Properties/Settings.settings
new file mode 100644
index 00000000..5e8d1669
--- /dev/null
+++ b/src/BuildUtil/Properties/Settings.settings
@@ -0,0 +1,12 @@
+
+
+
+
+
+ http://dv/Sign/Sign.asmx
+
+
+ http://hvsigncode/Sign.asmx
+
+
+
\ No newline at end of file
diff --git a/src/BuildUtil/Test.cs b/src/BuildUtil/Test.cs
new file mode 100644
index 00000000..688be1da
--- /dev/null
+++ b/src/BuildUtil/Test.cs
@@ -0,0 +1,125 @@
+// SoftEther VPN Source Code
+// Build Utility
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+using System;
+using System.Threading;
+using System.Text;
+using System.Configuration;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Security.Cryptography;
+using System.Web;
+using System.Web.Security;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+using System.Web.UI.WebControls.WebParts;
+using System.Web.UI.HtmlControls;
+using System.IO;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Drawing.Drawing2D;
+using System.Diagnostics;
+using System.Net;
+using System.Net.Security;
+using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
+using CoreUtil;
+
+namespace BuildUtil
+{
+ public static class TestClass
+ {
+ public static void Test()
+ {
+ Language[] langs = BuildHelper.GetLanguageList();
+
+ foreach (Language e in langs)
+ {
+ Con.WriteLine("{0} {1} {2} {3} {5} {4}",
+ e.Number, e.Id, e.Title, e.TitleUnicode, e.UnixLocaleIds, e.WindowsLocaleIds);
+ }
+ }
+ }
+}
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/BuildUtil/UnixBuildSoftwares.cs b/src/BuildUtil/UnixBuildSoftwares.cs
new file mode 100644
index 00000000..77bd9eb4
--- /dev/null
+++ b/src/BuildUtil/UnixBuildSoftwares.cs
@@ -0,0 +1,1015 @@
+// SoftEther VPN Source Code
+// Build Utility
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+using System;
+using System.Threading;
+using System.Text;
+using System.Configuration;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Security.Cryptography;
+using System.Web;
+using System.Web.Security;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+using System.Web.UI.WebControls.WebParts;
+using System.Web.UI.HtmlControls;
+using System.IO;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Drawing.Drawing2D;
+using System.Diagnostics;
+using System.Net;
+using System.Net.Security;
+using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
+using CoreUtil;
+
+namespace BuildUtil
+{
+ // Build the UNIX software
+ public class BuildSoftwareUnix : BuildSoftware
+ {
+ public readonly string[] SrcDirNameList =
+ {
+ @"bin\BuiltHamcoreFiles",
+ @"bin\hamcore",
+ "Cedar",
+ "Ham",
+ "Mayaqua",
+ "Neo",
+ "VGate",
+ "vpnbridge",
+ "vpnclient",
+ "vpncmd",
+ "vpnserver",
+ };
+
+ public readonly string CrossLibName;
+ public readonly string CrossLibBaseDir = Path.Combine(Paths.BaseDirName, @"BuildFiles\CrossLib");
+ public readonly bool UseGccBitsOption;
+ public readonly string CrossCompilerName;
+ public readonly bool NoPThreadOption;
+ public readonly string CrossCompilerOption;
+ public readonly string SrcKitDefaultDir;
+
+ public BuildSoftwareUnix(Software software, int buildNumber, int version, string buildName, Cpu cpu, OS os,
+ string crossLibName, bool useGccBitsOption, string crossCompilerName, bool noPthreadOption, string crossCompilerOption)
+ : base(software, buildNumber, version, buildName, cpu, os)
+ {
+ this.CrossLibName = crossLibName;
+ this.UseGccBitsOption = useGccBitsOption;
+ this.CrossCompilerName = crossCompilerName;
+ this.NoPThreadOption = noPthreadOption;
+ this.CrossCompilerOption = crossCompilerOption;
+
+#if !BU_SOFTETHER
+ this.SrcKitDefaultDir = Env.SystemDir.Substring(0, 2) + @"\tmp\vpn4_srckit";
+#else
+ this.SrcKitDefaultDir = Env.SystemDir.Substring(0, 2) + @"\tmp\se_vpn_srckit";
+#endif
+ }
+
+ // Run the build
+ public void Build(bool debugMode)
+ {
+ string mutexName = "buildsrckit_" + this.CrossLibName;
+
+ Mutex mutex = new Mutex(false, mutexName);
+
+ mutex.WaitOne();
+
+ try
+ {
+ if (this.BuildSrcKit(SrcKitDefaultDir, debugMode))
+ {
+ this.BuildWithCrossCompiler(SrcKitDefaultDir);
+ }
+ }
+ finally
+ {
+ mutex.ReleaseMutex();
+ }
+
+ this.Release(SrcKitDefaultDir);
+ }
+
+ public override void Build()
+ {
+ throw new NotImplementedException();
+ }
+
+ // Delegate to copy the source code
+ public bool CopySrcFilesDelegate(FileInfo info)
+ {
+ string[] ignoreExts =
+ {
+ ".exe", ".sys", ".dll", ".inf", ".vcproj", ".user",
+ ".ico", ".rc",
+ };
+ string name = info.FullName;
+
+ if (Str.InStr(name, @"\.svn\") ||
+ Str.InStr(name, @"\WinPcap\") ||
+ Str.InStr(name, @"_Debug\") ||
+ Str.InStr(name, @"_Release\") ||
+ Str.InStr(name, @"\BuiltHamcoreFiles\win32_"))
+ {
+ return false;
+ }
+
+ foreach (string ext in ignoreExts)
+ {
+ if (name.EndsWith(ext, StringComparison.InvariantCultureIgnoreCase))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ // Create a release
+ public virtual void Release(string baseOutputDir)
+ {
+ string srcDir = Path.Combine(baseOutputDir, this.CrossLibName + @"\src");
+ string releaseFileName = Path.Combine(Paths.ReleaseDir, this.OutputFileName);
+ Con.WriteLine("Generating '{0}'...", releaseFileName);
+
+ List files = new List();
+ string gccOptionForLink;
+ string gccOptionForCompile;
+
+ generateGccOptions(srcDir, false, false, out gccOptionForLink, out gccOptionForCompile);
+
+ string targetName = this.Software.ToString();
+
+ // Makefile
+ StringWriter mk = GenerateMakeFileForRelease(srcDir);
+ byte[] mkData = Str.NormalizeCrlf(Str.Utf8Encoding.GetBytes(mk.ToString()), new byte[] { 10 });
+
+ TarPacker tar = new TarPacker();
+
+ tar.AddFileSimple(targetName + @"\Makefile", mkData, 0, mkData.Length, DateTime.Now);
+
+ // Install Script
+ string isText = File.ReadAllText(Paths.UnixInstallScript);
+ isText = Str.ReplaceStr(isText, "", TitleString, false);
+ byte[] scriptData = Str.NormalizeCrlf(Str.Utf8Encoding.GetBytes(isText), new byte[] { 10 });
+ tar.AddFileSimple(targetName + @"\.install.sh", scriptData, 0, scriptData.Length, DateTime.Now);
+
+ // EULA
+ Encoding enc = Str.Utf8Encoding;
+
+ if (true)
+ {
+ string srcData = File.ReadAllText(Path.Combine(Paths.BinDirName, @"hamcore\eula.txt"),
+ enc);
+
+ byte[] destData = enc.GetBytes(srcData);
+
+ tar.AddFileSimple(targetName + @"\" + "ReadMeFirst_License.txt", destData, 0, destData.Length, DateTime.Now);
+ }
+
+ if (true)
+ {
+ string srcData = File.ReadAllText(Path.Combine(Paths.BinDirName, @"hamcore\warning_ja.txt"),
+ enc);
+
+ byte[] destData = enc.GetBytes(srcData);
+
+ tar.AddFileSimple(targetName + @"\" + "ReadMeFirst_Important_Notices_ja.txt", destData, 0, destData.Length, DateTime.Now);
+ }
+
+ if (true)
+ {
+ string srcData = File.ReadAllText(Path.Combine(Paths.BinDirName, @"hamcore\warning_en.txt"),
+ enc);
+
+ byte[] destData = enc.GetBytes(srcData);
+
+ tar.AddFileSimple(targetName + @"\" + "ReadMeFirst_Important_Notices_en.txt", destData, 0, destData.Length, DateTime.Now);
+ }
+
+
+ // Codes
+ string[] dirs =
+ {
+ Path.Combine(srcDir, "code"),
+ Path.Combine(srcDir, "lib"),
+ };
+
+ foreach (string dir in dirs)
+ {
+ string[] fileList = Directory.GetFiles(dir, "*.a", SearchOption.TopDirectoryOnly);
+
+ if (Path.GetFileName(dir).Equals("code", StringComparison.InvariantCultureIgnoreCase))
+ {
+ fileList = new string[]
+ {
+ Path.Combine(dir, string.Format("{0}.a", this.Software.ToString())),
+ Path.Combine(dir, "vpncmd.a"),
+ };
+ }
+
+ foreach (string fileName in fileList)
+ {
+ if (Str.StrCmpi(Path.GetFileName(fileName), "libpcap.a") == false)
+ {
+ // Libpcap.a is not included in the release
+ byte[] fileData = File.ReadAllBytes(fileName);
+
+ tar.AddFileSimple(targetName + @"\" + IO.GetRelativeFileName(fileName, srcDir),
+ fileData, 0, fileData.Length, DateTime.Now);
+ }
+ }
+ }
+
+ // License file
+ byte[] lsFileData = File.ReadAllBytes(Path.Combine(CrossLibBaseDir, @"License.txt"));
+ tar.AddFileSimple(targetName + @"\lib\License.txt", lsFileData, 0, lsFileData.Length, DateTime.Now);
+
+ // HamCore
+ byte[] hcData = File.ReadAllBytes(Path.Combine(Paths.BaseDirName, string.Format(@"bin\BuiltHamcoreFiles\hamcore_unix\hamcore.se2")));
+ tar.AddFileSimple(targetName + @"\hamcore.se2", hcData, 0, hcData.Length, DateTime.Now);
+
+ // Generate a tar
+ tar.Finish();
+ byte[] tarData = tar.CompressToGZip();
+
+ File.WriteAllBytes(releaseFileName, tarData);
+
+ Con.WriteLine("Finished.");
+ }
+
+ // Build by cross-compiler
+ public virtual void BuildWithCrossCompiler(string baseOutputDir)
+ {
+ // Create a batch file
+ string outDir = Path.Combine(baseOutputDir, this.CrossLibName);
+ string outSrcDir = Path.Combine(outDir, "src");
+
+ try
+ {
+ string xcDir = Path.Combine(Path.Combine(Paths.CrossCompilerBaseDir, this.CrossCompilerName), "bin");
+
+ if (Directory.Exists(xcDir) == false)
+ {
+ throw new ApplicationException(string.Format("dir '{0}' not found.", xcDir));
+ }
+
+ string batFileName = Path.Combine(outSrcDir, "cross_build.cmd");
+ StreamWriter w = new StreamWriter(batFileName, false, Str.ShiftJisEncoding);
+ w.WriteLine("SET PATH={0};%PATH%", xcDir);
+ w.WriteLine();
+ w.WriteLine(outSrcDir.Substring(0, 2));
+ w.WriteLine("CD {0}", outSrcDir);
+ w.WriteLine();
+ w.WriteLine("make clean");
+ w.WriteLine("make");
+ w.WriteLine();
+ w.WriteLine("EXIT /B %ERRORLEVEL%");
+ w.Close();
+
+ Semaphore sem = new Semaphore(BuildConfig.NumMultipleCompileTasks, BuildConfig.NumMultipleCompileTasks, "vpn_build_cross");
+ Con.WriteLine("Waiting for Semaphore...");
+ sem.WaitOne();
+ Con.WriteLine("Done.");
+ try
+ {
+ Win32BuildUtil.ExecCommand(Paths.CmdFileName, string.Format("/C \"{0}\"", batFileName));
+ }
+ finally
+ {
+ sem.Release();
+ }
+ }
+ catch
+ {
+ string[] files = Directory.GetFiles(Path.Combine(outSrcDir, "code"), "*.a", SearchOption.AllDirectories);
+ foreach (string file in files)
+ {
+ try
+ {
+ File.Delete(file);
+ }
+ catch
+ {
+ }
+ }
+ }
+ }
+
+ // SrcKit file name
+ public string SrcKitFileName
+ {
+ get
+ {
+ int build, version;
+ string name;
+ DateTime date;
+ Win32BuildUtil.ReadBuildInfoFromTextFile(out build, out version, out name, out date);
+ return string.Format("{0}-{3}-{1}.tar.gz", "srckit", this.CrossLibName,
+ Str.DateTimeToStrShort(BuildSoftwareList.ListCreatedDateTime),
+ build);
+ }
+ }
+
+ // Copy the source code
+ public virtual void CopyUnixSrc(string baseOutputDir)
+ {
+ // Generate an Output directory name
+ string outDir = baseOutputDir;
+ string outSrcDir = baseOutputDir;
+ Con.WriteLine("BuildSrcKit for '{0}'...", this.IDString);
+ Con.WriteLine("BuildSrcKit Output Dir = '{0}'.", outDir);
+
+ string tsFile = Path.Combine(outDir, "TimeStamp.txt");
+ string timeStamp = Str.DateTimeToStrShort(BuildSoftwareList.ListCreatedDateTime);
+ Con.WriteLine("timestamp={0}", timeStamp);
+
+ if (Directory.Exists(outDir))
+ {
+ }
+ else
+ {
+ Directory.CreateDirectory(outDir);
+ }
+
+ // Copy the source code
+ foreach (string srcDirName in SrcDirNameList)
+ {
+ string srcFullPath = Path.Combine(Paths.BaseDirName, srcDirName);
+ string destFullPath = Path.Combine(outSrcDir, srcDirName);
+
+ IO.CopyDir(srcFullPath, destFullPath, new IO.CopyDirPreCopyDelegate(CopySrcFilesDelegate), false, true, true, true, true);
+ }
+ IO.FileCopy(Path.Combine(Paths.BaseDirName, "CurrentBuild.txt"), Path.Combine(outSrcDir, "CurrentBuild.txt"), true, false);
+ }
+
+ // Build SrcKit
+ public virtual bool BuildSrcKit(string baseOutputDir, bool debugMode)
+ {
+ // Generate an Output directory name
+ string outDir = Path.Combine(baseOutputDir, this.CrossLibName);
+ string outSrcDir = Path.Combine(outDir, "src");
+ Con.WriteLine("BuildSrcKit for '{0}'...", this.IDString);
+ Con.WriteLine("CrossLib Name: '{0}'.", this.CrossLibName);
+ Con.WriteLine("BuildSrcKit Output Dir = '{0}'.", outDir);
+
+ string tsFile = Path.Combine(outDir, "TimeStamp.txt");
+ string timeStamp = Str.DateTimeToStrShort(BuildSoftwareList.ListCreatedDateTime);
+ Con.WriteLine("timestamp={0}", timeStamp);
+
+ if (Directory.Exists(outDir))
+ {
+ bool ok = false;
+ // See TimeStamp.txt file if the directory already exists
+ try
+ {
+ string[] ts = File.ReadAllLines(tsFile);
+ if (ts[0] == timeStamp)
+ {
+ ok = true;
+ }
+ }
+ catch
+ {
+ }
+
+ if (ok)
+ {
+ Con.WriteLine("Skipped for '{0}'.", this.IDString);
+ return false;
+ }
+ }
+ else
+ {
+ Directory.CreateDirectory(outDir);
+ }
+
+ // Copy the source code
+ foreach (string srcDirName in SrcDirNameList)
+ {
+ string srcFullPath = Path.Combine(Paths.BaseDirName, srcDirName);
+ string destFullPath = Path.Combine(outSrcDir, srcDirName);
+ bool delete_bom = true;
+
+ if (Str.InStr(srcDirName, "\\hamcore"))
+ {
+ delete_bom = false;
+ }
+
+ IO.CopyDir(srcFullPath, destFullPath, new IO.CopyDirPreCopyDelegate(CopySrcFilesDelegate), false, true, true, delete_bom);
+ }
+ IO.FileCopy(Path.Combine(Paths.BaseDirName, "CurrentBuild.txt"), Path.Combine(outSrcDir, "CurrentBuild.txt"), true, false);
+ IO.FileCopy(Path.Combine(Paths.BaseDirName, "GlobalConst.h"), Path.Combine(outSrcDir, "GlobalConst.h"), true, false);
+ IO.FileCopy(Path.Combine(Paths.BaseDirName, @"DebugFiles\Replace.h"), Path.Combine(outSrcDir, "Replace.h"), true, false);
+ IO.FileCopy(Path.Combine(Paths.BaseDirName, @"bin\BuiltHamcoreFiles\hamcore_unix\hamcore.se2"),
+ Path.Combine(outSrcDir, @"bin\hamcore.se2"), true, false);
+
+ // Copy Crosslibs
+ IO.CopyDir(Path.Combine(this.CrossLibBaseDir, this.CrossLibName), Path.Combine(outSrcDir, @"lib"),
+ delegate(FileInfo fi)
+ {
+ if (fi.DirectoryName.IndexOf(@".svn", StringComparison.InvariantCultureIgnoreCase) != -1)
+ {
+ return false;
+ }
+ return true;
+ }, false, true, true, false);
+
+ // Generate Makefile for compilation
+ byte[] makeFileDataForCross = Str.NormalizeCrlf(Str.Utf8Encoding.GetBytes(GenerateMakeFileForCompile(outSrcDir, debugMode, true).ToString()), new byte[] { 10, });
+ byte[] makeFileDataForSelf = Str.NormalizeCrlf(Str.Utf8Encoding.GetBytes(GenerateMakeFileForCompile(outSrcDir, debugMode, false).ToString()), new byte[] { 10, });
+
+ string makeFileName = Path.Combine(outSrcDir, "Makefile");
+ File.WriteAllBytes(makeFileName, makeFileDataForCross);
+
+ // TimeStamp.txt
+ File.WriteAllText(tsFile, timeStamp);
+
+ // Create a tar.gz
+ string tarGzFileName = Path.Combine(outSrcDir, this.SrcKitFileName);
+ Con.WriteLine("Creating '{0}'...", tarGzFileName);
+ List files = new List();
+
+ foreach (string srcDirName in Util.CombineArray(SrcDirNameList, new string[] { "lib" }))
+ {
+ string dirFullPath = Path.Combine(outSrcDir, srcDirName);
+ string[] fileList = Directory.GetFiles(dirFullPath, "*",
+ srcDirName.Equals("lib", StringComparison.InvariantCultureIgnoreCase) ? SearchOption.TopDirectoryOnly : SearchOption.AllDirectories);
+ foreach (string fileName in fileList)
+ {
+ files.Add(fileName);
+ }
+ }
+ files.Add(Path.Combine(outSrcDir, @"CurrentBuild.txt"));
+ files.Add(Path.Combine(outSrcDir, @"bin\hamcore.se2"));
+ files.Add(Path.Combine(outSrcDir, @"Replace.h"));
+ files.Add(Path.Combine(outSrcDir, @"GlobalConst.h"));
+
+ files.Sort();
+ TarPacker tar = new TarPacker();
+ foreach (string file in files)
+ {
+ byte[] fileData = File.ReadAllBytes(file);
+ tar.AddFileSimple(@"src\" + IO.GetRelativeFileName(file, outSrcDir),
+ fileData,
+ 0, fileData.Length, File.GetLastWriteTime(file), "0000750", "0000640");
+ }
+ tar.AddFileSimple(@"src\Makefile", makeFileDataForSelf, 0, makeFileDataForSelf.Length, DateTime.Now, "0000750", "0000640");
+ tar.Finish();
+ byte[] tarGzData = tar.CompressToGZip();
+ File.WriteAllBytes(tarGzFileName, tarGzData);
+
+ IO.MakeDir(Paths.ReleaseSrckitDir);
+ File.WriteAllBytes(Path.Combine(Paths.ReleaseSrckitDir, this.SrcKitFileName), tarGzData);
+
+ Con.WriteLine("Completed.");
+
+ return true;
+ }
+
+ // Compilation settings
+ public string Compiler = "gcc";
+ public List GccMacros = new List();
+
+ // Create a Makefile for release
+ public virtual StringWriter GenerateMakeFileForRelease(string srcDir)
+ {
+ string gccOptionForLink;
+ string gccOptionForCompile;
+
+ generateGccOptions(srcDir, false, false, out gccOptionForLink, out gccOptionForCompile);
+
+ string codeDir = Path.Combine(srcDir, "code");
+ string libDir = Path.Combine(srcDir, "lib");
+
+ string[] codeFiles = Directory.GetFiles(codeDir, "*.a");
+ string[] libFiles = Directory.GetFiles(libDir, "*.a");
+
+ StringWriter sr = new StringWriter();
+ sr.WriteLine("# {0}", this.TitleString);
+ sr.WriteLine("# Makefile");
+ sr.WriteLine("# ");
+
+#if !BU_SOFTETHER
+ sr.WriteLine("# Copyright (c) SoftEther Corporation. All Rights Reserved.");
+#else
+ sr.WriteLine("# Copyright (c) SoftEther VPN Project at University of Tsukuba, Japan. All Rights Reserved.");
+#endif
+ sr.WriteLine("# Platform: {0}", this.CrossLibName);
+ sr.WriteLine();
+ sr.WriteLine("CC={0}", this.Compiler);
+ sr.WriteLine("OPTIONS={0}", gccOptionForLink);
+ sr.WriteLine();
+ sr.WriteLine("default:");
+ sr.WriteLine("\t@./.install.sh");
+ sr.WriteLine();
+ sr.WriteLine("# NOTE:");
+ sr.WriteLine("# You have to read and agree the license agreement at the same directory");
+ sr.WriteLine("# before using this software.");
+ sr.WriteLine();
+ sr.WriteLine("i_read_and_agree_the_license_agreement:");
+
+ sr.WriteLine("\t@echo \"Preparing {0}...\"", BuildHelper.GetSoftwareTitle(this.Software));
+
+ foreach (string filename in libFiles)
+ {
+ sr.WriteLine("\t-ranlib lib/{0}", Path.GetFileName(filename));
+ }
+
+ sr.WriteLine("\t-ranlib code/{0}.a", this.Software.ToString());
+ sr.WriteLine("\t$(CC) code/{0}.a $(OPTIONS) -o {0}", this.Software.ToString());
+
+ sr.WriteLine("\t-ranlib code/{0}.a", "vpncmd");
+ sr.WriteLine("\t$(CC) code/{0}.a $(OPTIONS) -o {0}", "vpncmd");
+
+ if (this.Software == Software.vpnserver_vpnbridge || this.Software == Software.vpnbridge || this.Software == Software.vpnserver)
+ {
+ sr.WriteLine("\t./vpncmd /tool /cmd:Check");
+ }
+
+ Language[] langs = BuildHelper.GetLanguageList();
+
+ sr.WriteLine("\t@echo");
+ sr.WriteLine("\t@echo \"--------------------------------------------------------------------\"");
+ sr.WriteLine("\t@echo \"The preparation of {0} is completed !\"", BuildHelper.GetSoftwareTitle(this.Software));
+ sr.WriteLine("\t@echo");
+ sr.WriteLine("\t@echo");
+ sr.WriteLine("\t@echo \"*** How to switch the display language of the {0} Service ***\"", BuildHelper.GetSoftwareTitle(this.Software));
+ sr.WriteLine("\t@echo \"{0} supports the following languages:\"", BuildHelper.GetSoftwareTitle(this.Software));
+
+ foreach (Language lang in langs)
+ {
+ sr.WriteLine("\t@echo \" - {0}\"", lang.Title);
+ }
+
+ sr.WriteLine("\t@echo");
+ sr.WriteLine("\t@echo \"You can choose your prefered language of {0} at any time.\"", BuildHelper.GetSoftwareTitle(this.Software));
+ sr.WriteLine("\t@echo \"To switch the current language, open and edit the 'lang.config' file.\"");
+
+ sr.WriteLine("\t@echo");
+ sr.WriteLine("\t@echo");
+
+ sr.WriteLine("\t@echo \"*** How to start the {0} Service ***\"", BuildHelper.GetSoftwareTitle(this.Software));
+ sr.WriteLine("\t@echo");
+
+ sr.WriteLine("\t@echo \"Please execute './{0} start' to run the {1} Background Service.\"", this.Software.ToString(), BuildHelper.GetSoftwareTitle(this.Software));
+#if !BU_SOFTETHER
+ sr.WriteLine("\t@echo \"And please execute './vpncmd' to run the PacketiX VPN Command-Line Utility to configure {0}.\"", BuildHelper.GetSoftwareTitle(this.Software));
+#else
+ sr.WriteLine("\t@echo \"And please execute './vpncmd' to run the SoftEther VPN Command-Line Utility to configure {0}.\"", BuildHelper.GetSoftwareTitle(this.Software));
+#endif
+ sr.WriteLine("\t@echo \"Of course, you can use the VPN Server Manager GUI Application for Windows on the other Windows PC in order to configure the {0} remotely.\"", BuildHelper.GetSoftwareTitle(this.Software));
+
+ sr.WriteLine("\t@echo \"--------------------------------------------------------------------\"");
+ sr.WriteLine("\t@echo");
+
+ sr.WriteLine();
+
+ sr.WriteLine("clean:");
+ sr.WriteLine("\trm -f {0}", this.Software.ToString());
+ sr.WriteLine("\trm -f {0}", "vpncmd");
+ sr.WriteLine();
+
+ return sr;
+ }
+
+ // Generate Makefile for compilation
+ public virtual StringWriter GenerateMakeFileForCompile(string outDir, bool debugMode, bool crossCompile)
+ {
+ string[] programNames =
+ {
+ "Ham",
+ "vpnserver",
+ "vpnbridge",
+ "vpnclient",
+ "vpncmd",
+ };
+
+ string gccOptionForLinkDebug, gccOptionForLinkRelease;
+ string gccOptionForCompileDebug, gccOptionForCompileRelease;
+
+ generateGccOptions(outDir, false, crossCompile, out gccOptionForLinkRelease, out gccOptionForCompileRelease);
+ generateGccOptions(outDir, true, crossCompile, out gccOptionForLinkDebug, out gccOptionForCompileDebug);
+
+ StringWriter sr = new StringWriter();
+#if !BU_SOFTETHER
+ sr.WriteLine("# PacketiX VPN Source Code");
+ sr.WriteLine("# Copyright (c) SoftEther Corporation. All Rights Reserved.");
+#else
+ sr.WriteLine("# SoftEther VPN Source Code");
+ sr.WriteLine("# Copyright (c) SoftEther VPN Project at University of Tsukuba, Japan. All Rights Reserved.");
+#endif
+ sr.WriteLine("# Platform: {0}", this.CrossLibName);
+ sr.WriteLine();
+
+ // Variable declaration
+ sr.WriteLine("# Variables");
+ sr.WriteLine("CC={0}", this.Compiler);
+ sr.WriteLine();
+ sr.WriteLine("OPTIONS_COMPILE_DEBUG={0}", gccOptionForCompileDebug);
+ sr.WriteLine();
+ sr.WriteLine("OPTIONS_LINK_DEBUG={0}", gccOptionForLinkDebug);
+ sr.WriteLine();
+ sr.WriteLine("OPTIONS_COMPILE_RELEASE={0}", gccOptionForCompileRelease);
+ sr.WriteLine();
+ sr.WriteLine("OPTIONS_LINK_RELEASE={0}", gccOptionForLinkRelease);
+ sr.WriteLine();
+ sr.WriteLine("ifeq ($(DEBUG),YES)");
+ sr.WriteLine("\tOPTIONS_COMPILE=$(OPTIONS_COMPILE_DEBUG)");
+ sr.WriteLine("\tOPTIONS_LINK=$(OPTIONS_LINK_DEBUG)");
+ sr.WriteLine("else");
+ sr.WriteLine("\tOPTIONS_COMPILE=$(OPTIONS_COMPILE_RELEASE)");
+ sr.WriteLine("\tOPTIONS_LINK=$(OPTIONS_LINK_RELEASE)");
+ sr.WriteLine("endif");
+ sr.WriteLine();
+
+ string[] mayaquaHeaders = generateFileList(Path.Combine(outDir, "Mayaqua"), outDir, "*.h");
+ string[] cedarHeaders = generateFileList(Path.Combine(outDir, "Cedar"), outDir, "*.h");
+ string[] mayaquaSrcs = generateFileList(Path.Combine(outDir, "Mayaqua"), outDir, "*.c");
+ string[] cedarSrcs = generateFileList(Path.Combine(outDir, "Cedar"), outDir, "*.c");
+ List mayaquaObjs = new List();
+ List cedarObjs = new List();
+ List progSrcs = new List();
+ List progObjs = new List();
+ List progAs = new List();
+ List progBins = new List();
+
+ foreach (string progName in programNames)
+ {
+ string progName2 = progName;
+
+ if (progName2.Equals("vpnclient", StringComparison.InvariantCultureIgnoreCase) == false)
+ {
+ progSrcs.Add(string.Format("{0}/{0}.c", progName2));
+ }
+ else
+ {
+ progSrcs.Add(string.Format("{0}/vpncsvc.c", progName2));
+ }
+ progObjs.Add(string.Format("object/{0}.o", progName2));
+ progAs.Add(string.Format("code/{0}.a", progName));
+ progBins.Add(string.Format("bin/{0}", progName.ToLower()));
+ }
+
+ int i;
+ for (i = 0; i < mayaquaSrcs.Length; i++)
+ {
+ mayaquaObjs.Add(string.Format("object/Mayaqua/{0}.o", Path.GetFileNameWithoutExtension(mayaquaSrcs[i])));
+ }
+ for (i = 0; i < cedarSrcs.Length; i++)
+ {
+ cedarObjs.Add(string.Format("object/Cedar/{0}.o", Path.GetFileNameWithoutExtension(cedarSrcs[i])));
+ }
+ sr.WriteLine("# Files");
+ sr.WriteLine("HEADERS_MAYAQUA={0}", Str.CombineStringArray(mayaquaHeaders, " "));
+ sr.WriteLine("HEADERS_CEDAR={0}", Str.CombineStringArray(cedarHeaders, " "));
+ sr.WriteLine("OBJECTS_MAYAQUA={0}", Str.CombineStringArray(mayaquaObjs.ToArray(), " "));
+ sr.WriteLine("OBJECTS_CEDAR={0}", Str.CombineStringArray(cedarObjs.ToArray(), " "));
+ sr.WriteLine();
+
+ // Behavior
+ sr.WriteLine("# Build Action");
+ sr.WriteLine("default:\tbuild");
+ sr.WriteLine();
+ sr.WriteLine("build:\t$(OBJECTS_MAYAQUA) $(OBJECTS_CEDAR) {0}", Str.CombineStringArray(progBins.ToArray(), " "));
+ sr.WriteLine();
+
+ sr.WriteLine("# Mayaqua Kernel Code");
+ for (i = 0; i < mayaquaSrcs.Length; i++)
+ {
+ sr.WriteLine("{0}: {1} $(HEADERS_MAYAQUA)", mayaquaObjs[i], mayaquaSrcs[i]);
+ if (i == 0)
+ {
+ sr.WriteLine("\t@mkdir -p object/");
+ sr.WriteLine("\t@mkdir -p object/Mayaqua/");
+ sr.WriteLine("\t@mkdir -p object/Cedar/");
+ sr.WriteLine("\t@mkdir -p code/");
+ }
+ sr.WriteLine("\t$(CC) $(OPTIONS_COMPILE) -c {0} -o {1}", mayaquaSrcs[i], mayaquaObjs[i]);
+ sr.WriteLine();
+ }
+
+ sr.WriteLine("# Cedar Communication Module Code");
+ for (i = 0; i < cedarSrcs.Length; i++)
+ {
+ string line = string.Format("{0}: {1} $(HEADERS_MAYAQUA) $(HEADERS_CEDAR)", cedarObjs[i], cedarSrcs[i]);
+ if (cedarSrcs[i].EndsWith("Bridge.c", StringComparison.InvariantCultureIgnoreCase))
+ {
+ line += " Cedar/BridgeUnix.c";
+ }
+ sr.WriteLine(line);
+ sr.WriteLine("\t$(CC) $(OPTIONS_COMPILE) -c {0} -o {1}", cedarSrcs[i], cedarObjs[i]);
+ sr.WriteLine();
+ }
+
+ for (i = 0; i < programNames.Length; i++)
+ {
+ sr.WriteLine("# {0}", programNames[i]);
+ sr.WriteLine("{0}: {1} $(HEADERS_MAYAQUA) $(HEADERS_CEDAR) $(OBJECTS_MAYAQUA) $(OBJECTS_CEDAR)",
+ progBins[i], progAs[i]);
+ sr.WriteLine("\t$(CC) {0} $(OPTIONS_LINK) -o {1}", progAs[i], progBins[i]);
+ sr.WriteLine();
+ sr.WriteLine("{0}: {1} $(HEADERS_MAYAQUA) $(HEADERS_CEDAR) $(OBJECTS_MAYAQUA) $(OBJECTS_CEDAR)",
+ progAs[i], progObjs[i]);
+ sr.WriteLine("\trm -f {0}", progAs[i]);
+ sr.WriteLine("\tar r {0} $(OBJECTS_MAYAQUA) $(OBJECTS_CEDAR) {1}", progAs[i], progObjs[i]);
+ sr.WriteLine("\tranlib {0}", progAs[i]);
+ sr.WriteLine();
+ sr.WriteLine("{0}: {1} $(HEADERS_MAYAQUA) $(HEADERS_CEDAR) $(OBJECTS_MAYAQUA) $(OBJECTS_CEDAR)",
+ progObjs[i], progSrcs[i]);
+ sr.WriteLine("\t$(CC) $(OPTIONS_COMPILE) -c {0} -o {1}", progSrcs[i], progObjs[i]);
+ sr.WriteLine();
+ }
+
+ sr.WriteLine("# Clean");
+ sr.WriteLine("clean:");
+ sr.WriteLine("\t-rm -f $(OBJECTS_MAYAQUA)");
+ sr.WriteLine("\t-rm -f $(OBJECTS_CEDAR)");
+ for (i = 0; i < programNames.Length; i++)
+ {
+ sr.WriteLine("\t-rm -f {0}", progObjs[i]);
+ sr.WriteLine("\t-rm -f {0}", progAs[i]);
+ sr.WriteLine("\t-rm -f {0}", progBins[i]);
+ }
+ sr.WriteLine();
+
+ sr.WriteLine("# Help Strings");
+ sr.WriteLine("help:");
+ sr.WriteLine("\t@echo \"make [DEBUG=YES]\"");
+ sr.WriteLine();
+
+ return sr;
+ }
+
+ // Create a file list
+ string[] generateFileList(string dir, string baseDir, string searchPattern)
+ {
+ string[] files = Directory.GetFiles(dir, searchPattern, SearchOption.AllDirectories);
+ List ret = new List();
+
+ foreach (string file in files)
+ {
+ string name = IO.GetRelativeFileName(file, baseDir).Replace(@"\", "/");
+ ret.Add(name);
+ }
+
+ ret.Sort();
+
+ return ret.ToArray();
+ }
+
+ // Generate the GCC option string
+ void generateGccOptions(string outDir, bool debugMode, bool crossCompile, out string gccOptionForLink, out string gccOptionForCompile)
+ {
+ List macros = new List(this.GccMacros.ToArray());
+ List includes = new List();
+ List options = new List();
+ List libs = new List();
+
+ // Determine the macro
+ if (debugMode)
+ {
+ macros.Add("_DEBUG");
+ macros.Add("DEBUG");
+ }
+ else
+ {
+ macros.Add("NDEBUG");
+ macros.Add("VPN_SPEED");
+ macros.Add("MAYAQUA_REPLACE");
+ }
+
+ macros.Add("UNIX");
+ macros.Add("_REENTRANT");
+ macros.Add("REENTRANT");
+ macros.Add("_THREAD_SAFE");
+ macros.Add("_THREADSAFE");
+ macros.Add("THREAD_SAFE");
+ macros.Add("THREADSAFE");
+ macros.Add("_FILE_OFFSET_BITS=64");
+
+ // Decide the include directory
+ includes.Add("./");
+ includes.Add("./Cedar/");
+ includes.Add("./Mayaqua/");
+
+ // Determine options
+ if (debugMode)
+ {
+ options.Add("-g");
+ }
+ else
+ {
+ options.Add("-O2");
+ }
+ options.Add("-fsigned-char");
+ if (this.NoPThreadOption == false)
+ {
+ options.Add("-pthread");
+ }
+ if (this.UseGccBitsOption)
+ {
+ if (this.Cpu.Bits == CPUBits.Bits32)
+ {
+ options.Add("-m32");
+ }
+ else
+ {
+ options.Add("-m64");
+ }
+ }
+
+ // Determine library files
+ string[] libNames =
+ {
+ "libssl",
+ "libcrypto",
+ "libiconv",
+ "libcharset",
+ "libedit",
+ "libncurses",
+ "libz",
+ };
+ foreach (string libName in libNames)
+ {
+ libs.Add(string.Format("lib/{0}.a", libName));
+ }
+
+ if (crossCompile)
+ {
+ if (this.Os == OSList.MacOS)
+ {
+ // Include libpcap.a only when cross-compiling for Mac OS X
+ libs.Add(string.Format("lib/{0}.a", "libpcap"));
+ }
+ }
+
+ if (this.Os == OSList.Linux)
+ {
+ if (this.Cpu == CpuList.x86 || this.Cpu == CpuList.x64)
+ {
+ // Include libintelaes.a only for x86 / x64 in Linux
+ libs.Add(string.Format("lib/{0}.a", "libintelaes"));
+ }
+ }
+
+ gccOptionForCompile = MakeGccOptions(macros.ToArray(), includes.ToArray(), options.ToArray(), null);
+
+ if (crossCompile)
+ {
+ if (Str.IsEmptyStr(this.CrossCompilerOption) == false)
+ {
+ options.Add(this.CrossCompilerOption);
+ }
+ }
+
+ options.Add("-lm");
+
+ if (this.Os == OSList.Solaris)
+ {
+ options.Add("-lrt");
+ options.Add("-lnsl");
+ options.Add("-lsocket");
+ options.Add("-ldl");
+ }
+ else if (this.Os == OSList.Linux)
+ {
+ options.Add("-ldl");
+ options.Add("-lrt");
+ }
+ else if (this.Os == OSList.MacOS)
+ {
+ if (crossCompile == false)
+ {
+ // Include -lpcap for the user environment on Mac OS X
+ options.Add("-lpcap");
+ }
+ }
+
+ if (this.Cpu == CpuList.armeabi)
+ {
+ // Prevent to show a warning on linking in EABI binaries
+ // to EABIHF architecture in ARM
+ options.Add("-Wl,--no-warn-mismatch");
+ }
+
+ options.Add("-lpthread");
+
+ gccOptionForLink = MakeGccOptions(new string[0], new string[0], options.ToArray(), libs.ToArray());
+ }
+
+ public static string MakeGccOptions(string[] macros, string[] includeDirs, string[] options, string[] libs)
+ {
+ List o = new List();
+ foreach (string macro in macros)
+ {
+ o.Add(string.Format("-D{0}", macro));
+ }
+ foreach (string dir in includeDirs)
+ {
+ o.Add(string.Format("-I{0}", dir));
+ }
+ foreach (string opt in options)
+ {
+ o.Add(opt);
+ }
+ if (libs != null)
+ {
+ o.Add("-L./");
+ foreach (string lib in libs)
+ {
+ o.Add(lib);
+ }
+ }
+
+ return Str.CombineStringArray(o.ToArray(), " ");
+ }
+ }
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/BuildUtil/VpnBuilder.cs b/src/BuildUtil/VpnBuilder.cs
new file mode 100644
index 00000000..c6489c77
--- /dev/null
+++ b/src/BuildUtil/VpnBuilder.cs
@@ -0,0 +1,650 @@
+// SoftEther VPN Source Code
+// Build Utility
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+using System;
+using System.Threading;
+using System.Text;
+using System.Configuration;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Security.Cryptography;
+using System.Web;
+using System.Web.Security;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+using System.Web.UI.WebControls.WebParts;
+using System.Web.UI.HtmlControls;
+using System.IO;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Drawing.Drawing2D;
+using System.Diagnostics;
+using System.Net;
+using System.Net.Security;
+using System.Security.Cryptography.X509Certificates;
+using CoreUtil;
+
+namespace BuildUtil
+{
+ // Languages
+ public class Language
+ {
+ public int Number;
+ public string Id;
+ public string Title;
+ public string TitleUnicode;
+ public string WindowsLocaleIds;
+ public string UnixLocaleIds;
+ }
+
+ // Build helper class
+ public static class BuildHelper
+ {
+ // loads the language list text file
+ public static Language[] GetLanguageList()
+ {
+ return GetLanguageList(Path.Combine(Paths.BinDirName, @"hamcore\languages.txt"));
+ }
+ public static Language[] GetLanguageList(string filename)
+ {
+ List ret = new List();
+ string[] lines = File.ReadAllLines(filename, Str.Utf8Encoding);
+
+ foreach (string line in lines)
+ {
+ string s = line.Trim();
+
+ if (Str.IsEmptyStr(s) == false)
+ {
+ if (s.StartsWith("#", StringComparison.InvariantCultureIgnoreCase) == false)
+ {
+ string[] sps = { " ", "\t", };
+ string[] tokens = s.Split(sps, StringSplitOptions.RemoveEmptyEntries);
+
+ if (tokens.Length == 6)
+ {
+ Language e = new Language();
+
+ e.Number = Str.StrToInt(tokens[0]);
+ e.Id = tokens[1];
+ e.Title = Str.ReplaceStr(tokens[2], "_", " ");
+ e.TitleUnicode = tokens[3];
+ e.WindowsLocaleIds = tokens[4];
+ e.UnixLocaleIds = tokens[5];
+
+ ret.Add(e);
+
+ Con.WriteLine(tokens.Length);
+ }
+ }
+ }
+ }
+
+ return ret.ToArray();
+ }
+
+ // Build
+ public static void BuildMain(BuildSoftware soft, bool debugModeIfUnix)
+ {
+ int version, build;
+ string name;
+ DateTime date;
+
+ string title = Console.Title;
+ Console.Title = string.Format("Building {0}", soft.IDString);
+
+ try
+ {
+ Win32BuildUtil.ReadBuildInfoFromTextFile(out build, out version, out name, out date);
+
+ soft.SetBuildNumberVersionName(build, version, name, date);
+
+ Con.WriteLine("Building '{0}' - {1}...", soft.IDString, soft.TitleString);
+
+ BuildSoftwareUnix softUnix = soft as BuildSoftwareUnix;
+
+ if (softUnix == null)
+ {
+ soft.Build();
+ }
+ else
+ {
+ softUnix.Build(debugModeIfUnix);
+ }
+ }
+ finally
+ {
+ Console.Title = title;
+ }
+ }
+
+ // Convert the number to a version number
+ public static string VersionIntToString(int version)
+ {
+ return string.Format("{0}.{1:D2}", version / 100, version % 100);
+ }
+
+ // Get a product list that is included in the software
+ public static string GetSoftwareProductList(Software soft)
+ {
+ string ret = "";
+
+ switch (soft)
+ {
+ case Software.vpnbridge:
+ ret = "PacketiX VPN Bridge";
+ break;
+
+ case Software.vpnclient:
+ ret = "PacketiX VPN Client, PacketiX VPN Command-Line Admin Utility (vpncmd)";
+ break;
+
+ case Software.vpnserver:
+ ret = "PacketiX VPN Server, PacketiX VPN Command-Line Admin Utility (vpncmd)";
+ break;
+
+ case Software.vpnserver_vpnbridge:
+ ret = "PacketiX VPN Server, PacketiX VPN Bridge, PacketiX VPN Server Manager for Windows, PacketiX VPN Command-Line Admin Utility (vpncmd)";
+ break;
+
+ default:
+ throw new ApplicationException("invalid soft.");
+ }
+
+#if BU_SOFTETHER
+ ret = Str.ReplaceStr(ret, "PacketiX", "SoftEther", false);
+#endif
+
+ return ret;
+ }
+
+ // Get the title of the software
+ public static string GetSoftwareTitle(Software soft)
+ {
+ string ret = "";
+
+ switch (soft)
+ {
+ case Software.vpnbridge:
+ ret = "PacketiX VPN Bridge";
+ break;
+
+ case Software.vpnclient:
+ ret = "PacketiX VPN Client";
+ break;
+
+ case Software.vpnserver:
+ ret = "PacketiX VPN Server";
+ break;
+
+ case Software.vpnserver_vpnbridge:
+ ret = "PacketiX VPN Server and VPN Bridge";
+ break;
+
+ default:
+ throw new ApplicationException("invalid soft.");
+ }
+
+#if BU_SOFTETHER
+ ret = Str.ReplaceStr(ret, "PacketiX", "SoftEther", false);
+#endif
+
+ return ret;
+ }
+ }
+
+ // Basic path information
+ public static class Paths
+ {
+ public static readonly string ExeFileName = Env.ExeFileName;
+ public static readonly string ExeDirName = Env.ExeFileDir;
+ public static readonly string BinDirName = ExeDirName;
+ public static readonly string BaseDirName = IO.NormalizePath(Path.Combine(BinDirName, @"..\"));
+ public static readonly string UtilityDirName = IO.NormalizePath(Path.Combine(BinDirName, @"..\BuildFiles\Utility"));
+
+#if !BU_SOFTETHER
+ // PacketiX VPN (build by SoftEther)
+ public static readonly string VPN4SolutionFileName = Path.Combine(BaseDirName, "VPN4.sln");
+ public static readonly string DebugSnapshotBaseDir = @"S:\SE4\DebugFilesSnapshot";
+ public static readonly string ReleaseDestDir = @"s:\SE4\Releases";
+ public const string Prefix = "";
+#else
+#if !BU_OSS
+ // SoftEther VPN (build by SoftEther)
+ public static readonly string VPN4SolutionFileName = Path.Combine(BaseDirName, "SEVPN.sln");
+ public static readonly string DebugSnapshotBaseDir = @"S:\SE4\DebugFilesSnapshot_SEVPN";
+ public static readonly string ReleaseDestDir = @"s:\SE4\Releases_SEVPN";
+ public const string Prefix = "softether-";
+#else
+ // SoftEther VPN (build by Open Source Developers)
+ public static readonly string VPN4SolutionFileName = Path.Combine(BaseDirName, "SEVPN.sln");
+ public static readonly string DebugSnapshotBaseDir = IO.NormalizePath(Path.Combine(BaseDirName, @"..\output\debug"));
+ public static readonly string ReleaseDestDir = IO.NormalizePath(Path.Combine(BaseDirName, @"..\output\pkg"));
+ public const string Prefix = "softether_open-";
+#endif
+#endif
+
+ public static readonly string ReleaseDestDir_SEVPN = @"s:\SE4\Releases_SEVPN";
+
+ public static readonly string BuildHamcoreFilesDirName = Path.Combine(BinDirName, "BuiltHamcoreFiles");
+ public static readonly string VisualStudioVCDir;
+ public static readonly string VisualStudioVCBatchFileName;
+ public static readonly string DotNetFramework35Dir;
+ public static readonly string MSBuildFileName;
+ public static readonly string TmpDirName;
+ public static readonly DateTime StartDateTime = DateTime.Now;
+ public static readonly string StartDateTimeStr;
+ public static readonly string CmdFileName;
+ public static readonly string ManifestsDir = Path.Combine(BaseDirName, @"BuildFiles\Manifests");
+ public static readonly string XCopyExeFileName = Path.Combine(Env.SystemDir, "xcopy.exe");
+ public static readonly string ReleaseDir = Path.Combine(BaseDirName, @"tmp\Release");
+ public static readonly string ReleaseSrckitDir = Path.Combine(BaseDirName, @"tmp\ReleaseSrcKit");
+ public static readonly string StringsDir = Path.Combine(BaseDirName, @"BuildFiles\Strings");
+ public static readonly string CrossCompilerBaseDir = @"S:\CommomDev\xc";
+ public static readonly string UnixInstallScript = Path.Combine(BaseDirName, @"BuildFiles\UnixFiles\InstallScript.txt");
+ public static readonly string OssCommentsFile = Path.Combine(StringsDir, "OssComments.txt");
+ public static readonly string AutorunSrcDir = IO.NormalizePath(Path.Combine(BaseDirName, @"..\Autorun"));
+ public static readonly string MicrosoftSDKDir;
+ public static readonly string MakeCatFilename;
+ public static readonly string RcFilename;
+ public static readonly string SoftEtherBuildDir = Env.SystemDir.Substring(0, 2) + @"\tmp\softether_build_dir";
+ public static readonly string OpenSourceDestDir = Env.SystemDir.Substring(0, 2) + @"\tmp\softether_oss_dest_dir";
+
+ // Initialize
+ static Paths()
+ {
+ // Starting date and time string
+ Paths.StartDateTimeStr = Str.DateTimeToStrShort(Paths.StartDateTime);
+
+ // Check whether the execution path is the bin directory in the VPN directory
+ if (Paths.BinDirName.EndsWith(@"\bin", StringComparison.InvariantCultureIgnoreCase) == false)
+ {
+ throw new ApplicationException(string.Format("'{0}' is not a VPN bin directory.", Paths.BinDirName));
+ }
+ if (File.Exists(Paths.VPN4SolutionFileName) == false)
+ {
+ throw new ApplicationException(string.Format("'{0}' is not a VPN base directory.", Paths.BaseDirName));
+ }
+
+ // Get the VC++ directory
+ // Visual Studio 2008
+ Paths.VisualStudioVCDir = IO.RemoteLastEnMark(Reg.ReadStr(RegRoot.LocalMachine, @"SOFTWARE\Microsoft\VisualStudio\9.0\Setup\VC", "ProductDir"));
+ if (Str.IsEmptyStr(Paths.VisualStudioVCDir))
+ {
+ throw new ApplicationException("Visual C++ directory not found.\n");
+ }
+ if (Directory.Exists(Paths.VisualStudioVCDir) == false)
+ {
+ throw new ApplicationException(string.Format("Directory '{0}' not found.", Paths.VisualStudioVCDir));
+ }
+
+ // Get the VC++ batch file name
+ Paths.VisualStudioVCBatchFileName = Path.Combine(Paths.VisualStudioVCDir, "vcvarsall.bat");
+ if (File.Exists(Paths.VisualStudioVCBatchFileName) == false)
+ {
+ throw new ApplicationException(string.Format("File '{0}' not found.", Paths.VisualStudioVCBatchFileName));
+ }
+
+ bool x86_dir = false;
+
+ // Get Microsoft SDK 6.0a directory
+ Paths.MicrosoftSDKDir = IO.RemoteLastEnMark(Reg.ReadStr(RegRoot.LocalMachine, @"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v6.0A", "InstallationFolder"));
+
+ // Get makecat.exe file name
+ Paths.MakeCatFilename = Path.Combine(Paths.MicrosoftSDKDir, @"bin\" + (x86_dir ? @"x86\" : "") + "makecat.exe");
+
+ // Get the rc.exe file name
+ Paths.RcFilename = Path.Combine(Paths.MicrosoftSDKDir, @"bin\" + (x86_dir ? @"x86\" : "") + "rc.exe");
+
+ // Get the cmd.exe file name
+ Paths.CmdFileName = Path.Combine(Env.SystemDir, "cmd.exe");
+ if (File.Exists(Paths.CmdFileName) == false)
+ {
+ throw new ApplicationException(string.Format("File '{0}' not found.", Paths.CmdFileName));
+ }
+
+ // Get .NET Framework 3.5 directory
+ Paths.DotNetFramework35Dir = Path.Combine(Env.WindowsDir, @"Microsoft.NET\Framework\v3.5");
+
+ // Get msbuild.exe directory
+ Paths.MSBuildFileName = Path.Combine(Paths.DotNetFramework35Dir, "MSBuild.exe");
+ if (File.Exists(Paths.MSBuildFileName) == false)
+ {
+ throw new ApplicationException(string.Format("File '{0}' not found.", Paths.MSBuildFileName));
+ }
+
+ // Get the TMP directory
+ Paths.TmpDirName = Path.Combine(Paths.BaseDirName, "tmp");
+ if (Directory.Exists(Paths.TmpDirName) == false)
+ {
+ Directory.CreateDirectory(Paths.TmpDirName);
+ }
+ }
+
+ public static void DeleteAllReleaseTarGz()
+ {
+ if (Directory.Exists(Paths.ReleaseDir))
+ {
+ string[] files = Directory.GetFiles(Paths.ReleaseDir, "*.gz", SearchOption.AllDirectories);
+
+ foreach (string file in files)
+ {
+ File.Delete(file);
+ }
+ }
+
+ if (Directory.Exists(Paths.ReleaseSrckitDir))
+ {
+ string[] files = Directory.GetFiles(Paths.ReleaseSrckitDir, "*.gz", SearchOption.AllDirectories);
+
+ foreach (string file in files)
+ {
+ File.Delete(file);
+ }
+ }
+ }
+
+ public static void DeleteAllReleaseAdminKits()
+ {
+ if (Directory.Exists(Paths.ReleaseDir))
+ {
+ string[] files = Directory.GetFiles(Paths.ReleaseDir, "*.zip", SearchOption.AllDirectories);
+
+ foreach (string file in files)
+ {
+ if (Str.InStr(file, "vpnadminpak"))
+ {
+ File.Delete(file);
+ }
+ }
+ }
+ }
+
+ public static void DeleteAllReleaseManuals()
+ {
+ if (Directory.Exists(Paths.ReleaseDir))
+ {
+ string[] files = Directory.GetFiles(Paths.ReleaseDir, "*", SearchOption.AllDirectories);
+
+ foreach (string file in files)
+ {
+ if (Str.InStr(file, "vpnmanual"))
+ {
+ File.Delete(file);
+ }
+ }
+ }
+ }
+
+ public static void DeleteAllReleaseExe()
+ {
+ if (Directory.Exists(Paths.ReleaseDir))
+ {
+ string[] files = Directory.GetFiles(Paths.ReleaseDir, "*.exe", SearchOption.AllDirectories);
+
+ foreach (string file in files)
+ {
+ if (Str.InStr(file, "vpnmanual") == false)
+ {
+ File.Delete(file);
+ }
+ }
+ }
+ }
+ }
+
+ // HamCore build utility
+ public static class HamCoreBuildUtil
+ {
+ // Identify whether a file is necessary only in the Win32
+ public static bool IsFileForOnlyWin32(string filename)
+ {
+ string[] filesOnlyWin32 =
+ {
+ ".exe",
+ ".dll",
+ ".sys",
+ ".inf",
+ ".wav",
+ };
+
+ foreach (string ext in filesOnlyWin32)
+ {
+ if (filename.EndsWith(ext, StringComparison.InvariantCultureIgnoreCase))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // Delete svn file
+ public static void DeleteSVNFilesFromHamCoreBuilder(HamCoreBuilder b)
+ {
+ List removeFiles = new List();
+ foreach (HamCoreBuilderFileEntry f in b.FileList)
+ {
+ string name = f.Name;
+ if (name.StartsWith(".svn", StringComparison.InvariantCultureIgnoreCase) ||
+ name.IndexOf(@"\.svn", StringComparison.InvariantCultureIgnoreCase) != -1)
+ {
+ removeFiles.Add(name);
+ }
+ }
+ foreach (string file in removeFiles)
+ {
+ b.DeleteFile(file);
+ }
+ }
+
+ // Build Hamcore file
+ public static void BuildHamcore()
+ {
+ string srcDirNameBasic = Path.Combine(Paths.BinDirName, "hamcore");
+ // Create the destination directory
+ string win32DestDir = Path.Combine(Paths.BuildHamcoreFilesDirName, "hamcore_win32");
+ string win32DestFileName = Path.Combine(win32DestDir, "hamcore.se2");
+ string unixDestDir = Path.Combine(Paths.BuildHamcoreFilesDirName, "hamcore_unix");
+ string unixDestFileName = Path.Combine(unixDestDir, "hamcore.se2");
+ IO.MakeDir(win32DestDir);
+ IO.MakeDir(unixDestDir);
+
+
+ BuildHamcoreEx(srcDirNameBasic, win32DestFileName, unixDestFileName);
+
+ // Copy to bin\hamcore.se2
+ try
+ {
+ string binHamcoreFileName = Path.Combine(Paths.BinDirName, "hamcore.se2");
+
+ try
+ {
+ File.Delete(binHamcoreFileName);
+ }
+ catch
+ {
+ }
+
+ File.Copy(win32DestFileName, binHamcoreFileName, true);
+ }
+ catch
+ {
+ }
+ }
+
+ public static void BuildHamcoreEx(string srcDirNameBasic, string win32DestFileName, string unixDestFileName)
+ {
+ HamCoreBuilder b = new HamCoreBuilder();
+ b.AddDir(srcDirNameBasic);
+ Con.WriteLine("* Building hamcore ...");
+
+ DeleteSVNFilesFromHamCoreBuilder(b);
+
+ try
+ {
+ File.Delete(win32DestFileName);
+ }
+ catch
+ {
+ }
+ b.Build(win32DestFileName);
+
+ // unix
+ List removeFiles = new List();
+ foreach (HamCoreBuilderFileEntry f in b.FileList)
+ {
+ if (IsFileForOnlyWin32(f.Name))
+ {
+ removeFiles.Add(f.Name);
+ }
+ }
+ foreach (string removeFile in removeFiles)
+ {
+ b.DeleteFile(removeFile);
+ }
+
+ DeleteSVNFilesFromHamCoreBuilder(b);
+
+ try
+ {
+ File.Delete(unixDestFileName);
+ }
+ catch
+ {
+ }
+ b.Build(unixDestFileName);
+ }
+ }
+
+ // Number of bits
+ public enum CPUBits
+ {
+ Both,
+ Bits32,
+ Bits64,
+ }
+
+ // Conversion a string to the number of bits
+ public static class CPUBitsUtil
+ {
+ public static CPUBits StringToCPUBits(string str)
+ {
+ if (str.Equals("32bit", StringComparison.InvariantCultureIgnoreCase))
+ {
+ return CPUBits.Bits32;
+ }
+ else if (str.Equals("64bit", StringComparison.InvariantCultureIgnoreCase))
+ {
+ return CPUBits.Bits64;
+ }
+ else if (str.Equals("intel", StringComparison.InvariantCultureIgnoreCase))
+ {
+ return CPUBits.Both;
+ }
+
+ throw new ApplicationException(string.Format("Invalid bits string '{0}'.", str));
+ }
+
+ public static string CPUBitsToString(CPUBits bits)
+ {
+ switch (bits)
+ {
+ case CPUBits.Bits32:
+ return "32bit";
+
+ case CPUBits.Bits64:
+ return "64bit";
+
+ case CPUBits.Both:
+ return "intel";
+ }
+
+ throw new ApplicationException("bits invalid.");
+ }
+ }
+}
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/BuildUtil/VpnBuilderConfig.cs b/src/BuildUtil/VpnBuilderConfig.cs
new file mode 100644
index 00000000..d3d74cc7
--- /dev/null
+++ b/src/BuildUtil/VpnBuilderConfig.cs
@@ -0,0 +1,513 @@
+// SoftEther VPN Source Code
+// Build Utility
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+using System;
+using System.Threading;
+using System.Text;
+using System.Configuration;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Security.Cryptography;
+using System.Web;
+using System.Web.Security;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+using System.Web.UI.WebControls.WebParts;
+using System.Web.UI.HtmlControls;
+using System.IO;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Drawing.Drawing2D;
+using System.Diagnostics;
+using System.Net;
+using System.Net.Security;
+using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
+using CoreUtil;
+
+namespace BuildUtil
+{
+ // Build settings
+ public static class BuildConfig
+ {
+ public static readonly int NumMultipleCompileTasks = 4;
+ }
+
+ // Software List
+ public static class BuildSoftwareList
+ {
+ // List creation date and time
+ public static DateTime ListCreatedDateTime = DateTime.Now;
+
+ // ========== Windows ==========
+ // Server and Bridge
+ public static readonly BuildSoftware vpnserver_win32_x86x64_ja =
+ new BuildSoftwareWin32(Software.vpnserver_vpnbridge, 0, 0, "", CpuList.intel, OSList.Windows);
+
+ // Client
+ public static readonly BuildSoftware vpnclient_win32_x86x64_ja =
+ new BuildSoftwareWin32(Software.vpnclient, 0, 0, "", CpuList.intel, OSList.Windows);
+
+ // ========== Linux ==========
+ // Server
+ public static readonly BuildSoftware vpnserver_linux_x86_ja =
+ new BuildSoftwareUnix(Software.vpnserver, 0, 0, "", CpuList.x86, OSList.Linux,
+ "linux-x86-32bit", true, "linux-x86-32bit-3.4.6", false,
+ null);
+ public static readonly BuildSoftware vpnserver_linux_x64_ja =
+ new BuildSoftwareUnix(Software.vpnserver, 0, 0, "", CpuList.x64, OSList.Linux,
+ "linux-x86-64bit", true, "linux-x86-64bit-3.4.6", false,
+ null);
+ public static readonly BuildSoftware vpnserver_linux_arm_ja =
+ new BuildSoftwareUnix(Software.vpnserver, 0, 0, "", CpuList.arm, OSList.Linux,
+ "linux-arm-32bit", false, "linux-arm-32bit-3.4.6", false,
+ null);
+ public static readonly BuildSoftware vpnserver_linux_armeabi_ja =
+ new BuildSoftwareUnix(Software.vpnserver, 0, 0, "", CpuList.armeabi, OSList.Linux,
+ "linux-armeabi-32bit", false, "linux-armeabi-32bit-4.3.2", true,
+ null);
+ public static readonly BuildSoftware vpnserver_linux_mipsel_ja =
+ new BuildSoftwareUnix(Software.vpnserver, 0, 0, "", CpuList.mipsel, OSList.Linux,
+ "linux-mipsel-32bit", false, "linux-mipsel-32bit-3.4.6", false,
+ null);
+ public static readonly BuildSoftware vpnserver_linux_ppc_ja =
+ new BuildSoftwareUnix(Software.vpnserver, 0, 0, "", CpuList.ppc32, OSList.Linux,
+ "linux-ppc-32bit", false, "linux-ppc-32bit-3.4.6", false,
+ null);
+ public static readonly BuildSoftware vpnserver_linux_sh4_ja =
+ new BuildSoftwareUnix(Software.vpnserver, 0, 0, "", CpuList.sh4, OSList.Linux,
+ "linux-sh4-32bit", false, "linux-sh4-32bit-3.4.6", false,
+ null);
+
+ // Client
+ public static readonly BuildSoftware vpnclient_linux_x86_ja =
+ new BuildSoftwareUnix(Software.vpnclient, 0, 0, "", CpuList.x86, OSList.Linux,
+ "linux-x86-32bit", true, "linux-x86-32bit-3.4.6", false,
+ null);
+ public static readonly BuildSoftware vpnclient_linux_x64_ja =
+ new BuildSoftwareUnix(Software.vpnclient, 0, 0, "", CpuList.x64, OSList.Linux,
+ "linux-x86-64bit", true, "linux-x86-64bit-3.4.6", false,
+ null);
+ public static readonly BuildSoftware vpnclient_linux_arm_ja =
+ new BuildSoftwareUnix(Software.vpnclient, 0, 0, "", CpuList.arm, OSList.Linux,
+ "linux-arm-32bit", false, "linux-arm-32bit-3.4.6", false,
+ null);
+ public static readonly BuildSoftware vpnclient_linux_armeabi_ja =
+ new BuildSoftwareUnix(Software.vpnclient, 0, 0, "", CpuList.armeabi, OSList.Linux,
+ "linux-armeabi-32bit", false, "linux-armeabi-32bit-4.3.2", true,
+ null);
+ public static readonly BuildSoftware vpnclient_linux_mipsel_ja =
+ new BuildSoftwareUnix(Software.vpnclient, 0, 0, "", CpuList.mipsel, OSList.Linux,
+ "linux-mipsel-32bit", false, "linux-mipsel-32bit-3.4.6", false,
+ null);
+ public static readonly BuildSoftware vpnclient_linux_ppc_ja =
+ new BuildSoftwareUnix(Software.vpnclient, 0, 0, "", CpuList.ppc32, OSList.Linux,
+ "linux-ppc-32bit", false, "linux-ppc-32bit-3.4.6", false,
+ null);
+ public static readonly BuildSoftware vpnclient_linux_sh4_ja =
+ new BuildSoftwareUnix(Software.vpnclient, 0, 0, "", CpuList.sh4, OSList.Linux,
+ "linux-sh4-32bit", false, "linux-sh4-32bit-3.4.6", false,
+ null);
+
+ // Bridge
+ public static readonly BuildSoftware vpnbridge_linux_x86_ja =
+ new BuildSoftwareUnix(Software.vpnbridge, 0, 0, "", CpuList.x86, OSList.Linux,
+ "linux-x86-32bit", true, "linux-x86-32bit-3.4.6", false,
+ null);
+ public static readonly BuildSoftware vpnbridge_linux_x64_ja =
+ new BuildSoftwareUnix(Software.vpnbridge, 0, 0, "", CpuList.x64, OSList.Linux,
+ "linux-x86-64bit", true, "linux-x86-64bit-3.4.6", false,
+ null);
+ public static readonly BuildSoftware vpnbridge_linux_arm_ja =
+ new BuildSoftwareUnix(Software.vpnbridge, 0, 0, "", CpuList.arm, OSList.Linux,
+ "linux-arm-32bit", false, "linux-arm-32bit-3.4.6", false,
+ null);
+ public static readonly BuildSoftware vpnbridge_linux_armeabi_ja =
+ new BuildSoftwareUnix(Software.vpnbridge, 0, 0, "", CpuList.armeabi, OSList.Linux,
+ "linux-armeabi-32bit", false, "linux-armeabi-32bit-4.3.2", true,
+ null);
+ public static readonly BuildSoftware vpnbridge_linux_mipsel_ja =
+ new BuildSoftwareUnix(Software.vpnbridge, 0, 0, "", CpuList.mipsel, OSList.Linux,
+ "linux-mipsel-32bit", false, "linux-mipsel-32bit-3.4.6", false,
+ null);
+ public static readonly BuildSoftware vpnbridge_linux_ppc_ja =
+ new BuildSoftwareUnix(Software.vpnbridge, 0, 0, "", CpuList.ppc32, OSList.Linux,
+ "linux-ppc-32bit", false, "linux-ppc-32bit-3.4.6", false,
+ null);
+ public static readonly BuildSoftware vpnbridge_linux_sh4_ja =
+ new BuildSoftwareUnix(Software.vpnbridge, 0, 0, "", CpuList.sh4, OSList.Linux,
+ "linux-sh4-32bit", false, "linux-sh4-32bit-3.4.6", false,
+ null);
+
+
+ // ========== FreeBSD ==========
+ // Server
+ public static readonly BuildSoftware vpnserver_bsd_x86_ja =
+ new BuildSoftwareUnix(Software.vpnserver, 0, 0, "", CpuList.x86, OSList.FreeBSD,
+ "freebsd-x86-32bit", true, "freebsd-x86-32bit-3.4.6", false,
+ null);
+ public static readonly BuildSoftware vpnserver_bsd_x64_ja =
+ new BuildSoftwareUnix(Software.vpnserver, 0, 0, "", CpuList.x64, OSList.FreeBSD,
+ "freebsd-x86-64bit", true, "freebsd-x86-64bit-3.4.6", false,
+ null);
+
+ // Bridge
+ public static readonly BuildSoftware vpnbridge_bsd_x86_ja =
+ new BuildSoftwareUnix(Software.vpnbridge, 0, 0, "", CpuList.x86, OSList.FreeBSD,
+ "freebsd-x86-32bit", true, "freebsd-x86-32bit-3.4.6", false,
+ null);
+ public static readonly BuildSoftware vpnbridge_bsd_x64_ja =
+ new BuildSoftwareUnix(Software.vpnbridge, 0, 0, "", CpuList.x64, OSList.FreeBSD,
+ "freebsd-x86-64bit", true, "freebsd-x86-64bit-3.4.6", false,
+ null);
+
+
+ // ========== Mac OS X ==========
+ // Server
+ public static readonly BuildSoftware vpnserver_macos_ppc32_ja =
+ new BuildSoftwareUnix(Software.vpnserver, 0, 0, "", CpuList.ppc32, OSList.MacOS,
+ "macos-ppc-32bit", true, "macos-ppc-32bit-4.0.4", true,
+ "-isysroot /cygdrive/s/CommomDev/xc/common/apple_xcode/xcode_2.4/Developer/SDKs/MacOSX10.4u.sdk");
+ public static readonly BuildSoftware vpnserver_macos_ppc64_ja =
+ new BuildSoftwareUnix(Software.vpnserver, 0, 0, "", CpuList.ppc64, OSList.MacOS,
+ "macos-ppc-64bit", true, "macos-ppc-64bit-4.0.4", true,
+ null);
+ public static readonly BuildSoftware vpnserver_macos_x86_ja =
+ new BuildSoftwareUnix(Software.vpnserver, 0, 0, "", CpuList.x86, OSList.MacOS,
+ "macos-x86-32bit", true, "macos-x86-32bit-4.0.4", true,
+ "-isysroot /cygdrive/s/CommomDev/xc/common/apple_xcode/xcode_2.4/Developer/SDKs/MacOSX10.4u.sdk");
+ public static readonly BuildSoftware vpnserver_macos_x64_ja =
+ new BuildSoftwareUnix(Software.vpnserver, 0, 0, "", CpuList.x64, OSList.MacOS,
+ "macos-x86-64bit", true, "macos-x86-64bit-4.0.4", true,
+ null);
+
+ // Bridge
+ public static readonly BuildSoftware vpnbridge_macos_ppc32_ja =
+ new BuildSoftwareUnix(Software.vpnbridge, 0, 0, "", CpuList.ppc32, OSList.MacOS,
+ "macos-ppc-32bit", true, "macos-ppc-32bit-4.0.4", true,
+ "-isysroot /cygdrive/s/CommomDev/xc/common/apple_xcode/xcode_2.4/Developer/SDKs/MacOSX10.4u.sdk");
+ public static readonly BuildSoftware vpnbridge_macos_ppc64_ja =
+ new BuildSoftwareUnix(Software.vpnbridge, 0, 0, "", CpuList.ppc64, OSList.MacOS,
+ "macos-ppc-64bit", true, "macos-ppc-64bit-4.0.4", true,
+ null);
+ public static readonly BuildSoftware vpnbridge_macos_x86_ja =
+ new BuildSoftwareUnix(Software.vpnbridge, 0, 0, "", CpuList.x86, OSList.MacOS,
+ "macos-x86-32bit", true, "macos-x86-32bit-4.0.4", true,
+ "-isysroot /cygdrive/s/CommomDev/xc/common/apple_xcode/xcode_2.4/Developer/SDKs/MacOSX10.4u.sdk");
+ public static readonly BuildSoftware vpnbridge_macos_x64_ja =
+ new BuildSoftwareUnix(Software.vpnbridge, 0, 0, "", CpuList.x64, OSList.MacOS,
+ "macos-x86-64bit", true, "macos-x86-64bit-4.0.4", true,
+ null);
+
+ // ========== Solaris ==========
+ // Server
+ public static readonly BuildSoftware vpnserver_solaris_sparc32_ja =
+ new BuildSoftwareUnix(Software.vpnserver, 0, 0, "", CpuList.sparc32, OSList.Solaris,
+ "solaris-sparc-32bit", true, "solaris-sparc-32bit-3.4.6", true,
+ null);
+ public static readonly BuildSoftware vpnserver_solaris_sparc64_ja =
+ new BuildSoftwareUnix(Software.vpnserver, 0, 0, "", CpuList.sparc64, OSList.Solaris,
+ "solaris-sparc-64bit", true, "solaris-sparc-64bit-3.4.6", true,
+ null);
+ public static readonly BuildSoftware vpnserver_solaris_x86_ja =
+ new BuildSoftwareUnix(Software.vpnserver, 0, 0, "", CpuList.x86, OSList.Solaris,
+ "solaris-x86-32bit", true, "solaris-x86-32bit-3.4.6", true,
+ null);
+ public static readonly BuildSoftware vpnserver_solaris_x64_ja =
+ new BuildSoftwareUnix(Software.vpnserver, 0, 0, "", CpuList.x64, OSList.Solaris,
+ "solaris-x86-64bit", true, "solaris-x86-64bit-3.4.6", true,
+ null);
+
+ // Bridge
+ public static readonly BuildSoftware vpnbridge_solaris_sparc32_ja =
+ new BuildSoftwareUnix(Software.vpnbridge, 0, 0, "", CpuList.sparc32, OSList.Solaris,
+ "solaris-sparc-32bit", true, "solaris-sparc-32bit-3.4.6", true,
+ null);
+ public static readonly BuildSoftware vpnbridge_solaris_sparc64_ja =
+ new BuildSoftwareUnix(Software.vpnbridge, 0, 0, "", CpuList.sparc64, OSList.Solaris,
+ "solaris-sparc-64bit", true, "solaris-sparc-64bit-3.4.6", true,
+ null);
+ public static readonly BuildSoftware vpnbridge_solaris_x86_ja =
+ new BuildSoftwareUnix(Software.vpnbridge, 0, 0, "", CpuList.x86, OSList.Solaris,
+ "solaris-x86-32bit", true, "solaris-x86-32bit-3.4.6", true,
+ null);
+ public static readonly BuildSoftware vpnbridge_solaris_x64_ja =
+ new BuildSoftwareUnix(Software.vpnbridge, 0, 0, "", CpuList.x64, OSList.Solaris,
+ "solaris-x86-64bit", true, "solaris-x86-64bit-3.4.6", true,
+ null);
+
+ static BuildSoftwareList()
+ {
+ foreach (BuildSoftware soft in List)
+ {
+ BuildSoftwareUnix s = soft as BuildSoftwareUnix;
+ if (s != null)
+ {
+ // Make different settings for each OS
+ if (soft.Os == OSList.Linux)
+ {
+ s.GccMacros.Add("UNIX_LINUX");
+ }
+ else if (soft.Os == OSList.FreeBSD)
+ {
+ s.GccMacros.Add("UNIX_BSD");
+ s.GccMacros.Add("BRIDGE_BPF");
+ s.GccMacros.Add("NO_VLAN");
+ }
+ else if (soft.Os == OSList.MacOS)
+ {
+ s.GccMacros.Add("UNIX_MACOS");
+ s.GccMacros.Add("BRIDGE_PCAP");
+ s.GccMacros.Add("NO_VLAN");
+ }
+ else if (soft.Os == OSList.Solaris)
+ {
+ s.GccMacros.Add("UNIX_SOLARIS");
+ s.GccMacros.Add("NO_VLAN");
+ }
+ if (s.Cpu.Bits == CPUBits.Bits64)
+ {
+ s.GccMacros.Add("CPU_64");
+ }
+ s.GccMacros.Add("CPU_" + s.Cpu.Name.ToUpperInvariant());
+ }
+ }
+ }
+
+ public static BuildSoftware[] List
+ {
+ get
+ {
+ List o = new List();
+ foreach (FieldInfo fi in typeof(BuildSoftwareList).GetFields(BindingFlags.Static | BindingFlags.Public))
+ if (fi.FieldType == typeof(BuildSoftware))
+ o.Add((BuildSoftware)fi.GetValue(null));
+ return o.ToArray();
+ }
+ }
+
+ public static BuildSoftware Find(Software soft, OS os, Cpu cpu)
+ {
+ foreach (BuildSoftware s in List)
+ {
+ if (s.Software == soft && s.Os == os && s.Cpu == cpu)
+ {
+ return s;
+ }
+ }
+ return null;
+ }
+ }
+
+ // OS List
+ public static class OSList
+ {
+ // Windows
+ public static readonly OS Windows = new OS("windows", "Windows",
+ "Windows 98 / 98 SE / ME / NT 4.0 SP6a / 2000 SP4 / XP SP2, SP3 / Server 2003 SP2 / Vista SP1, SP2 / Server 2008 SP1, SP2 / Hyper-V Server 2008 / 7 SP1 / Server 2008 R2 SP1 / Hyper-V Server 2008 R2 / 8 / Server 2012 / Hyper-V Server 2012 / 8.1 / Server 2012 R2 / Hyper-V Server 2012 R2",
+ new Cpu[]
+ {
+ CpuList.intel,
+ });
+
+ // Linux
+ public static readonly OS Linux = new OS("linux", "Linux",
+ "Linux Kernel 2.4 / 2.6 / 3.x",
+ new Cpu[]
+ {
+ CpuList.x86,
+ CpuList.x64,
+ CpuList.mipsel,
+ CpuList.ppc32,
+ CpuList.ppc64,
+ CpuList.sh4,
+ CpuList.arm,
+ CpuList.armeabi,
+ });
+
+ // FreeBSD
+ public static readonly OS FreeBSD = new OS("freebsd", "FreeBSD",
+ "FreeBSD 5 / 6 / 7 / 8 / 9",
+ new Cpu[]
+ {
+ CpuList.x86,
+ CpuList.x64,
+ });
+
+ // Solaris
+ public static readonly OS Solaris = new OS("solaris", "Solaris",
+ "Solaris 8 / 9 / 10 / 11",
+ new Cpu[]
+ {
+ CpuList.x86,
+ CpuList.x64,
+ CpuList.sparc32,
+ CpuList.sparc64,
+ });
+
+ // Mac OS X
+ public static readonly OS MacOS = new OS("macos", "Mac OS X",
+ "Mac OS X 10.4 Tiger / 10.5 Leopard / 10.6 Snow Leopard / 10.7 Lion / 10.8 Mountain Lion",
+ new Cpu[]
+ {
+ CpuList.x86,
+ CpuList.x64,
+ CpuList.ppc32,
+ CpuList.ppc64,
+ });
+
+ static OSList()
+ {
+ OSList.Windows.IsWindows = true;
+ }
+
+ public static OS[] List
+ {
+ get
+ {
+ List o = new List();
+ foreach (FieldInfo fi in typeof(OSList).GetFields(BindingFlags.Static | BindingFlags.Public))
+ if (fi.FieldType == typeof(OS))
+ o.Add((OS)fi.GetValue(null));
+ return o.ToArray();
+ }
+ }
+
+ public static OS FindByName(string name)
+ {
+ foreach (OS os in List)
+ {
+ if (os.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
+ {
+ return os;
+ }
+ }
+
+ throw new ApplicationException(name);
+ }
+ }
+
+ // CPU List
+ public static class CpuList
+ {
+ public static readonly Cpu x86 = new Cpu("x86", "Intel x86", CPUBits.Bits32);
+ public static readonly Cpu x64 = new Cpu("x64", "Intel x64 / AMD64", CPUBits.Bits64);
+ public static readonly Cpu intel = new Cpu("x86_x64", "Intel", CPUBits.Both);
+ public static readonly Cpu arm = new Cpu("arm", "ARM legacy ABI", CPUBits.Bits32);
+ public static readonly Cpu armeabi = new Cpu("arm_eabi", "ARM EABI", CPUBits.Bits32);
+ public static readonly Cpu mipsel = new Cpu("mips_el", "MIPS Little-Endian", CPUBits.Bits32);
+ public static readonly Cpu ppc32 = new Cpu("powerpc", "PowerPC", CPUBits.Bits32);
+ public static readonly Cpu ppc64 = new Cpu("powerpc64", "PowerPC G5", CPUBits.Bits64);
+ public static readonly Cpu sh4 = new Cpu("sh4", "SH-4", CPUBits.Bits32);
+ public static readonly Cpu sparc32 = new Cpu("sparc", "SPARC", CPUBits.Bits32);
+ public static readonly Cpu sparc64 = new Cpu("sparc64", "SPARC", CPUBits.Bits64);
+
+ public static Cpu[] List
+ {
+ get
+ {
+ List o = new List();
+ foreach (FieldInfo fi in typeof(CpuList).GetFields(BindingFlags.Static | BindingFlags.Public))
+ if (fi.FieldType == typeof(Cpu))
+ o.Add((Cpu)fi.GetValue(null));
+ return o.ToArray();
+ }
+ }
+
+ public static Cpu FindByName(string name)
+ {
+ foreach (Cpu c in List)
+ {
+ if (c.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
+ {
+ return c;
+ }
+ }
+
+ throw new ApplicationException(name);
+ }
+ }
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/BuildUtil/VpnBuilderConfigTypes.cs b/src/BuildUtil/VpnBuilderConfigTypes.cs
new file mode 100644
index 00000000..8ef91a6e
--- /dev/null
+++ b/src/BuildUtil/VpnBuilderConfigTypes.cs
@@ -0,0 +1,303 @@
+// SoftEther VPN Source Code
+// Build Utility
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+using System;
+using System.Threading;
+using System.Text;
+using System.Configuration;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Security.Cryptography;
+using System.Web;
+using System.Web.Security;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+using System.Web.UI.WebControls.WebParts;
+using System.Web.UI.HtmlControls;
+using System.IO;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Drawing.Drawing2D;
+using System.Diagnostics;
+using System.Net;
+using System.Net.Security;
+using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
+using CoreUtil;
+
+namespace BuildUtil
+{
+ // CPU data
+ public class Cpu
+ {
+ public string Name; // CPU name
+ public string Title; // CPU display name
+ public CPUBits Bits; // Bit length
+
+ public Cpu(string name, string title, CPUBits bits)
+ {
+ this.Name = name;
+ this.Title = title;
+ this.Bits = bits;
+ }
+ }
+
+ // OS data
+ public class OS : ICloneable
+ {
+ public string Name; // OS name
+ public string Title; // OS Display Name
+ public string OSSimpleList; // OS simple list
+ public Cpu[] CpuList; // CPU support list
+ public bool IsWindows = false; // Whether Windows
+ public bool IsOnlyFiles = false; // Whether only EXE file package
+
+ public OS(string name, string title, string simpleList, Cpu[] cpuList)
+ {
+ this.Name = name;
+ this.Title = title;
+ this.OSSimpleList = simpleList;
+ this.CpuList = cpuList;
+ }
+
+ public object Clone()
+ {
+ return this.MemberwiseClone();
+ }
+ }
+
+ // Type of software
+ public enum Software
+ {
+ vpnserver,
+ vpnbridge,
+ vpnclient,
+ vpnserver_vpnbridge,
+ }
+
+ // Class to build the software
+ public class BuildSoftware
+ {
+ public Software Software; // Software
+ public int Version; // Version number
+ public int BuildNumber; // Build Number
+ public string BuildName; // Build name
+ public Cpu Cpu; // CPU
+ public OS Os; // OS
+ public DateTime BuildDate; // Build date
+
+ public BuildSoftware(Software software, int buildNumber, int version, string buildName, Cpu cpu, OS os)
+ {
+ this.Software = software;
+ this.BuildNumber = buildNumber;
+ this.Version = version;
+ this.BuildName = buildName;
+ this.Cpu = cpu;
+ this.Os = os;
+ }
+
+ public void SetBuildNumberVersionName(int buildNumber, int version, string buildName, DateTime date)
+ {
+ this.BuildNumber = buildNumber;
+ this.Version = version;
+ this.BuildName = buildName;
+ this.BuildDate = date;
+ }
+
+ public BuildSoftware(string filename)
+ {
+ filename = Path.GetFileName(filename);
+
+ if (filename.StartsWith(Paths.Prefix, StringComparison.InvariantCultureIgnoreCase))
+ {
+ filename = filename.Substring(Paths.Prefix.Length);
+ }
+
+ if (filename.EndsWith(".tar.gz", StringComparison.InvariantCultureIgnoreCase))
+ {
+ filename = Str.ReplaceStr(filename, ".tar.gz", "");
+ }
+ else
+ {
+ filename = Path.GetFileNameWithoutExtension(filename);
+ }
+ char[] sps = {'-'};
+
+ string[] tokens = filename.Split(sps, StringSplitOptions.RemoveEmptyEntries);
+ if (tokens.Length != 8)
+ {
+ throw new ApplicationException(filename);
+ }
+
+ if (tokens[1].StartsWith("v", StringComparison.InvariantCultureIgnoreCase) == false)
+ {
+ throw new ApplicationException(filename);
+ }
+
+ this.Software = (Software)Enum.Parse(typeof(Software), tokens[0], true);
+ this.Version = (int)(double.Parse(tokens[1].Substring(1)) * 100);
+ this.BuildNumber = int.Parse(tokens[2]);
+ this.BuildName = tokens[3];
+
+ string[] ds = tokens[4].Split('.');
+ this.BuildDate = new DateTime(int.Parse(ds[0]), int.Parse(ds[1]), int.Parse(ds[2]));
+ this.Os = OSList.FindByName(tokens[5]);
+ this.Cpu = CpuList.FindByName(tokens[6]);
+ }
+
+ // Generate a string of file name equivalent
+ public virtual string FileNameBaseString
+ {
+ get
+ {
+ return string.Format("{0}-v{6}-{1}-{2}-{8:D4}.{9:D2}.{10:D2}-{4}-{3}-{7}",
+ Paths.Prefix + this.Software.ToString(),
+ this.BuildNumber,
+ this.BuildName,
+ this.Cpu.Name,
+ this.Os.Name,
+ 0,
+ BuildHelper.VersionIntToString(this.Version),
+ CPUBitsUtil.CPUBitsToString(this.Cpu.Bits),
+ BuildDate.Year, BuildDate.Month, BuildDate.Day).ToLower();
+ }
+ }
+
+ // Generate an identifier
+ public virtual string IDString
+ {
+ get
+ {
+ return string.Format("{0}-{2}-{3}-{4}",
+ Paths.Prefix + this.Software.ToString(),
+ 0,
+ this.Os.Name,
+ this.Cpu.Name,
+ CPUBitsUtil.CPUBitsToString(this.Cpu.Bits));
+ }
+ }
+
+ // Generate a title string
+ public virtual string TitleString
+ {
+ get
+ {
+ return string.Format("{0} (Ver {2}, Build {1}, {3}) for {5}", BuildHelper.GetSoftwareTitle(this.Software),
+ this.BuildNumber, BuildHelper.VersionIntToString(this.Version), this.Cpu.Title, 0, this.Os.Title);
+ }
+ }
+
+ // Generate extension
+ public virtual string OutputFileExt
+ {
+ get
+ {
+ if (this.Os.IsWindows)
+ {
+ return ".exe";
+ }
+ else
+ {
+ return ".tar.gz";
+ }
+ }
+ }
+
+ // Generate the output file name
+ public virtual string OutputFileName
+ {
+ get
+ {
+ return this.FileNameBaseString + this.OutputFileExt;
+ }
+ }
+
+ // Run the build
+ public virtual void Build()
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/BuildUtil/Web References/HvSignService/Reference.cs b/src/BuildUtil/Web References/HvSignService/Reference.cs
new file mode 100644
index 00000000..80e6b8f1
--- /dev/null
+++ b/src/BuildUtil/Web References/HvSignService/Reference.cs
@@ -0,0 +1,282 @@
+//------------------------------------------------------------------------------
+//
+// ã“ã®ã‚³ãƒ¼ãƒ‰ã¯ãƒ„ールã«ã‚ˆã£ã¦ç”Ÿæˆã•ã‚Œã¾ã—ãŸã€‚
+// ランタイムãƒãƒ¼ã‚¸ãƒ§ãƒ³:2.0.50727.5466
+//
+// ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã¸ã®å¤‰æ›´ã¯ã€ä»¥ä¸‹ã®çŠ¶æ³ä¸‹ã§ä¸æ£ãªå‹•ä½œã®åŽŸå› ã«ãªã£ãŸã‚Šã€
+// コードãŒå†ç”Ÿæˆã•ã‚Œã‚‹ã¨ãã«æ失ã—ãŸã‚Šã—ã¾ã™ã€‚
+//
+//------------------------------------------------------------------------------
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+//
+// ã“ã®ã‚½ãƒ¼ã‚¹ コード㯠Microsoft.VSDesignerã€ãƒãƒ¼ã‚¸ãƒ§ãƒ³ 2.0.50727.5466 ã«ã‚ˆã£ã¦è‡ªå‹•ç”Ÿæˆã•ã‚Œã¾ã—ãŸã€‚
+//
+#pragma warning disable 1591
+
+namespace BuildUtil.HvSignService {
+ using System.Diagnostics;
+ using System.Web.Services;
+ using System.ComponentModel;
+ using System.Web.Services.Protocols;
+ using System;
+ using System.Xml.Serialization;
+
+
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "2.0.50727.5420")]
+ [System.Diagnostics.DebuggerStepThroughAttribute()]
+ [System.ComponentModel.DesignerCategoryAttribute("code")]
+ [System.Web.Services.WebServiceBindingAttribute(Name="SignSoap", Namespace="http://hvsigncode/")]
+ public partial class Sign : System.Web.Services.Protocols.SoapHttpClientProtocol {
+
+ private System.Threading.SendOrPostCallback HelloWorldOperationCompleted;
+
+ private System.Threading.SendOrPostCallback ExecSignOperationCompleted;
+
+ private bool useDefaultCredentialsSetExplicitly;
+
+ ///
+ public Sign() {
+ this.Url = global::BuildUtil.Properties.Settings.Default.BuildUtilTmp_HvSignService_Sign;
+ if ((this.IsLocalFileSystemWebService(this.Url) == true)) {
+ this.UseDefaultCredentials = true;
+ this.useDefaultCredentialsSetExplicitly = false;
+ }
+ else {
+ this.useDefaultCredentialsSetExplicitly = true;
+ }
+ }
+
+ public new string Url {
+ get {
+ return base.Url;
+ }
+ set {
+ if ((((this.IsLocalFileSystemWebService(base.Url) == true)
+ && (this.useDefaultCredentialsSetExplicitly == false))
+ && (this.IsLocalFileSystemWebService(value) == false))) {
+ base.UseDefaultCredentials = false;
+ }
+ base.Url = value;
+ }
+ }
+
+ public new bool UseDefaultCredentials {
+ get {
+ return base.UseDefaultCredentials;
+ }
+ set {
+ base.UseDefaultCredentials = value;
+ this.useDefaultCredentialsSetExplicitly = true;
+ }
+ }
+
+ ///
+ public event HelloWorldCompletedEventHandler HelloWorldCompleted;
+
+ ///
+ public event ExecSignCompletedEventHandler ExecSignCompleted;
+
+ ///
+ [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://hvsigncode/HelloWorld", RequestNamespace="http://hvsigncode/", ResponseNamespace="http://hvsigncode/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
+ public string HelloWorld() {
+ object[] results = this.Invoke("HelloWorld", new object[0]);
+ return ((string)(results[0]));
+ }
+
+ ///
+ public void HelloWorldAsync() {
+ this.HelloWorldAsync(null);
+ }
+
+ ///
+ public void HelloWorldAsync(object userState) {
+ if ((this.HelloWorldOperationCompleted == null)) {
+ this.HelloWorldOperationCompleted = new System.Threading.SendOrPostCallback(this.OnHelloWorldOperationCompleted);
+ }
+ this.InvokeAsync("HelloWorld", new object[0], this.HelloWorldOperationCompleted, userState);
+ }
+
+ private void OnHelloWorldOperationCompleted(object arg) {
+ if ((this.HelloWorldCompleted != null)) {
+ System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));
+ this.HelloWorldCompleted(this, new HelloWorldCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));
+ }
+ }
+
+ ///
+ [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://hvsigncode/ExecSign", RequestNamespace="http://hvsigncode/", ResponseNamespace="http://hvsigncode/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
+ public string ExecSign(string src_filename, bool driver_mode, string description, int cert_id) {
+ object[] results = this.Invoke("ExecSign", new object[] {
+ src_filename,
+ driver_mode,
+ description,
+ cert_id});
+ return ((string)(results[0]));
+ }
+
+ ///
+ public void ExecSignAsync(string src_filename, bool driver_mode, string description, int cert_id) {
+ this.ExecSignAsync(src_filename, driver_mode, description, cert_id, null);
+ }
+
+ ///
+ public void ExecSignAsync(string src_filename, bool driver_mode, string description, int cert_id, object userState) {
+ if ((this.ExecSignOperationCompleted == null)) {
+ this.ExecSignOperationCompleted = new System.Threading.SendOrPostCallback(this.OnExecSignOperationCompleted);
+ }
+ this.InvokeAsync("ExecSign", new object[] {
+ src_filename,
+ driver_mode,
+ description,
+ cert_id}, this.ExecSignOperationCompleted, userState);
+ }
+
+ private void OnExecSignOperationCompleted(object arg) {
+ if ((this.ExecSignCompleted != null)) {
+ System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));
+ this.ExecSignCompleted(this, new ExecSignCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));
+ }
+ }
+
+ ///
+ public new void CancelAsync(object userState) {
+ base.CancelAsync(userState);
+ }
+
+ private bool IsLocalFileSystemWebService(string url) {
+ if (((url == null)
+ || (url == string.Empty))) {
+ return false;
+ }
+ System.Uri wsUri = new System.Uri(url);
+ if (((wsUri.Port >= 1024)
+ && (string.Compare(wsUri.Host, "localHost", System.StringComparison.OrdinalIgnoreCase) == 0))) {
+ return true;
+ }
+ return false;
+ }
+ }
+
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "2.0.50727.5420")]
+ public delegate void HelloWorldCompletedEventHandler(object sender, HelloWorldCompletedEventArgs e);
+
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "2.0.50727.5420")]
+ [System.Diagnostics.DebuggerStepThroughAttribute()]
+ [System.ComponentModel.DesignerCategoryAttribute("code")]
+ public partial class HelloWorldCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs {
+
+ private object[] results;
+
+ internal HelloWorldCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) :
+ base(exception, cancelled, userState) {
+ this.results = results;
+ }
+
+ ///
+ public string Result {
+ get {
+ this.RaiseExceptionIfNecessary();
+ return ((string)(this.results[0]));
+ }
+ }
+ }
+
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "2.0.50727.5420")]
+ public delegate void ExecSignCompletedEventHandler(object sender, ExecSignCompletedEventArgs e);
+
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "2.0.50727.5420")]
+ [System.Diagnostics.DebuggerStepThroughAttribute()]
+ [System.ComponentModel.DesignerCategoryAttribute("code")]
+ public partial class ExecSignCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs {
+
+ private object[] results;
+
+ internal ExecSignCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) :
+ base(exception, cancelled, userState) {
+ this.results = results;
+ }
+
+ ///
+ public string Result {
+ get {
+ this.RaiseExceptionIfNecessary();
+ return ((string)(this.results[0]));
+ }
+ }
+ }
+}
+
+#pragma warning restore 1591
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/BuildUtil/Web References/HvSignService/Sign.disco b/src/BuildUtil/Web References/HvSignService/Sign.disco
new file mode 100644
index 00000000..e5cb0c0b
--- /dev/null
+++ b/src/BuildUtil/Web References/HvSignService/Sign.disco
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/BuildUtil/Web References/HvSignService/Sign.wsdl b/src/BuildUtil/Web References/HvSignService/Sign.wsdl
new file mode 100644
index 00000000..4a6f0777
--- /dev/null
+++ b/src/BuildUtil/Web References/HvSignService/Sign.wsdl
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/BuildUtil/Web References/SignService/Reference.cs b/src/BuildUtil/Web References/SignService/Reference.cs
new file mode 100644
index 00000000..6ad8706a
--- /dev/null
+++ b/src/BuildUtil/Web References/SignService/Reference.cs
@@ -0,0 +1,281 @@
+//------------------------------------------------------------------------------
+//
+// ã“ã®ã‚³ãƒ¼ãƒ‰ã¯ãƒ„ールã«ã‚ˆã£ã¦ç”Ÿæˆã•ã‚Œã¾ã—ãŸã€‚
+// ランタイムãƒãƒ¼ã‚¸ãƒ§ãƒ³:2.0.50727.4927
+//
+// ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã¸ã®å¤‰æ›´ã¯ã€ä»¥ä¸‹ã®çŠ¶æ³ä¸‹ã§ä¸æ£ãªå‹•ä½œã®åŽŸå› ã«ãªã£ãŸã‚Šã€
+// コードãŒå†ç”Ÿæˆã•ã‚Œã‚‹ã¨ãã«æ失ã—ãŸã‚Šã—ã¾ã™ã€‚
+//
+//------------------------------------------------------------------------------
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+//
+// ã“ã®ã‚½ãƒ¼ã‚¹ コード㯠Microsoft.VSDesignerã€ãƒãƒ¼ã‚¸ãƒ§ãƒ³ 2.0.50727.4927 ã«ã‚ˆã£ã¦è‡ªå‹•ç”Ÿæˆã•ã‚Œã¾ã—ãŸã€‚
+//
+#pragma warning disable 1591
+
+namespace BuildUtil.SignService {
+ using System.Diagnostics;
+ using System.Web.Services;
+ using System.ComponentModel;
+ using System.Web.Services.Protocols;
+ using System;
+ using System.Xml.Serialization;
+
+
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "2.0.50727.4927")]
+ [System.Diagnostics.DebuggerStepThroughAttribute()]
+ [System.ComponentModel.DesignerCategoryAttribute("code")]
+ [System.Web.Services.WebServiceBindingAttribute(Name="SignSoap", Namespace="http://dv/Sign/")]
+ public partial class Sign : System.Web.Services.Protocols.SoapHttpClientProtocol {
+
+ private System.Threading.SendOrPostCallback HelloWorldOperationCompleted;
+
+ private System.Threading.SendOrPostCallback DoSignOperationCompleted;
+
+ private bool useDefaultCredentialsSetExplicitly;
+
+ ///
+ public Sign() {
+ this.Url = global::BuildUtil.Properties.Settings.Default.BuildUtil_SignService_Sign;
+ if ((this.IsLocalFileSystemWebService(this.Url) == true)) {
+ this.UseDefaultCredentials = true;
+ this.useDefaultCredentialsSetExplicitly = false;
+ }
+ else {
+ this.useDefaultCredentialsSetExplicitly = true;
+ }
+ }
+
+ public new string Url {
+ get {
+ return base.Url;
+ }
+ set {
+ if ((((this.IsLocalFileSystemWebService(base.Url) == true)
+ && (this.useDefaultCredentialsSetExplicitly == false))
+ && (this.IsLocalFileSystemWebService(value) == false))) {
+ base.UseDefaultCredentials = false;
+ }
+ base.Url = value;
+ }
+ }
+
+ public new bool UseDefaultCredentials {
+ get {
+ return base.UseDefaultCredentials;
+ }
+ set {
+ base.UseDefaultCredentials = value;
+ this.useDefaultCredentialsSetExplicitly = true;
+ }
+ }
+
+ ///
+ public event HelloWorldCompletedEventHandler HelloWorldCompleted;
+
+ ///
+ public event DoSignCompletedEventHandler DoSignCompleted;
+
+ ///
+ [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://dv/Sign/HelloWorld", RequestNamespace="http://dv/Sign/", ResponseNamespace="http://dv/Sign/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
+ public string HelloWorld() {
+ object[] results = this.Invoke("HelloWorld", new object[0]);
+ return ((string)(results[0]));
+ }
+
+ ///
+ public void HelloWorldAsync() {
+ this.HelloWorldAsync(null);
+ }
+
+ ///
+ public void HelloWorldAsync(object userState) {
+ if ((this.HelloWorldOperationCompleted == null)) {
+ this.HelloWorldOperationCompleted = new System.Threading.SendOrPostCallback(this.OnHelloWorldOperationCompleted);
+ }
+ this.InvokeAsync("HelloWorld", new object[0], this.HelloWorldOperationCompleted, userState);
+ }
+
+ private void OnHelloWorldOperationCompleted(object arg) {
+ if ((this.HelloWorldCompleted != null)) {
+ System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));
+ this.HelloWorldCompleted(this, new HelloWorldCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));
+ }
+ }
+
+ ///
+ [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://dv/Sign/DoSign", RequestNamespace="http://dv/Sign/", ResponseNamespace="http://dv/Sign/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
+ [return: System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")]
+ public byte[] DoSign([System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] byte[] srcData, bool driverMode, string description) {
+ object[] results = this.Invoke("DoSign", new object[] {
+ srcData,
+ driverMode,
+ description});
+ return ((byte[])(results[0]));
+ }
+
+ ///
+ public void DoSignAsync(byte[] srcData, bool driverMode, string description) {
+ this.DoSignAsync(srcData, driverMode, description, null);
+ }
+
+ ///
+ public void DoSignAsync(byte[] srcData, bool driverMode, string description, object userState) {
+ if ((this.DoSignOperationCompleted == null)) {
+ this.DoSignOperationCompleted = new System.Threading.SendOrPostCallback(this.OnDoSignOperationCompleted);
+ }
+ this.InvokeAsync("DoSign", new object[] {
+ srcData,
+ driverMode,
+ description}, this.DoSignOperationCompleted, userState);
+ }
+
+ private void OnDoSignOperationCompleted(object arg) {
+ if ((this.DoSignCompleted != null)) {
+ System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));
+ this.DoSignCompleted(this, new DoSignCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));
+ }
+ }
+
+ ///
+ public new void CancelAsync(object userState) {
+ base.CancelAsync(userState);
+ }
+
+ private bool IsLocalFileSystemWebService(string url) {
+ if (((url == null)
+ || (url == string.Empty))) {
+ return false;
+ }
+ System.Uri wsUri = new System.Uri(url);
+ if (((wsUri.Port >= 1024)
+ && (string.Compare(wsUri.Host, "localHost", System.StringComparison.OrdinalIgnoreCase) == 0))) {
+ return true;
+ }
+ return false;
+ }
+ }
+
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "2.0.50727.4927")]
+ public delegate void HelloWorldCompletedEventHandler(object sender, HelloWorldCompletedEventArgs e);
+
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "2.0.50727.4927")]
+ [System.Diagnostics.DebuggerStepThroughAttribute()]
+ [System.ComponentModel.DesignerCategoryAttribute("code")]
+ public partial class HelloWorldCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs {
+
+ private object[] results;
+
+ internal HelloWorldCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) :
+ base(exception, cancelled, userState) {
+ this.results = results;
+ }
+
+ ///
+ public string Result {
+ get {
+ this.RaiseExceptionIfNecessary();
+ return ((string)(this.results[0]));
+ }
+ }
+ }
+
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "2.0.50727.4927")]
+ public delegate void DoSignCompletedEventHandler(object sender, DoSignCompletedEventArgs e);
+
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "2.0.50727.4927")]
+ [System.Diagnostics.DebuggerStepThroughAttribute()]
+ [System.ComponentModel.DesignerCategoryAttribute("code")]
+ public partial class DoSignCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs {
+
+ private object[] results;
+
+ internal DoSignCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) :
+ base(exception, cancelled, userState) {
+ this.results = results;
+ }
+
+ ///
+ public byte[] Result {
+ get {
+ this.RaiseExceptionIfNecessary();
+ return ((byte[])(this.results[0]));
+ }
+ }
+ }
+}
+
+#pragma warning restore 1591
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/BuildUtil/Web References/SignService/Sign.disco b/src/BuildUtil/Web References/SignService/Sign.disco
new file mode 100644
index 00000000..2fe47490
--- /dev/null
+++ b/src/BuildUtil/Web References/SignService/Sign.disco
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/BuildUtil/Web References/SignService/Sign.wsdl b/src/BuildUtil/Web References/SignService/Sign.wsdl
new file mode 100644
index 00000000..fdb6fb28
--- /dev/null
+++ b/src/BuildUtil/Web References/SignService/Sign.wsdl
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/BuildUtil/Win32BuildSoftware.cs b/src/BuildUtil/Win32BuildSoftware.cs
new file mode 100644
index 00000000..8991da55
--- /dev/null
+++ b/src/BuildUtil/Win32BuildSoftware.cs
@@ -0,0 +1,160 @@
+// SoftEther VPN Source Code
+// Build Utility
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+using System;
+using System.Threading;
+using System.Text;
+using System.Configuration;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Security.Cryptography;
+using System.Web;
+using System.Web.Security;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+using System.Web.UI.WebControls.WebParts;
+using System.Web.UI.HtmlControls;
+using System.IO;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Drawing.Drawing2D;
+using System.Diagnostics;
+using System.Net;
+using System.Net.Security;
+using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
+using CoreUtil;
+
+namespace BuildUtil
+{
+ // Build Win32 software
+ public class BuildSoftwareWin32 : BuildSoftware
+ {
+ public BuildSoftwareWin32(Software software, int buildNumber, int version, string buildName, Cpu cpu, OS os)
+ : base(software, buildNumber, version, buildName, cpu, os)
+ {
+ }
+
+ // Run the build
+ public override void Build()
+ {
+ Semaphore sem = new Semaphore(BuildConfig.NumMultipleCompileTasks, BuildConfig.NumMultipleCompileTasks, "vpn_build_cross");
+ Con.WriteLine("Waiting for Semaphore...");
+ sem.WaitOne();
+ Con.WriteLine("Done.");
+ try
+ {
+ // Run the build
+ buildInstaller();
+ }
+ finally
+ {
+ sem.Release();
+ }
+ }
+
+ // Build the installer
+ void buildInstaller()
+ {
+ string outFileName = Path.Combine(Paths.ReleaseDir, this.OutputFileName);
+
+ string vpnsetup_exe = Path.Combine(Paths.BinDirName, "vpnsetup.exe");
+
+ try
+ {
+ File.Delete(outFileName);
+ }
+ catch
+ {
+ }
+
+ Win32BuildUtil.ExecCommand(vpnsetup_exe, string.Format("/SFXMODE:{1} /SFXOUT:\"{0}\"",
+ outFileName, Software.ToString()));
+
+ CodeSign.SignFile(outFileName, outFileName, "VPN Software", false);
+ }
+ }
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/BuildUtil/Win32BuildUtil.cs b/src/BuildUtil/Win32BuildUtil.cs
new file mode 100644
index 00000000..5f478966
--- /dev/null
+++ b/src/BuildUtil/Win32BuildUtil.cs
@@ -0,0 +1,1063 @@
+// SoftEther VPN Source Code
+// Build Utility
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+using System;
+using System.Threading;
+using System.Text;
+using System.Configuration;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Security.Cryptography;
+using System.Web;
+using System.Web.Security;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+using System.Web.UI.WebControls.WebParts;
+using System.Web.UI.HtmlControls;
+using System.IO;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Drawing.Drawing2D;
+using System.Diagnostics;
+using System.Net;
+using System.Net.Security;
+using System.Security.Cryptography.X509Certificates;
+using CoreUtil;
+
+namespace BuildUtil
+{
+ // Build utility for Win32
+ public static class Win32BuildUtil
+ {
+ // Generate vpnweb.ocx
+ public static void GenerateVpnWebOcxCab(string dstFileName, string ocxFileName)
+ {
+ int build, version;
+ string name;
+ DateTime date;
+ ReadBuildInfoFromTextFile(out build, out version, out name, out date);
+
+ string cabVer = string.Format("{0},{1},0,{2}", version / 100, version % 100, build);
+ string cabFileName = IO.CreateTempFileNameByExt(".cab");
+ Mutex m = new Mutex(false, "cabtmp_mutex");
+
+ m.WaitOne();
+
+ try
+ {
+ // Building the cab
+ string cabTmpDir = Path.Combine(Paths.TmpDirName, "cabtmp");
+
+ IO.MakeDir(cabTmpDir);
+ IO.DeleteFilesAndSubDirsInDir(cabTmpDir);
+
+ File.Copy(Path.Combine(Paths.BinDirName, ocxFileName), Path.Combine(cabTmpDir, "vpnweb.ocx"));
+
+ string infText = File.ReadAllText(Path.Combine(Path.Combine(Paths.BaseDirName, @"BuildFiles\OcxCabInf"), "vpnweb.inf"));
+ infText = Str.ReplaceStr(infText, "$CAB_VERSION$", cabVer);
+ File.WriteAllText(Path.Combine(cabTmpDir, "vpnweb.inf"), infText);
+
+ Win32BuildUtil.ExecCommand(Path.Combine(Paths.BaseDirName, @"BuildFiles\Utility\cabarc.exe"),
+ string.Format(@"-s 6144 n {0}\vpnweb.cab {0}\vpnweb.ocx {0}\vpnweb.inf", cabTmpDir));
+
+ File.Copy(Path.Combine(cabTmpDir, "vpnweb.cab"), cabFileName, true);
+ }
+ finally
+ {
+ m.ReleaseMutex();
+ }
+
+ CodeSign.SignFile(cabFileName, cabFileName, "VPN Software", false);
+
+ File.Copy(cabFileName, dstFileName, true);
+ }
+
+ // Generate a version information resource
+ public static void GenerateVersionInfoResource(string targetExeName, string outName, string rc_name)
+ {
+ int build, version;
+ string name;
+ DateTime date;
+ ReadBuildInfoFromTextFile(out build, out version, out name, out date);
+
+ if (Str.IsEmptyStr(rc_name))
+ {
+ rc_name = "ver.rc";
+ }
+
+ string templateFileName = Path.Combine(Paths.BaseDirName, @"BuildFiles\VerScript\" + rc_name);
+ string body = Str.ReadTextFile(templateFileName);
+
+ string exeFileName = Path.GetFileName(targetExeName);
+ string internalName = Path.GetFileNameWithoutExtension(exeFileName);
+
+#if !BU_SOFTETHER
+ body = Str.ReplaceStr(body, "$PRODUCTNAME$", "PacketiX VPN");
+#else
+ body = Str.ReplaceStr(body, "$PRODUCTNAME$", "SoftEther VPN");
+#endif
+ body = Str.ReplaceStr(body, "$INTERNALNAME$", internalName);
+ body = Str.ReplaceStr(body, "$YEAR$", date.Year.ToString());
+ body = Str.ReplaceStr(body, "$FILENAME$", exeFileName);
+ body = Str.ReplaceStr(body, "$VER_MAJOR$", (version / 100).ToString());
+ body = Str.ReplaceStr(body, "$VER_MINOR$", (version % 100).ToString());
+ body = Str.ReplaceStr(body, "$VER_BUILD$", build.ToString());
+
+ IO f = IO.CreateTempFileByExt(".rc");
+ string filename = f.Name;
+
+ f.Write(Str.AsciiEncoding.GetBytes(body));
+
+ f.Close();
+
+ ExecCommand(Paths.RcFilename, "\"" + filename + "\"");
+
+ string rcDir = Path.GetDirectoryName(filename);
+ string rcFilename = Path.GetFileName(filename);
+ string rcFilename2 = Path.GetFileNameWithoutExtension(rcFilename);
+
+ string resFilename = Path.Combine(rcDir, rcFilename2) + ".res";
+
+ IO.MakeDirIfNotExists(Path.GetDirectoryName(outName));
+
+ IO.FileCopy(resFilename, outName, true, false);
+ }
+
+ // Flush to disk
+ public static void Flush()
+ {
+ string txt = IO.CreateTempFileNameByExt(".txt");
+ byte[] ret = Secure.Rand(64);
+
+ FileStream f = File.Create(txt);
+
+ f.Write(ret, 0, ret.Length);
+
+ f.Flush();
+
+ f.Close();
+
+ File.Delete(txt);
+ }
+
+ // Increment the build number
+ public static void IncrementBuildNumber()
+ {
+ int build, version;
+ string name;
+ DateTime date;
+
+ ReadBuildInfoFromTextFile(out build, out version, out name, out date);
+ build++;
+
+ WriteBuildInfoToTextFile(build, version, name, date);
+
+ SetNowDate();
+
+ Con.WriteLine("New build number: {0}", build);
+ }
+
+ // Set the date and time
+ public static void SetNowDate()
+ {
+ int build, version;
+ string name;
+ DateTime date;
+
+ ReadBuildInfoFromTextFile(out build, out version, out name, out date);
+
+ date = DateTime.Now;
+
+ WriteBuildInfoToTextFile(build, version, name, date);
+ }
+
+ // Write the build number and the version number in the text file
+ public static void WriteBuildInfoToTextFile(int build, int version, string name, DateTime date)
+ {
+ string filename = Path.Combine(Paths.BaseDirName, "CurrentBuild.txt");
+
+ WriteBuildInfoToTextFile(build, version, name, date, filename);
+ }
+ public static void WriteBuildInfoToTextFile(int build, int version, string name, DateTime date, string filename)
+ {
+ using (StreamWriter w = new StreamWriter(filename))
+ {
+ w.WriteLine("BUILD_NUMBER {0}", build);
+ w.WriteLine("VERSION {0}", version);
+ w.WriteLine("BUILD_NAME {0}", name);
+ w.WriteLine("BUILD_DATE {0}", Str.DateTimeToStrShort(date));
+
+ w.Flush();
+ w.Close();
+ }
+ }
+
+ // Read the build number and the version number from a text file
+ public static void ReadBuildInfoFromTextFile(out int build, out int version, out string name, out DateTime date)
+ {
+ string filename = Path.Combine(Paths.BaseDirName, "CurrentBuild.txt");
+
+ ReadBuildInfoFromTextFile(out build, out version, out name, out date, filename);
+ }
+ public static void ReadBuildInfoFromTextFile(out int build, out int version, out string name, out DateTime date, string filename)
+ {
+ char[] seps = { '\t', ' ', };
+ name = "";
+ date = new DateTime(0);
+
+ using (StreamReader r = new StreamReader(filename))
+ {
+ build = version = 0;
+
+ while (true)
+ {
+ string line = r.ReadLine();
+ if (line == null)
+ {
+ break;
+ }
+
+ string[] tokens = line.Split(seps, StringSplitOptions.RemoveEmptyEntries);
+ if (tokens.Length == 2)
+ {
+ if (tokens[0].Equals("BUILD_NUMBER", StringComparison.InvariantCultureIgnoreCase))
+ {
+ build = int.Parse(tokens[1]);
+ }
+
+ if (tokens[0].Equals("VERSION", StringComparison.InvariantCultureIgnoreCase))
+ {
+ version = int.Parse(tokens[1]);
+ }
+
+ if (tokens[0].Equals("BUILD_NAME", StringComparison.InvariantCultureIgnoreCase))
+ {
+ name = tokens[1];
+
+ name = Str.ReplaceStr(name, "-", "_");
+ }
+
+ if (tokens[0].Equals("BUILD_DATE", StringComparison.InvariantCultureIgnoreCase))
+ {
+ date = Str.StrToDateTime(tokens[1]);
+ }
+ }
+ }
+
+ r.Close();
+
+ if (build == 0 || version == 0 || Str.IsEmptyStr(name) || date.Ticks == 0)
+ {
+ throw new ApplicationException(string.Format("Wrong file data: '{0}'", filename));
+ }
+ }
+ }
+
+ // Normalize the build information
+ public static void NormalizeBuildInfo()
+ {
+ SetNowDate();
+
+ int build, version;
+ string name;
+ DateTime date;
+ ReadBuildInfoFromTextFile(out build, out version, out name, out date);
+ string username = Env.UserName;
+ string pcname = Env.MachineName;
+
+ NormalizeSourceCode(build, version, username, pcname, date);
+ }
+
+ // Apply build number, version number, user name, and PC name to the source code
+ public static void NormalizeSourceCode(int buildNumber, int version, string userName, string pcName, DateTime date)
+ {
+ DateTime now = date;
+ char[] seps = { '\t', ' ', };
+
+ int i = pcName.IndexOf(".");
+ if (i != -1)
+ {
+ pcName = pcName.Substring(0, i);
+ }
+
+ userName = userName.ToLower();
+ pcName = pcName.ToLower();
+
+ string[] files = Util.CombineArray(
+ Directory.GetFiles(Paths.BaseDirName, "*.h", SearchOption.AllDirectories));
+
+ foreach (string file in files)
+ {
+ string dir = Path.GetDirectoryName(file);
+ if (Str.InStr(dir, @"\.svn\") == false &&
+ Str.InStr(IO.GetRelativeFileName(file, Paths.BaseDirName), @"tmp\") == false)
+ {
+ byte[] srcData = File.ReadAllBytes(file);
+
+ int bomSize;
+ Encoding enc = Str.GetEncoding(srcData, out bomSize);
+ if (enc == null)
+ {
+ enc = Str.Utf8Encoding;
+ }
+ StringReader r = new StringReader(enc.GetString(Util.ExtractByteArray(srcData, bomSize, srcData.Length - bomSize)));
+ StringWriter w = new StringWriter();
+ bool somethingChanged = false;
+
+ while (true)
+ {
+ string line = r.ReadLine();
+ if (line == null)
+ {
+ break;
+ }
+ string newLine = null;
+
+ string[] tokens = line.Split(seps, StringSplitOptions.RemoveEmptyEntries);
+
+ if (tokens.Length >= 1)
+ {
+ if (file.EndsWith(".h", StringComparison.InvariantCultureIgnoreCase))
+ {
+ if (tokens.Length == 3)
+ {
+ // Build number portion of the source code
+ if (tokens[0].Equals("//") && tokens[1].Equals("Build") && Str.IsNumber(tokens[2]))
+ {
+ newLine = line.Replace(tokens[2], buildNumber.ToString());
+ }
+ }
+ }
+
+ if (file.EndsWith(".h", StringComparison.InvariantCultureIgnoreCase))
+ {
+ if (tokens.Length == 3)
+ {
+ // String part of the version information of Cedar.h
+ if (tokens[0].Equals("#define") && tokens[1].Equals("CEDAR_BUILD"))
+ {
+ newLine = line.Replace(tokens[2], buildNumber.ToString());
+ }
+
+ if (tokens[0].Equals("#define") && tokens[1].Equals("CEDAR_VER"))
+ {
+ newLine = line.Replace(tokens[2], version.ToString());
+ }
+
+ if (tokens[0].Equals("#define") && tokens[1].Equals("BUILDER_NAME"))
+ {
+ newLine = line.Replace(tokens[2], "\"" + userName + "\"");
+ }
+
+ if (tokens[0].Equals("#define") && tokens[1].Equals("BUILD_PLACE"))
+ {
+ newLine = line.Replace(tokens[2], "\"" + pcName + "\"");
+ }
+
+ if (tokens[0].Equals("#define") && tokens[1].Equals("BUILD_DATE_Y"))
+ {
+ newLine = line.Replace(tokens[2], date.Year.ToString());
+ }
+
+ if (tokens[0].Equals("#define") && tokens[1].Equals("BUILD_DATE_M"))
+ {
+ newLine = line.Replace(tokens[2], date.Month.ToString());
+ }
+
+ if (tokens[0].Equals("#define") && tokens[1].Equals("BUILD_DATE_D"))
+ {
+ newLine = line.Replace(tokens[2], date.Day.ToString());
+ }
+
+ if (tokens[0].Equals("#define") && tokens[1].Equals("BUILD_DATE_HO"))
+ {
+ newLine = line.Replace(tokens[2], date.Hour.ToString());
+ }
+
+ if (tokens[0].Equals("#define") && tokens[1].Equals("BUILD_DATE_MI"))
+ {
+ newLine = line.Replace(tokens[2], date.Minute.ToString());
+ }
+
+ if (tokens[0].Equals("#define") && tokens[1].Equals("BUILD_DATE_SE"))
+ {
+ newLine = line.Replace(tokens[2], date.Second.ToString());
+ }
+ }
+
+ if (tokens.Length >= 3)
+ {
+ if (tokens[0].Equals("#define") && tokens[1].Equals("SUPPORTED_WINDOWS_LIST"))
+ {
+ newLine = "#define\tSUPPORTED_WINDOWS_LIST\t\t\"" + OSList.Windows.OSSimpleList + "\"";
+ }
+ }
+ }
+ }
+
+ if (newLine == null || newLine == line)
+ {
+ w.WriteLine(line);
+ }
+ else
+ {
+ w.WriteLine(newLine);
+
+ somethingChanged = true;
+ }
+ }
+
+ if (somethingChanged)
+ {
+ byte[] retData = Str.ConvertEncoding(Str.Utf8Encoding.GetBytes(w.ToString()), enc, bomSize != 0);
+
+ File.WriteAllBytes(file, retData);
+
+ Con.WriteLine("Modified: '{0}'.", file);
+ }
+ }
+ }
+ }
+
+ // Get the DebugSnapshot directory name
+ public static string GetDebugSnapstotDirName()
+ {
+ return Path.Combine(Paths.DebugSnapshotBaseDir, Str.DateTimeToStrShort(BuildSoftwareList.ListCreatedDateTime));
+ }
+
+ // Copy DebugSnapshot
+ public static void CopyDebugSnapshot()
+ {
+ string snapDir = GetDebugSnapstotDirName();
+
+ CopyDebugSnapshot(snapDir);
+ }
+ public static void CopyDebugSnapshot(string snapDir, params string[] exclude_exts)
+ {
+ IO.CopyDir(Paths.BaseDirName, Path.Combine(snapDir, "Main"),
+ delegate(FileInfo fi)
+ {
+ string srcPath = fi.FullName;
+ string[] exts_default =
+ {
+ ".ncb", ".aps", ".suo", ".old", ".scc", ".vssscc", ".vspscc", ".cache", ".psess", ".tmp", ".dmp",
+ };
+
+ List exts = new List();
+
+ foreach (string ext in exts_default)
+ {
+ exts.Add(ext);
+ }
+
+ foreach (string ext in exclude_exts)
+ {
+ exts.Add(ext);
+ }
+
+ if (Str.InStr(srcPath, @"\.svn\", false))
+ {
+ return false;
+ }
+
+ if (Str.InStr(srcPath.Substring(3), @"\tmp\", false))
+ {
+ return false;
+ }
+
+ if (Str.InStr(srcPath, @"_log\", false))
+ {
+ return false;
+ }
+
+ if (Str.InStr(srcPath, @"\backup.vpn_", false))
+ {
+ return false;
+ }
+
+ foreach (string ext in exts)
+ {
+ if (srcPath.EndsWith(ext, StringComparison.InvariantCultureIgnoreCase))
+ {
+ return false;
+ }
+ }
+
+ if (Str.InStr(srcPath, @"\hamcore\", false))
+ {
+ return true;
+ }
+
+ if (Str.InStr(srcPath, @"\hamcore_", false))
+ {
+ return true;
+ }
+
+ return true;
+ },
+ false, true, false, false);
+ }
+
+ // Execute building in Visual Studio
+ public static void BuildMain()
+ {
+ Mutex x = new Mutex(false, "VpnBuilderWin32_BuildMain");
+
+ x.WaitOne();
+
+ try
+ {
+ // Generate the contents of the batch file
+ string batFileName = Path.Combine(Paths.TmpDirName, "vc_build.cmd");
+ StreamWriter bat = new StreamWriter(batFileName, false, Str.ShiftJisEncoding);
+ bat.WriteLine("call \"{0}\"", Paths.VisualStudioVCBatchFileName);
+ bat.WriteLine("echo on");
+ bat.WriteLine("\"{0}\" /toolsversion:3.5 /verbosity:detailed /target:Clean /property:Configuration=Release /property:Platform=Win32 \"{1}\"",
+ Paths.MSBuildFileName, Paths.VPN4SolutionFileName);
+ bat.WriteLine("IF ERRORLEVEL 1 GOTO LABEL_ERROR");
+
+ bat.WriteLine("\"{0}\" /toolsversion:3.5 /verbosity:detailed /target:Clean /property:Configuration=Release /property:Platform=x64 \"{1}\"",
+ Paths.MSBuildFileName, Paths.VPN4SolutionFileName);
+ bat.WriteLine("IF ERRORLEVEL 1 GOTO LABEL_ERROR");
+
+ bat.WriteLine("\"{0}\" /toolsversion:3.5 /verbosity:detailed /target:Rebuild /property:Configuration=Release /property:Platform=Win32 \"{1}\"",
+ Paths.MSBuildFileName, Paths.VPN4SolutionFileName);
+ bat.WriteLine("IF ERRORLEVEL 1 GOTO LABEL_ERROR");
+
+ bat.WriteLine("\"{0}\" /toolsversion:3.5 /verbosity:detailed /target:Rebuild /property:Configuration=Release /property:Platform=x64 \"{1}\"",
+ Paths.MSBuildFileName, Paths.VPN4SolutionFileName);
+ bat.WriteLine("IF ERRORLEVEL 1 GOTO LABEL_ERROR");
+
+ bat.WriteLine(":LABEL_ERROR");
+
+ bat.WriteLine("EXIT %ERRORLEVEL%");
+
+ bat.Close();
+
+ ExecCommand(Paths.CmdFileName, string.Format("/C \"{0}\"", batFileName));
+
+ BuildReplaceHeader();
+ }
+ finally
+ {
+ x.ReleaseMutex();
+ }
+ }
+
+ // Generate the Replace.h
+ public static void BuildReplaceHeader()
+ {
+ List o = new List();
+ int maxLen = 0;
+
+ // Read the map file
+ string[] lines = File.ReadAllLines(Path.Combine(Paths.BaseDirName, @"DebugFiles\map\Win32_Release\vpnserver.map"));
+ char[] sps = { ' ', '\t', };
+
+ foreach (string line in lines)
+ {
+ string[] tokens = line.Trim().Split(sps, StringSplitOptions.RemoveEmptyEntries);
+
+ if (tokens.Length == 5)
+ {
+ if (tokens[0].StartsWith("0001:", StringComparison.InvariantCultureIgnoreCase))
+ {
+ if (tokens[0].Length == 13)
+ {
+ if (tokens[2].Length == 8)
+ {
+ if (tokens[3].Equals("f", StringComparison.InvariantCultureIgnoreCase))
+ {
+ if (tokens[4].StartsWith("Mayaqua:", StringComparison.InvariantCultureIgnoreCase) ||
+ tokens[4].StartsWith("Cedar:", StringComparison.InvariantCultureIgnoreCase))
+ {
+ string name = tokens[1];
+
+ if (name.Length >= 2)
+ {
+ if (Str.InStr(name, "mktime") == false &&
+ Str.InStr(name, "gmtime") == false &&
+ Str.InStr(name, "stdin") == false &&
+ Str.InStr(name, "stdout") == false &&
+ Str.InStr(name, "@") == false &&
+ Str.InStr(name, "localtime") == false)
+ {
+ string tmp = tokens[4].Split(':')[1];
+
+ if (tmp[0] >= 'A' && tmp[0] <= 'Z' &&
+ Str.InStr(tmp, "_") == false)
+ {
+ o.Add(name.Substring(1));
+
+ maxLen = Math.Max(maxLen, name.Length);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ o.Sort();
+
+ // Generate the Replace.h
+ string filename = Path.Combine(Paths.BaseDirName, @"DebugFiles\Replace.h");
+ StreamWriter w = new StreamWriter(filename);
+
+ w.WriteLine("// PacketiX VPN Function Name Replacement Header File");
+ w.WriteLine("//");
+ w.WriteLine("// Copyright (c) SoftEther Corporation.");
+ w.WriteLine("// All Rights Reserved.");
+ w.WriteLine("//");
+ w.WriteLine("// SoftEther Confidential");
+ w.WriteLine("//");
+ w.WriteLine();
+
+ foreach (string name in o)
+ {
+ if (Str.StrCmpi(name, "VLanGetPacketAdapter") == false)
+ {
+ string tmp = Str.ByteToHex(Secure.HashMD5(Str.Utf8Encoding.GetBytes("xx" + name)), "");
+ string tmp2 = "VPN_" + tmp.Substring(0, 12).ToUpper();
+
+ w.WriteLine("#define {0,-" + maxLen.ToString() + "} {1}",
+ name, tmp2);
+ }
+ }
+
+ w.WriteLine();
+
+ w.Flush();
+ w.Close();
+ }
+
+ // Command execution
+ public static void ExecCommand(string exe, string arg)
+ {
+ ExecCommand(exe, arg, false);
+ }
+ public static void ExecCommand(string exe, string arg, bool shell_execute)
+ {
+ Process p = new Process();
+ p.StartInfo.FileName = exe;
+ p.StartInfo.Arguments = arg;
+ p.StartInfo.UseShellExecute = shell_execute;
+
+ if (shell_execute)
+ {
+ p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
+ }
+
+ Con.WriteLine("Executing '{0} {1}'...", exe, arg);
+
+ p.Start();
+
+ p.WaitForExit();
+
+ int ret = p.ExitCode;
+ if (ret != 0)
+ {
+ throw new ApplicationException(string.Format("Child process '{0}' returned error code {1}.", exe, ret));
+ }
+
+ Kernel.SleepThread(50);
+ }
+
+ // Get whether the specified fileis a target of signature
+ public static bool IsFileSignable(string fileName)
+ {
+ if (fileName.IndexOf(@".svn", StringComparison.InvariantCultureIgnoreCase) != -1 ||
+ fileName.StartsWith(".svn", StringComparison.InvariantCultureIgnoreCase))
+ {
+ return false;
+ }
+ if (fileName.EndsWith("vpn16.exe", StringComparison.InvariantCultureIgnoreCase))
+ {
+ return false;
+ }
+ if (fileName.EndsWith("BuildUtil.exe", StringComparison.InvariantCultureIgnoreCase))
+ {
+ return false;
+ }
+ if (fileName.EndsWith("BuildUtilTmp.exe", StringComparison.InvariantCultureIgnoreCase))
+ {
+ return false;
+ }
+ if (fileName.EndsWith("CoreUtil.dll", StringComparison.InvariantCultureIgnoreCase))
+ {
+ return false;
+ }
+ if (fileName.EndsWith("npptools.dll", StringComparison.InvariantCultureIgnoreCase))
+ {
+ return false;
+ }
+ if (fileName.EndsWith("winpcap_installer.exe", StringComparison.InvariantCultureIgnoreCase))
+ {
+ return false;
+ }
+ if (fileName.EndsWith("winpcap_installer_win9x.exe", StringComparison.InvariantCultureIgnoreCase))
+ {
+ return false;
+ }
+ if (fileName.EndsWith("VpnGatePlugin_x64.dll", StringComparison.InvariantCultureIgnoreCase))
+ {
+ return false;
+ }
+ if (fileName.EndsWith("VpnGatePlugin_x86.dll", StringComparison.InvariantCultureIgnoreCase))
+ {
+ return false;
+ }
+ if (Str.InStr(fileName, "_nosign", false))
+ {
+ return false;
+ }
+
+ if (fileName.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase) ||
+ fileName.EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase) ||
+ fileName.EndsWith(".ocx", StringComparison.InvariantCultureIgnoreCase) ||
+ fileName.EndsWith(".sys", StringComparison.InvariantCultureIgnoreCase))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ // Create and sign the Inf file and the catalog file for SeLow
+ public static void SignSeLowInfFiles(string cpu)
+ {
+ int build, version;
+ string name;
+ DateTime date;
+
+ ReadBuildInfoFromTextFile(out build, out version, out name, out date);
+
+ string hamcore = Path.Combine(Paths.BinDirName, "hamcore");
+ string sys_src = Path.Combine(hamcore, "SeLow_" + cpu + ".sys");
+ string inf_src = Path.Combine(hamcore, "SeLow_" + cpu + ".inf");
+
+ Con.WriteLine("Generating INF Files for SeLow...");
+
+ string dst_dir = Path.Combine(hamcore, @"inf\selow_" + cpu);
+
+ if (ExeSignChecker.CheckFileDigitalSignature(sys_src) == false ||
+ ExeSignChecker.IsKernelModeSignedFile(sys_src) == false)
+ {
+ throw new ApplicationException(sys_src + " is not signed.");
+ }
+
+ generateINFFilesForPlatform(inf_src, sys_src, null, dst_dir, version, build, date, true);
+
+ Con.WriteLine("Generating INF Files for SeLow Ok.");
+ }
+
+ // Create Inf file for Windows 8
+ public static void GenerateINFFilesForWindows8(string cpu)
+ {
+ int build, version;
+ string name;
+ DateTime date;
+ ReadBuildInfoFromTextFile(out build, out version, out name, out date);
+
+ string hamcore = Path.Combine(Paths.BinDirName, "hamcore");
+ string inf_src_x86 = Path.Combine(hamcore, "vpn_driver.inf");
+ string inf_src_x64 = Path.Combine(hamcore, "vpn_driver_x64.inf");
+ string sys_src_x86 = Path.Combine(hamcore, "vpn_driver.sys");
+ string sys_src_x64 = Path.Combine(hamcore, "vpn_driver_x64.sys");
+ string sys6_src_x86 = Path.Combine(hamcore, "vpn_driver6.sys");
+ string sys6_src_x64 = Path.Combine(hamcore, "vpn_driver6_x64.sys");
+
+ Con.WriteLine("Generating INF Files for Windows 8...");
+
+ string dst_x86 = Path.Combine(hamcore, @"inf\x86");
+ string dst_x64 = Path.Combine(hamcore, @"inf\x64");
+
+ if (Str.StrCmpi(cpu, "x64"))
+ {
+ if (ExeSignChecker.CheckFileDigitalSignature(sys_src_x64) == false || ExeSignChecker.IsKernelModeSignedFile(sys_src_x64) == false)
+ {
+ throw new ApplicationException(sys_src_x64 + " is not signed.");
+ }
+
+ generateINFFilesForPlatform(inf_src_x64, sys_src_x64, sys6_src_x64, dst_x64, version, build, date, false);
+ }
+ else
+ {
+ if (ExeSignChecker.CheckFileDigitalSignature(sys_src_x86) == false || ExeSignChecker.IsKernelModeSignedFile(sys_src_x86) == false)
+ {
+ throw new ApplicationException(sys_src_x86 + " is not signed.");
+ }
+
+ generateINFFilesForPlatform(inf_src_x86, sys_src_x86, sys6_src_x86, dst_x86, version, build, date, false);
+ }
+
+ Con.WriteLine("Generating INF Files for Windows 8 Ok.");
+ }
+ static void generateINFFilesForPlatform(string inf, string sys, string sys6, string dstDir, int ver, int build, DateTime date, bool selow)
+ {
+
+ string cdfFileName = Path.Combine(dstDir, "inf.cdf");
+ string catFileName = Path.Combine(dstDir, "inf.cat");
+ StringWriter sw = new StringWriter();
+
+ string txt = File.ReadAllText(inf, Str.ShiftJisEncoding);
+
+ IO.DeleteFilesAndSubDirsInDir(dstDir);
+ IO.MakeDirIfNotExists(dstDir);
+
+ string dst_sys_name = Path.Combine(dstDir, Path.GetFileName(sys));
+ File.Copy(sys, dst_sys_name, true);
+
+ string dst_sys6_name = null;
+ if (sys6 != null)
+ {
+ dst_sys6_name = Path.Combine(dstDir, Path.GetFileName(sys6));
+ File.Copy(sys6, dst_sys6_name, true);
+ }
+
+ sw.WriteLine("[CatalogHeader]");
+ sw.WriteLine("name=inf.cat");
+ sw.WriteLine();
+ sw.WriteLine("[CatalogFiles]");
+ sw.WriteLine("{0}={0}", Path.GetFileName(dst_sys_name));
+
+ if (sys6 != null)
+ {
+ sw.WriteLine("{0}={0}", Path.GetFileName(dst_sys6_name));
+ }
+
+ int i;
+ for (i = 1; i < 128; i++)
+ {
+ string name = "VPN";
+ if (i >= 2)
+ {
+ name += i.ToString();
+ }
+
+ if (selow)
+ {
+ name = "selow";
+ }
+
+ //string mac = "00AC0011" + i.ToString("X2") + "01";
+ string mac = "000001000001";
+ string sys_name = "Neo_" + name + ".sys";
+
+ string body = txt;
+ body = Str.ReplaceStr(body, "$TAG_SYS_NAME$", sys_name);
+ body = Str.ReplaceStr(body, "$TAG_INSTANCE_NAME$", name);
+ body = Str.ReplaceStr(body, "$TAG_MAC_ADDRESS$", mac);
+ body = Str.ReplaceStr(body, "$YEAR$", date.Year.ToString("D4"));
+ body = Str.ReplaceStr(body, "$MONTH$", date.Month.ToString("D2"));
+ body = Str.ReplaceStr(body, "$DAY$", date.Day.ToString("D2"));
+ body = Str.ReplaceStr(body, "$VER_MAJOR$", (ver / 100).ToString());
+ body = Str.ReplaceStr(body, "$VER_MINOR$", (ver % 100).ToString());
+ body = Str.ReplaceStr(body, "$VER_BUILD$", build.ToString());
+ body = Str.ReplaceStr(body, "[Manufacturer]", "CatalogFile.NT\t\t\t\t= inf_" + name + ".cat\r\n\r\n[Manufacturer]");
+
+ string dst_inf_name = Path.Combine(dstDir, "INF_" + name + ".inf");
+
+ if (selow)
+ {
+ dst_inf_name = Path.Combine(dstDir, Path.GetFileName(inf));
+ }
+
+ if (selow)
+ {
+ body += "\r\n; Auto Generated " + Str.DateTimeToStrShortWithMilliSecs(DateTime.Now) + "\r\n\r\n";
+ }
+
+ File.WriteAllText(dst_inf_name, body, Str.ShiftJisEncoding);
+
+ sw.WriteLine("{0}={0}", Path.GetFileName(dst_inf_name));
+
+ if (selow)
+ {
+ break;
+ }
+ }
+ sw.WriteLine();
+
+ File.WriteAllText(cdfFileName, sw.ToString());
+
+ // generate catalog file
+ Directory.SetCurrentDirectory(dstDir);
+ ExecCommand(Paths.MakeCatFilename, string.Format("\"{0}\"", cdfFileName));
+
+ // sign catalog file
+ CodeSign.SignFile(catFileName, catFileName, "Catalog File", false);
+
+ // delete cdf file
+ File.Delete(cdfFileName);
+
+ // delete sys file
+ File.Delete(dst_sys_name);
+
+ if (sys6 != null)
+ {
+ File.Delete(dst_sys6_name);
+ }
+ }
+
+ // Sign for all binary files (series mode)
+ public static void SignAllBinaryFilesSerial()
+ {
+ string[] files = Directory.GetFiles(Paths.BinDirName, "*", SearchOption.AllDirectories);
+
+ foreach (string file in files)
+ {
+ if (IsFileSignable(file))
+ {
+ bool isDriver = file.EndsWith(".sys", StringComparison.InvariantCultureIgnoreCase);
+
+ // Check whether this file is signed
+ bool isSigned = ExeSignChecker.CheckFileDigitalSignature(file);
+ if (isSigned && isDriver)
+ {
+ isSigned = ExeSignChecker.IsKernelModeSignedFile(file);
+ }
+
+ Con.WriteLine("The file '{0}': {1}.", file, isSigned ? "Already signed" : "Not yet signed");
+
+ if (isSigned == false)
+ {
+ Con.WriteLine("Signing...");
+
+ CodeSign.SignFile(file, file, "VPN Software", isDriver);
+ }
+ }
+ }
+ }
+
+ // Sign for all binary files (parallel mode)
+ public static void SignAllBinaryFiles()
+ {
+ string[] files = Directory.GetFiles(Paths.BinDirName, "*", SearchOption.AllDirectories);
+
+ List filename_list = new List();
+
+ foreach (string file in files)
+ {
+ if (IsFileSignable(file))
+ {
+ bool isDriver = file.EndsWith(".sys", StringComparison.InvariantCultureIgnoreCase);
+
+ // Check whether this file is signed
+ bool isSigned = ExeSignChecker.CheckFileDigitalSignature(file);
+ if (isSigned && isDriver)
+ {
+ isSigned = ExeSignChecker.IsKernelModeSignedFile(file);
+ }
+
+ Con.WriteLine("The file '{0}': {1}.", file, isSigned ? "Already signed" : "Not yet signed");
+
+ if (isSigned == false)
+ {
+ filename_list.Add(file);
+ }
+ }
+ }
+
+ Con.WriteLine("Start ProcessWorkQueue for Signing...\n");
+ ThreadObj.ProcessWorkQueue(sign_thread, 40, filename_list.ToArray());
+ Con.WriteLine("ProcessWorkQueue for Signing completed.\n");
+ }
+
+ // Binary file signature thread
+ static void sign_thread(object param)
+ {
+ string filename = (string)param;
+ bool isDriver = filename.EndsWith(".sys", StringComparison.InvariantCultureIgnoreCase);
+
+ Con.WriteLine("Signing...");
+
+ CodeSign.SignFile(filename, filename, "VPN Software", isDriver);
+ }
+ }
+}
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/BuildUtil/app.config b/src/BuildUtil/app.config
new file mode 100644
index 00000000..39279829
--- /dev/null
+++ b/src/BuildUtil/app.config
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+ http://dv/Sign/Sign.asmx
+
+
+ http://hvsigncode/Sign.asmx
+
+
+
+
\ No newline at end of file
diff --git a/src/Cedar/Account.c b/src/Cedar/Account.c
new file mode 100644
index 00000000..42acda2e
--- /dev/null
+++ b/src/Cedar/Account.c
@@ -0,0 +1,1419 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Account.c
+// Account Manager
+
+#include "CedarPch.h"
+
+// Policy items
+POLICY_ITEM policy_item[] =
+{
+// ID, Value, Omittable, Min, Max, Default, Unit name
+// Ver 2.0
+ {0, false, false, 0, 0, 0, NULL}, // Access
+ {1, false, false, 0, 0, 0, NULL}, // DHCPFilter
+ {2, false, false, 0, 0, 0, NULL}, // DHCPNoServer
+ {3, false, false, 0, 0, 0, NULL}, // DHCPForce
+ {4, false, false, 0, 0, 0, NULL}, // NoBridge
+ {5, false, false, 0, 0, 0, NULL}, // NoRouting
+ {6, false, false, 0, 0, 0, NULL}, // CheckMac
+ {7, false, false, 0, 0, 0, NULL}, // CheckIP
+ {8, false, false, 0, 0, 0, NULL}, // ArpDhcpOnly
+ {9, false, false, 0, 0, 0, NULL}, // PrivacyFilter
+ {10, false, false, 0, 0, 0, NULL}, // NoServer
+ {11, false, false, 0, 0, 0, NULL}, // NoBroadcastLimiter
+ {12, false, false, 0, 0, 0, NULL}, // MonitorPort
+ {13, true, false, 1, 32, 32, "POL_INT_COUNT"}, // MaxConnection
+ {14, true, false, 5, 60, 20, "POL_INT_SEC"}, // TimeOut
+ {15, true, true, 1, 65535, 0, "POL_INT_COUNT"}, // MaxMac
+ {16, true, true, 1, 65535, 0, "POL_INT_COUNT"}, // MaxIP
+ {17, true, true, 1, 4294967295UL, 0, "POL_INT_BPS"}, // MaxUpload
+ {18, true, true, 1, 4294967295UL, 0, "POL_INT_BPS"}, // MaxDownload
+ {19, false, false, 0, 0, 0, NULL}, // FixPassword
+ {20, true, true, 1, 65535, 0, "POL_INT_COUNT"}, // MultiLogins
+ {21, false, false, 0, 0, 0, NULL}, // NoQoS
+// Ver 3.0
+ {22, false, false, 0, 0, 0, NULL}, // RSandRAFilter
+ {23, false, false, 0, 0, 0, NULL}, // RAFilter
+ {24, false, false, 0, 0, 0, NULL}, // DHCPv6Filter
+ {25, false, false, 0, 0, 0, NULL}, // DHCPv6NoServer
+ {26, false, false, 0, 0, 0, NULL}, // NoRoutingV6
+ {27, false, false, 0, 0, 0, NULL}, // CheckIPv6
+ {28, false, false, 0, 0, 0, NULL}, // NoServerV6
+ {29, true, true, 1, 65535, 0, "POL_INT_COUNT"}, // MaxIPv6
+ {30, false, false, 0, 0, 0, NULL}, // NoSavePassword
+ {31, true, true, 1, 4294967295UL, 0, "POL_INT_SEC"}, // AutoDisconnect
+ {32, false, false, 0, 0, 0, NULL}, // FilterIPv4
+ {33, false, false, 0, 0, 0, NULL}, // FilterIPv6
+ {34, false, false, 0, 0, 0, NULL}, // FilterNonIP
+ {35, false, false, 0, 0, 0, NULL}, // NoIPv6DefaultRouterInRA
+ {36, false, false, 0, 0, 0, NULL}, // NoIPv6DefaultRouterInRAWhenIPv6
+ {37, true, true, 1, 4095, 0, "POL_INT_VLAN"}, // VLanId
+};
+
+// Normalize policy name
+char *NormalizePolicyName(char *name)
+{
+ // Validate arguments
+ if (name == NULL)
+ {
+ return NULL;
+ }
+
+ return PolicyIdToStr(PolicyStrToId(name));
+}
+
+// Format policy value
+void FormatPolicyValue(wchar_t *str, UINT size, UINT id, UINT value)
+{
+ POLICY_ITEM *p;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return;
+ }
+
+ p = GetPolicyItem(id);
+
+ if (p->TypeInt == false)
+ {
+ // bool type
+ if (value == 0)
+ {
+ UniStrCpy(str, size, L"No");
+ }
+ else
+ {
+ UniStrCpy(str, size, L"Yes");
+ }
+ }
+ else
+ {
+ // int type
+ if (value == 0 && p->AllowZero)
+ {
+ UniStrCpy(str, size, _UU("CMD_NO_SETTINGS"));
+ }
+ else
+ {
+ UniFormat(str, size, _UU(p->FormatStr), value);
+ }
+ }
+}
+
+// Get description string for range of the policy value
+void GetPolicyValueRangeStr(wchar_t *str, UINT size, UINT id)
+{
+ POLICY_ITEM *p;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return;
+ }
+
+ p = GetPolicyItem(id);
+
+ if (p->TypeInt == false)
+ {
+ // bool type
+ UniStrCpy(str, size, _UU("CMD_PolicyList_Range_Bool"));
+ }
+ else
+ {
+ wchar_t *tag;
+ wchar_t tmp1[256], tmp2[256];
+
+ // int type
+ if (p->AllowZero)
+ {
+ tag = _UU("CMD_PolicyList_Range_Int_2");
+ }
+ else
+ {
+ tag = _UU("CMD_PolicyList_Range_Int_1");
+ }
+
+ UniFormat(tmp1, sizeof(tmp1), _UU(p->FormatStr), p->MinValue);
+ UniFormat(tmp2, sizeof(tmp2), _UU(p->FormatStr), p->MaxValue);
+
+ UniFormat(str, size, tag, tmp1, tmp2);
+ }
+}
+
+// Get a policy item for id
+POLICY_ITEM *GetPolicyItem(UINT id)
+{
+ return &policy_item[id];
+}
+
+// Does cascade connection support the specified policy?
+bool PolicyIsSupportedForCascade(UINT i)
+{
+ if (i == 0 || i == 4 || i == 5 || i == 9 || i == 12 || i == 13 ||
+ i == 14 || i == 19 || i == 20 || i == 21 || i == 26 || i == 30 || i == 31 || i == 36)
+ {
+ // These items are not supported by cascade connection.
+ return false;
+ }
+
+ return true;
+}
+
+// Get policy name
+char *PolicyIdToStr(UINT i)
+{
+ switch (i)
+ {
+ // Ver 2.0
+ case 0: return "Access";
+ case 1: return "DHCPFilter";
+ case 2: return "DHCPNoServer";
+ case 3: return "DHCPForce";
+ case 4: return "NoBridge";
+ case 5: return "NoRouting";
+ case 6: return "CheckMac";
+ case 7: return "CheckIP";
+ case 8: return "ArpDhcpOnly";
+ case 9: return "PrivacyFilter";
+ case 10: return "NoServer";
+ case 11: return "NoBroadcastLimiter";
+ case 12: return "MonitorPort";
+ case 13: return "MaxConnection";
+ case 14: return "TimeOut";
+ case 15: return "MaxMac";
+ case 16: return "MaxIP";
+ case 17: return "MaxUpload";
+ case 18: return "MaxDownload";
+ case 19: return "FixPassword";
+ case 20: return "MultiLogins";
+ case 21: return "NoQoS";
+
+ // Ver 3.0
+ case 22: return "RSandRAFilter";
+ case 23: return "RAFilter";
+ case 24: return "DHCPv6Filter";
+ case 25: return "DHCPv6NoServer";
+ case 26: return "NoRoutingV6";
+ case 27: return "CheckIPv6";
+ case 28: return "NoServerV6";
+ case 29: return "MaxIPv6";
+ case 30: return "NoSavePassword";
+ case 31: return "AutoDisconnect";
+ case 32: return "FilterIPv4";
+ case 33: return "FilterIPv6";
+ case 34: return "FilterNonIP";
+ case 35: return "NoIPv6DefaultRouterInRA";
+ case 36: return "NoIPv6DefaultRouterInRAWhenIPv6";
+ case 37: return "VLanId";
+ }
+
+ return NULL;
+}
+
+// Get policy id for name
+UINT PolicyStrToId(char *name)
+{
+ UINT i;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return INFINITE;
+ }
+
+ for (i = 0;i < NUM_POLICY_ITEM;i++)
+ {
+ if (StartWith(PolicyIdToStr(i), name))
+ {
+ return i;
+ }
+ }
+
+ return INFINITE;
+}
+
+// Get number of policies
+UINT PolicyNum()
+{
+ return NUM_POLICY_ITEM;
+}
+
+// Check the name is valid for account name
+bool IsUserName(char *name)
+{
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (name == NULL)
+ {
+ return false;
+ }
+
+ StrCpy(tmp, sizeof(tmp), name);
+ name = tmp;
+
+ Trim(name);
+
+ if (StrLen(name) == 0)
+ {
+ return false;
+ }
+
+ if (StrCmpi(name, "*") == 0)
+ {
+ return true;
+ }
+
+ if (IsSafeStr(name) == false)
+ {
+ return false;
+ }
+
+ if (StrCmpi(name, LINK_USER_NAME) == 0)
+ {
+ return false;
+ }
+
+ if (StartWith(name, L3_USERNAME))
+ {
+ return false;
+ }
+
+ if (StrCmpi(name, LINK_USER_NAME_PRINT) == 0)
+ {
+ return false;
+ }
+
+ if (StrCmpi(name, SNAT_USER_NAME) == 0)
+ {
+ return false;
+ }
+
+ if (StrCmpi(name, SNAT_USER_NAME_PRINT) == 0)
+ {
+ return false;
+ }
+
+ if (StrCmpi(name, BRIDGE_USER_NAME) == 0)
+ {
+ return false;
+ }
+
+ if (StrCmpi(name, BRIDGE_USER_NAME_PRINT) == 0)
+ {
+ return false;
+ }
+
+ if (StrCmpi(name, ADMINISTRATOR_USERNAME) == 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Get policy title
+wchar_t *GetPolicyTitle(UINT id)
+{
+ char tmp[MAX_SIZE];
+ Format(tmp, sizeof(tmp), "POL_%u", id);
+
+ return _UU(tmp);
+}
+
+// Get policy description
+wchar_t *GetPolicyDescription(UINT id)
+{
+ char tmp[MAX_SIZE];
+ Format(tmp, sizeof(tmp), "POL_EX_%u", id);
+
+ return _UU(tmp);
+}
+
+// Clone the policy value
+POLICY *ClonePolicy(POLICY *policy)
+{
+ POLICY *ret;
+ // Validate arguments
+ if (policy == NULL)
+ {
+ return NULL;
+ }
+
+ ret = ZeroMalloc(sizeof(POLICY));
+ Copy(ret, policy, sizeof(POLICY));
+
+ return ret;
+}
+
+// Overwrite policy value (If old version data overwrites new version, leave new version value as it is.)
+void OverwritePolicy(POLICY **target, POLICY *p)
+{
+ // Validate arguments
+ if (target == NULL)
+ {
+ return;
+ }
+
+ if (p == NULL)
+ {
+ // Erase policy
+ if (*target != NULL)
+ {
+ Free(*target);
+ *target = NULL;
+ }
+ }
+ else
+ {
+ if (p->Ver3)
+ {
+ // Ver 3
+ if (*target != NULL)
+ {
+ Free(*target);
+ *target = NULL;
+ }
+
+ *target = ClonePolicy(p);
+ }
+ else
+ {
+ // Ver 2
+ if (*target == NULL)
+ {
+ *target = ClonePolicy(p);
+ }
+ else
+ {
+ Copy(*target, p, NUM_POLICY_ITEM_FOR_VER2 * sizeof(UINT));
+ }
+ }
+ }
+}
+
+// Set user policy
+void SetUserPolicy(USER *u, POLICY *policy)
+{
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+
+ Lock(u->lock);
+ {
+ OverwritePolicy(&u->Policy, policy);
+ }
+ Unlock(u->lock);
+}
+
+// Get user policy
+POLICY *GetUserPolicy(USER *u)
+{
+ POLICY *ret;
+ // Validate arguments
+ if (u == NULL)
+ {
+ return NULL;
+ }
+
+ Lock(u->lock);
+ {
+ if (u->Policy == NULL)
+ {
+ ret = NULL;
+ }
+ else
+ {
+ ret = ClonePolicy(u->Policy);
+ }
+ }
+ Unlock(u->lock);
+
+ return ret;
+}
+
+// Set group policy
+void SetGroupPolicy(USERGROUP *g, POLICY *policy)
+{
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ Lock(g->lock);
+ {
+ OverwritePolicy(&g->Policy, policy);
+ }
+ Unlock(g->lock);
+}
+
+// Get group policy
+POLICY *GetGroupPolicy(USERGROUP *g)
+{
+ POLICY *ret;
+ // Validate arguments
+ if (g == NULL)
+ {
+ return NULL;
+ }
+
+ Lock(g->lock);
+ {
+ if (g->Policy == NULL)
+ {
+ ret = NULL;
+ }
+ else
+ {
+ ret = ClonePolicy(g->Policy);
+ }
+ }
+ Unlock(g->lock);
+
+ return ret;
+}
+
+// Get default policy template
+POLICY *GetDefaultPolicy()
+{
+ static POLICY def_policy =
+ {
+ true,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ 32,
+ 20,
+ 0,
+ 0,
+ 0,
+ 0,
+ false,
+ 0,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ 0,
+ false,
+ 0,
+ false,
+ false,
+ false,
+ false,
+ false,
+ };
+
+ return &def_policy;
+}
+
+// Create a NT authentication data
+void *NewNTAuthData(wchar_t *username)
+{
+ AUTHNT *a;
+ // Validate arguments
+ a = ZeroMallocEx(sizeof(AUTHNT), true);
+ a->NtUsername = CopyUniStr(username);
+
+ return a;
+}
+
+// Create a Radius authentication data
+void *NewRadiusAuthData(wchar_t *username)
+{
+ AUTHRADIUS *a;
+ // Validate arguments
+ a = ZeroMallocEx(sizeof(AUTHRADIUS), true);
+ a->RadiusUsername = CopyUniStr(username);
+
+ return a;
+}
+
+// Create a root certification authentication data
+void *NewRootCertAuthData(X_SERIAL *serial, wchar_t *common_name)
+{
+ AUTHROOTCERT *a;
+
+ a = ZeroMallocEx(sizeof(AUTHROOTCERT), true);
+ if (common_name != NULL && UniIsEmptyStr(common_name) == false)
+ {
+ a->CommonName = CopyUniStr(common_name);
+ }
+ if (serial != NULL && serial->size >= 1)
+ {
+ a->Serial = CloneXSerial(serial);
+ }
+
+ return a;
+}
+
+// Create an authentication data for user certification
+void *NewUserCertAuthData(X *x)
+{
+ AUTHUSERCERT *a;
+
+ a = ZeroMalloc(sizeof(AUTHUSERCERT));
+ a->UserX = CloneX(x);
+
+ return a;
+}
+
+// Hash the password
+void HashPassword(void *dst, char *username, char *password)
+{
+ BUF *b;
+ char *username_upper;
+ // Validate arguments
+ if (dst == NULL || username == NULL || password == NULL)
+ {
+ return;
+ }
+
+ b = NewBuf();
+ username_upper = CopyStr(username);
+ StrUpper(username_upper);
+ WriteBuf(b, password, StrLen(password));
+ WriteBuf(b, username_upper, StrLen(username_upper));
+ Hash(dst, b->Buf, b->Size, true);
+
+ FreeBuf(b);
+ Free(username_upper);
+}
+
+// Create a password authentication data
+void *NewPasswordAuthData(char *username, char *password)
+{
+ AUTHPASSWORD *pw;
+ // Validate arguments
+ if (username == NULL || password == NULL)
+ {
+ return NULL;
+ }
+
+ pw = ZeroMalloc(sizeof(AUTHPASSWORD));
+ HashPassword(pw->HashedKey, username, password);
+ GenerateNtPasswordHash(pw->NtLmSecureHash, password);
+
+ return pw;
+}
+
+// Create a password authentication data for the hashed password
+void *NewPasswordAuthDataRaw(UCHAR *hashed_password, UCHAR *ntlm_secure_hash)
+{
+ AUTHPASSWORD *pw;
+ // Validate arguments
+ if (hashed_password == NULL)
+ {
+ return NULL;
+ }
+
+ pw = ZeroMalloc(sizeof(AUTHPASSWORD));
+ Copy(pw->HashedKey, hashed_password, SHA1_SIZE);
+
+ if (ntlm_secure_hash != NULL)
+ {
+ Copy(pw->NtLmSecureHash, ntlm_secure_hash, MD5_SIZE);
+ }
+
+ return pw;
+}
+
+// Clone authentication data
+void *CopyAuthData(void *authdata, UINT authtype)
+{
+ AUTHPASSWORD *pw = (AUTHPASSWORD *)authdata;
+ AUTHUSERCERT *usercert = (AUTHUSERCERT *)authdata;
+ AUTHROOTCERT *rootcert = (AUTHROOTCERT *)authdata;
+ AUTHRADIUS *radius = (AUTHRADIUS *)authdata;
+ AUTHNT *nt = (AUTHNT *)authdata;
+ // Validate arguments
+ if (authdata == NULL || authtype == AUTHTYPE_ANONYMOUS)
+ {
+ return NULL;
+ }
+
+ switch (authtype)
+ {
+ case AUTHTYPE_PASSWORD:
+ {
+ AUTHPASSWORD *ret = ZeroMalloc(sizeof(AUTHPASSWORD));
+ Copy(ret, pw, sizeof(AUTHPASSWORD));
+ return ret;
+ }
+ break;
+
+ case AUTHTYPE_USERCERT:
+ {
+ AUTHUSERCERT *ret = ZeroMalloc(sizeof(AUTHUSERCERT));
+ ret->UserX = CloneX(usercert->UserX);
+ return ret;
+ }
+ break;
+
+ case AUTHTYPE_ROOTCERT:
+ {
+ AUTHROOTCERT *ret = ZeroMalloc(sizeof(AUTHROOTCERT));
+ ret->CommonName = CopyUniStr(rootcert->CommonName);
+ ret->Serial = CloneXSerial(rootcert->Serial);
+ return ret;
+ }
+ break;
+
+ case AUTHTYPE_RADIUS:
+ {
+ AUTHRADIUS *ret = ZeroMalloc(sizeof(AUTHRADIUS));
+ ret->RadiusUsername = UniCopyStr(radius->RadiusUsername);
+ return ret;
+ }
+ break;
+
+ case AUTHTYPE_NT:
+ {
+ AUTHNT *ret = ZeroMalloc(sizeof(AUTHNT));
+ ret->NtUsername = UniCopyStr(nt->NtUsername);
+ return ret;
+ }
+ break;
+ }
+
+ return NULL;
+}
+
+// Set authentication data to the user
+void SetUserAuthData(USER *u, UINT authtype, void *authdata)
+{
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+ if (authtype != AUTHTYPE_ANONYMOUS && authdata == NULL)
+ {
+ return;
+ }
+
+ Lock(u->lock);
+ {
+ if (u->AuthType != AUTHTYPE_ANONYMOUS)
+ {
+ if (u->AuthType == AUTHTYPE_PASSWORD && authtype == AUTHTYPE_PASSWORD)
+ {
+ AUTHPASSWORD *pw_old = (AUTHPASSWORD *)u->AuthData;
+ AUTHPASSWORD *pw_new = (AUTHPASSWORD *)authdata;
+
+ // Copy NTLM hash for new password from old data, if the password is not changed
+ // and management tool don't send NTLM hash.
+
+ if (Cmp(pw_old->HashedKey, pw_new->HashedKey, SHA1_SIZE) == 0)
+ {
+ if (IsZero(pw_new->NtLmSecureHash, MD5_SIZE))
+ {
+ Copy(pw_new->NtLmSecureHash, pw_old->NtLmSecureHash, MD5_SIZE);
+ }
+ }
+ }
+
+ // Free current authentication data
+ FreeAuthData(u->AuthType, u->AuthData);
+ }
+ // Set new authentication data
+ u->AuthType = authtype;
+ u->AuthData = authdata;
+ }
+ Unlock(u->lock);
+}
+
+// Cumulate group traffic data
+void AddGroupTraffic(USERGROUP *g, TRAFFIC *diff)
+{
+ // Validate arguments
+ if (g == NULL || diff == NULL)
+ {
+ return;
+ }
+
+ Lock(g->lock);
+ {
+ AddTraffic(g->Traffic, diff);
+ }
+ Unlock(g->lock);
+}
+
+// Cumulate user traffic data
+void AddUserTraffic(USER *u, TRAFFIC *diff)
+{
+ // Validate arguments
+ if (u == NULL || diff == NULL)
+ {
+ return;
+ }
+
+ Lock(u->lock);
+ {
+ AddTraffic(u->Traffic, diff);
+ }
+ Unlock(u->lock);
+}
+
+// Set traffic data for group
+void SetGroupTraffic(USERGROUP *g, TRAFFIC *t)
+{
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ Lock(g->lock);
+ {
+ if (t != NULL)
+ {
+ Copy(g->Traffic, t, sizeof(TRAFFIC));
+ }
+ else
+ {
+ Zero(g->Traffic, sizeof(TRAFFIC));
+ }
+ }
+ Unlock(g->lock);
+}
+
+// Set traffic data for user
+void SetUserTraffic(USER *u, TRAFFIC *t)
+{
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+
+ Lock(u->lock);
+ {
+ if (t != NULL)
+ {
+ Copy(u->Traffic, t, sizeof(TRAFFIC));
+ }
+ else
+ {
+ Zero(u->Traffic, sizeof(TRAFFIC));
+ }
+ }
+ Unlock(u->lock);
+}
+
+// Join the user to the group
+void JoinUserToGroup(USER *u, USERGROUP *g)
+{
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+
+ if (g != NULL)
+ {
+ // Join
+ Lock(u->lock);
+ {
+ Lock(g->lock);
+ {
+ if (u->Group != NULL)
+ {
+ // Remove the user from current group first
+ //
+ ReleaseGroup(u->Group);
+ u->Group = NULL;
+ Free(u->GroupName);
+ u->GroupName = NULL;
+ }
+ // Join the user to the group
+ u->GroupName = CopyStr(g->Name);
+ u->Group = g;
+ AddRef(g->ref);
+ }
+ Unlock(g->lock);
+ }
+ Unlock(u->lock);
+ }
+ else
+ {
+ // Withdrawal
+ Lock(u->lock);
+ {
+ if (u->Group != NULL)
+ {
+ // Remove the user from current group
+ ReleaseGroup(u->Group);
+ u->Group = NULL;
+ Free(u->GroupName);
+ u->GroupName = NULL;
+ }
+ }
+ Unlock(u->lock);
+ }
+}
+
+// Validate group name
+bool AcIsGroup(HUB *h, char *name)
+{
+ USERGROUP *g;
+ // Validate arguments
+ if (h == NULL || name == NULL || NO_ACCOUNT_DB(h))
+ {
+ return false;
+ }
+
+ g = AcGetGroup(h, name);
+ if (g == NULL)
+ {
+ return false;
+ }
+ ReleaseGroup(g);
+
+ return true;
+}
+
+// Validate user name
+bool AcIsUser(HUB *h, char *name)
+{
+ USER *u;
+ // Validate arguments
+ if (h == NULL || name == NULL || NO_ACCOUNT_DB(h))
+ {
+ return false;
+ }
+
+ u = AcGetUser(h, name);
+ if (u == NULL)
+ {
+ return false;
+ }
+ ReleaseUser(u);
+
+ return true;
+}
+
+// Get group object
+USERGROUP *AcGetGroup(HUB *h, char *name)
+{
+ USERGROUP *g, t;
+ // Validate arguments
+ if (h == NULL || name == NULL || NO_ACCOUNT_DB(h))
+ {
+ return NULL;
+ }
+
+ t.Name = name;
+ g = Search(h->HubDb->GroupList, &t);
+ if (g == NULL)
+ {
+ return NULL;
+ }
+ AddRef(g->ref);
+
+ return g;
+}
+
+// Get user object
+USER *AcGetUser(HUB *h, char *name)
+{
+ USER *u, t;
+ // Validate arguments
+ if (h == NULL || name == NULL || NO_ACCOUNT_DB(h))
+ {
+ return NULL;
+ }
+
+ t.Name = name;
+ u = Search(h->HubDb->UserList, &t);
+ if (u == NULL)
+ {
+ return NULL;
+ }
+ AddRef(u->ref);
+
+ return u;
+}
+
+// Delete the user
+bool AcDeleteUser(HUB *h, char *name)
+{
+ USER *u;
+ // Validate arguments
+ if (h == NULL || name == NULL)
+ {
+ return false;
+ }
+
+ u = AcGetUser(h, name);
+ if (u == NULL)
+ {
+ return false;
+ }
+
+ if (Delete(h->HubDb->UserList, u))
+ {
+ ReleaseUser(u);
+ }
+
+ ReleaseUser(u);
+
+ return true;
+}
+
+// Delete the group
+bool AcDeleteGroup(HUB *h, char *name)
+{
+ USERGROUP *g;
+ UINT i;
+ // Validate arguments
+ if (h == NULL || name == NULL)
+ {
+ return false;
+ }
+
+ g = AcGetGroup(h, name);
+ if (g == NULL)
+ {
+ return false;
+ }
+
+ if (Delete(h->HubDb->GroupList, g))
+ {
+ ReleaseGroup(g);
+ }
+
+ for (i = 0;i < LIST_NUM(h->HubDb->UserList);i++)
+ {
+ USER *u = LIST_DATA(h->HubDb->UserList, i);
+ Lock(u->lock);
+ {
+ if (u->Group == g)
+ {
+ JoinUserToGroup(u, NULL);
+ }
+ }
+ Unlock(u->lock);
+ }
+
+ ReleaseGroup(g);
+
+ return true;
+}
+
+// Add new group to the hub
+bool AcAddGroup(HUB *h, USERGROUP *g)
+{
+ // Validate arguments
+ if (h == NULL || g == NULL || NO_ACCOUNT_DB(h))
+ {
+ return false;
+ }
+
+ if (LIST_NUM(h->HubDb->GroupList) >= MAX_GROUPS)
+ {
+ return false;
+ }
+
+ if (AcIsGroup(h, g->Name) != false)
+ {
+ return false;
+ }
+
+ Insert(h->HubDb->GroupList, g);
+ AddRef(g->ref);
+
+ return true;
+}
+
+// Add new user in the hub
+bool AcAddUser(HUB *h, USER *u)
+{
+ // Validate arguments
+ if (h == NULL || u == NULL || NO_ACCOUNT_DB(h))
+ {
+ return false;
+ }
+
+ if (LIST_NUM(h->HubDb->UserList) >= MAX_USERS)
+ {
+ return false;
+ }
+
+ if (AcIsUser(h, u->Name) != false)
+ {
+ return false;
+ }
+
+ Insert(h->HubDb->UserList, u);
+ AddRef(u->ref);
+
+ return true;
+}
+
+// Release user object (decrease reference counter)
+void ReleaseUser(USER *u)
+{
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+
+ if (Release(u->ref) == 0)
+ {
+ CleanupUser(u);
+ }
+}
+
+// Cleanup the user object
+void CleanupUser(USER *u)
+{
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+
+ DeleteLock(u->lock);
+ Free(u->Name);
+ Free(u->RealName);
+ Free(u->Note);
+ Free(u->GroupName);
+ if (u->Group != NULL)
+ {
+ ReleaseGroup(u->Group);
+ }
+
+ // Free authntication data
+ FreeAuthData(u->AuthType, u->AuthData);
+
+ if (u->Policy)
+ {
+ // Free policy data
+ Free(u->Policy);
+ }
+
+ FreeTraffic(u->Traffic);
+
+ Free(u);
+}
+
+// Free authntication data
+void FreeAuthData(UINT authtype, void *authdata)
+{
+ AUTHPASSWORD *pw = (AUTHPASSWORD *)authdata;
+ AUTHUSERCERT *uc = (AUTHUSERCERT *)authdata;
+ AUTHROOTCERT *rc = (AUTHROOTCERT *)authdata;
+ AUTHRADIUS *rd = (AUTHRADIUS *)authdata;
+ AUTHNT *nt = (AUTHNT *)authdata;
+ // Validate arguments
+ if (authtype == AUTHTYPE_ANONYMOUS || authdata == NULL)
+ {
+ return;
+ }
+
+ switch (authtype)
+ {
+ case AUTHTYPE_PASSWORD:
+ // Password authentication
+ // Nothing to free
+ break;
+
+ case AUTHTYPE_USERCERT:
+ // User certification
+ FreeX(uc->UserX);
+ break;
+
+ case AUTHTYPE_ROOTCERT:
+ // Root certification
+ if (rc->Serial != NULL)
+ {
+ FreeXSerial(rc->Serial);
+ }
+ if (rc->CommonName != NULL)
+ {
+ Free(rc->CommonName);
+ }
+ break;
+
+ case AUTHTYPE_RADIUS:
+ // Radius authentication
+ Free(rd->RadiusUsername);
+ break;
+
+ case AUTHTYPE_NT:
+ // Windows NT authentication
+ Free(nt->NtUsername);
+ break;
+ }
+
+ Free(authdata);
+}
+
+// Create new user object
+USER *NewUser(char *name, wchar_t *realname, wchar_t *note, UINT authtype, void *authdata)
+{
+ USER *u;
+ // Validate arguments
+ if (name == NULL || realname == NULL || note == NULL)
+ {
+ return NULL;
+ }
+ if (authtype != AUTHTYPE_ANONYMOUS && authdata == NULL)
+ {
+ return NULL;
+ }
+
+ u = ZeroMalloc(sizeof(USER));
+ u->lock = NewLock();
+ u->ref = NewRef();
+ u->Name = CopyStr(name);
+ u->RealName = CopyUniStr(realname);
+ u->Note = CopyUniStr(note);
+ u->GroupName = NULL;
+ u->Group = NULL;
+ u->AuthType = authtype;
+ u->AuthData = authdata;
+ u->CreatedTime = SystemTime64();
+ u->UpdatedTime = SystemTime64();
+
+ u->Policy = NULL;
+ u->Traffic = NewTraffic();
+
+ return u;
+}
+
+// Release group object (decrease reference counter)
+void ReleaseGroup(USERGROUP *g)
+{
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ if (Release(g->ref) == 0)
+ {
+ CleanupGroup(g);
+ }
+}
+
+// Cleanup the group object
+void CleanupGroup(USERGROUP *g)
+{
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ Free(g->Name);
+ Free(g->RealName);
+ Free(g->Note);
+
+ if (g->Policy)
+ {
+ // Free policy data
+ Free(g->Policy);
+ }
+
+
+ FreeTraffic(g->Traffic);
+
+ DeleteLock(g->lock);
+ Free(g);
+}
+
+// Create new group object
+USERGROUP *NewGroup(char *name, wchar_t *realname, wchar_t *note)
+{
+ USERGROUP *g;
+ // Validate arguments
+ if (name == NULL || realname == NULL || note == NULL)
+ {
+ return NULL;
+ }
+
+ g = ZeroMalloc(sizeof(USERGROUP));
+ g->lock = NewLock();
+ g->ref = NewRef();
+ g->Name = CopyStr(name);
+ g->RealName = CopyUniStr(realname);
+ g->Note = CopyUniStr(note);
+ g->Policy = NULL;
+ g->Traffic = NewTraffic();
+
+ return g;
+}
+
+// Lock the account database for the hub
+void AcLock(HUB *h)
+{
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+ if (NO_ACCOUNT_DB(h))
+ {
+ return;
+ }
+
+ // Lock group list and user list
+ LockList(h->HubDb->GroupList);
+ LockList(h->HubDb->UserList);
+}
+
+// Unlock the account database for the hub
+void AcUnlock(HUB *h)
+{
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+ if (NO_ACCOUNT_DB(h))
+ {
+ return;
+ }
+
+ // Unlock group list and user list
+ UnlockList(h->HubDb->UserList);
+ UnlockList(h->HubDb->GroupList);
+}
+
+// Compare group names (for sort)
+int CompareGroupName(void *p1, void *p2)
+{
+ USERGROUP *g1, *g2;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ g1 = *(USERGROUP **)p1;
+ g2 = *(USERGROUP **)p2;
+ if (g1 == NULL || g2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(g1->Name, g2->Name);
+}
+
+// Compare user names (for sort)
+int CompareUserName(void *p1, void *p2)
+{
+ USER *u1, *u2;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ u1 = *(USER **)p1;
+ u2 = *(USER **)p2;
+ if (u1 == NULL || u2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(u1->Name, u2->Name);
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Account.h b/src/Cedar/Account.h
new file mode 100644
index 00000000..95d1d9fe
--- /dev/null
+++ b/src/Cedar/Account.h
@@ -0,0 +1,293 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Account.h
+// Header of Account.c
+
+#ifndef ACCOUNT_H
+#define ACCOUNT_H
+
+// Policy item
+struct POLICY_ITEM
+{
+ UINT Index;
+ bool TypeInt;
+ bool AllowZero;
+ UINT MinValue;
+ UINT MaxValue;
+ UINT DefaultValue;
+ char *FormatStr;
+};
+
+// Policy
+struct POLICY
+{
+ // For Ver 2.0
+ bool Access; // Grant access
+ bool DHCPFilter; // Filter DHCP packets (IPv4)
+ bool DHCPNoServer; // Prohibit the behavior of the DHCP server (IPv4)
+ bool DHCPForce; // Force DHCP-assigned IP address (IPv4)
+ bool NoBridge; // Prohibit the bridge behavior
+ bool NoRouting; // Prohibit the router behavior (IPv4)
+ bool CheckMac; // Prohibit the duplicate MAC address
+ bool CheckIP; // Prohibit a duplicate IP address (IPv4)
+ bool ArpDhcpOnly; // Prohibit the broadcast other than ARP, DHCP, ICMPv6
+ bool PrivacyFilter; // Privacy filter mode
+ bool NoServer; // Prohibit to operate as a TCP/IP server (IPv4)
+ bool NoBroadcastLimiter; // Not to limit the number of broadcast
+ bool MonitorPort; // Allow monitoring mode
+ UINT MaxConnection; // Maximum number of TCP connections
+ UINT TimeOut; // Communication time-out period
+ UINT MaxMac; // Maximum number of MAC address
+ UINT MaxIP; // Maximum number of IP address (IPv4)
+ UINT MaxUpload; // Upload bandwidth
+ UINT MaxDownload; // Download bandwidth
+ bool FixPassword; // User can not change password
+ UINT MultiLogins; // Multiple logins limit
+ bool NoQoS; // Prohibit the use of VoIP / QoS features
+
+ // For Ver 3.0
+ bool RSandRAFilter; // Filter the Router Solicitation / Advertising packet (IPv6)
+ bool RAFilter; // Filter the router advertisement packet (IPv6)
+ bool DHCPv6Filter; // Filter DHCP packets (IPv6)
+ bool DHCPv6NoServer; // Prohibit the behavior of the DHCP server (IPv6)
+ bool NoRoutingV6; // Prohibit the router behavior (IPv6)
+ bool CheckIPv6; // Prohibit the duplicate IP address (IPv6)
+ bool NoServerV6; // Prohibit to operate as a TCP/IP server (IPv6)
+ UINT MaxIPv6; // Maximum number of IP address (IPv6)
+ bool NoSavePassword; // Prohibit to save the password in the VPN Client
+ UINT AutoDisconnect; // Disconnect the VPN Client automatically at a certain period of time
+ bool FilterIPv4; // Filter all IPv4 packets
+ bool FilterIPv6; // Filter all IPv6 packets
+ bool FilterNonIP; // Filter all non-IP packets
+ bool NoIPv6DefaultRouterInRA; // Delete the default router specification from the IPv6 router advertisement
+ bool NoIPv6DefaultRouterInRAWhenIPv6; // Delete the default router specification from the IPv6 router advertisement (Enable IPv6 connection)
+ UINT VLanId; // Specify the VLAN ID
+
+ bool Ver3; // Whether version 3.0
+};
+
+// Group
+struct USERGROUP
+{
+ LOCK *lock; // Lock
+ REF *ref; // Reference counter
+ char *Name; // Group name
+ wchar_t *RealName; // Display name
+ wchar_t *Note; // Note
+ POLICY *Policy; // Policy
+ TRAFFIC *Traffic; // Traffic data
+};
+
+// User
+struct USER
+{
+ LOCK *lock; // Lock
+ REF *ref; // Reference counter
+ char *Name; // User name
+ wchar_t *RealName; // Real name
+ wchar_t *Note; // Note
+ char *GroupName; // Group name
+ USERGROUP *Group; // Group
+ UINT AuthType; // Authentication type
+ void *AuthData; // Authentication data
+ UINT64 CreatedTime; // Creation date and time
+ UINT64 UpdatedTime; // Updating date
+ UINT64 ExpireTime; // Expiration date
+ UINT64 LastLoginTime; // Last login time
+ UINT NumLogin; // Total number of logins
+ POLICY *Policy; // Policy
+ TRAFFIC *Traffic; // Traffic data
+};
+
+// Password authentication data
+struct AUTHPASSWORD
+{
+ UCHAR HashedKey[SHA1_SIZE]; // Hashed passwords
+ UCHAR NtLmSecureHash[MD5_SIZE]; // Encrypted password for the NTLM
+};
+
+// User certificate authentication data
+struct AUTHUSERCERT
+{
+ X *UserX; // X509 certificate for the user
+};
+
+// Root certification authority authentication data
+struct AUTHROOTCERT
+{
+ X_SERIAL *Serial; // Serial number
+ wchar_t *CommonName; // CommonName
+};
+
+// Radius authentication data
+struct AUTHRADIUS
+{
+ wchar_t *RadiusUsername; // User name in the Radius
+};
+
+// Windows NT authentication data
+struct AUTHNT
+{
+ wchar_t *NtUsername; // User name on NT
+};
+
+
+
+// Macro
+#define POLICY_CURRENT_VERSION 3
+#define NUM_POLICY_ITEM ((sizeof(POLICY) / sizeof(UINT)) - 1)
+#define NUM_POLICY_ITEM_FOR_VER2 22
+#define NUM_POLICY_ITEM_FOR_VER3 38
+
+#define IS_POLICY_FOR_VER2(index) (((index) >= 0) && ((index) < NUM_POLICY_ITEM_FOR_VER2))
+#define IS_POLICY_FOR_VER3(index) (((index) >= 0) && ((index) < NUM_POLICY_ITEM_FOR_VER3))
+
+#define IS_POLICY_FOR_CURRENT_VER(index, ver) ((ver) >= 3 ? IS_POLICY_FOR_VER3(index) : IS_POLICY_FOR_VER2(index))
+
+#define POLICY_BOOL(p, i) (((bool *)(p))[(i)])
+#define POLICY_INT(p, i) (((UINT *)(p))[(i)])
+
+extern POLICY_ITEM policy_item[];
+
+
+
+
+// Function prototype
+int CompareUserName(void *p1, void *p2);
+int CompareGroupName(void *p1, void *p2);
+void AcLock(HUB *h);
+void AcUnlock(HUB *h);
+USERGROUP *NewGroup(char *name, wchar_t *realname, wchar_t *note);
+void ReleaseGroup(USERGROUP *g);
+void CleanupGroup(USERGROUP *g);
+USER *NewUser(char *name, wchar_t *realname, wchar_t *note, UINT authtype, void *authdata);
+void ReleaseUser(USER *u);
+void CleanupUser(USER *u);
+void FreeAuthData(UINT authtype, void *authdata);
+bool AcAddUser(HUB *h, USER *u);
+bool AcAddGroup(HUB *h, USERGROUP *g);
+USER *AcGetUser(HUB *h, char *name);
+USERGROUP *AcGetGroup(HUB *h, char *name);
+bool AcIsUser(HUB *h, char *name);
+bool AcIsGroup(HUB *h, char *name);
+bool AcDeleteUser(HUB *h, char *name);
+bool AcDeleteGroup(HUB *h, char *name);
+void JoinUserToGroup(USER *u, USERGROUP *g);
+void SetUserTraffic(USER *u, TRAFFIC *t);
+void SetGroupTraffic(USERGROUP *g, TRAFFIC *t);
+void AddUserTraffic(USER *u, TRAFFIC *diff);
+void AddGroupTraffic(USERGROUP *g, TRAFFIC *diff);
+void SetUserAuthData(USER *u, UINT authtype, void *authdata);
+void *NewPasswordAuthData(char *username, char *password);
+void *NewPasswordAuthDataRaw(UCHAR *hashed_password, UCHAR *ntlm_secure_hash);
+void *NewUserCertAuthData(X *x);
+void *NewRootCertAuthData(X_SERIAL *serial, wchar_t *common_name);
+void *NewRadiusAuthData(wchar_t *username);
+void *NewNTAuthData(wchar_t *username);
+void HashPassword(void *dst, char *username, char *password);
+POLICY *GetDefaultPolicy();
+POLICY *ClonePolicy(POLICY *policy);
+void SetUserPolicy(USER *u, POLICY *policy);
+void OverwritePolicy(POLICY **target, POLICY *p);
+POLICY *GetUserPolicy(USER *u);
+void SetGroupPolicy(USERGROUP *g, POLICY *policy);
+POLICY *GetGroupPolicy(USERGROUP *g);
+wchar_t *GetPolicyTitle(UINT id);
+wchar_t *GetPolicyDescription(UINT id);
+bool IsUserName(char *name);
+void *CopyAuthData(void *authdata, UINT authtype);
+UINT PolicyNum();
+bool PolicyIsSupportedForCascade(UINT i);
+UINT PolicyStrToId(char *name);
+char *PolicyIdToStr(UINT i);
+POLICY_ITEM *GetPolicyItem(UINT id);
+void GetPolicyValueRangeStr(wchar_t *str, UINT size, UINT id);
+void FormatPolicyValue(wchar_t *str, UINT size, UINT id, UINT value);
+char *NormalizePolicyName(char *name);
+
+
+#endif // ACCOUNT_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Admin.c b/src/Cedar/Admin.c
new file mode 100644
index 00000000..9bec72a4
--- /dev/null
+++ b/src/Cedar/Admin.c
@@ -0,0 +1,13742 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Admin.c
+// RPC Module for Management
+
+#include "CedarPch.h"
+
+// Macro for RPC function declaration
+#define DECLARE_RPC_EX(rpc_name, data_type, function, in_rpc, out_rpc, free_rpc) \
+ else if (StrCmpi(name, rpc_name) == 0) \
+ { \
+ data_type *t; \
+ t = ZeroMalloc(sizeof(data_type)); \
+ in_rpc(t, p); \
+ err = function(a, t); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ out_rpc(ret, t); \
+ } \
+ free_rpc(t); \
+ Free(t); \
+ ok = true; \
+ }
+#define DECLARE_RPC(rpc_name, data_type, function, in_rpc, out_rpc) \
+ else if (StrCmpi(name, rpc_name) == 0) \
+ { \
+ data_type *t; \
+ t = ZeroMalloc(sizeof(data_type)); \
+ in_rpc(t, p); \
+ err = function(a, t); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ out_rpc(ret, t); \
+ } \
+ Free(t); \
+ ok = true; \
+ }
+#define DECLARE_SC_EX(rpc_name, data_type, function, in_rpc, out_rpc, free_rpc) \
+ UINT function(RPC *r, data_type *t) \
+ { \
+ PACK *p, *ret; \
+ UINT err; \
+ if (r == NULL || t == NULL) \
+ { \
+ return ERR_INTERNAL_ERROR; \
+ } \
+ p = NewPack(); \
+ out_rpc(p, t); \
+ free_rpc(t); \
+ Zero(t, sizeof(data_type)); \
+ ret = AdminCall(r, rpc_name, p); \
+ err = GetErrorFromPack(ret); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ in_rpc(t, ret); \
+ } \
+ FreePack(ret); \
+ return err; \
+ }
+#define DECLARE_SC(rpc_name, data_type, function, in_rpc, out_rpc) \
+ UINT function(RPC *r, data_type *t) \
+ { \
+ PACK *p, *ret; \
+ UINT err; \
+ if (r == NULL || t == NULL) \
+ { \
+ return ERR_INTERNAL_ERROR; \
+ } \
+ p = NewPack(); \
+ out_rpc(p, t); \
+ ret = AdminCall(r, rpc_name, p); \
+ err = GetErrorFromPack(ret); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ in_rpc(t, ret); \
+ } \
+ FreePack(ret); \
+ return err; \
+ }
+#define CHECK_RIGHT \
+ if (a->ServerAdmin == false && (t->HubName == NULL || StrCmpi(a->HubName, t->HubName) != 0)) \
+ return ERR_NOT_ENOUGH_RIGHT; \
+ if (IsEmptyStr(t->HubName)) \
+ return ERR_INVALID_PARAMETER;
+#define SERVER_ADMIN_ONLY \
+ if (a->ServerAdmin == false) \
+ return ERR_NOT_ENOUGH_RIGHT;
+#define NO_SUPPORT_FOR_BRIDGE \
+ if (a->Server->Cedar->Bridge) \
+ return ERR_NOT_SUPPORTED;
+
+// Get server Caps (Guessing from the build number if failed to get Caps)
+CAPSLIST *ScGetCapsEx(RPC *rpc)
+{
+ RPC_SERVER_INFO info;
+ CAPSLIST *t;
+ bool is_bridge = false;
+ // Validate arguments
+ if (rpc == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&info, sizeof(info));
+ ScGetServerInfo(rpc, &info);
+
+ t = ZeroMalloc(sizeof(CAPSLIST));
+
+ // Try to get Caps by RPC
+ if (ScGetCaps(rpc, t) != ERR_NO_ERROR)
+ {
+ UINT build;
+
+ Free(t);
+ t = NewCapsList();
+
+ // Since acquisition of Caps went wrong, get build number
+ build = info.ServerBuildInt;
+
+ is_bridge = (SearchStrEx(info.ServerProductName, "bridge", 0, false) == INFINITE) ? false : true;
+
+ AddCapsInt(t, "i_max_packet_size", 1514);
+
+ if (is_bridge == false)
+ {
+ AddCapsInt(t, "i_max_hubs", 4096);
+ AddCapsInt(t, "i_max_sessions", 4096);
+
+ if (info.ServerType != SERVER_TYPE_FARM_MEMBER)
+ {
+ AddCapsInt(t, "i_max_users_per_hub", 10000);
+ AddCapsInt(t, "i_max_groups_per_hub", 10000);
+ AddCapsInt(t, "i_max_access_lists", 4096);
+ }
+ else
+ {
+ AddCapsInt(t, "i_max_users_per_hub", 0);
+ AddCapsInt(t, "i_max_groups_per_hub", 0);
+ AddCapsInt(t, "i_max_access_lists", 0);
+ }
+ }
+ else
+ {
+ AddCapsInt(t, "i_max_hubs", 0);
+ AddCapsInt(t, "i_max_sessions", 0);
+ AddCapsInt(t, "i_max_users_per_hub", 0);
+ AddCapsInt(t, "i_max_groups_per_hub", 0);
+ AddCapsInt(t, "i_max_access_lists", 0);
+ }
+
+ AddCapsInt(t, "i_max_mac_tables", 10000);
+ AddCapsInt(t, "i_max_ip_tables", 10000);
+
+ if (info.ServerType == SERVER_TYPE_STANDALONE)
+ {
+ AddCapsBool(t, "b_support_securenat", (build >= 3600) ? true : false);
+ AddCapsInt(t, "i_max_secnat_tables", 4096);
+ }
+ else
+ {
+ AddCapsBool(t, "b_support_securenat", false);
+ AddCapsInt(t, "i_max_secnat_tables", 0);
+ }
+
+ if (is_bridge)
+ {
+ AddCapsBool(t, "b_bridge", true);
+ }
+ else if (info.ServerType == SERVER_TYPE_STANDALONE)
+ {
+ AddCapsBool(t, "b_standalone", true);
+ }
+ else if (info.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ AddCapsBool(t, "b_cluster_controller", true);
+ }
+ else
+ {
+ AddCapsBool(t, "b_cluster_member", true);
+ }
+
+ AddCapsBool(t, "b_support_config_hub", info.ServerType != SERVER_TYPE_FARM_MEMBER &&
+ is_bridge == false);
+
+ AddCapsBool(t, "b_vpn_client_connect", is_bridge == false ? true : false);
+
+ AddCapsBool(t, "b_support_radius", info.ServerType != SERVER_TYPE_FARM_MEMBER &&
+ is_bridge == false);
+
+ if (build >= 3600)
+ {
+ RPC_BRIDGE_SUPPORT b;
+ Zero(&b, sizeof(b));
+ if (ScGetBridgeSupport(rpc, &b) == ERR_NO_ERROR)
+ {
+ AddCapsBool(t, "b_local_bridge", b.IsBridgeSupportedOs);
+ AddCapsBool(t, "b_must_install_pcap", b.IsWinPcapNeeded);
+ }
+ else
+ {
+ AddCapsBool(t, "b_local_bridge", false);
+ AddCapsBool(t, "b_must_install_pcap", false);
+ }
+ }
+ else
+ {
+ AddCapsBool(t, "b_local_bridge", false);
+ AddCapsBool(t, "b_must_install_pcap", false);
+ }
+
+ AddCapsBool(t, "b_tap_supported", false);
+
+ if (info.ServerType == SERVER_TYPE_STANDALONE)
+ {
+ AddCapsBool(t, "b_support_cascade", true);
+ }
+ else
+ {
+ AddCapsBool(t, "b_support_cascade", false);
+ }
+
+ AddCapsBool(t, "b_support_cascade_cert", false);
+ AddCapsBool(t, "b_support_config_log", info.ServerType != SERVER_TYPE_FARM_MEMBER);
+ AddCapsBool(t, "b_support_autodelete", false);
+ }
+ else
+ {
+ // Success getting Caps
+ if (info.ServerBuildInt <= 4350)
+ {
+ if (is_bridge == false)
+ {
+ // b_support_cluster should be true for build 4300 or earlier
+ CAPS *caps = GetCaps(t, "b_support_cluster");
+ if (caps == NULL)
+ {
+ AddCapsBool(t, "b_support_cluster", true);
+ }
+ else
+ {
+ caps->Value = 1;
+ }
+ }
+ }
+ }
+
+ if (true)
+ {
+ TOKEN_LIST *names;
+
+ // Fill items that doesn't exist in server-side as false
+ names = GetTableNameStartWith("CT_b_");
+ if (names != NULL)
+ {
+ UINT i;
+ for (i = 0;i < names->NumTokens;i++)
+ {
+ char *name = names->Token[i] + 3;
+
+ if (GetCaps(t, name) == NULL)
+ {
+ AddCapsBool(t, name, false);
+ }
+ }
+
+ FreeToken(names);
+ }
+ }
+
+ FreeRpcServerInfo(&info);
+
+ return t;
+}
+
+// Dispatch routine for Administration RPC
+PACK *AdminDispatch(RPC *rpc, char *name, PACK *p)
+{
+ ADMIN *a;
+ PACK *ret;
+ UINT err;
+ SERVER *server = NULL;
+ CEDAR *cedar = NULL;
+ bool ok = false;
+ // Validate arguments
+ if (rpc == NULL || name == NULL || p == NULL)
+ {
+ return NULL;
+ }
+
+ ret = NewPack();
+ err = ERR_NO_ERROR;
+
+ // Administration structure
+ a = (ADMIN *)rpc->Param;
+ if (a == NULL)
+ {
+ FreePack(ret);
+ return NULL;
+ }
+
+ server = a->Server;
+
+ if (server != NULL)
+ {
+ cedar = server->Cedar;
+ }
+
+ Lock(cedar->CedarSuperLock);
+
+ if (true)
+ {
+ char tmp[MAX_PATH];
+ char ip[MAX_PATH];
+ UINT rpc_id = 0;
+
+ StrCpy(ip, sizeof(ip), "Unknown");
+
+ if (rpc->Sock != NULL)
+ {
+ IPToStr(ip, sizeof(ip), &rpc->Sock->RemoteIP);
+ rpc_id = rpc->Sock->socket;
+ }
+
+ Format(tmp, sizeof(tmp), "RPC: RPC-%u (%s): Entering RPC [%s]...",
+ rpc_id, ip, name);
+
+ SiDebugLog(a->Server, tmp);
+ }
+
+ if (0) {}
+
+ // RPC function declaration: from here
+ DECLARE_RPC_EX("Test", RPC_TEST, StTest, InRpcTest, OutRpcTest, FreeRpcTest)
+ DECLARE_RPC_EX("GetServerInfo", RPC_SERVER_INFO, StGetServerInfo, InRpcServerInfo, OutRpcServerInfo, FreeRpcServerInfo)
+ DECLARE_RPC("GetServerStatus", RPC_SERVER_STATUS, StGetServerStatus, InRpcServerStatus, OutRpcServerStatus)
+ DECLARE_RPC("CreateListener", RPC_LISTENER, StCreateListener, InRpcListener, OutRpcListener)
+ DECLARE_RPC_EX("EnumListener", RPC_LISTENER_LIST, StEnumListener, InRpcListenerList, OutRpcListenerList, FreeRpcListenerList)
+ DECLARE_RPC("DeleteListener", RPC_LISTENER, StDeleteListener, InRpcListener, OutRpcListener)
+ DECLARE_RPC("EnableListener", RPC_LISTENER, StEnableListener, InRpcListener, OutRpcListener)
+ DECLARE_RPC("SetServerPassword", RPC_SET_PASSWORD, StSetServerPassword, InRpcSetPassword, OutRpcSetPassword)
+ DECLARE_RPC_EX("SetFarmSetting", RPC_FARM, StSetFarmSetting, InRpcFarm, OutRpcFarm, FreeRpcFarm)
+ DECLARE_RPC_EX("GetFarmSetting", RPC_FARM, StGetFarmSetting, InRpcFarm, OutRpcFarm, FreeRpcFarm)
+ DECLARE_RPC_EX("GetFarmInfo", RPC_FARM_INFO, StGetFarmInfo, InRpcFarmInfo, OutRpcFarmInfo, FreeRpcFarmInfo)
+ DECLARE_RPC_EX("EnumFarmMember", RPC_ENUM_FARM, StEnumFarmMember, InRpcEnumFarm, OutRpcEnumFarm, FreeRpcEnumFarm)
+ DECLARE_RPC("GetFarmConnectionStatus", RPC_FARM_CONNECTION_STATUS, StGetFarmConnectionStatus, InRpcFarmConnectionStatus, OutRpcFarmConnectionStatus)
+ DECLARE_RPC_EX("SetServerCert", RPC_KEY_PAIR, StSetServerCert, InRpcKeyPair, OutRpcKeyPair, FreeRpcKeyPair)
+ DECLARE_RPC_EX("GetServerCert", RPC_KEY_PAIR, StGetServerCert, InRpcKeyPair, OutRpcKeyPair, FreeRpcKeyPair)
+ DECLARE_RPC_EX("GetServerCipher", RPC_STR, StGetServerCipher, InRpcStr, OutRpcStr, FreeRpcStr)
+ DECLARE_RPC_EX("SetServerCipher", RPC_STR, StSetServerCipher, InRpcStr, OutRpcStr, FreeRpcStr)
+ DECLARE_RPC("CreateHub", RPC_CREATE_HUB, StCreateHub, InRpcCreateHub, OutRpcCreateHub)
+ DECLARE_RPC("SetHub", RPC_CREATE_HUB, StSetHub, InRpcCreateHub, OutRpcCreateHub)
+ DECLARE_RPC("GetHub", RPC_CREATE_HUB, StGetHub, InRpcCreateHub, OutRpcCreateHub)
+ DECLARE_RPC_EX("EnumHub", RPC_ENUM_HUB, StEnumHub, InRpcEnumHub, OutRpcEnumHub, FreeRpcEnumHub)
+ DECLARE_RPC("DeleteHub", RPC_DELETE_HUB, StDeleteHub, InRpcDeleteHub, OutRpcDeleteHub)
+ DECLARE_RPC("GetHubRadius", RPC_RADIUS, StGetHubRadius, InRpcRadius, OutRpcRadius)
+ DECLARE_RPC("SetHubRadius", RPC_RADIUS, StSetHubRadius, InRpcRadius, OutRpcRadius)
+ DECLARE_RPC_EX("EnumConnection", RPC_ENUM_CONNECTION, StEnumConnection, InRpcEnumConnection, OutRpcEnumConnection, FreeRpcEnumConnetion)
+ DECLARE_RPC("DisconnectConnection", RPC_DISCONNECT_CONNECTION, StDisconnectConnection, InRpcDisconnectConnection, OutRpcDisconnectConnection)
+ DECLARE_RPC("GetConnectionInfo", RPC_CONNECTION_INFO, StGetConnectionInfo, InRpcConnectionInfo, OutRpcConnectionInfo)
+ DECLARE_RPC("SetHubOnline", RPC_SET_HUB_ONLINE, StSetHubOnline, InRpcSetHubOnline, OutRpcSetHubOnline)
+ DECLARE_RPC("GetHubStatus", RPC_HUB_STATUS, StGetHubStatus, InRpcHubStatus, OutRpcHubStatus)
+ DECLARE_RPC("SetHubLog", RPC_HUB_LOG, StSetHubLog, InRpcHubLog, OutRpcHubLog)
+ DECLARE_RPC("GetHubLog", RPC_HUB_LOG, StGetHubLog, InRpcHubLog, OutRpcHubLog)
+ DECLARE_RPC_EX("AddCa", RPC_HUB_ADD_CA, StAddCa, InRpcHubAddCa, OutRpcHubAddCa, FreeRpcHubAddCa)
+ DECLARE_RPC_EX("EnumCa", RPC_HUB_ENUM_CA, StEnumCa, InRpcHubEnumCa, OutRpcHubEnumCa, FreeRpcHubEnumCa)
+ DECLARE_RPC_EX("GetCa", RPC_HUB_GET_CA, StGetCa, InRpcHubGetCa, OutRpcHubGetCa, FreeRpcHubGetCa)
+ DECLARE_RPC("DeleteCa", RPC_HUB_DELETE_CA, StDeleteCa, InRpcHubDeleteCa, OutRpcHubDeleteCa)
+ DECLARE_RPC("SetLinkOnline", RPC_LINK, StSetLinkOnline, InRpcLink, OutRpcLink)
+ DECLARE_RPC("SetLinkOffline", RPC_LINK, StSetLinkOffline, InRpcLink, OutRpcLink)
+ DECLARE_RPC("DeleteLink", RPC_LINK, StDeleteLink, InRpcLink, OutRpcLink)
+ DECLARE_RPC("RenameLink", RPC_RENAME_LINK, StRenameLink, InRpcRenameLink, OutRpcRenameLink)
+ DECLARE_RPC_EX("CreateLink", RPC_CREATE_LINK, StCreateLink, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+ DECLARE_RPC_EX("GetLink", RPC_CREATE_LINK, StGetLink, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+ DECLARE_RPC_EX("SetLink", RPC_CREATE_LINK, StSetLink, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+ DECLARE_RPC_EX("EnumLink", RPC_ENUM_LINK, StEnumLink, InRpcEnumLink, OutRpcEnumLink, FreeRpcEnumLink)
+ DECLARE_RPC_EX("GetLinkStatus", RPC_LINK_STATUS, StGetLinkStatus, InRpcLinkStatus, OutRpcLinkStatus, FreeRpcLinkStatus)
+ DECLARE_RPC("AddAccess", RPC_ADD_ACCESS, StAddAccess, InRpcAddAccess, OutRpcAddAccess)
+ DECLARE_RPC("DeleteAccess", RPC_DELETE_ACCESS, StDeleteAccess, InRpcDeleteAccess, OutRpcDeleteAccess)
+ DECLARE_RPC_EX("EnumAccess", RPC_ENUM_ACCESS_LIST, StEnumAccess, InRpcEnumAccessList, OutRpcEnumAccessList, FreeRpcEnumAccessList)
+ DECLARE_RPC_EX("SetAccessList", RPC_ENUM_ACCESS_LIST, StSetAccessList, InRpcEnumAccessList, OutRpcEnumAccessList, FreeRpcEnumAccessList)
+ DECLARE_RPC_EX("CreateUser", RPC_SET_USER, StCreateUser, InRpcSetUser, OutRpcSetUser, FreeRpcSetUser)
+ DECLARE_RPC_EX("SetUser", RPC_SET_USER, StSetUser, InRpcSetUser, OutRpcSetUser, FreeRpcSetUser)
+ DECLARE_RPC_EX("GetUser", RPC_SET_USER, StGetUser, InRpcSetUser, OutRpcSetUser, FreeRpcSetUser)
+ DECLARE_RPC("DeleteUser", RPC_DELETE_USER, StDeleteUser, InRpcDeleteUser, OutRpcDeleteUser)
+ DECLARE_RPC_EX("EnumUser", RPC_ENUM_USER, StEnumUser, InRpcEnumUser, OutRpcEnumUser, FreeRpcEnumUser)
+ DECLARE_RPC_EX("CreateGroup", RPC_SET_GROUP, StCreateGroup, InRpcSetGroup, OutRpcSetGroup, FreeRpcSetGroup)
+ DECLARE_RPC_EX("SetGroup", RPC_SET_GROUP, StSetGroup, InRpcSetGroup, OutRpcSetGroup, FreeRpcSetGroup)
+ DECLARE_RPC_EX("GetGroup", RPC_SET_GROUP, StGetGroup, InRpcSetGroup, OutRpcSetGroup, FreeRpcSetGroup)
+ DECLARE_RPC("DeleteGroup", RPC_DELETE_USER, StDeleteGroup, InRpcDeleteUser, OutRpcDeleteUser)
+ DECLARE_RPC_EX("EnumGroup", RPC_ENUM_GROUP, StEnumGroup, InRpcEnumGroup, OutRpcEnumGroup, FreeRpcEnumGroup)
+ DECLARE_RPC_EX("EnumSession", RPC_ENUM_SESSION, StEnumSession, InRpcEnumSession, OutRpcEnumSession, FreeRpcEnumSession)
+ DECLARE_RPC_EX("GetSessionStatus", RPC_SESSION_STATUS, StGetSessionStatus, InRpcSessionStatus, OutRpcSessionStatus, FreeRpcSessionStatus)
+ DECLARE_RPC("DeleteSession", RPC_DELETE_SESSION, StDeleteSession, InRpcDeleteSession, OutRpcDeleteSession)
+ DECLARE_RPC_EX("EnumMacTable", RPC_ENUM_MAC_TABLE, StEnumMacTable, InRpcEnumMacTable, OutRpcEnumMacTable, FreeRpcEnumMacTable)
+ DECLARE_RPC("DeleteMacTable", RPC_DELETE_TABLE, StDeleteMacTable, InRpcDeleteTable, OutRpcDeleteTable)
+ DECLARE_RPC_EX("EnumIpTable", RPC_ENUM_IP_TABLE, StEnumIpTable, InRpcEnumIpTable, OutRpcEnumIpTable, FreeRpcEnumIpTable)
+ DECLARE_RPC("DeleteIpTable", RPC_DELETE_TABLE, StDeleteIpTable, InRpcDeleteTable, OutRpcDeleteTable)
+ DECLARE_RPC("SetKeep", RPC_KEEP, StSetKeep, InRpcKeep, OutRpcKeep)
+ DECLARE_RPC("GetKeep", RPC_KEEP, StGetKeep, InRpcKeep, OutRpcKeep)
+ DECLARE_RPC("EnableSecureNAT", RPC_HUB, StEnableSecureNAT, InRpcHub, OutRpcHub)
+ DECLARE_RPC("DisableSecureNAT", RPC_HUB, StDisableSecureNAT, InRpcHub, OutRpcHub)
+ DECLARE_RPC("SetSecureNATOption", VH_OPTION, StSetSecureNATOption, InVhOption, OutVhOption)
+ DECLARE_RPC("GetSecureNATOption", VH_OPTION, StGetSecureNATOption, InVhOption, OutVhOption)
+ DECLARE_RPC_EX("EnumNAT", RPC_ENUM_NAT, StEnumNAT, InRpcEnumNat, OutRpcEnumNat, FreeRpcEnumNat)
+ DECLARE_RPC_EX("EnumDHCP", RPC_ENUM_DHCP, StEnumDHCP, InRpcEnumDhcp, OutRpcEnumDhcp, FreeRpcEnumDhcp)
+ DECLARE_RPC("GetSecureNATStatus", RPC_NAT_STATUS, StGetSecureNATStatus, InRpcNatStatus, OutRpcNatStatus)
+ DECLARE_RPC_EX("EnumEthernet", RPC_ENUM_ETH, StEnumEthernet, InRpcEnumEth, OutRpcEnumEth, FreeRpcEnumEth)
+ DECLARE_RPC("AddLocalBridge", RPC_LOCALBRIDGE, StAddLocalBridge, InRpcLocalBridge, OutRpcLocalBridge)
+ DECLARE_RPC("DeleteLocalBridge", RPC_LOCALBRIDGE, StDeleteLocalBridge, InRpcLocalBridge, OutRpcLocalBridge)
+ DECLARE_RPC_EX("EnumLocalBridge", RPC_ENUM_LOCALBRIDGE, StEnumLocalBridge, InRpcEnumLocalBridge, OutRpcEnumLocalBridge, FreeRpcEnumLocalBridge)
+ DECLARE_RPC("GetBridgeSupport", RPC_BRIDGE_SUPPORT, StGetBridgeSupport, InRpcBridgeSupport, OutRpcBridgeSupport)
+ DECLARE_RPC("RebootServer", RPC_TEST, StRebootServer, InRpcTest, OutRpcTest)
+ DECLARE_RPC_EX("GetCaps", CAPSLIST, StGetCaps, InRpcCapsList, OutRpcCapsList, FreeRpcCapsList)
+ DECLARE_RPC_EX("GetConfig", RPC_CONFIG, StGetConfig, InRpcConfig, OutRpcConfig, FreeRpcConfig)
+ DECLARE_RPC_EX("SetConfig", RPC_CONFIG, StSetConfig, InRpcConfig, OutRpcConfig, FreeRpcConfig)
+ DECLARE_RPC_EX("GetDefaultHubAdminOptions", RPC_ADMIN_OPTION, StGetDefaultHubAdminOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+ DECLARE_RPC_EX("GetHubAdminOptions", RPC_ADMIN_OPTION, StGetHubAdminOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+ DECLARE_RPC_EX("SetHubAdminOptions", RPC_ADMIN_OPTION, StSetHubAdminOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+ DECLARE_RPC_EX("GetHubExtOptions", RPC_ADMIN_OPTION, StGetHubExtOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+ DECLARE_RPC_EX("SetHubExtOptions", RPC_ADMIN_OPTION, StSetHubExtOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+ DECLARE_RPC("AddL3Switch", RPC_L3SW, StAddL3Switch, InRpcL3Sw, OutRpcL3Sw)
+ DECLARE_RPC("DelL3Switch", RPC_L3SW, StDelL3Switch, InRpcL3Sw, OutRpcL3Sw)
+ DECLARE_RPC_EX("EnumL3Switch", RPC_ENUM_L3SW, StEnumL3Switch, InRpcEnumL3Sw, OutRpcEnumL3Sw, FreeRpcEnumL3Sw)
+ DECLARE_RPC("StartL3Switch", RPC_L3SW, StStartL3Switch, InRpcL3Sw, OutRpcL3Sw)
+ DECLARE_RPC("StopL3Switch", RPC_L3SW, StStopL3Switch, InRpcL3Sw, OutRpcL3Sw)
+ DECLARE_RPC("AddL3If", RPC_L3IF, StAddL3If, InRpcL3If, OutRpcL3If)
+ DECLARE_RPC("DelL3If", RPC_L3IF, StDelL3If, InRpcL3If, OutRpcL3If)
+ DECLARE_RPC_EX("EnumL3If", RPC_ENUM_L3IF, StEnumL3If, InRpcEnumL3If, OutRpcEnumL3If, FreeRpcEnumL3If)
+ DECLARE_RPC("AddL3Table", RPC_L3TABLE, StAddL3Table, InRpcL3Table, OutRpcL3Table)
+ DECLARE_RPC("DelL3Table", RPC_L3TABLE, StDelL3Table, InRpcL3Table, OutRpcL3Table)
+ DECLARE_RPC_EX("EnumL3Table", RPC_ENUM_L3TABLE, StEnumL3Table, InRpcEnumL3Table, OutRpcEnumL3Table, FreeRpcEnumL3Table)
+ DECLARE_RPC_EX("EnumCrl", RPC_ENUM_CRL, StEnumCrl, InRpcEnumCrl, OutRpcEnumCrl, FreeRpcEnumCrl)
+ DECLARE_RPC_EX("AddCrl", RPC_CRL, StAddCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+ DECLARE_RPC_EX("DelCrl", RPC_CRL, StDelCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+ DECLARE_RPC_EX("GetCrl", RPC_CRL, StGetCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+ DECLARE_RPC_EX("SetCrl", RPC_CRL, StSetCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+ DECLARE_RPC_EX("SetAcList", RPC_AC_LIST, StSetAcList, InRpcAcList, OutRpcAcList, FreeRpcAcList)
+ DECLARE_RPC_EX("GetAcList", RPC_AC_LIST, StGetAcList, InRpcAcList, OutRpcAcList, FreeRpcAcList)
+ DECLARE_RPC_EX("EnumLogFile", RPC_ENUM_LOG_FILE, StEnumLogFile, InRpcEnumLogFile, OutRpcEnumLogFile, FreeRpcEnumLogFile)
+ DECLARE_RPC_EX("ReadLogFile", RPC_READ_LOG_FILE, StReadLogFile, InRpcReadLogFile, OutRpcReadLogFile, FreeRpcReadLogFile)
+ DECLARE_RPC("AddLicenseKey", RPC_TEST, StAddLicenseKey, InRpcTest, OutRpcTest)
+ DECLARE_RPC("DelLicenseKey", RPC_TEST, StDelLicenseKey, InRpcTest, OutRpcTest)
+ DECLARE_RPC_EX("EnumLicenseKey", RPC_ENUM_LICENSE_KEY, StEnumLicenseKey, InRpcEnumLicenseKey, OutRpcEnumLicenseKey, FreeRpcEnumLicenseKey)
+ DECLARE_RPC("GetLicenseStatus", RPC_LICENSE_STATUS, StGetLicenseStatus, InRpcLicenseStatus, OutRpcLicenseStatus)
+ DECLARE_RPC("SetSysLog", SYSLOG_SETTING, StSetSysLog, InRpcSysLogSetting, OutRpcSysLogSetting)
+ DECLARE_RPC("GetSysLog", SYSLOG_SETTING, StGetSysLog, InRpcSysLogSetting, OutRpcSysLogSetting)
+ DECLARE_RPC_EX("EnumEthVLan", RPC_ENUM_ETH_VLAN, StEnumEthVLan, InRpcEnumEthVLan, OutRpcEnumEthVLan, FreeRpcEnumEthVLan)
+ DECLARE_RPC("SetEnableEthVLan", RPC_TEST, StSetEnableEthVLan, InRpcTest, OutRpcTest)
+ DECLARE_RPC_EX("SetHubMsg", RPC_MSG, StSetHubMsg, InRpcMsg, OutRpcMsg, FreeRpcMsg)
+ DECLARE_RPC_EX("GetHubMsg", RPC_MSG, StGetHubMsg, InRpcMsg, OutRpcMsg, FreeRpcMsg)
+ DECLARE_RPC("Crash", RPC_TEST, StCrash, InRpcTest, OutRpcTest)
+ DECLARE_RPC_EX("GetAdminMsg", RPC_MSG, StGetAdminMsg, InRpcMsg, OutRpcMsg, FreeRpcMsg)
+ DECLARE_RPC("Flush", RPC_TEST, StFlush, InRpcTest, OutRpcTest)
+ DECLARE_RPC("Debug", RPC_TEST, StDebug, InRpcTest, OutRpcTest)
+ DECLARE_RPC("SetIPsecServices", IPSEC_SERVICES, StSetIPsecServices, InIPsecServices, OutIPsecServices)
+ DECLARE_RPC("GetIPsecServices", IPSEC_SERVICES, StGetIPsecServices, InIPsecServices, OutIPsecServices)
+ DECLARE_RPC("AddEtherIpId", ETHERIP_ID, StAddEtherIpId, InEtherIpId, OutEtherIpId)
+ DECLARE_RPC("GetEtherIpId", ETHERIP_ID, StGetEtherIpId, InEtherIpId, OutEtherIpId)
+ DECLARE_RPC("DeleteEtherIpId", ETHERIP_ID, StDeleteEtherIpId, InEtherIpId, OutEtherIpId)
+ DECLARE_RPC_EX("EnumEtherIpId", RPC_ENUM_ETHERIP_ID, StEnumEtherIpId, InRpcEnumEtherIpId, OutRpcEnumEtherIpId, FreeRpcEnumEtherIpId)
+ DECLARE_RPC("SetOpenVpnSstpConfig", OPENVPN_SSTP_CONFIG, StSetOpenVpnSstpConfig, InOpenVpnSstpConfig, OutOpenVpnSstpConfig)
+ DECLARE_RPC("GetOpenVpnSstpConfig", OPENVPN_SSTP_CONFIG, StGetOpenVpnSstpConfig, InOpenVpnSstpConfig, OutOpenVpnSstpConfig)
+ DECLARE_RPC("GetDDnsClientStatus", DDNS_CLIENT_STATUS, StGetDDnsClientStatus, InDDnsClientStatus, OutDDnsClientStatus)
+ DECLARE_RPC("ChangeDDnsClientHostname", RPC_TEST, StChangeDDnsClientHostname, InRpcTest, OutRpcTest)
+ DECLARE_RPC("RegenerateServerCert", RPC_TEST, StRegenerateServerCert, InRpcTest, OutRpcTest)
+ DECLARE_RPC_EX("MakeOpenVpnConfigFile", RPC_READ_LOG_FILE, StMakeOpenVpnConfigFile, InRpcReadLogFile, OutRpcReadLogFile, FreeRpcReadLogFile)
+ DECLARE_RPC("SetSpecialListener", RPC_SPECIAL_LISTENER, StSetSpecialListener, InRpcSpecialListener, OutRpcSpecialListener)
+ DECLARE_RPC("GetSpecialListener", RPC_SPECIAL_LISTENER, StGetSpecialListener, InRpcSpecialListener, OutRpcSpecialListener)
+ DECLARE_RPC("GetAzureStatus", RPC_AZURE_STATUS, StGetAzureStatus, InRpcAzureStatus, OutRpcAzureStatus)
+ DECLARE_RPC("SetAzureStatus", RPC_AZURE_STATUS, StSetAzureStatus, InRpcAzureStatus, OutRpcAzureStatus)
+ DECLARE_RPC("GetDDnsInternetSettng", INTERNET_SETTING, StGetDDnsInternetSetting, InRpcInternetSetting, OutRpcInternetSetting)
+ DECLARE_RPC("SetDDnsInternetSettng", INTERNET_SETTING, StSetDDnsInternetSetting, InRpcInternetSetting, OutRpcInternetSetting)
+ // RPC function declaration: till here
+
+
+ if (ok == false)
+ {
+ err = ERR_NOT_SUPPORTED;
+ }
+
+ if (err != ERR_NO_ERROR)
+ {
+ PackAddInt(ret, "error", err);
+ }
+
+ if (true)
+ {
+ char tmp[MAX_PATH];
+ char ip[MAX_PATH];
+ UINT rpc_id = 0;
+
+ StrCpy(ip, sizeof(ip), "Unknown");
+
+ if (rpc->Sock != NULL)
+ {
+ IPToStr(ip, sizeof(ip), &rpc->Sock->RemoteIP);
+ rpc_id = rpc->Sock->socket;
+ }
+
+ Format(tmp, sizeof(tmp), "RPC: RPC-%u (%s): Leaving RPC [%s] (Error: %u).",
+ rpc_id, ip, name, err);
+
+ SiDebugLog(a->Server, tmp);
+ }
+
+ Unlock(cedar->CedarSuperLock);
+
+ return ret;
+}
+
+// RPC call function declaration: from here
+DECLARE_SC_EX("Test", RPC_TEST, ScTest, InRpcTest, OutRpcTest, FreeRpcTest)
+DECLARE_SC_EX("GetServerInfo", RPC_SERVER_INFO, ScGetServerInfo, InRpcServerInfo, OutRpcServerInfo, FreeRpcServerInfo)
+DECLARE_SC("GetServerStatus", RPC_SERVER_STATUS, ScGetServerStatus, InRpcServerStatus, OutRpcServerStatus)
+DECLARE_SC("CreateListener", RPC_LISTENER, ScCreateListener, InRpcListener, OutRpcListener)
+DECLARE_SC_EX("EnumListener", RPC_LISTENER_LIST, ScEnumListener, InRpcListenerList, OutRpcListenerList, FreeRpcListenerList)
+DECLARE_SC("DeleteListener", RPC_LISTENER, ScDeleteListener, InRpcListener, OutRpcListener)
+DECLARE_SC("EnableListener", RPC_LISTENER, ScEnableListener, InRpcListener, OutRpcListener)
+DECLARE_SC("SetServerPassword", RPC_SET_PASSWORD, ScSetServerPassword, InRpcSetPassword, OutRpcSetPassword)
+DECLARE_SC_EX("SetFarmSetting", RPC_FARM, ScSetFarmSetting, InRpcFarm, OutRpcFarm, FreeRpcFarm)
+DECLARE_SC_EX("GetFarmSetting", RPC_FARM, ScGetFarmSetting, InRpcFarm, OutRpcFarm, FreeRpcFarm)
+DECLARE_SC_EX("GetFarmInfo", RPC_FARM_INFO, ScGetFarmInfo, InRpcFarmInfo, OutRpcFarmInfo, FreeRpcFarmInfo)
+DECLARE_SC_EX("EnumFarmMember", RPC_ENUM_FARM, ScEnumFarmMember, InRpcEnumFarm, OutRpcEnumFarm, FreeRpcEnumFarm)
+DECLARE_SC("GetFarmConnectionStatus", RPC_FARM_CONNECTION_STATUS, ScGetFarmConnectionStatus, InRpcFarmConnectionStatus, OutRpcFarmConnectionStatus)
+DECLARE_SC_EX("SetServerCert", RPC_KEY_PAIR, ScSetServerCert, InRpcKeyPair, OutRpcKeyPair, FreeRpcKeyPair)
+DECLARE_SC_EX("GetServerCert", RPC_KEY_PAIR, ScGetServerCert, InRpcKeyPair, OutRpcKeyPair, FreeRpcKeyPair)
+DECLARE_SC_EX("GetServerCipher", RPC_STR, ScGetServerCipher, InRpcStr, OutRpcStr, FreeRpcStr)
+DECLARE_SC_EX("SetServerCipher", RPC_STR, ScSetServerCipher, InRpcStr, OutRpcStr, FreeRpcStr)
+DECLARE_SC("CreateHub", RPC_CREATE_HUB, ScCreateHub, InRpcCreateHub, OutRpcCreateHub)
+DECLARE_SC("SetHub", RPC_CREATE_HUB, ScSetHub, InRpcCreateHub, OutRpcCreateHub)
+DECLARE_SC("GetHub", RPC_CREATE_HUB, ScGetHub, InRpcCreateHub, OutRpcCreateHub)
+DECLARE_SC_EX("EnumHub", RPC_ENUM_HUB, ScEnumHub, InRpcEnumHub, OutRpcEnumHub, FreeRpcEnumHub)
+DECLARE_SC("DeleteHub", RPC_DELETE_HUB, ScDeleteHub, InRpcDeleteHub, OutRpcDeleteHub)
+DECLARE_SC("GetHubRadius", RPC_RADIUS, ScGetHubRadius, InRpcRadius, OutRpcRadius)
+DECLARE_SC("SetHubRadius", RPC_RADIUS, ScSetHubRadius, InRpcRadius, OutRpcRadius)
+DECLARE_SC_EX("EnumConnection", RPC_ENUM_CONNECTION, ScEnumConnection, InRpcEnumConnection, OutRpcEnumConnection, FreeRpcEnumConnetion)
+DECLARE_SC("DisconnectConnection", RPC_DISCONNECT_CONNECTION, ScDisconnectConnection, InRpcDisconnectConnection, OutRpcDisconnectConnection)
+DECLARE_SC("GetConnectionInfo", RPC_CONNECTION_INFO, ScGetConnectionInfo, InRpcConnectionInfo, OutRpcConnectionInfo)
+DECLARE_SC("SetHubOnline", RPC_SET_HUB_ONLINE, ScSetHubOnline, InRpcSetHubOnline, OutRpcSetHubOnline)
+DECLARE_SC("GetHubStatus", RPC_HUB_STATUS, ScGetHubStatus, InRpcHubStatus, OutRpcHubStatus)
+DECLARE_SC("SetHubLog", RPC_HUB_LOG, ScSetHubLog, InRpcHubLog, OutRpcHubLog)
+DECLARE_SC("GetHubLog", RPC_HUB_LOG, ScGetHubLog, InRpcHubLog, OutRpcHubLog)
+DECLARE_SC_EX("AddCa", RPC_HUB_ADD_CA, ScAddCa, InRpcHubAddCa, OutRpcHubAddCa, FreeRpcHubAddCa)
+DECLARE_SC_EX("EnumCa", RPC_HUB_ENUM_CA, ScEnumCa, InRpcHubEnumCa, OutRpcHubEnumCa, FreeRpcHubEnumCa)
+DECLARE_SC_EX("GetCa", RPC_HUB_GET_CA, ScGetCa, InRpcHubGetCa, OutRpcHubGetCa, FreeRpcHubGetCa)
+DECLARE_SC("DeleteCa", RPC_HUB_DELETE_CA, ScDeleteCa, InRpcHubDeleteCa, OutRpcHubDeleteCa)
+DECLARE_SC_EX("CreateLink", RPC_CREATE_LINK, ScCreateLink, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+DECLARE_SC_EX("GetLink", RPC_CREATE_LINK, ScGetLink, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+DECLARE_SC_EX("SetLink", RPC_CREATE_LINK, ScSetLink, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+DECLARE_SC_EX("EnumLink", RPC_ENUM_LINK, ScEnumLink, InRpcEnumLink, OutRpcEnumLink, FreeRpcEnumLink)
+DECLARE_SC_EX("GetLinkStatus", RPC_LINK_STATUS, ScGetLinkStatus, InRpcLinkStatus, OutRpcLinkStatus, FreeRpcLinkStatus)
+DECLARE_SC("SetLinkOnline", RPC_LINK, ScSetLinkOnline, InRpcLink, OutRpcLink)
+DECLARE_SC("SetLinkOffline", RPC_LINK, ScSetLinkOffline, InRpcLink, OutRpcLink)
+DECLARE_SC("DeleteLink", RPC_LINK, ScDeleteLink, InRpcLink, OutRpcLink)
+DECLARE_SC("RenameLink", RPC_RENAME_LINK, ScRenameLink, InRpcRenameLink, OutRpcRenameLink)
+DECLARE_SC("AddAccess", RPC_ADD_ACCESS, ScAddAccess, InRpcAddAccess, OutRpcAddAccess)
+DECLARE_SC("DeleteAccess", RPC_DELETE_ACCESS, ScDeleteAccess, InRpcDeleteAccess, OutRpcDeleteAccess)
+DECLARE_SC_EX("EnumAccess", RPC_ENUM_ACCESS_LIST, ScEnumAccess, InRpcEnumAccessList, OutRpcEnumAccessList, FreeRpcEnumAccessList)
+DECLARE_SC_EX("SetAccessList", RPC_ENUM_ACCESS_LIST, ScSetAccessList, InRpcEnumAccessList, OutRpcEnumAccessList, FreeRpcEnumAccessList)
+DECLARE_SC_EX("CreateUser", RPC_SET_USER, ScCreateUser, InRpcSetUser, OutRpcSetUser, FreeRpcSetUser)
+DECLARE_SC_EX("SetUser", RPC_SET_USER, ScSetUser, InRpcSetUser, OutRpcSetUser, FreeRpcSetUser)
+DECLARE_SC_EX("GetUser", RPC_SET_USER, ScGetUser, InRpcSetUser, OutRpcSetUser, FreeRpcSetUser)
+DECLARE_SC("DeleteUser", RPC_DELETE_USER, ScDeleteUser, InRpcDeleteUser, OutRpcDeleteUser)
+DECLARE_SC_EX("EnumUser", RPC_ENUM_USER, ScEnumUser, InRpcEnumUser, OutRpcEnumUser, FreeRpcEnumUser)
+DECLARE_SC_EX("CreateGroup", RPC_SET_GROUP, ScCreateGroup, InRpcSetGroup, OutRpcSetGroup, FreeRpcSetGroup)
+DECLARE_SC_EX("SetGroup", RPC_SET_GROUP, ScSetGroup, InRpcSetGroup, OutRpcSetGroup, FreeRpcSetGroup)
+DECLARE_SC_EX("GetGroup", RPC_SET_GROUP, ScGetGroup, InRpcSetGroup, OutRpcSetGroup, FreeRpcSetGroup)
+DECLARE_SC("DeleteGroup", RPC_DELETE_USER, ScDeleteGroup, InRpcDeleteUser, OutRpcDeleteUser)
+DECLARE_SC_EX("EnumGroup", RPC_ENUM_GROUP, ScEnumGroup, InRpcEnumGroup, OutRpcEnumGroup, FreeRpcEnumGroup)
+DECLARE_SC_EX("EnumSession", RPC_ENUM_SESSION, ScEnumSession, InRpcEnumSession, OutRpcEnumSession, FreeRpcEnumSession)
+DECLARE_SC_EX("GetSessionStatus", RPC_SESSION_STATUS, ScGetSessionStatus, InRpcSessionStatus, OutRpcSessionStatus, FreeRpcSessionStatus)
+DECLARE_SC("DeleteSession", RPC_DELETE_SESSION, ScDeleteSession, InRpcDeleteSession, OutRpcDeleteSession)
+DECLARE_SC_EX("EnumMacTable", RPC_ENUM_MAC_TABLE, ScEnumMacTable, InRpcEnumMacTable, OutRpcEnumMacTable, FreeRpcEnumMacTable)
+DECLARE_SC("DeleteMacTable", RPC_DELETE_TABLE, ScDeleteMacTable, InRpcDeleteTable, OutRpcDeleteTable)
+DECLARE_SC_EX("EnumIpTable", RPC_ENUM_IP_TABLE, ScEnumIpTable, InRpcEnumIpTable, OutRpcEnumIpTable, FreeRpcEnumIpTable)
+DECLARE_SC("DeleteIpTable", RPC_DELETE_TABLE, ScDeleteIpTable, InRpcDeleteTable, OutRpcDeleteTable)
+DECLARE_SC("SetKeep", RPC_KEEP, ScSetKeep, InRpcKeep, OutRpcKeep)
+DECLARE_SC("GetKeep", RPC_KEEP, ScGetKeep, InRpcKeep, OutRpcKeep)
+DECLARE_SC("EnableSecureNAT", RPC_HUB, ScEnableSecureNAT, InRpcHub, OutRpcHub)
+DECLARE_SC("DisableSecureNAT", RPC_HUB, ScDisableSecureNAT, InRpcHub, OutRpcHub)
+DECLARE_SC("SetSecureNATOption", VH_OPTION, ScSetSecureNATOption, InVhOption, OutVhOption)
+DECLARE_SC("GetSecureNATOption", VH_OPTION, ScGetSecureNATOption, InVhOption, OutVhOption)
+DECLARE_SC_EX("EnumNAT", RPC_ENUM_NAT, ScEnumNAT, InRpcEnumNat, OutRpcEnumNat, FreeRpcEnumNat)
+DECLARE_SC_EX("EnumDHCP", RPC_ENUM_DHCP, ScEnumDHCP, InRpcEnumDhcp, OutRpcEnumDhcp, FreeRpcEnumDhcp)
+DECLARE_SC("GetSecureNATStatus", RPC_NAT_STATUS, ScGetSecureNATStatus, InRpcNatStatus, OutRpcNatStatus)
+DECLARE_SC_EX("EnumEthernet", RPC_ENUM_ETH, ScEnumEthernet, InRpcEnumEth, OutRpcEnumEth, FreeRpcEnumEth)
+DECLARE_SC("AddLocalBridge", RPC_LOCALBRIDGE, ScAddLocalBridge, InRpcLocalBridge, OutRpcLocalBridge)
+DECLARE_SC("DeleteLocalBridge", RPC_LOCALBRIDGE, ScDeleteLocalBridge, InRpcLocalBridge, OutRpcLocalBridge)
+DECLARE_SC_EX("EnumLocalBridge", RPC_ENUM_LOCALBRIDGE, ScEnumLocalBridge, InRpcEnumLocalBridge, OutRpcEnumLocalBridge, FreeRpcEnumLocalBridge)
+DECLARE_SC("GetBridgeSupport", RPC_BRIDGE_SUPPORT, ScGetBridgeSupport, InRpcBridgeSupport, OutRpcBridgeSupport)
+DECLARE_SC("RebootServer", RPC_TEST, ScRebootServer, InRpcTest, OutRpcTest)
+DECLARE_SC_EX("GetCaps", CAPSLIST, ScGetCaps, InRpcCapsList, OutRpcCapsList, FreeRpcCapsList)
+DECLARE_SC_EX("GetConfig", RPC_CONFIG, ScGetConfig, InRpcConfig, OutRpcConfig, FreeRpcConfig)
+DECLARE_SC_EX("SetConfig", RPC_CONFIG, ScSetConfig, InRpcConfig, OutRpcConfig, FreeRpcConfig)
+DECLARE_SC_EX("GetHubAdminOptions", RPC_ADMIN_OPTION, ScGetHubAdminOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+DECLARE_SC_EX("SetHubAdminOptions", RPC_ADMIN_OPTION, ScSetHubAdminOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+DECLARE_SC_EX("GetHubExtOptions", RPC_ADMIN_OPTION, ScGetHubExtOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+DECLARE_SC_EX("SetHubExtOptions", RPC_ADMIN_OPTION, ScSetHubExtOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+DECLARE_SC_EX("GetDefaultHubAdminOptions", RPC_ADMIN_OPTION, ScGetDefaultHubAdminOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+DECLARE_SC("AddL3Switch", RPC_L3SW, ScAddL3Switch, InRpcL3Sw, OutRpcL3Sw)
+DECLARE_SC("DelL3Switch", RPC_L3SW, ScDelL3Switch, InRpcL3Sw, OutRpcL3Sw)
+DECLARE_SC_EX("EnumL3Switch", RPC_ENUM_L3SW, ScEnumL3Switch, InRpcEnumL3Sw, OutRpcEnumL3Sw, FreeRpcEnumL3Sw)
+DECLARE_SC("StartL3Switch", RPC_L3SW, ScStartL3Switch, InRpcL3Sw, OutRpcL3Sw)
+DECLARE_SC("StopL3Switch", RPC_L3SW, ScStopL3Switch, InRpcL3Sw, OutRpcL3Sw)
+DECLARE_SC("AddL3If", RPC_L3IF, ScAddL3If, InRpcL3If, OutRpcL3If)
+DECLARE_SC("DelL3If", RPC_L3IF, ScDelL3If, InRpcL3If, OutRpcL3If)
+DECLARE_SC_EX("EnumL3If", RPC_ENUM_L3IF, ScEnumL3If, InRpcEnumL3If, OutRpcEnumL3If, FreeRpcEnumL3If)
+DECLARE_SC("AddL3Table", RPC_L3TABLE, ScAddL3Table, InRpcL3Table, OutRpcL3Table)
+DECLARE_SC("DelL3Table", RPC_L3TABLE, ScDelL3Table, InRpcL3Table, OutRpcL3Table)
+DECLARE_SC_EX("EnumL3Table", RPC_ENUM_L3TABLE, ScEnumL3Table, InRpcEnumL3Table, OutRpcEnumL3Table, FreeRpcEnumL3Table)
+DECLARE_SC_EX("EnumCrl", RPC_ENUM_CRL, ScEnumCrl, InRpcEnumCrl, OutRpcEnumCrl, FreeRpcEnumCrl)
+DECLARE_SC_EX("AddCrl", RPC_CRL, ScAddCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+DECLARE_SC_EX("DelCrl", RPC_CRL, ScDelCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+DECLARE_SC_EX("GetCrl", RPC_CRL, ScGetCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+DECLARE_SC_EX("SetCrl", RPC_CRL, ScSetCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+DECLARE_SC_EX("SetAcList", RPC_AC_LIST, ScSetAcList, InRpcAcList, OutRpcAcList, FreeRpcAcList)
+DECLARE_SC_EX("GetAcList", RPC_AC_LIST, ScGetAcList, InRpcAcList, OutRpcAcList, FreeRpcAcList)
+DECLARE_SC_EX("EnumLogFile", RPC_ENUM_LOG_FILE, ScEnumLogFile, InRpcEnumLogFile, OutRpcEnumLogFile, FreeRpcEnumLogFile)
+DECLARE_SC_EX("ReadLogFile", RPC_READ_LOG_FILE, ScReadLogFile, InRpcReadLogFile, OutRpcReadLogFile, FreeRpcReadLogFile)
+DECLARE_SC("AddLicenseKey", RPC_TEST, ScAddLicenseKey, InRpcTest, OutRpcTest)
+DECLARE_SC("DelLicenseKey", RPC_TEST, ScDelLicenseKey, InRpcTest, OutRpcTest)
+DECLARE_SC_EX("EnumLicenseKey", RPC_ENUM_LICENSE_KEY, ScEnumLicenseKey, InRpcEnumLicenseKey, OutRpcEnumLicenseKey, FreeRpcEnumLicenseKey)
+DECLARE_SC("GetLicenseStatus", RPC_LICENSE_STATUS, ScGetLicenseStatus, InRpcLicenseStatus, OutRpcLicenseStatus)
+DECLARE_SC("SetSysLog", SYSLOG_SETTING, ScSetSysLog, InRpcSysLogSetting, OutRpcSysLogSetting)
+DECLARE_SC("GetSysLog", SYSLOG_SETTING, ScGetSysLog, InRpcSysLogSetting, OutRpcSysLogSetting)
+DECLARE_SC_EX("EnumEthVLan", RPC_ENUM_ETH_VLAN, ScEnumEthVLan, InRpcEnumEthVLan, OutRpcEnumEthVLan, FreeRpcEnumEthVLan)
+DECLARE_SC("SetEnableEthVLan", RPC_TEST, ScSetEnableEthVLan, InRpcTest, OutRpcTest)
+DECLARE_SC_EX("SetHubMsg", RPC_MSG, ScSetHubMsg, InRpcMsg, OutRpcMsg, FreeRpcMsg)
+DECLARE_SC_EX("GetHubMsg", RPC_MSG, ScGetHubMsg, InRpcMsg, OutRpcMsg, FreeRpcMsg)
+DECLARE_SC("Crash", RPC_TEST, ScCrash, InRpcTest, OutRpcTest)
+DECLARE_SC_EX("GetAdminMsg", RPC_MSG, ScGetAdminMsg, InRpcMsg, OutRpcMsg, FreeRpcMsg)
+DECLARE_SC("Flush", RPC_TEST, ScFlush, InRpcTest, OutRpcTest)
+DECLARE_SC("Debug", RPC_TEST, ScDebug, InRpcTest, OutRpcTest)
+DECLARE_SC("SetIPsecServices", IPSEC_SERVICES, ScSetIPsecServices, InIPsecServices, OutIPsecServices)
+DECLARE_SC("GetIPsecServices", IPSEC_SERVICES, ScGetIPsecServices, InIPsecServices, OutIPsecServices)
+DECLARE_SC("AddEtherIpId", ETHERIP_ID, ScAddEtherIpId, InEtherIpId, OutEtherIpId)
+DECLARE_SC("GetEtherIpId", ETHERIP_ID, ScGetEtherIpId, InEtherIpId, OutEtherIpId)
+DECLARE_SC("DeleteEtherIpId", ETHERIP_ID, ScDeleteEtherIpId, InEtherIpId, OutEtherIpId)
+DECLARE_SC_EX("EnumEtherIpId", RPC_ENUM_ETHERIP_ID, ScEnumEtherIpId, InRpcEnumEtherIpId, OutRpcEnumEtherIpId, FreeRpcEnumEtherIpId)
+DECLARE_SC("SetOpenVpnSstpConfig", OPENVPN_SSTP_CONFIG, ScSetOpenVpnSstpConfig, InOpenVpnSstpConfig, OutOpenVpnSstpConfig)
+DECLARE_SC("GetOpenVpnSstpConfig", OPENVPN_SSTP_CONFIG, ScGetOpenVpnSstpConfig, InOpenVpnSstpConfig, OutOpenVpnSstpConfig)
+DECLARE_SC("GetDDnsClientStatus", DDNS_CLIENT_STATUS, ScGetDDnsClientStatus, InDDnsClientStatus, OutDDnsClientStatus)
+DECLARE_SC("ChangeDDnsClientHostname", RPC_TEST, ScChangeDDnsClientHostname, InRpcTest, OutRpcTest)
+DECLARE_SC("RegenerateServerCert", RPC_TEST, ScRegenerateServerCert, InRpcTest, OutRpcTest)
+DECLARE_SC_EX("MakeOpenVpnConfigFile", RPC_READ_LOG_FILE, ScMakeOpenVpnConfigFile, InRpcReadLogFile, OutRpcReadLogFile, FreeRpcReadLogFile)
+DECLARE_SC("SetSpecialListener", RPC_SPECIAL_LISTENER, ScSetSpecialListener, InRpcSpecialListener, OutRpcSpecialListener)
+DECLARE_SC("GetSpecialListener", RPC_SPECIAL_LISTENER, ScGetSpecialListener, InRpcSpecialListener, OutRpcSpecialListener)
+DECLARE_SC("GetAzureStatus", RPC_AZURE_STATUS, ScGetAzureStatus, InRpcAzureStatus, OutRpcAzureStatus)
+DECLARE_SC("SetAzureStatus", RPC_AZURE_STATUS, ScSetAzureStatus, InRpcAzureStatus, OutRpcAzureStatus)
+DECLARE_SC("GetDDnsInternetSettng", INTERNET_SETTING, ScGetDDnsInternetSetting, InRpcInternetSetting, OutRpcInternetSetting)
+DECLARE_SC("SetDDnsInternetSettng", INTERNET_SETTING, ScSetDDnsInternetSetting, InRpcInternetSetting, OutRpcInternetSetting)
+// RPC call function declaration: till here
+
+// Setting VPN Gate Server Configuration
+UINT StSetVgsConfig(ADMIN *a, VGS_CONFIG *t)
+{
+ return ERR_NOT_SUPPORTED;
+}
+
+// Get VPN Gate configuration
+UINT StGetVgsConfig(ADMIN *a, VGS_CONFIG *t)
+{
+ return ERR_NOT_SUPPORTED;
+}
+
+// Get DDNS proxy configuration
+UINT StGetDDnsInternetSetting(ADMIN *a, INTERNET_SETTING *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (s->DDnsClient == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ Zero(t, sizeof(INTERNET_SETTING));
+
+ DCGetInternetSetting(s->DDnsClient, t);
+
+ return ret;
+}
+
+// Set DDNS proxy configuration
+UINT StSetDDnsInternetSetting(ADMIN *a, INTERNET_SETTING *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (s->DDnsClient == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ DCSetInternetSetting(s->DDnsClient, t);
+
+ IncrementServerConfigRevision(s);
+
+ return ret;
+}
+
+// Get Azure status
+UINT StGetAzureStatus(ADMIN *a, RPC_AZURE_STATUS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ AZURE_CLIENT *ac;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (SiIsAzureSupported(s) == false)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ ac = s->AzureClient;
+ if (ac == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ Zero(t, sizeof(RPC_AZURE_STATUS));
+
+ Lock(ac->Lock);
+ {
+ t->IsConnected = ac->IsConnected;
+ t->IsEnabled = ac->IsEnabled;
+ }
+ Unlock(ac->Lock);
+
+ return ERR_NO_ERROR;
+}
+
+// Set Azure status
+UINT StSetAzureStatus(ADMIN *a, RPC_AZURE_STATUS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (SiIsAzureSupported(s) == false)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ SiSetAzureEnable(s, t->IsEnabled);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get special listener status
+UINT StGetSpecialListener(ADMIN *a, RPC_SPECIAL_LISTENER *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ Zero(t, sizeof(RPC_SPECIAL_LISTENER));
+ t->VpnOverDnsListener = s->EnableVpnOverDns;
+ t->VpnOverIcmpListener = s->EnableVpnOverIcmp;
+
+ return ERR_NO_ERROR;
+}
+
+// Set special listener status
+UINT StSetSpecialListener(ADMIN *a, RPC_SPECIAL_LISTENER *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ // Check ports
+ if (t->VpnOverDnsListener && (MAKEBOOL(s->EnableVpnOverDns) != MAKEBOOL(t->VpnOverDnsListener)))
+ {
+ if (SiCanOpenVpnOverDnsPort() == false)
+ {
+ return ERR_SPECIAL_LISTENER_DNS_ERROR;
+ }
+ }
+
+ if (t->VpnOverIcmpListener && (MAKEBOOL(s->EnableVpnOverIcmp) != MAKEBOOL(t->VpnOverIcmpListener)))
+ {
+ if (SiCanOpenVpnOverIcmpPort() == false)
+ {
+ return ERR_SPECIAL_LISTENER_ICMP_ERROR;
+ }
+ }
+
+ s->EnableVpnOverDns = t->VpnOverDnsListener;
+ s->EnableVpnOverIcmp = t->VpnOverIcmpListener;
+
+ SiApplySpecialListenerStatus(s);
+
+ ALog(a, NULL, "LA_SET_SPECIAL_LISTENER");
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Set configurations for OpenVPN and SSTP
+UINT StSetOpenVpnSstpConfig(ADMIN *a, OPENVPN_SSTP_CONFIG *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ SiSetOpenVPNAndSSTPConfig(s, t);
+
+ ALog(a, NULL, "LA_SET_OVPN_SSTP_CONFIG");
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get configurations for OpenVPN and SSTP
+UINT StGetOpenVpnSstpConfig(ADMIN *a, OPENVPN_SSTP_CONFIG *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ Zero(t, sizeof(OPENVPN_SSTP_CONFIG));
+ SiGetOpenVPNAndSSTPConfig(s, t);
+
+ return ERR_NO_ERROR;
+}
+
+// Get status of DDNS client
+UINT StGetDDnsClientStatus(ADMIN *a, DDNS_CLIENT_STATUS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (s->DDnsClient == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ Zero(t, sizeof(DDNS_CLIENT_STATUS));
+ DCGetStatus(s->DDnsClient, t);
+
+ return ERR_NO_ERROR;
+}
+
+// Change host-name for DDNS client
+UINT StChangeDDnsClientHostname(ADMIN *a, RPC_TEST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (s->DDnsClient == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ ret = DCChangeHostName(s->DDnsClient, t->StrValue);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ ALog(a, NULL, "LA_DDNS_HOSTNAME_CHANGED", t->StrValue);
+ }
+
+ IncrementServerConfigRevision(s);
+
+ return ret;
+}
+
+// Regenerate server certification
+UINT StRegenerateServerCert(ADMIN *a, RPC_TEST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ X *x;
+ K *k;
+
+ SERVER_ADMIN_ONLY;
+
+ SiGenerateDefaultCertEx(&x, &k, t->StrValue);
+
+ SetCedarCert(c, x, k);
+
+ ALog(a, NULL, "LA_REGENERATE_SERVER_CERT", t->StrValue);
+
+ IncrementServerConfigRevision(s);
+
+ FreeX(x);
+ FreeK(k);
+
+ return ERR_NO_ERROR;
+}
+
+// Generate OpenVPN configuration files
+UINT StMakeOpenVpnConfigFile(ADMIN *a, RPC_READ_LOG_FILE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ ZIP_PACKER *p;
+ FIFO *f;
+ BUF *readme_buf;
+ BUF *readme_pdf_buf;
+ BUF *sample_buf;
+ OPENVPN_SSTP_CONFIG config;
+ LIST *port_list;
+ char my_hostname[MAX_SIZE];
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ SiGetOpenVPNAndSSTPConfig(s, &config);
+
+ if (config.EnableOpenVPN == false)
+ {
+ return ERR_OPENVPN_IS_NOT_ENABLED;
+ }
+
+ port_list = StrToIntList(config.OpenVPNPortList, true);
+
+ FreeRpcReadLogFile(t);
+ Zero(t, sizeof(RPC_READ_LOG_FILE));
+
+ p = NewZipPacker();
+
+ // readme.txt
+ readme_buf = ReadDump("|openvpn_readme.txt");
+
+ // readme.pdf
+ readme_pdf_buf = ReadDump("|openvpn_readme.pdf");
+
+ // sample.ovpn
+ sample_buf = ReadDump("|openvpn_sample.ovpn");
+
+ // host name
+ GetMachineHostName(my_hostname, sizeof(my_hostname));
+ my_hostname[16] = 0;
+
+ if (readme_buf == NULL || sample_buf == NULL || readme_pdf_buf == NULL)
+ {
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ BUF *config_l3_buf, *config_l2_buf;
+ X *x = NULL;
+ BUF *x_buf;
+ char protocol[MAX_SIZE];
+ UINT port = OPENVPN_UDP_PORT;
+ char port_str[MAX_SIZE];
+ char hostname[MAX_SIZE];
+ char tag_before_hostname[MAX_SIZE];
+ DDNS_CLIENT_STATUS ddns;
+ UCHAR *zero_buffer;
+ UINT zero_buffer_size = 128 * 1024;
+ char name_tmp[MAX_SIZE];
+ X *dummy_x = NULL;
+ K *dummy_private_k = NULL;
+ K *dummy_public_k = NULL;
+ BUF *dummy_x_buf = NULL;
+ BUF *dummy_k_buf = NULL;
+
+ zero_buffer = ZeroMalloc(zero_buffer_size);
+
+
+ if (x == NULL)
+ {
+ Lock(c->lock);
+ {
+ x = CloneX(c->ServerX);
+ }
+ Unlock(c->lock);
+ }
+
+ x_buf = XToBuf(x, true);
+
+ SeekBufToEnd(x_buf);
+ WriteBufChar(x_buf, 0);
+ SeekBufToBegin(x_buf);
+
+ // Generate dummy certification
+ if (x != NULL)
+ {
+ if (RsaGen(&dummy_private_k, &dummy_public_k, x->bits))
+ {
+ NAME *name;
+ wchar_t cn[128];
+
+ UniToStr64(cn, Rand64());
+
+ name = NewName(cn, cn, cn, L"US", NULL, NULL);
+
+ dummy_x = NewRootX(dummy_public_k, dummy_private_k, name, MAX(GetDaysUntil2038(), SERVER_DEFAULT_CERT_DAYS), NULL);
+
+ FreeName(name);
+
+ dummy_x_buf = XToBuf(dummy_x, true);
+ SeekBufToEnd(dummy_x_buf);
+ WriteBufChar(dummy_x_buf, 0);
+ SeekBufToBegin(dummy_x_buf);
+
+ dummy_k_buf = KToBuf(dummy_private_k, true, NULL);
+ SeekBufToEnd(dummy_k_buf);
+ WriteBufChar(dummy_k_buf, 0);
+ SeekBufToBegin(dummy_k_buf);
+ }
+ }
+
+ FreeX(x);
+ Zero(hostname, sizeof(hostname));
+ Zero(tag_before_hostname, sizeof(tag_before_hostname));
+
+ Zero(&ddns, sizeof(ddns));
+ if (s->DDnsClient != NULL)
+ {
+ DCGetStatus(s->DDnsClient, &ddns);
+
+ if (IsEmptyStr(ddns.CurrentHostName) == false && IsEmptyStr(ddns.DnsSuffix) == false &&
+ ddns.Err_IPv4 == ERR_NO_ERROR)
+ {
+ StrCpy(tag_before_hostname, sizeof(tag_before_hostname),
+ "# Note: The below hostname is came from the Dynamic DNS Client function\r\n"
+ "# which is running on the VPN Server. If you don't want to use\r\n"
+ "# the Dynamic DNS hostname, replace it to either IP address or\r\n"
+ "# other domain's hostname.\r\n\r\n");
+
+ Format(hostname, sizeof(hostname), "%s.v4%s", ddns.CurrentHostName, ddns.DnsSuffix);
+ }
+ }
+
+ if (IsEmptyStr(hostname))
+ {
+ IP myip;
+
+ Zero(&myip, sizeof(myip));
+ GetCurrentGlobalIP(&myip, false);
+
+ if (IsZeroIP(&myip))
+ {
+ GetCurrentGlobalIPGuess(&myip, false);
+ }
+
+ IPToStr(hostname, sizeof(hostname), &myip);
+ }
+
+ SeekBuf(sample_buf, sample_buf->Size, 0);
+ WriteBuf(sample_buf, zero_buffer, zero_buffer_size);
+
+ config_l3_buf = CloneBuf(sample_buf);
+ config_l2_buf = CloneBuf(sample_buf);
+
+ // Generate contents of configuration
+ if (LIST_NUM(port_list) >= 1)
+ {
+ StrCpy(protocol, sizeof(protocol), "udp");
+
+ if (IsIntInList(port_list, OPENVPN_UDP_PORT))
+ {
+ port = OPENVPN_UDP_PORT;
+ }
+ else
+ {
+ port = *((UINT *)(LIST_DATA(port_list, 0)));
+ }
+ }
+ else
+ {
+ RPC_LISTENER_LIST tt;
+ UINT i;
+
+ port = 0;
+
+ StrCpy(protocol, sizeof(protocol), "tcp");
+
+ Zero(&tt, sizeof(tt));
+
+ StEnumListener(a, &tt);
+
+ for (i = 0;i < tt.NumPort;i++)
+ {
+ if (tt.Enables[i] && tt.Errors[i] == false)
+ {
+ port = tt.Ports[i];
+ break;
+ }
+ }
+
+ FreeRpcListenerList(&tt);
+
+ if (port == 0)
+ {
+ StrCpy(protocol, sizeof(protocol), "udp");
+ port = OPENVPN_UDP_PORT;
+ }
+ }
+
+ ToStr(port_str, port);
+
+ if (IsEmptyStr(my_hostname) == false)
+ {
+ StrCat(my_hostname, sizeof(my_hostname), "_");
+
+ StrLower(my_hostname);
+ }
+
+ ZipAddFileSimple(p, "readme.txt", LocalTime64(), 0, readme_buf->Buf, readme_buf->Size);
+ ZipAddFileSimple(p, "readme.pdf", LocalTime64(), 0, readme_pdf_buf->Buf, readme_pdf_buf->Size);
+
+ ReplaceStrEx((char *)config_l3_buf->Buf, config_l3_buf->Size, (char *)config_l3_buf->Buf,
+ "$TAG_TUN_TAP$", "tun", false);
+ ReplaceStrEx((char *)config_l3_buf->Buf, config_l3_buf->Size, (char *)config_l3_buf->Buf,
+ "$TAG_PROTO$", protocol, false);
+ ReplaceStrEx((char *)config_l3_buf->Buf, config_l3_buf->Size, (char *)config_l3_buf->Buf,
+ "$TAG_HOSTNAME$", hostname, false);
+ ReplaceStrEx((char *)config_l3_buf->Buf, config_l3_buf->Size, (char *)config_l3_buf->Buf,
+ "$TAG_BEFORE_REMOTE$", tag_before_hostname, false);
+ ReplaceStrEx((char *)config_l3_buf->Buf, config_l3_buf->Size, (char *)config_l3_buf->Buf,
+ "$TAG_PORT$", port_str, false);
+
+ if (x_buf != NULL)
+ {
+ ReplaceStrEx((char *)config_l3_buf->Buf, config_l3_buf->Size, (char *)config_l3_buf->Buf,
+ "$CA$", x_buf->Buf, false);
+ }
+
+ if (dummy_x_buf != NULL)
+ {
+ ReplaceStrEx((char *)config_l3_buf->Buf, config_l3_buf->Size, (char *)config_l3_buf->Buf,
+ "$CERT$", dummy_x_buf->Buf, false);
+ }
+
+ if (dummy_k_buf != NULL)
+ {
+ ReplaceStrEx((char *)config_l3_buf->Buf, config_l3_buf->Size, (char *)config_l3_buf->Buf,
+ "$KEY$", dummy_k_buf->Buf, false);
+ }
+
+ Format(name_tmp, sizeof(name_tmp), "%sopenvpn_remote_access_l3.ovpn", my_hostname);
+ ZipAddFileSimple(p, name_tmp, LocalTime64(), 0, config_l3_buf->Buf, StrLen(config_l3_buf->Buf));
+
+ ReplaceStrEx((char *)config_l2_buf->Buf, config_l2_buf->Size, (char *)config_l2_buf->Buf,
+ "$TAG_TUN_TAP$", "tap", false);
+ ReplaceStrEx((char *)config_l2_buf->Buf, config_l2_buf->Size, (char *)config_l2_buf->Buf,
+ "$TAG_PROTO$", protocol, false);
+ ReplaceStrEx((char *)config_l2_buf->Buf, config_l2_buf->Size, (char *)config_l2_buf->Buf,
+ "$TAG_HOSTNAME$", hostname, false);
+ ReplaceStrEx((char *)config_l2_buf->Buf, config_l2_buf->Size, (char *)config_l2_buf->Buf,
+ "$TAG_BEFORE_REMOTE$", tag_before_hostname, false);
+ ReplaceStrEx((char *)config_l2_buf->Buf, config_l2_buf->Size, (char *)config_l2_buf->Buf,
+ "$TAG_PORT$", port_str, false);
+
+ if (x_buf != NULL)
+ {
+ ReplaceStrEx((char *)config_l2_buf->Buf, config_l2_buf->Size, (char *)config_l2_buf->Buf,
+ "$CA$", x_buf->Buf, false);
+ }
+
+ if (dummy_x_buf != NULL)
+ {
+ ReplaceStrEx((char *)config_l2_buf->Buf, config_l2_buf->Size, (char *)config_l2_buf->Buf,
+ "$CERT$", dummy_x_buf->Buf, false);
+ }
+
+ if (dummy_k_buf != NULL)
+ {
+ ReplaceStrEx((char *)config_l2_buf->Buf, config_l2_buf->Size, (char *)config_l2_buf->Buf,
+ "$KEY$", dummy_k_buf->Buf, false);
+ }
+
+ Format(name_tmp, sizeof(name_tmp), "%sopenvpn_site_to_site_bridge_l2.ovpn", my_hostname);
+ ZipAddFileSimple(p, name_tmp, LocalTime64(), 0, config_l2_buf->Buf, StrLen(config_l2_buf->Buf));
+
+ FreeBuf(config_l3_buf);
+ FreeBuf(config_l2_buf);
+
+ f = ZipFinish(p);
+
+ if (f != NULL)
+ {
+ t->Buffer = NewBuf();
+ WriteBuf(t->Buffer, FifoPtr(f), FifoSize(f));
+ SeekBuf(t->Buffer, 0, 0);
+ }
+
+ FreeBuf(readme_buf);
+ FreeBuf(sample_buf);
+ FreeBuf(readme_pdf_buf);
+ FreeBuf(x_buf);
+
+ FreeX(dummy_x);
+ FreeK(dummy_private_k);
+ FreeK(dummy_public_k);
+
+ FreeBuf(dummy_k_buf);
+ FreeBuf(dummy_x_buf);
+
+ Free(zero_buffer);
+ }
+
+ FreeStrList(port_list);
+
+ FreeZipPacker(p);
+
+ return ERR_NO_ERROR;
+}
+
+// Set IPsec service configuration
+UINT StSetIPsecServices(ADMIN *a, IPSEC_SERVICES *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (GetServerCapsBool(s, "b_support_ipsec") == false || s->IPsecServer == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ IPsecServerSetServices(s->IPsecServer, t);
+
+ ALog(a, NULL, "LA_SET_IPSEC_CONFIG");
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get IPsec service configuration
+UINT StGetIPsecServices(ADMIN *a, IPSEC_SERVICES *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (GetServerCapsBool(s, "b_support_ipsec") == false || s->IPsecServer == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ Zero(t, sizeof(IPSEC_SERVICES));
+ IPsecServerGetServices(s->IPsecServer, t);
+
+ return ERR_NO_ERROR;
+}
+
+// Add EtherIP ID setting
+UINT StAddEtherIpId(ADMIN *a, ETHERIP_ID *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (GetServerCapsBool(s, "b_support_ipsec") == false || s->IPsecServer == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ AddEtherIPId(s->IPsecServer, t);
+
+ ALog(a, NULL, "LA_ADD_ETHERIP_ID", t->Id);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get EtherIP ID setting
+UINT StGetEtherIpId(ADMIN *a, ETHERIP_ID *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ char id[MAX_SIZE];
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (GetServerCapsBool(s, "b_support_ipsec") == false || s->IPsecServer == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ StrCpy(id, sizeof(id), t->Id);
+
+ Zero(t, sizeof(ETHERIP_ID));
+ if (SearchEtherIPId(s->IPsecServer, t, id) == false)
+ {
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ return ERR_NO_ERROR;
+}
+
+// Delete EtherIP ID setting
+UINT StDeleteEtherIpId(ADMIN *a, ETHERIP_ID *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ char id[MAX_SIZE];
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (GetServerCapsBool(s, "b_support_ipsec") == false || s->IPsecServer == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ StrCpy(id, sizeof(id), t->Id);
+
+ if (DeleteEtherIPId(s->IPsecServer, id) == false)
+ {
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ ALog(a, NULL, "LA_DEL_ETHERIP_ID", id);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate EtherIP ID settings
+UINT StEnumEtherIpId(ADMIN *a, RPC_ENUM_ETHERIP_ID *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (GetServerCapsBool(s, "b_support_ipsec") == false || s->IPsecServer == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ FreeRpcEnumEtherIpId(t);
+ Zero(t, sizeof(RPC_ENUM_ETHERIP_ID));
+
+ Lock(s->IPsecServer->LockSettings);
+ {
+ UINT i;
+ UINT num;
+
+ num = LIST_NUM(s->IPsecServer->EtherIPIdList);
+
+ t->NumItem = num;
+ t->IdList = ZeroMalloc(sizeof(ETHERIP_ID) * num);
+
+ for (i = 0;i < num;i++)
+ {
+ ETHERIP_ID *d = &t->IdList[i];
+ ETHERIP_ID *src = LIST_DATA(s->IPsecServer->EtherIPIdList, i);
+
+ Copy(d, src, sizeof(ETHERIP_ID));
+ }
+ }
+ Unlock(s->IPsecServer->LockSettings);
+
+ return ERR_NO_ERROR;
+}
+
+// Set message of today on hub
+UINT StSetHubMsg(ADMIN *a, RPC_MSG *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+ if (UniStrLen(t->Msg) > HUB_MAXMSG_LEN)
+ {
+ return ERR_MEMORY_NOT_ENOUGH;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ h = GetHub(c, hubname);
+
+ if (h == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_msg") != 0)
+ {
+ ret = ERR_NOT_ENOUGH_RIGHT;
+ }
+ else
+ {
+ SetHubMsg(h, t->Msg);
+ }
+
+ ReleaseHub(h);
+ }
+
+ IncrementServerConfigRevision(s);
+
+ return ret;
+}
+
+// Get message of today on hub
+UINT StGetHubMsg(ADMIN *a, RPC_MSG *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+ if (UniStrLen(t->Msg) > HUB_MAXMSG_LEN)
+ {
+ return ERR_MEMORY_NOT_ENOUGH;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ h = GetHub(c, hubname);
+
+ if (h == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ FreeRpcMsg(t);
+ Zero(t, sizeof(t));
+
+ t->Msg = GetHubMsg(h);
+
+ ReleaseHub(h);
+ }
+
+ return ret;
+}
+
+// Do debug function
+UINT StDebug(ADMIN *a, RPC_TEST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ RPC_TEST t2;
+
+ SERVER_ADMIN_ONLY;
+
+ Zero(&t2, sizeof(t2));
+
+ ret = SiDebug(s, &t2, t->IntValue, t->StrValue);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ Copy(t, &t2, sizeof(RPC_TEST));
+ }
+ else
+ {
+ Zero(t, sizeof(RPC_TEST));
+ }
+
+ return ret;
+}
+
+// Flush configuration file
+UINT StFlush(ADMIN *a, RPC_TEST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ UINT size;
+
+ SERVER_ADMIN_ONLY;
+
+ size = SiWriteConfigurationFile(s);
+
+ t->IntValue = size;
+
+ return ERR_NO_ERROR;
+}
+
+// Do Crash
+UINT StCrash(ADMIN *a, RPC_TEST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+
+#ifdef OS_WIN32
+ MsSetEnableMinidump(false);
+#endif // OS_WIN32
+
+ CrashNow();
+
+ return ERR_NO_ERROR;
+}
+
+// Get message for administrators
+UINT StGetAdminMsg(ADMIN *a, RPC_MSG *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ RPC_WINVER server_ver;
+ RPC_WINVER client_ver;
+ wchar_t winver_msg_client[3800];
+ wchar_t winver_msg_server[3800];
+ UINT tmpsize;
+ wchar_t *tmp;
+
+ FreeRpcMsg(t);
+ Zero(t, sizeof(RPC_MSG));
+
+ // Check for Windows version
+ GetWinVer(&server_ver);
+ Copy(&client_ver, &a->ClientWinVer, sizeof(RPC_WINVER));
+
+ Zero(winver_msg_client, sizeof(winver_msg_client));
+ Zero(winver_msg_server, sizeof(winver_msg_server));
+
+ if (IsSupportedWinVer(&client_ver) == false)
+ {
+ SYSTEMTIME st;
+
+ LocalTime(&st);
+
+ UniFormat(winver_msg_client, sizeof(winver_msg_client), _UU("WINVER_ERROR_FORMAT"),
+ _UU("WINVER_ERROR_PC_LOCAL"),
+ client_ver.Title,
+ _UU("WINVER_ERROR_VPNSERVER"),
+ SUPPORTED_WINDOWS_LIST,
+ _UU("WINVER_ERROR_PC_LOCAL"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ st.wYear, st.wMonth);
+ }
+
+ if (IsSupportedWinVer(&server_ver) == false)
+ {
+ SYSTEMTIME st;
+
+ LocalTime(&st);
+
+ UniFormat(winver_msg_server, sizeof(winver_msg_server), _UU("WINVER_ERROR_FORMAT"),
+ _UU("WINVER_ERROR_PC_REMOTE"),
+ server_ver.Title,
+ _UU("WINVER_ERROR_VPNSERVER"),
+ SUPPORTED_WINDOWS_LIST,
+ _UU("WINVER_ERROR_PC_REMOTE"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ st.wYear, st.wMonth);
+ }
+
+ tmpsize = UniStrSize(winver_msg_client) + UniStrSize(winver_msg_server) + 10000;
+
+ tmp = ZeroMalloc(tmpsize);
+
+ if (
+ c->Bridge == false)
+ {
+ if (GetCurrentLangId() != SE_LANG_ENGLISH)
+ {
+ UniStrCat(tmp, tmpsize, _UU("OSS_MSG"));
+ }
+ }
+
+ UniStrCat(tmp, tmpsize, winver_msg_client);
+ UniStrCat(tmp, tmpsize, winver_msg_server);
+
+ t->Msg = tmp;
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate VLAN tag transparent setting
+UINT StEnumEthVLan(ADMIN *a, RPC_ENUM_ETH_VLAN *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+
+#ifdef OS_WIN32
+ if (GetServerCapsBool(s, "b_support_eth_vlan") == false)
+ {
+ ret = ERR_NOT_SUPPORTED;
+ }
+ else
+ {
+ FreeRpcEnumEthVLan(t);
+ Zero(t, sizeof(RPC_ENUM_ETH_VLAN));
+
+ if (EnumEthVLanWin32(t) == false)
+ {
+ ret = ERR_INTERNAL_ERROR;
+ }
+ }
+#else // OS_WIN32
+ ret = ERR_NOT_SUPPORTED;
+#endif // OS_WIN32
+
+ return ret;
+}
+
+// Set VLAN tag transparent setting
+UINT StSetEnableEthVLan(ADMIN *a, RPC_TEST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+
+#ifdef OS_WIN32
+ if (GetServerCapsBool(s, "b_support_eth_vlan") == false)
+ {
+ ret = ERR_NOT_SUPPORTED;
+ }
+ else if (MsIsAdmin() == false)
+ {
+ ret = ERR_NOT_ENOUGH_RIGHT;
+ }
+ else
+ {
+ if (SetVLanEnableStatus(t->StrValue, MAKEBOOL(t->IntValue)) == false)
+ {
+ ret = ERR_INTERNAL_ERROR;
+ }
+ }
+#else // OS_WIN32
+ ret = ERR_NOT_SUPPORTED;
+#endif // OS_WIN32
+
+ return ret;
+}
+
+// Get license status
+UINT StGetLicenseStatus(ADMIN *a, RPC_LICENSE_STATUS *t)
+{
+ return ERR_NOT_SUPPORTED;
+}
+
+// Enumerate license key
+UINT StEnumLicenseKey(ADMIN *a, RPC_ENUM_LICENSE_KEY *t)
+{
+ return ERR_NOT_SUPPORTED;
+}
+
+// Add new license key
+UINT StAddLicenseKey(ADMIN *a, RPC_TEST *t)
+{
+ return ERR_NOT_SUPPORTED;
+}
+
+// Delete a license key
+UINT StDelLicenseKey(ADMIN *a, RPC_TEST *t)
+{
+ return ERR_NOT_SUPPORTED;
+}
+
+// Download a log file
+BUF *DownloadFileFromServer(RPC *r, char *server_name, char *filepath, UINT total_size, DOWNLOAD_PROC *proc, void *param)
+{
+ UINT offset;
+ BUF *buf;
+ // Validate arguments
+ if (r == NULL || filepath == NULL)
+ {
+ return NULL;
+ }
+
+ if (server_name == NULL)
+ {
+ server_name = "";
+ }
+
+ offset = 0;
+
+ buf = NewBuf();
+
+ while (true)
+ {
+ DOWNLOAD_PROGRESS g;
+ RPC_READ_LOG_FILE t;
+ UINT ret;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.FilePath, sizeof(t.FilePath), filepath);
+ t.Offset = offset;
+ StrCpy(t.ServerName, sizeof(t.ServerName), server_name);
+
+ ret = ScReadLogFile(r, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Failed
+ FreeRpcReadLogFile(&t);
+ FreeBuf(buf);
+ return NULL;
+ }
+
+ if (t.Buffer == NULL)
+ {
+ // read to the end
+ break;
+ }
+
+ // Update current progress
+ offset += t.Buffer->Size;
+ Zero(&g, sizeof(g));
+ g.Param = param;
+ g.CurrentSize = offset;
+ g.TotalSize = MAX(total_size, offset);
+ g.ProgressPercent = (UINT)(MAKESURE((UINT64)g.CurrentSize * 100ULL / (UINT64)(MAX(g.TotalSize, 1)), 0, 100ULL));
+
+ WriteBuf(buf, t.Buffer->Buf, t.Buffer->Size);
+
+ FreeRpcReadLogFile(&t);
+
+ if (proc != NULL)
+ {
+ if (proc(&g) == false)
+ {
+ // Canceled by user
+ FreeBuf(buf);
+ return NULL;
+ }
+ }
+ }
+
+ if (buf->Size == 0)
+ {
+ // Downloading failed
+ FreeBuf(buf);
+ return NULL;
+ }
+
+ return buf;
+}
+
+// Read a log file
+UINT StReadLogFile(ADMIN *a, RPC_READ_LOG_FILE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ char logfilename[MAX_PATH];
+ char servername[MAX_HOST_NAME_LEN + 1];
+ UINT offset;
+ bool local = true;
+
+ if (IsEmptyStr(t->FilePath))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ StrCpy(logfilename, sizeof(logfilename), t->FilePath);
+ StrCpy(servername, sizeof(servername), t->ServerName);
+ offset = t->Offset;
+
+ if (s->ServerType != SERVER_TYPE_FARM_CONTROLLER)
+ {
+ GetMachineName(servername, sizeof(servername));
+ }
+
+ // Check the permission to read the log file
+ if (a->LogFileList == NULL)
+ {
+ // Cache not found
+ return ERR_OBJECT_NOT_FOUND;
+ }
+ if (CheckLogFileNameFromEnumList(a->LogFileList, logfilename, servername) == false)
+ {
+ // There is no such file in the log file list
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ FreeRpcReadLogFile(t);
+ Zero(t, sizeof(RPC_READ_LOG_FILE));
+
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ UINT i;
+
+ // When the host name in request is a cluster member, redirect the request
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+
+ if (f->Me == false)
+ {
+ if (StrCmpi(f->hostname, servername) == 0)
+ {
+ RPC_READ_LOG_FILE tt;
+
+ Zero(&tt, sizeof(tt));
+ local = false;
+
+ StrCpy(tt.ServerName, sizeof(tt.ServerName), servername);
+ StrCpy(tt.FilePath, sizeof(tt.FilePath), logfilename);
+ tt.Offset = offset;
+
+ if (SiCallReadLogFile(s, f, &tt))
+ {
+ if (tt.Buffer != NULL && tt.Buffer->Size > 0)
+ {
+ t->Buffer = NewBuf();
+ WriteBuf(t->Buffer, tt.Buffer->Buf, tt.Buffer->Size);
+ }
+ }
+
+ FreeRpcReadLogFile(&tt);
+
+ break;
+ }
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+
+ // Read a local file
+ if (local)
+ {
+ SiReadLocalLogFile(s, logfilename, offset, t);
+ }
+
+ if (offset == 0)
+ {
+ ALog(a, NULL, "LA_READ_LOG_FILE", servername, logfilename);
+ }
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate log files
+UINT StEnumLogFile(ADMIN *a, RPC_ENUM_LOG_FILE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT i;
+ bool no_access = false;
+
+ HUB *h;
+
+ if (a->ServerAdmin == false)
+ {
+ h = GetHub(c, a->HubName);
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_read_log_file") != 0)
+ {
+ no_access = true;
+ }
+
+ ReleaseHub(h);
+ }
+ else
+ {
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ // Since Management session will become unstable if log files are
+ // enumerated on a cluster controller, it forbids.
+ return ERR_NOT_SUPPORTED;
+ }
+ }
+
+ if (no_access)
+ {
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ FreeRpcEnumLogFile(t);
+ Zero(t, sizeof(RPC_ENUM_LOG_FILE));
+
+ // Enumerate local log files
+ SiEnumLocalLogFileList(s, a->ServerAdmin ? NULL : a->HubName, t);
+
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ UINT i;
+ LIST *tt_list = NewListFast(NULL);
+
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+
+ if (f->Me == false)
+ {
+ // Enumerate log files on other cluster members.
+ RPC_ENUM_LOG_FILE *tt;
+ tt = ZeroMalloc(sizeof(RPC_ENUM_LOG_FILE));
+
+ if (SiCallEnumLogFileList(s, f, tt, a->ServerAdmin ? "" : a->HubName))
+ {
+ UINT i;
+ for (i = 0;i < tt->NumItem;i++)
+ {
+ RPC_ENUM_LOG_FILE_ITEM *e = &tt->Items[i];
+
+ StrCpy(e->ServerName, sizeof(e->ServerName), f->hostname);
+ }
+
+ Add(tt_list, tt);
+ }
+ else
+ {
+ Free(tt);
+ }
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+
+ for (i = 0;i < LIST_NUM(tt_list);i++)
+ {
+ RPC_ENUM_LOG_FILE *tt = LIST_DATA(tt_list, i);
+
+ AdjoinRpcEnumLogFile(t, tt);
+ FreeRpcEnumLogFile(tt);
+
+ Free(tt);
+ }
+
+ ReleaseList(tt_list);
+ }
+
+ // Cache the last list of log files on RPC session
+ if (a->LogFileList != NULL)
+ {
+ FreeEnumLogFile(a->LogFileList);
+ }
+
+ a->LogFileList = NewListFast(CmpLogFile);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_LOG_FILE_ITEM *e = &t->Items[i];
+ LOG_FILE *f = ZeroMalloc(sizeof(LOG_FILE));
+
+ f->FileSize = e->FileSize;
+ f->UpdatedTime = e->UpdatedTime;
+ StrCpy(f->Path, sizeof(f->Path), e->FilePath);
+ StrCpy(f->ServerName, sizeof(f->ServerName), e->ServerName);
+
+ Insert(a->LogFileList, f);
+ }
+
+ return ERR_NO_ERROR;
+}
+
+
+// Get access control list
+UINT StGetAcList(ADMIN *a, RPC_AC_LIST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ FreeRpcAcList(t);
+ Zero(t, sizeof(RPC_AC_LIST));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ h = GetHub(c, hubname);
+
+ if (h == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ if (h->HubDb == NULL)
+ {
+ ret = ERR_NOT_SUPPORTED;
+ }
+ else
+ {
+ HUBDB *db = h->HubDb;
+
+ LockList(db->AcList);
+ {
+ t->o = NewAcList();
+
+ SetAcList(t->o, db->AcList);
+ }
+ UnlockList(db->AcList);
+ }
+ ReleaseHub(h);
+ }
+
+ return ret;
+}
+
+// Set access control list
+UINT StSetAcList(ADMIN *a, RPC_AC_LIST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+
+ if (c->Bridge)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ h = GetHub(c, hubname);
+
+ if (h == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_access_control_list") != 0)
+ {
+ ret = ERR_NOT_ENOUGH_RIGHT;
+ }
+ else
+ {
+ if (h->HubDb == NULL)
+ {
+ ret = ERR_NOT_SUPPORTED;
+ }
+ else
+ {
+ HUBDB *db = h->HubDb;
+
+ LockList(db->AcList);
+ {
+ SetAcList(db->AcList, t->o);
+
+ {
+ ALog(a, h, "LA_SET_AC_LIST", LIST_NUM(t->o));
+
+ IncrementServerConfigRevision(s);
+ }
+ }
+ UnlockList(db->AcList);
+ }
+ }
+ ReleaseHub(h);
+ }
+
+ return ret;
+}
+
+// Set CRL (Certificate Revocation List) entry
+UINT StSetCrl(ADMIN *a, RPC_CRL *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ UINT key;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ key = t->Key;
+
+ h = GetHub(c, hubname);
+
+ if (h == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_crl_list") != 0)
+ {
+ ret = ERR_NOT_ENOUGH_RIGHT;
+ }
+ else
+ {
+ if (h->HubDb == NULL)
+ {
+ ret = ERR_NOT_SUPPORTED;
+ }
+ else
+ {
+ LockList(h->HubDb->CrlList);
+ {
+ CRL *crl = ListKeyToPointer(h->HubDb->CrlList, t->Key);
+
+ if (crl == NULL)
+ {
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ CRL *new_crl = CopyCrl(t->Crl);
+ if (ReplaceListPointer(h->HubDb->CrlList, crl, new_crl))
+ {
+ ALog(a, h, "LA_ADD_CRL");
+ FreeCrl(crl);
+
+ IncrementServerConfigRevision(s);
+ }
+ }
+ }
+ UnlockList(h->HubDb->CrlList);
+ }
+ }
+
+ ReleaseHub(h);
+ }
+
+ return ret;
+}
+
+// Get CRL (Certificate Revocation List) entry
+UINT StGetCrl(ADMIN *a, RPC_CRL *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ UINT key;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ key = t->Key;
+
+ FreeRpcCrl(t);
+ Zero(t, sizeof(RPC_CRL));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+ t->Key = key;
+
+ h = GetHub(c, hubname);
+
+ if (h == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ if (h->HubDb == NULL)
+ {
+ ret = ERR_NOT_SUPPORTED;
+ }
+ else
+ {
+ LockList(h->HubDb->CrlList);
+ {
+ CRL *crl = ListKeyToPointer(h->HubDb->CrlList, t->Key);
+
+ if (crl == NULL)
+ {
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ t->Crl = CopyCrl(crl);
+ }
+ }
+ UnlockList(h->HubDb->CrlList);
+ }
+
+ ReleaseHub(h);
+ }
+
+ return ret;
+}
+
+// Delete CRL (Certificate Revocation List) entry
+UINT StDelCrl(ADMIN *a, RPC_CRL *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ h = GetHub(c, hubname);
+
+ if (h == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_crl_list") != 0)
+ {
+ ret = ERR_NOT_ENOUGH_RIGHT;
+ }
+ else
+ {
+ if (h->HubDb == NULL)
+ {
+ ret = ERR_NOT_SUPPORTED;
+ }
+ else
+ {
+ LockList(h->HubDb->CrlList);
+ {
+ CRL *crl = ListKeyToPointer(h->HubDb->CrlList, t->Key);
+
+ if (crl == NULL)
+ {
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ ALog(a, h, "LA_DEL_CRL");
+ FreeCrl(crl);
+ Delete(h->HubDb->CrlList, crl);
+ }
+ }
+ UnlockList(h->HubDb->CrlList);
+ }
+ }
+
+ ReleaseHub(h);
+ }
+
+ return ret;
+}
+
+// Add new CRL (Certificate Revocation List) entry
+UINT StAddCrl(ADMIN *a, RPC_CRL *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ if (c->Bridge)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ h = GetHub(c, hubname);
+
+ if (h == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_crl_list") != 0)
+ {
+ ret = ERR_NOT_ENOUGH_RIGHT;
+ }
+ else
+ {
+ if (h->HubDb == NULL)
+ {
+ ret = ERR_NOT_SUPPORTED;
+ }
+ else
+ {
+ LockList(h->HubDb->CrlList);
+ {
+ if (LIST_NUM(h->HubDb->CrlList) < MAX_HUB_CRLS)
+ {
+ CRL *crl = CopyCrl(t->Crl);
+
+ Insert(h->HubDb->CrlList, crl);
+
+ ALog(a, h, "LA_SET_CRL");
+
+ IncrementServerConfigRevision(s);
+ }
+ }
+ UnlockList(h->HubDb->CrlList);
+ }
+ }
+
+ ReleaseHub(h);
+ }
+
+ return ret;
+}
+
+// Get CRL (Certificate Revocation List) index
+UINT StEnumCrl(ADMIN *a, RPC_ENUM_CRL *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ FreeRpcEnumCrl(t);
+ Zero(t, sizeof(RPC_ENUM_CRL));
+
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ h = GetHub(c, hubname);
+
+ if (h == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ if (h->HubDb == NULL)
+ {
+ ret = ERR_NOT_SUPPORTED;
+ }
+ else
+ {
+ LockList(h->HubDb->CrlList);
+ {
+ UINT i;
+
+ t->NumItem = LIST_NUM(h->HubDb->CrlList);
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_CRL_ITEM) * t->NumItem);
+
+ for (i = 0;i < LIST_NUM(h->HubDb->CrlList);i++)
+ {
+ CRL *crl = LIST_DATA(h->HubDb->CrlList, i);
+ wchar_t *info = GenerateCrlStr(crl);
+
+ UniStrCpy(t->Items[i].CrlInfo, sizeof(t->Items[i].CrlInfo), info);
+ Free(info);
+
+ t->Items[i].Key = POINTER_TO_KEY(crl);
+ }
+ }
+ UnlockList(h->HubDb->CrlList);
+ }
+
+ ReleaseHub(h);
+ }
+
+ return ret;
+}
+
+// Get routing table on virtual L3 switch
+UINT StEnumL3Table(ADMIN *a, RPC_ENUM_L3TABLE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ L3SW *sw;
+ char name[MAX_HUBNAME_LEN + 1];
+
+ if (IsEmptyStr(t->Name))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ StrCpy(name, sizeof(name), t->Name);
+ FreeRpcEnumL3Table(t);
+ Zero(t, sizeof(RPC_ENUM_L3TABLE));
+ StrCpy(t->Name, sizeof(t->Name), name);
+
+ sw = L3GetSw(c, t->Name);
+
+ if (sw == NULL)
+ {
+ ret = ERR_LAYER3_SW_NOT_FOUND;
+ }
+ else
+ {
+ UINT i;
+
+ Lock(sw->lock);
+ {
+ t->NumItem = LIST_NUM(sw->TableList);
+ t->Items = ZeroMalloc(sizeof(RPC_L3TABLE) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ L3TABLE *tbl = LIST_DATA(sw->TableList, i);
+ RPC_L3TABLE *e = &t->Items[i];
+
+ StrCpy(e->Name, sizeof(e->Name), name);
+ e->NetworkAddress = tbl->NetworkAddress;
+ e->SubnetMask = tbl->SubnetMask;
+ e->GatewayAddress = tbl->GatewayAddress;
+ e->Metric = tbl->Metric;
+ }
+ }
+ Unlock(sw->lock);
+
+ ReleaseL3Sw(sw);
+ }
+
+ return ret;
+}
+
+// Delete routing table entry on virtual L3 switch
+UINT StDelL3Table(ADMIN *a, RPC_L3TABLE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ L3SW *sw;
+
+ SERVER_ADMIN_ONLY;
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ sw = L3GetSw(c, t->Name);
+
+ if (sw == NULL)
+ {
+ ret = ERR_LAYER3_SW_NOT_FOUND;
+ }
+ else
+ {
+ L3TABLE tbl;
+
+ Zero(&tbl, sizeof(tbl));
+ tbl.NetworkAddress = t->NetworkAddress;
+ tbl.SubnetMask = t->SubnetMask;
+ tbl.GatewayAddress = t->GatewayAddress;
+ tbl.Metric = t->Metric;
+
+ if (L3DelTable(sw, &tbl) == false)
+ {
+ ret = ERR_LAYER3_TABLE_DEL_FAILED;
+ }
+ else
+ {
+ char tmp[MAX_SIZE];
+ IPToStr32(tmp, sizeof(tmp), tbl.NetworkAddress);
+ ALog(a, NULL, "LA_DEL_L3_TABLE", tmp, t->Name);
+
+ IncrementServerConfigRevision(s);
+ }
+
+ ReleaseL3Sw(sw);
+ }
+
+ return ret;
+}
+
+// Add new routing table entry on virtual L3 switch
+UINT StAddL3Table(ADMIN *a, RPC_L3TABLE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ L3SW *sw;
+
+ if (IsNetworkAddress32(t->NetworkAddress, t->SubnetMask) == false ||
+ IsHostIPAddress32(t->GatewayAddress) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ SERVER_ADMIN_ONLY;
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ sw = L3GetSw(c, t->Name);
+
+ if (sw == NULL)
+ {
+ ret = ERR_LAYER3_SW_NOT_FOUND;
+ }
+ else
+ {
+ L3TABLE tbl;
+
+ Zero(&tbl, sizeof(tbl));
+ tbl.NetworkAddress = t->NetworkAddress;
+ tbl.SubnetMask = t->SubnetMask;
+ tbl.GatewayAddress = t->GatewayAddress;
+ tbl.Metric = t->Metric;
+
+ if (L3AddTable(sw, &tbl) == false)
+ {
+ ret = ERR_LAYER3_TABLE_ADD_FAILED;
+ }
+ else
+ {
+ char tmp[MAX_SIZE];
+ IPToStr32(tmp, sizeof(tmp), tbl.NetworkAddress);
+ ALog(a, NULL, "LA_ADD_L3_TABLE", tmp, t->Name);
+
+ IncrementServerConfigRevision(s);
+ }
+
+ ReleaseL3Sw(sw);
+ }
+
+ return ret;
+}
+
+// Enumerate virtual interfaces on virtual L3 switch
+UINT StEnumL3If(ADMIN *a, RPC_ENUM_L3IF *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ L3SW *sw;
+ char name[MAX_HUBNAME_LEN + 1];
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ StrCpy(name, sizeof(name), t->Name);
+
+ FreeRpcEnumL3If(t);
+ Zero(t, sizeof(RPC_ENUM_L3IF));
+
+ StrCpy(t->Name, sizeof(t->Name), name);
+
+ sw = L3GetSw(c, t->Name);
+
+ if (sw == NULL)
+ {
+ ret = ERR_LAYER3_SW_NOT_FOUND;
+ }
+ else
+ {
+ Lock(sw->lock);
+ {
+ UINT i;
+
+ t->NumItem = LIST_NUM(sw->IfList);
+ t->Items = ZeroMalloc(sizeof(RPC_L3IF) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ L3IF *f = LIST_DATA(sw->IfList, i);
+ RPC_L3IF *e = &t->Items[i];
+
+ StrCpy(e->Name, sizeof(e->Name), sw->Name);
+ StrCpy(e->HubName, sizeof(e->HubName), f->HubName);
+ e->IpAddress = f->IpAddress;
+ e->SubnetMask = f->SubnetMask;
+ }
+ }
+ Unlock(sw->lock);
+
+ ReleaseL3Sw(sw);
+ }
+
+ return ret;
+}
+
+// Delete a virtual interface on virtual L3 switch
+UINT StDelL3If(ADMIN *a, RPC_L3IF *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ L3SW *sw;
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ SERVER_ADMIN_ONLY;
+
+ sw = L3GetSw(c, t->Name);
+
+ if (sw == NULL)
+ {
+ ret = ERR_LAYER3_SW_NOT_FOUND;
+ }
+ else
+ {
+ if (L3DelIf(sw, t->HubName) == false)
+ {
+ ret = ERR_LAYER3_IF_DEL_FAILED;
+ }
+ else
+ {
+ ALog(a, NULL, "LA_DEL_L3_IF", t->HubName, t->Name);
+
+ IncrementServerConfigRevision(s);
+ }
+ ReleaseL3Sw(sw);
+ }
+
+ return ret;
+}
+
+// Add new virtual interface on virtual L3 switch
+UINT StAddL3If(ADMIN *a, RPC_L3IF *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ L3SW *sw;
+
+
+ if (IsSubnetMask32(t->SubnetMask) == false || IsHostIPAddress32(t->IpAddress) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ if ((t->IpAddress & (~t->SubnetMask)) == 0)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ SERVER_ADMIN_ONLY;
+
+ sw = L3GetSw(c, t->Name);
+
+ if (sw == NULL)
+ {
+ ret = ERR_LAYER3_SW_NOT_FOUND;
+ }
+ else
+ {
+ Lock(sw->lock);
+ {
+ if (L3SearchIf(sw, t->HubName) != NULL)
+ {
+ // Already exists
+ ret = ERR_LAYER3_IF_EXISTS;
+ }
+ else
+ {
+ if (L3AddIf(sw, t->HubName, t->IpAddress, t->SubnetMask) == false)
+ {
+ ret = ERR_LAYER3_IF_ADD_FAILED;
+ }
+ else
+ {
+ ALog(a, NULL, "LA_ADD_L3_IF", t->HubName, t->Name);
+
+ IncrementServerConfigRevision(s);
+ }
+ }
+ }
+ Unlock(sw->lock);
+ ReleaseL3Sw(sw);
+ }
+
+ return ret;
+}
+
+// Stop a virtual layer-3 switch
+UINT StStopL3Switch(ADMIN *a, RPC_L3SW *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ L3SW *sw;
+
+ if (IsEmptyStr(t->Name))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ SERVER_ADMIN_ONLY;
+
+ sw = L3GetSw(c, t->Name);
+
+ if (sw == NULL)
+ {
+ ret = ERR_LAYER3_SW_NOT_FOUND;
+ }
+ else
+ {
+ L3SwStop(sw);
+ ALog(a, NULL, "LA_STOP_L3_SW", sw->Name);
+ ReleaseL3Sw(sw);
+
+ IncrementServerConfigRevision(s);
+ }
+
+ return ret;
+}
+
+// Start a virtual layer-3 switch
+UINT StStartL3Switch(ADMIN *a, RPC_L3SW *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ L3SW *sw;
+
+ if (IsEmptyStr(t->Name))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ SERVER_ADMIN_ONLY;
+
+ sw = L3GetSw(c, t->Name);
+
+ if (sw == NULL)
+ {
+ ret = ERR_LAYER3_SW_NOT_FOUND;
+ }
+ else
+ {
+ Lock(sw->lock);
+ {
+ // Count the registered virtual interfaces
+ if (LIST_NUM(sw->IfList) >= 1)
+ {
+ L3SwStart(sw);
+
+ ALog(a, NULL, "LA_START_L3_SW", sw->Name);
+
+ IncrementServerConfigRevision(s);
+ }
+ else
+ {
+ ret = ERR_LAYER3_CANT_START_SWITCH;
+ }
+ }
+ Unlock(sw->lock);
+
+ ReleaseL3Sw(sw);
+ }
+
+ return ret;
+}
+
+// Enumerate virtual layer-3 switches
+UINT StEnumL3Switch(ADMIN *a, RPC_ENUM_L3SW *t)
+{
+ UINT i;
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ FreeRpcEnumL3Sw(t);
+ Zero(t, sizeof(RPC_ENUM_L3SW));
+
+ LockList(c->L3SwList);
+ {
+ t->NumItem = LIST_NUM(c->L3SwList);
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_L3SW_ITEM) * t->NumItem);
+ for (i = 0;i < LIST_NUM(c->L3SwList);i++)
+ {
+ L3SW *sw = LIST_DATA(c->L3SwList, i);
+ RPC_ENUM_L3SW_ITEM *e = &t->Items[i];
+
+ Lock(sw->lock);
+ {
+ StrCpy(e->Name, sizeof(e->Name), sw->Name);
+ e->NumInterfaces = LIST_NUM(sw->IfList);
+ e->NumTables = LIST_NUM(sw->TableList);
+ e->Active = sw->Active;
+ e->Online = sw->Online;
+ }
+ Unlock(sw->lock);
+ }
+ }
+ UnlockList(c->L3SwList);
+
+ return ret;
+}
+
+// Delete a virtual layer-3 switch
+UINT StDelL3Switch(ADMIN *a, RPC_L3SW *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ if (IsEmptyStr(t->Name))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ SERVER_ADMIN_ONLY;
+
+ if (L3DelSw(c, t->Name) == false)
+ {
+ ret = ERR_LAYER3_SW_NOT_FOUND;
+ }
+ else
+ {
+ ALog(a, NULL, "LA_DEL_L3_SW", t->Name);
+
+ IncrementServerConfigRevision(s);
+ }
+
+ return ret;
+}
+
+// Add a new virtual layer-3 switch
+UINT StAddL3Switch(ADMIN *a, RPC_L3SW *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ L3SW *sw;
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (IsEmptyStr(t->Name))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (IsSafeStr(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ SERVER_ADMIN_ONLY;
+
+ // Duplication check
+ sw = L3GetSw(c, t->Name);
+ if (sw != NULL)
+ {
+ // Already exists
+ ReleaseL3Sw(sw);
+ ret = ERR_LAYER3_SW_EXISTS;
+ }
+ else
+ {
+ LockList(c->L3SwList);
+ {
+ if (LIST_NUM(c->L3SwList) >= GetServerCapsInt(s, "i_max_l3_sw"))
+ {
+ // No more virtual interfaces
+ sw = NULL;
+ }
+ else
+ {
+ // Create
+ sw = L3AddSw(c, t->Name);
+
+ if (sw != NULL)
+ {
+ ALog(a, NULL, "LA_ADD_L3_SW", t->Name);
+
+ IncrementServerConfigRevision(s);
+ }
+ }
+ }
+ UnlockList(c->L3SwList);
+
+ if (sw == NULL)
+ {
+ // Failed
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ // Success
+ ReleaseL3Sw(sw);
+ }
+ }
+
+ return ret;
+}
+
+// Set hub extended options
+UINT StSetHubExtOptions(ADMIN *a, RPC_ADMIN_OPTION *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ bool not_server_admin = false;
+
+ if (t->NumItem > MAX_HUB_ADMIN_OPTIONS)
+ {
+ return ERR_TOO_MANT_ITEMS;
+ }
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+
+ CHECK_RIGHT;
+
+ if (a->ServerAdmin == false)
+ {
+ not_server_admin = true;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (GetHubAdminOption(h, "deny_hub_admin_change_ext_option") && not_server_admin)
+ {
+ // Insufficient permission
+ ReleaseHub(h);
+
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ // Update setting
+ Lock(h->lock);
+ {
+ DataToHubOptionStruct(h->Option, t);
+ }
+ Unlock(h->lock);
+
+ ALog(a, NULL, "LA_SET_HUB_EXT_OPTION", h->Name);
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get hub extended options
+UINT StGetHubExtOptions(ADMIN *a, RPC_ADMIN_OPTION *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ FreeRpcAdminOption(t);
+ Zero(t, sizeof(RPC_ADMIN_OPTION));
+
+ StrCpy(t->HubName, sizeof(t->HubName), h->Name);
+
+ // Get options
+ Lock(h->lock);
+ {
+ HubOptionStructToData(t, h->Option, h->Name);
+ }
+ Unlock(h->lock);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Set hub administration options
+UINT StSetHubAdminOptions(ADMIN *a, RPC_ADMIN_OPTION *t)
+{
+ UINT i;
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ bool not_server_admin = false;
+
+
+ if (t->NumItem > MAX_HUB_ADMIN_OPTIONS)
+ {
+ return ERR_TOO_MANT_ITEMS;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ if (a->ServerAdmin == false)
+ {
+ not_server_admin = true;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (GetHubAdminOption(h, "allow_hub_admin_change_option") == false
+ && not_server_admin)
+ {
+ // Insufficient permission
+ ReleaseHub(h);
+
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ LockList(h->AdminOptionList);
+ {
+ DeleteAllHubAdminOption(h, false);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ ADMIN_OPTION *e = &t->Items[i];
+ ADMIN_OPTION *a = ZeroMalloc(sizeof(ADMIN_OPTION));
+
+ StrCpy(a->Name, sizeof(a->Name), e->Name);
+ a->Value = e->Value;
+
+ Insert(h->AdminOptionList, a);
+ }
+
+ AddHubAdminOptionsDefaults(h, false);
+ }
+ UnlockList(h->AdminOptionList);
+
+ ALog(a, NULL, "LA_SET_HUB_ADMIN_OPTION", h->Name);
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get hub administration options
+UINT StGetHubAdminOptions(ADMIN *a, RPC_ADMIN_OPTION *t)
+{
+ UINT i;
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ CHECK_RIGHT;
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ FreeRpcAdminOption(t);
+ Zero(t, sizeof(RPC_ADMIN_OPTION));
+
+ StrCpy(t->HubName, sizeof(t->HubName), h->Name);
+
+ LockList(h->AdminOptionList);
+ {
+ t->NumItem = LIST_NUM(h->AdminOptionList);
+ t->Items = ZeroMalloc(sizeof(ADMIN_OPTION) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ ADMIN_OPTION *a = LIST_DATA(h->AdminOptionList, i);
+ ADMIN_OPTION *e = &t->Items[i];
+
+ StrCpy(e->Name, sizeof(e->Name), a->Name);
+ e->Value = a->Value;
+ }
+ }
+ UnlockList(h->AdminOptionList);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Get default hub administration options
+UINT StGetDefaultHubAdminOptions(ADMIN *a, RPC_ADMIN_OPTION *t)
+{
+ UINT i;
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (a->Server->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ FreeRpcAdminOption(t);
+ Zero(t, sizeof(RPC_ADMIN_OPTION));
+
+ t->NumItem = num_admin_options;
+ t->Items = ZeroMalloc(sizeof(ADMIN_OPTION) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ ADMIN_OPTION *a = &t->Items[i];
+
+ StrCpy(a->Name, sizeof(a->Name), admin_options[i].Name);
+ a->Value = admin_options[i].Value;
+ }
+
+ return ERR_NO_ERROR;
+}
+
+// Get configuration file stream
+UINT StGetConfig(ADMIN *a, RPC_CONFIG *t)
+{
+ SERVER *s;
+
+ SERVER_ADMIN_ONLY;
+
+ FreeRpcConfig(t);
+ Zero(t, sizeof(RPC_CONFIG));
+
+ s = a->Server;
+
+ ALog(a, NULL, "LA_GET_CONFIG");
+
+ if (s->CfgRw != NULL)
+ {
+ FOLDER *f = SiWriteConfigurationToCfg(s);
+ BUF *b = CfgFolderToBuf(f, true);
+
+ StrCpy(t->FileName, sizeof(t->FileName), s->CfgRw->FileName + (s->CfgRw->FileName[0] == '@' ? 1 : 0));
+
+ t->FileData = ZeroMalloc(b->Size + 1);
+ Copy(t->FileData, b->Buf, b->Size);
+
+ CfgDeleteFolder(f);
+ FreeBuf(b);
+
+ return ERR_NO_ERROR;
+ }
+ else
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+}
+
+// Overwrite configuration file by specified data
+UINT StSetConfig(ADMIN *a, RPC_CONFIG *t)
+{
+ SERVER *s;
+ IO *o;
+ char filename[MAX_PATH];
+
+ SERVER_ADMIN_ONLY;
+
+ s = a->Server;
+ if (s->CfgRw == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ // Write new configuration file
+ Format(filename, sizeof(filename), "%s.new", s->CfgRw->FileName);
+
+ o = FileCreate(filename);
+
+ FileWrite(o, t->FileData, StrLen(t->FileData));
+
+ FileClose(o);
+
+ IncrementServerConfigRevision(s);
+
+ ALog(a, NULL, "LA_SET_CONFIG");
+
+ // Reboot server itself
+ SiRebootServer(s->Cedar->Bridge);
+
+ return ERR_NO_ERROR;
+}
+
+// Get capabilities
+UINT StGetCaps(ADMIN *a, CAPSLIST *t)
+{
+ FreeRpcCapsList(t);
+ Zero(t, sizeof(CAPSLIST));
+
+ GetServerCapsMain(a->Server, t);
+
+ return ERR_NO_ERROR;
+}
+
+// Reboot server itself
+UINT StRebootServer(ADMIN *a, RPC_TEST *t)
+{
+ SERVER_ADMIN_ONLY;
+
+ ALog(a, NULL, "LA_REBOOT_SERVER");
+
+ SiRebootServerEx(a->Server->Cedar->Bridge, t->IntValue);
+
+ return ERR_NO_ERROR;
+}
+
+// Get availability to localbridge function
+UINT StGetBridgeSupport(ADMIN *a, RPC_BRIDGE_SUPPORT *t)
+{
+ Zero(t, sizeof(RPC_BRIDGE_SUPPORT));
+
+ t->IsBridgeSupportedOs = IsBridgeSupported();
+ t->IsWinPcapNeeded = IsNeedWinPcap();
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate Ethernet devices
+UINT StEnumEthernet(ADMIN *a, RPC_ENUM_ETH *t)
+{
+ TOKEN_LIST *o;
+ UINT i;
+ char tmp[MAX_SIZE];
+ bool unix_support = false;
+
+ SERVER_ADMIN_ONLY;
+
+#ifdef OS_UNIX
+ unix_support = EthIsInterfaceDescriptionSupportedUnix();
+#endif // OS_UNIX
+
+ o = GetEthList();
+ if (o == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ FreeRpcEnumEth(t);
+ Zero(t, sizeof(RPC_ENUM_ETH));
+
+ t->NumItem = o->NumTokens;
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_ETH_ITEM) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_ETH_ITEM *e = &t->Items[i];
+
+ StrCpy(e->DeviceName, sizeof(e->DeviceName), o->Token[i]);
+
+ StrCpy(tmp, sizeof(tmp), e->DeviceName);
+
+#ifdef OS_WIN32
+ GetEthNetworkConnectionName(e->NetworkConnectionName, sizeof(e->NetworkConnectionName), e->DeviceName);
+#else
+ if (unix_support == false)
+ {
+ StrCpy(tmp, sizeof(tmp), "");
+ }
+ else
+ {
+ if (EthGetInterfaceDescriptionUnix(e->DeviceName, tmp, sizeof(tmp)) == false)
+ {
+ StrCpy(tmp, sizeof(tmp), e->DeviceName);
+ }
+ }
+
+ StrToUni(e->NetworkConnectionName, sizeof(e->NetworkConnectionName), tmp);
+#endif
+ }
+
+ FreeToken(o);
+
+ return ERR_NO_ERROR;
+}
+
+// Add a new local bridge
+UINT StAddLocalBridge(ADMIN *a, RPC_LOCALBRIDGE *t)
+{
+ if (IsEmptyStr(t->DeviceName) || IsEmptyStr(t->HubName))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ SERVER_ADMIN_ONLY;
+
+
+ if (IsEthSupported() == false)
+ {
+ return ERR_LOCAL_BRIDGE_UNSUPPORTED;
+ }
+
+#ifdef OS_WIN32
+ if (true)
+ {
+ char tmp[MAX_SIZE];
+ UINT id = Win32EthGetNameAndIdFromCombinedName(tmp, sizeof(tmp), t->DeviceName);
+
+ if (id == 0)
+ {
+ // If a ID is not specified in Win32, adding will fail
+ return ERR_OBJECT_NOT_FOUND;
+ }
+ }
+#endif // OS_WIN32
+
+ ALog(a, NULL, "LA_ADD_BRIDGE", t->HubName, t->DeviceName);
+
+ AddLocalBridge(a->Server->Cedar, t->HubName, t->DeviceName, false, false, t->TapMode, NULL, false);
+
+ IncrementServerConfigRevision(a->Server);
+
+ return ERR_NO_ERROR;
+}
+
+// Delete a local bridge
+UINT StDeleteLocalBridge(ADMIN *a, RPC_LOCALBRIDGE *t)
+{
+ if (IsEmptyStr(t->DeviceName) || IsEmptyStr(t->HubName))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ SERVER_ADMIN_ONLY;
+
+ ALog(a, NULL, "LA_DELETE_BRIDGE", t->HubName, t->DeviceName);
+
+ if (DeleteLocalBridge(a->Server->Cedar, t->HubName, t->DeviceName) == false)
+ {
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ IncrementServerConfigRevision(a->Server);
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate local bridges
+UINT StEnumLocalBridge(ADMIN *a, RPC_ENUM_LOCALBRIDGE *t)
+{
+ UINT i;
+ CEDAR *c;
+
+ if (IsEthSupported() == false)
+ {
+ return ERR_LOCAL_BRIDGE_UNSUPPORTED;
+ }
+
+ FreeRpcEnumLocalBridge(t);
+ Zero(t, sizeof(RPC_ENUM_LOCALBRIDGE));
+
+ c = a->Server->Cedar;
+
+ LockList(c->LocalBridgeList);
+ {
+ t->NumItem = LIST_NUM(c->LocalBridgeList);
+ t->Items = ZeroMalloc(sizeof(RPC_LOCALBRIDGE) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_LOCALBRIDGE *e = &t->Items[i];
+ LOCALBRIDGE *br = LIST_DATA(c->LocalBridgeList, i);
+
+ if (br->Bridge == false)
+ {
+ e->Online = e->Active = false;
+ }
+ else
+ {
+ e->Online = true;
+ if (br->Bridge->Active)
+ {
+ e->Active = true;
+ }
+ else
+ {
+ e->Active = false;
+ }
+ }
+ StrCpy(e->DeviceName, sizeof(e->DeviceName), br->DeviceName);
+ StrCpy(e->HubName, sizeof(e->HubName), br->HubName);
+
+ e->TapMode = br->TapMode;
+ }
+ }
+ UnlockList(c->LocalBridgeList);
+
+ return ERR_NO_ERROR;
+}
+
+// Set syslog function setting
+UINT StSetSysLog(ADMIN *a, SYSLOG_SETTING *t)
+{
+ SERVER *s = a->Server;
+
+ SERVER_ADMIN_ONLY;
+
+ if (GetServerCapsBool(s, "b_support_syslog") == false)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ SiSetSysLogSetting(s, t);
+
+ IncrementServerConfigRevision(s);
+ ALog(a, NULL, "LA_SET_SYSLOG");
+
+ return ERR_NO_ERROR;
+}
+
+// Get syslog function setting
+UINT StGetSysLog(ADMIN *a, SYSLOG_SETTING *t)
+{
+ SERVER *s = a->Server;
+
+ SiGetSysLogSetting(s, t);
+
+ if (a->ServerAdmin == false)
+ {
+ // Hide server name for non-administrator
+ if (t->SaveType == SYSLOG_NONE)
+ {
+ StrCpy(t->Hostname, sizeof(t->Hostname), "");
+ t->Port = 0;
+ }
+ else
+ {
+ StrCpy(t->Hostname, sizeof(t->Hostname), "Secret");
+ t->Port = 0;
+ }
+ }
+
+ return ERR_NO_ERROR;
+}
+
+// Set keep-alive function setting
+UINT StSetKeep(ADMIN *a, RPC_KEEP *t)
+{
+ SERVER *s = a->Server;
+
+ if (t->UseKeepConnect)
+ {
+ if (IsEmptyStr(t->KeepConnectHost) ||
+ t->KeepConnectPort == 0 ||
+ t->KeepConnectPort >= 65536)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+
+ SERVER_ADMIN_ONLY;
+
+ Lock(s->Keep->lock);
+ {
+ KEEP *keep = s->Keep;
+ keep->Enable = t->UseKeepConnect;
+ keep->Server = true;
+ StrCpy(keep->ServerName, sizeof(keep->ServerName), t->KeepConnectHost);
+ keep->ServerPort = t->KeepConnectPort;
+ keep->UdpMode = t->KeepConnectProtocol;
+ keep->Interval = t->KeepConnectInterval * 1000;
+ if (keep->Interval < 5000)
+ {
+ keep->Interval = 5000;
+ }
+ else if (keep->Interval > 600000)
+ {
+ keep->Interval = 600000;
+ }
+ }
+ Unlock(s->Keep->lock);
+
+ ALog(a, NULL, "LA_SET_KEEP");
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get keep-alive function setting
+UINT StGetKeep(ADMIN *a, RPC_KEEP *t)
+{
+ SERVER *s = a->Server;
+
+ Zero(t, sizeof(RPC_KEEP));
+
+ Lock(s->Keep->lock);
+ {
+ KEEP *k = s->Keep;
+ t->UseKeepConnect = k->Enable;
+ StrCpy(t->KeepConnectHost, sizeof(t->KeepConnectHost), k->ServerName);
+ t->KeepConnectPort = k->ServerPort;
+ t->KeepConnectProtocol = k->UdpMode;
+ t->KeepConnectInterval = k->Interval / 1000;
+ }
+ Unlock(s->Keep->lock);
+
+ return ERR_NO_ERROR;
+}
+
+// Delete IP address table entry
+UINT StDeleteIpTable(ADMIN *a, RPC_DELETE_TABLE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_delete_iptable") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ LockList(h->IpTable);
+ {
+ if (IsInListKey(h->IpTable, t->Key))
+ {
+ IP_TABLE_ENTRY *e = ListKeyToPointer(h->IpTable, t->Key);
+ Free(e);
+ Delete(h->IpTable, e);
+ }
+ else
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ }
+ UnlockList(h->IpTable);
+
+ if (ret == ERR_OBJECT_NOT_FOUND)
+ {
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ UINT i;
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ if (f->Me == false)
+ {
+ SiCallDeleteIpTable(s, f, t->HubName, t->Key);
+ ret = ERR_NO_ERROR;
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+ }
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Get local IP address table
+UINT SiEnumIpTable(SERVER *s, char *hubname, RPC_ENUM_IP_TABLE *t)
+{
+ CEDAR *c;
+ UINT i;
+ HUB *h = NULL;
+ // Validate arguments
+ if (s == NULL || hubname == NULL || t == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ c = s->Cedar;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, hubname);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ LockList(h->IpTable);
+ {
+ t->NumIpTable = LIST_NUM(h->IpTable);
+ t->IpTables = ZeroMalloc(sizeof(RPC_ENUM_IP_TABLE_ITEM) * t->NumIpTable);
+
+ for (i = 0;i < t->NumIpTable;i++)
+ {
+ RPC_ENUM_IP_TABLE_ITEM *e = &t->IpTables[i];
+ IP_TABLE_ENTRY *table = LIST_DATA(h->IpTable, i);
+
+ e->Key = POINTER_TO_KEY(table);
+ StrCpy(e->SessionName, sizeof(e->SessionName), table->Session->Name);
+ e->Ip = IPToUINT(&table->Ip);
+ Copy(&e->IpV6, &table->Ip, sizeof(IP));
+ e->DhcpAllocated = table->DhcpAllocated;
+ e->CreatedTime = TickToTime(table->CreatedTime);
+ e->UpdatedTime = TickToTime(table->UpdatedTime);
+
+ GetMachineName(e->RemoteHostname, sizeof(e->RemoteHostname));
+ }
+ }
+ UnlockList(h->IpTable);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Get IP address table
+UINT StEnumIpTable(ADMIN *a, RPC_ENUM_IP_TABLE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT i;
+
+ CHECK_RIGHT;
+
+ // Get local IP address table
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ FreeRpcEnumIpTable(t);
+ Zero(t, sizeof(RPC_ENUM_IP_TABLE));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ ret = SiEnumIpTable(s, hubname, t);
+ if (ret != ERR_NO_ERROR)
+ {
+ return ret;
+ }
+
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ // Get remote IP address table
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ if (f->Me == false)
+ {
+ RPC_ENUM_IP_TABLE tmp;
+
+ Zero(&tmp, sizeof(tmp));
+
+ SiCallEnumIpTable(s, f, hubname, &tmp);
+
+ AdjoinRpcEnumIpTable(t, &tmp);
+ FreeRpcEnumIpTable(&tmp);
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+
+ return ret;
+}
+
+// Delete MAC address table entry
+UINT StDeleteMacTable(ADMIN *a, RPC_DELETE_TABLE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_delete_mactable") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ LockList(h->MacTable);
+ {
+ if (IsInListKey(h->MacTable, t->Key))
+ {
+ MAC_TABLE_ENTRY *e = ListKeyToPointer(h->MacTable, t->Key);
+ Free(e);
+ Delete(h->MacTable, e);
+ }
+ else
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ }
+ UnlockList(h->MacTable);
+
+ if (ret == ERR_OBJECT_NOT_FOUND)
+ {
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ UINT i;
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ if (f->Me == false)
+ {
+ SiCallDeleteMacTable(s, f, t->HubName, t->Key);
+ ret = ERR_NO_ERROR;
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+ }
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Get local MAC address table
+UINT SiEnumMacTable(SERVER *s, char *hubname, RPC_ENUM_MAC_TABLE *t)
+{
+ CEDAR *c;
+ UINT i;
+ HUB *h = NULL;
+ // Validate arguments
+ if (s == NULL || hubname == NULL || t == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ c = s->Cedar;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, hubname);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ LockList(h->MacTable);
+ {
+ t->NumMacTable = LIST_NUM(h->MacTable);
+ t->MacTables = ZeroMalloc(sizeof(RPC_ENUM_MAC_TABLE_ITEM) * t->NumMacTable);
+
+ for (i = 0;i < t->NumMacTable;i++)
+ {
+ RPC_ENUM_MAC_TABLE_ITEM *e = &t->MacTables[i];
+ MAC_TABLE_ENTRY *mac = LIST_DATA(h->MacTable, i);
+
+ e->Key = POINTER_TO_KEY(mac);
+ StrCpy(e->SessionName, sizeof(e->SessionName), mac->Session->Name);
+ Copy(e->MacAddress, mac->MacAddress, sizeof(e->MacAddress));
+ e->CreatedTime = TickToTime(mac->CreatedTime);
+ e->UpdatedTime = TickToTime(mac->UpdatedTime);
+ e->VlanId = mac->VlanId;
+
+ GetMachineName(e->RemoteHostname, sizeof(e->RemoteHostname));
+ }
+ }
+ UnlockList(h->MacTable);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Get MAC address table
+UINT StEnumMacTable(ADMIN *a, RPC_ENUM_MAC_TABLE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT i;
+
+ CHECK_RIGHT;
+
+ // Get local MAC address table
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ FreeRpcEnumMacTable(t);
+ Zero(t, sizeof(RPC_ENUM_MAC_TABLE));
+
+ ret = SiEnumMacTable(s, hubname, t);
+ if (ret != ERR_NO_ERROR)
+ {
+ return ret;
+ }
+
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ // Get remote MAC address table
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ if (f->Me == false)
+ {
+ RPC_ENUM_MAC_TABLE tmp;
+
+ Zero(&tmp, sizeof(tmp));
+
+ SiCallEnumMacTable(s, f, hubname, &tmp);
+
+ AdjoinRpcEnumMacTable(t, &tmp);
+ FreeRpcEnumMacTable(&tmp);
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+
+ return ret;
+}
+
+// Delete a session
+UINT StDeleteSession(ADMIN *a, RPC_DELETE_SESSION *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ char name[MAX_SESSION_NAME_LEN + 1];
+ SESSION *sess;
+
+ if (IsEmptyStr(t->Name))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ StrCpy(name, sizeof(name), t->Name);
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_disconnect_session") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ sess = GetSessionByName(h, name);
+
+ if (sess == NULL)
+ {
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ // Cluster controller
+ UINT i;
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ if (f->Me == false)
+ {
+ // Try to disconnect
+ SiCallDeleteSession(s, f, t->HubName, t->Name);
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+ else
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ }
+ else
+ {
+ if (sess->LinkModeServer)
+ {
+ ret = ERR_LINK_CANT_DISCONNECT;
+ }
+ else if (sess->SecureNATMode)
+ {
+ ret = ERR_SNAT_CANT_DISCONNECT;
+ }
+ else if (sess->BridgeMode)
+ {
+ ret = ERR_BRIDGE_CANT_DISCONNECT;
+ }
+ else if (sess->L3SwitchMode)
+ {
+ ret = ERR_LAYER3_CANT_DISCONNECT;
+ }
+ else
+ {
+ StopSession(sess);
+ }
+ ReleaseSession(sess);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ ALog(a, h, "LA_DELETE_SESSION", t->Name);
+ }
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Get session status
+UINT StGetSessionStatus(ADMIN *a, RPC_SESSION_STATUS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ char name[MAX_SESSION_NAME_LEN + 1];
+ SESSION *sess;
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ StrCpy(name, sizeof(name), t->Name);
+
+ if (IsEmptyStr(t->Name))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_query_session") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ FreeRpcSessionStatus(t);
+ Zero(t, sizeof(RPC_SESSION_STATUS));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+ StrCpy(t->Name, sizeof(t->Name), name);
+
+ sess = GetSessionByName(h, t->Name);
+
+ if (sess == NULL)
+ {
+ if (s->ServerType != SERVER_TYPE_FARM_CONTROLLER)
+ {
+ // Session is not found
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ else
+ {
+ UINT i;
+ // Try to find the session on other cluster member
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ if (f->Me == false)
+ {
+ RPC_SESSION_STATUS tmp;
+ Zero(&tmp, sizeof(tmp));
+ StrCpy(tmp.HubName, sizeof(tmp.HubName), t->HubName);
+ StrCpy(tmp.Name, sizeof(tmp.Name), t->Name);
+
+ if (SiCallGetSessionStatus(s, f, &tmp))
+ {
+ if (StrLen(tmp.HubName) != 0)
+ {
+ // Success to get session status
+ Copy(t, &tmp, sizeof(RPC_SESSION_STATUS));
+ break;
+ }
+ else
+ {
+ FreeRpcSessionStatus(&tmp);
+ }
+ }
+ }
+ }
+
+ if (i == LIST_NUM(s->FarmMemberList))
+ {
+ // not found after all
+ //
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+ }
+ else
+ {
+ SESSION *s = sess;
+
+ Lock(s->lock);
+ {
+ StrCpy(t->Username, sizeof(t->Username), s->Username);
+ StrCpy(t->RealUsername, sizeof(t->RealUsername), s->UserNameReal);
+ StrCpy(t->GroupName, sizeof(t->GroupName), s->GroupName);
+ Copy(&t->NodeInfo, &s->NodeInfo, sizeof(NODE_INFO));
+
+ if (s->Connection != NULL)
+ {
+ t->ClientIp = IPToUINT(&s->Connection->ClientIp);
+ if (IsIP6(&s->Connection->ClientIp))
+ {
+ Copy(&t->ClientIp6, &s->Connection->ClientIp.ipv6_addr, sizeof(t->ClientIp6));
+ }
+
+ StrCpy(t->ClientHostName, sizeof(t->ClientHostName), s->Connection->ClientHostname);
+ }
+ }
+ Unlock(s->lock);
+
+ CiGetSessionStatus(&t->Status, s);
+
+ ReleaseSession(s);
+ }
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Main routine of session enumeration
+void SiEnumSessionMain(SERVER *s, RPC_ENUM_SESSION *t)
+{
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT ret = ERR_NO_ERROR;
+ UINT num;
+ UINT i;
+ // Validate arguments
+ if (s == NULL || t == NULL)
+ {
+ return;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ FreeRpcEnumSession(t);
+ Zero(t, sizeof(RPC_ENUM_SESSION));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ // Local session enumeration
+ num = 0;
+ SiEnumLocalSession(s, hubname, t);
+
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ LIST *fm_list;
+
+ fm_list = NewListFast(NULL);
+
+ // Remote session enumeration
+ LockList(s->FarmMemberList);
+ {
+ while (true)
+ {
+ bool escape = true;
+
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+
+ if (IsInList(fm_list, f) == false)
+ {
+ Add(fm_list, f);
+ escape = false;
+
+ if (f->Me == false)
+ {
+ RPC_ENUM_SESSION tmp;
+
+ Zero(&tmp, sizeof(tmp));
+
+ SiCallEnumSession(s, f, hubname, &tmp);
+
+ AdjoinRpcEnumSession(t, &tmp);
+ FreeRpcEnumSession(&tmp);
+ }
+
+ break;
+ }
+ }
+
+ if (escape)
+ {
+ break;
+ }
+
+ UnlockList(s->FarmMemberList);
+ LockList(s->FarmMemberList);
+ }
+ }
+ UnlockList(s->FarmMemberList);
+
+ ReleaseList(fm_list);
+ }
+}
+
+// Enumerate sessions
+UINT StEnumSession(ADMIN *a, RPC_ENUM_SESSION *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_enum_session") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ SiEnumSessionMain(s, t);
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Enumerate groups
+UINT StEnumGroup(ADMIN *a, RPC_ENUM_GROUP *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ CHECK_RIGHT;
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ AcLock(h);
+ {
+ UINT i, j;
+
+ FreeRpcEnumGroup(t);
+ Zero(t, sizeof(RPC_ENUM_GROUP));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ t->NumGroup = LIST_NUM(h->HubDb->GroupList);
+ t->Groups = ZeroMalloc(sizeof(RPC_ENUM_GROUP_ITEM) * t->NumGroup);
+
+ for (i = 0;i < t->NumGroup;i++)
+ {
+ RPC_ENUM_GROUP_ITEM *e = &t->Groups[i];
+ USERGROUP *g = LIST_DATA(h->HubDb->GroupList, i);
+
+ Lock(g->lock);
+ {
+ StrCpy(e->Name, sizeof(e->Name), g->Name);
+ UniStrCpy(e->Realname, sizeof(e->Realname), g->RealName);
+ UniStrCpy(e->Note, sizeof(e->Note), g->Note);
+ if (g->Policy != NULL)
+ {
+ if (g->Policy->Access == false)
+ {
+ e->DenyAccess = true;
+ }
+ }
+ }
+ Unlock(g->lock);
+
+ e->NumUsers = 0;
+
+
+ LockList(h->HubDb->UserList);
+ {
+ for (j = 0;j < LIST_NUM(h->HubDb->UserList);j++)
+ {
+ USER *u = LIST_DATA(h->HubDb->UserList, j);
+
+ Lock(u->lock);
+ {
+ if (u->Group == g)
+ {
+ e->NumUsers++;
+ }
+ }
+ Unlock(u->lock);
+ }
+ }
+ UnlockList(h->HubDb->UserList);
+ }
+ }
+ AcUnlock(h);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Delete a group
+UINT StDeleteGroup(ADMIN *a, RPC_DELETE_USER *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+
+ if (IsEmptyStr(t->Name) || IsSafeStr(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ CHECK_RIGHT;
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_groups") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ AcLock(h);
+ {
+ if (AcDeleteGroup(h, t->Name) == false)
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ }
+ AcUnlock(h);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ ALog(a, h, "LA_DELETE_GROUP", t->Name);
+ }
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ret;
+}
+
+// Get group information
+UINT StGetGroup(ADMIN *a, RPC_SET_GROUP *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ if (IsEmptyStr(t->Name) || IsSafeStr(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ AcLock(h);
+ {
+ USERGROUP *g = AcGetGroup(h, t->Name);
+
+ if (g == NULL)
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ else
+ {
+ FreeRpcSetGroup(t);
+ Zero(t, sizeof(RPC_SET_GROUP));
+
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ Lock(g->lock);
+ {
+ StrCpy(t->Name, sizeof(t->Name), g->Name);
+ UniStrCpy(t->Realname, sizeof(t->Realname), g->RealName);
+ UniStrCpy(t->Note, sizeof(t->Note), g->Note);
+ Copy(&t->Traffic, g->Traffic, sizeof(TRAFFIC));
+ }
+ Unlock(g->lock);
+
+ t->Policy = GetGroupPolicy(g);
+
+ ReleaseGroup(g);
+ }
+ }
+ AcUnlock(h);
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Set group setting
+UINT StSetGroup(ADMIN *a, RPC_SET_GROUP *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+
+ if (IsEmptyStr(t->Name) || IsSafeStr(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_groups") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ AcLock(h);
+ {
+ USERGROUP *g = AcGetGroup(h, t->Name);
+ if (g == NULL)
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ else
+ {
+ Lock(g->lock);
+ {
+ Free(g->RealName);
+ Free(g->Note);
+ g->RealName = UniCopyStr(t->Realname);
+ g->Note = UniCopyStr(t->Note);
+ }
+ Unlock(g->lock);
+
+ SetGroupPolicy(g, t->Policy);
+
+ ReleaseGroup(g);
+
+ ALog(a, h, "LA_SET_GROUP", t->Name);
+ }
+ }
+ AcUnlock(h);
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ret;
+}
+
+// Create a group
+UINT StCreateGroup(ADMIN *a, RPC_SET_GROUP *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+
+ if (IsEmptyStr(t->Name) || IsSafeStr(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ CHECK_RIGHT;
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_groups") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ AcLock(h);
+ {
+ if (AcIsGroup(h, t->Name))
+ {
+ ret = ERR_GROUP_ALREADY_EXISTS;
+ }
+ else
+ {
+ USERGROUP *g = NewGroup(t->Name, t->Realname, t->Note);
+ SetGroupPolicy(g, t->Policy);
+
+ if ((LIST_NUM(h->HubDb->GroupList) >= GetServerCapsInt(a->Server, "i_max_users_per_hub")) ||
+ ((GetHubAdminOption(h, "max_groups") != 0) && (LIST_NUM(h->HubDb->GroupList) >= GetHubAdminOption(h, "max_groups"))))
+ {
+ ret = ERR_TOO_MANY_GROUP;
+ }
+ else
+ {
+ AcAddGroup(h, g);
+ }
+
+ ReleaseGroup(g);
+
+ ALog(a, h, "LA_CREATE_GROUP", t->Name);
+ }
+ }
+ AcUnlock(h);
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ret;
+}
+
+// Enumerate users
+UINT StEnumUser(ADMIN *a, RPC_ENUM_USER *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT i, num;
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ FreeRpcEnumUser(t);
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ Zero(t, sizeof(RPC_ENUM_USER));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ LockList(h->HubDb->UserList);
+ {
+ num = LIST_NUM(h->HubDb->UserList);
+
+ t->NumUser = num;
+ t->Users = ZeroMalloc(sizeof(RPC_ENUM_USER_ITEM) * num);
+
+ for (i = 0;i < num;i++)
+ {
+ USER *u = LIST_DATA(h->HubDb->UserList, i);
+
+ Lock(u->lock);
+ {
+ RPC_ENUM_USER_ITEM *e = &t->Users[i];
+
+ StrCpy(e->Name, sizeof(e->Name), u->Name);
+ StrCpy(e->GroupName, sizeof(e->GroupName), u->GroupName);
+ UniStrCpy(e->Realname, sizeof(e->Realname), u->RealName);
+ UniStrCpy(e->Note, sizeof(e->Note), u->Note);
+ e->AuthType = u->AuthType;
+ e->LastLoginTime = u->LastLoginTime;
+ e->NumLogin = u->NumLogin;
+
+ if (u->Policy != NULL)
+ {
+ e->DenyAccess = u->Policy->Access ? false : true;
+ }
+
+ Copy(&e->Traffic, u->Traffic, sizeof(TRAFFIC));
+ e->IsTrafficFilled = true;
+
+ e->Expires = u->ExpireTime;
+ e->IsExpiresFilled = true;
+ }
+ Unlock(u->lock);
+ }
+ }
+ UnlockList(h->HubDb->UserList);
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Delete a user
+UINT StDeleteUser(ADMIN *a, RPC_DELETE_USER *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+
+
+ if (IsEmptyStr(t->Name) || IsUserName(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_users") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ ALog(a, h, "LA_DELETE_USER", t->Name);
+
+ AcLock(h);
+ {
+ if (AcDeleteUser(h, t->Name) == false)
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ }
+ AcUnlock(h);
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ret;
+}
+
+// Get user setting
+UINT StGetUser(ADMIN *a, RPC_SET_USER *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+ USER *u = NULL;
+ USERGROUP *g = NULL;
+ char name[MAX_USERNAME_LEN + 1];
+ char hubname[MAX_HUBNAME_LEN + 1];
+ StrCpy(name, sizeof(name), t->Name);
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ if (IsEmptyStr(t->Name) || IsUserName(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ FreeRpcSetUser(t);
+ Zero(t, sizeof(RPC_SET_USER));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+ StrCpy(t->Name, sizeof(t->Name), name);
+
+ LockHubList(c);
+ {
+ h = GetHub(c, hubname);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ AcLock(h);
+ {
+ u = AcGetUser(h, name);
+ if (u == NULL)
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ else
+ {
+ Lock(u->lock);
+ {
+ StrCpy(t->GroupName, sizeof(t->GroupName), u->GroupName);
+ UniStrCpy(t->Realname, sizeof(t->Realname), u->RealName);
+ UniStrCpy(t->Note, sizeof(t->Note), u->Note);
+ t->CreatedTime = u->CreatedTime;
+ t->UpdatedTime = u->UpdatedTime;
+ t->ExpireTime = u->ExpireTime;
+
+ t->AuthType = u->AuthType;
+ t->AuthData = CopyAuthData(u->AuthData, t->AuthType);
+ t->NumLogin = u->NumLogin;
+ Copy(&t->Traffic, u->Traffic, sizeof(TRAFFIC));
+ if (u->Policy != NULL)
+ {
+ t->Policy = ClonePolicy(u->Policy);
+ }
+ }
+ Unlock(u->lock);
+
+ ReleaseUser(u);
+ }
+ }
+ AcUnlock(h);
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Set user setting
+UINT StSetUser(ADMIN *a, RPC_SET_USER *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+ USER *u = NULL;
+ USERGROUP *g = NULL;
+
+
+ if (IsEmptyStr(t->Name) || IsUserName(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ if (t->AuthType == AUTHTYPE_USERCERT || t->AuthType == AUTHTYPE_RADIUS || t->AuthType == AUTHTYPE_ROOTCERT || t->AuthType == AUTHTYPE_NT)
+ {
+ return ERR_NOT_SUPPORTED_AUTH_ON_OPENSOURCE;
+ }
+
+ if (StrCmpi(t->Name, "*") == 0)
+ {
+ if (t->AuthType != AUTHTYPE_RADIUS && t->AuthType != AUTHTYPE_NT)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+
+ if (t->AuthType == AUTHTYPE_USERCERT)
+ {
+ AUTHUSERCERT *c = t->AuthData;
+ if (c != NULL && c->UserX != NULL &&
+ c->UserX->is_compatible_bit == false)
+ {
+ return ERR_NOT_RSA_1024;
+ }
+ if (c == NULL || c->UserX == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_users") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ AcLock(h);
+ {
+ u = AcGetUser(h, t->Name);
+ if (u == NULL)
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ else
+ {
+ Lock(u->lock);
+ {
+ if (StrLen(t->GroupName) != 0)
+ {
+ g = AcGetGroup(h, t->GroupName);
+
+ if (g != NULL)
+ {
+ JoinUserToGroup(u, g);
+ ReleaseGroup(g);
+ }
+ else
+ {
+ ret = ERR_GROUP_NOT_FOUND;
+ }
+ }
+ else
+ {
+ JoinUserToGroup(u, NULL);
+ }
+
+ if (ret != ERR_GROUP_NOT_FOUND)
+ {
+ Free(u->RealName);
+ Free(u->Note);
+ u->RealName = UniCopyStr(t->Realname);
+ u->Note = UniCopyStr(t->Note);
+ SetUserAuthData(u, t->AuthType, CopyAuthData(t->AuthData, t->AuthType));
+ u->ExpireTime = t->ExpireTime;
+ u->UpdatedTime = SystemTime64();
+
+ SetUserPolicy(u, t->Policy);
+ }
+ }
+ Unlock(u->lock);
+
+ IncrementServerConfigRevision(s);
+
+ ReleaseUser(u);
+ }
+ }
+ AcUnlock(h);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ ALog(a, h, "LA_SET_USER", t->Name);
+ }
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Create a user
+UINT StCreateUser(ADMIN *a, RPC_SET_USER *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+ USER *u;
+ USERGROUP *g = NULL;
+
+
+ if (IsEmptyStr(t->Name) || IsUserName(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ if (t->AuthType == AUTHTYPE_USERCERT || t->AuthType == AUTHTYPE_RADIUS || t->AuthType == AUTHTYPE_ROOTCERT || t->AuthType == AUTHTYPE_NT)
+ {
+ return ERR_NOT_SUPPORTED_AUTH_ON_OPENSOURCE;
+ }
+
+ if (t->AuthType == AUTHTYPE_USERCERT)
+ {
+ AUTHUSERCERT *c = t->AuthData;
+ if (c != NULL && c->UserX != NULL &&
+ c->UserX->is_compatible_bit == false)
+ {
+ return ERR_NOT_RSA_1024;
+ }
+ if (c == NULL || c->UserX == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+
+ if (IsUserName(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (StrCmpi(t->Name, "*") == 0)
+ {
+ if (t->AuthType != AUTHTYPE_RADIUS && t->AuthType != AUTHTYPE_NT)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_users") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ u = NewUser(t->Name, t->Realname, t->Note, t->AuthType, CopyAuthData(t->AuthData, t->AuthType));
+ if (u == NULL)
+ {
+ ReleaseHub(h);
+ return ERR_INTERNAL_ERROR;
+ }
+
+ u->ExpireTime = t->ExpireTime;
+
+ SetUserPolicy(u, t->Policy);
+
+ AcLock(h);
+ {
+ if ((LIST_NUM(h->HubDb->UserList) >= GetServerCapsInt(a->Server, "i_max_users_per_hub")) ||
+ ((GetHubAdminOption(h, "max_users") != 0) && (LIST_NUM(h->HubDb->UserList) >= GetHubAdminOption(h, "max_users"))))
+ {
+ ret = ERR_TOO_MANY_USER;
+ }
+ else if (SiTooManyUserObjectsInServer(s, false))
+ {
+ ret = ERR_TOO_MANY_USERS_CREATED;
+ ALog(a, h, "ERR_128");
+ }
+ else if (AcIsUser(h, t->Name))
+ {
+ ret = ERR_USER_ALREADY_EXISTS;
+ }
+ else
+ {
+ if (StrLen(t->GroupName) != 0)
+ {
+ g = AcGetGroup(h, t->GroupName);
+ if (g == NULL)
+ {
+ ret = ERR_GROUP_NOT_FOUND;
+ }
+ }
+
+ if (ret != ERR_GROUP_NOT_FOUND)
+ {
+ if (g != NULL)
+ {
+ JoinUserToGroup(u, g);
+ ReleaseGroup(g);
+ }
+
+ AcAddUser(h, u);
+ ALog(a, h, "LA_CREATE_USER", t->Name);
+
+ IncrementServerConfigRevision(s);
+ }
+ }
+ }
+ AcUnlock(h);
+
+ ReleaseUser(u);
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Get access list
+UINT StEnumAccess(ADMIN *a, RPC_ENUM_ACCESS_LIST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT i;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ FreeRpcEnumAccessList(t);
+ Zero(t, sizeof(RPC_ENUM_ACCESS_LIST));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ LockList(h->AccessList);
+ {
+ t->NumAccess = LIST_NUM(h->AccessList);
+ t->Accesses = ZeroMalloc(sizeof(ACCESS) * t->NumAccess);
+
+ for (i = 0;i < LIST_NUM(h->AccessList);i++)
+ {
+ ACCESS *a = &t->Accesses[i];
+ Copy(a, LIST_DATA(h->AccessList, i), sizeof(ACCESS));
+ a->UniqueId = HashPtrToUINT(LIST_DATA(h->AccessList, i));
+ }
+ }
+ UnlockList(h->AccessList);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Delete access list entry
+UINT StDeleteAccess(ADMIN *a, RPC_DELETE_ACCESS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT i;
+ bool exists;
+
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_access_list") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ exists = false;
+
+ LockList(h->AccessList);
+ {
+ for (i = 0;i < LIST_NUM(h->AccessList);i++)
+ {
+ ACCESS *access = LIST_DATA(h->AccessList, i);
+
+ if ((t->Id < MAX_ACCESSLISTS && access->Id == t->Id) ||
+ (t->Id >= MAX_ACCESSLISTS && HashPtrToUINT(access) == t->Id))
+ {
+ Free(access);
+ Delete(h->AccessList, access);
+ exists = true;
+
+ break;
+ }
+ }
+ }
+ UnlockList(h->AccessList);
+
+ if (exists == false)
+ {
+ ReleaseHub(h);
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ ALog(a, h, "LA_DELETE_ACCESS");
+
+ IncrementServerConfigRevision(s);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Set access list
+UINT StSetAccessList(ADMIN *a, RPC_ENUM_ACCESS_LIST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT i;
+ bool no_jitter = false;
+ bool no_include = false;
+ UINT ret = ERR_NO_ERROR;
+
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ if (t->NumAccess > GetServerCapsInt(a->Server, "i_max_access_lists"))
+ {
+ return ERR_TOO_MANY_ACCESS_LIST;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ no_jitter = GetHubAdminOption(h, "no_delay_jitter_packet_loss");
+ no_include = GetHubAdminOption(h, "no_access_list_include_file");
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_access_list") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "max_accesslists") != 0 &&
+ t->NumAccess > GetHubAdminOption(h, "max_accesslists"))
+ {
+ ReleaseHub(h);
+ return ERR_TOO_MANY_ACCESS_LIST;
+ }
+
+ LockList(h->AccessList);
+ {
+ UINT i;
+
+ // Confirm whether the access list of form which cannot handle by the old client already exists
+ if (a->ClientBuild < 6560)
+ {
+ for (i = 0;i < LIST_NUM(h->AccessList);i++)
+ {
+ ACCESS *access = LIST_DATA(h->AccessList, i);
+ if (access->IsIPv6 ||
+ access->Jitter != 0 || access->Loss != 0 || access->Delay != 0)
+ {
+ ret = ERR_VERSION_INVALID;
+ break;
+ }
+ }
+ }
+
+ if (a->ClientBuild < 8234)
+ {
+ for (i = 0;i < LIST_NUM(h->AccessList);i++)
+ {
+ ACCESS *access = LIST_DATA(h->AccessList, i);
+
+ if (IsEmptyStr(access->RedirectUrl) == false)
+ {
+ ret = ERR_VERSION_INVALID;
+ break;
+ }
+ }
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Delete whole access list
+ for (i = 0;i < LIST_NUM(h->AccessList);i++)
+ {
+ ACCESS *access = LIST_DATA(h->AccessList, i);
+ Free(access);
+ }
+
+ DeleteAll(h->AccessList);
+ }
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ ALog(a, h, "LA_SET_ACCESS_LIST", t->NumAccess);
+
+ // Add whole access list
+ for (i = 0;i < t->NumAccess;i++)
+ {
+ ACCESS *a = &t->Accesses[i];
+
+ if (no_jitter)
+ {
+ a->Jitter = a->Loss = a->Delay = 0;
+ }
+
+ if (no_include)
+ {
+ if (StartWith(a->SrcUsername, ACCESS_LIST_INCLUDED_PREFIX) ||
+ StartWith(a->SrcUsername, ACCESS_LIST_EXCLUDED_PREFIX))
+ {
+ ClearStr(a->SrcUsername, sizeof(a->SrcUsername));
+ }
+
+ if (StartWith(a->DestUsername, ACCESS_LIST_INCLUDED_PREFIX) ||
+ StartWith(a->DestUsername, ACCESS_LIST_EXCLUDED_PREFIX))
+ {
+ ClearStr(a->DestUsername, sizeof(a->DestUsername));
+ }
+ }
+
+ if (i == (t->NumAccess - 1))
+ {
+ Sort(h->AccessList);
+ }
+
+ AddAccessListEx(h, a, ((i != (t->NumAccess - 1)) ? true : false), ((i != (t->NumAccess - 1)) ? true : false));
+ }
+
+ UnlockList(h->AccessList);
+
+ IncrementServerConfigRevision(s);
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+ }
+ else
+ {
+ UnlockList(h->AccessList);
+ }
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Add access list entry
+UINT StAddAccess(ADMIN *a, RPC_ADD_ACCESS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ bool no_jitter = false;
+ bool no_include = false;
+
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ no_jitter = GetHubAdminOption(h, "no_delay_jitter_packet_loss");
+ no_include = GetHubAdminOption(h, "no_access_list_include_file");
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_access_list") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ if ((LIST_NUM(h->AccessList) >= GetServerCapsInt(a->Server, "i_max_access_lists") ||
+ (GetHubAdminOption(h, "max_accesslists") != 0) && (LIST_NUM(h->AccessList) >= GetHubAdminOption(h, "max_accesslists"))))
+ {
+ ReleaseHub(h);
+ return ERR_TOO_MANY_ACCESS_LIST;
+ }
+
+ ALog(a, h, "LA_ADD_ACCESS");
+
+ if (no_jitter)
+ {
+ t->Access.Jitter = t->Access.Delay = t->Access.Loss = 0;
+ }
+
+ if (no_include)
+ {
+ if (no_include)
+ {
+ if (StartWith(t->Access.SrcUsername, ACCESS_LIST_INCLUDED_PREFIX) ||
+ StartWith(t->Access.SrcUsername, ACCESS_LIST_EXCLUDED_PREFIX))
+ {
+ ClearStr(t->Access.SrcUsername, sizeof(t->Access.SrcUsername));
+ }
+
+ if (StartWith(t->Access.DestUsername, ACCESS_LIST_INCLUDED_PREFIX) ||
+ StartWith(t->Access.DestUsername, ACCESS_LIST_EXCLUDED_PREFIX))
+ {
+ ClearStr(t->Access.DestUsername, sizeof(t->Access.DestUsername));
+ }
+ }
+ }
+
+ AddAccessList(h, &t->Access);
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Rename link (cascade connection)
+UINT StRenameLink(ADMIN *a, RPC_RENAME_LINK *t)
+{
+ UINT i;
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ LINK *k;
+ bool exists = false;
+
+ if (UniIsEmptyStr(t->OldAccountName) || UniIsEmptyStr(t->NewAccountName))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ if (UniStrCmpi(t->NewAccountName, t->OldAccountName) == 0)
+ {
+ // Noop if new name is same to old name
+ return ERR_NO_ERROR;
+ }
+
+ h = GetHub(c, t->HubName);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_cascade") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ k = NULL;
+
+ // Find specified link
+ LockList(h->LinkList);
+ {
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *kk = LIST_DATA(h->LinkList, i);
+ Lock(kk->lock);
+ {
+ if (UniStrCmpi(kk->Option->AccountName, t->OldAccountName) == 0)
+ {
+ k = kk;
+ AddRef(kk->ref);
+ }
+ }
+ Unlock(kk->lock);
+
+ if (k != NULL)
+ {
+ break;
+ }
+ }
+
+ exists = false;
+
+ if (k != NULL)
+ {
+ // Check whether the new link name is same to other links
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *kk = LIST_DATA(h->LinkList, i);
+ Lock(kk->lock);
+ {
+ if (UniStrCmpi(kk->Option->AccountName, t->NewAccountName) == 0)
+ {
+ // duplicated
+ exists = true;
+ }
+ }
+ Unlock(kk->lock);
+ }
+
+ if (exists)
+ {
+ // Already same name exists
+ ret = ERR_LINK_ALREADY_EXISTS;
+ }
+ else
+ {
+ // Do rename
+ UniStrCpy(k->Option->AccountName, sizeof(k->Option->AccountName), t->NewAccountName);
+
+ ALog(a, h, "LA_RENAME_LINK", t->OldAccountName, t->NewAccountName);
+
+ IncrementServerConfigRevision(s);
+ }
+ }
+ }
+ UnlockList(h->LinkList);
+
+ if (k == NULL)
+ {
+ // specified link is not found
+ ReleaseHub(h);
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ ReleaseLink(k);
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Delete a link
+UINT StDeleteLink(ADMIN *a, RPC_LINK *t)
+{
+ UINT i;
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ wchar_t accountname[MAX_ACCOUNT_NAME_LEN + 1];
+ LINK *k;
+
+ if (UniIsEmptyStr(t->AccountName))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_cascade") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ UniStrCpy(accountname, sizeof(accountname), t->AccountName);
+ k = NULL;
+
+ // Find specified link
+ LockList(h->LinkList);
+ {
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *kk = LIST_DATA(h->LinkList, i);
+ Lock(kk->lock);
+ {
+ if (UniStrCmpi(kk->Option->AccountName, accountname) == 0)
+ {
+ k = kk;
+ AddRef(kk->ref);
+ }
+ }
+ Unlock(kk->lock);
+
+ if (k != NULL)
+ {
+ break;
+ }
+ }
+ }
+ UnlockList(h->LinkList);
+
+ if (k == NULL)
+ {
+ // Specified link is not found
+ ReleaseHub(h);
+
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ ALog(a, h, "LA_DELETE_LINK", t->AccountName);
+
+ SetLinkOffline(k);
+
+ IncrementServerConfigRevision(s);
+
+ DelLink(h, k);
+
+ ReleaseLink(k);
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Make a link into off-line
+UINT StSetLinkOffline(ADMIN *a, RPC_LINK *t)
+{
+ UINT i;
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ wchar_t accountname[MAX_ACCOUNT_NAME_LEN + 1];
+ LINK *k;
+
+
+ if (UniIsEmptyStr(t->AccountName))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_cascade") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ UniStrCpy(accountname, sizeof(accountname), t->AccountName);
+ k = NULL;
+
+ // Find specified link
+ LockList(h->LinkList);
+ {
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *kk = LIST_DATA(h->LinkList, i);
+ Lock(kk->lock);
+ {
+ if (UniStrCmpi(kk->Option->AccountName, accountname) == 0)
+ {
+ k = kk;
+ AddRef(kk->ref);
+ }
+ }
+ Unlock(kk->lock);
+
+ if (k != NULL)
+ {
+ break;
+ }
+ }
+ }
+ UnlockList(h->LinkList);
+
+ if (k == NULL)
+ {
+ // Link is not found
+ ReleaseHub(h);
+
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ ALog(a, h, "LA_SET_LINK_OFFLINE", t->AccountName);
+
+ SetLinkOffline(k);
+
+ IncrementServerConfigRevision(s);
+
+ ReleaseLink(k);
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Make a link into on-line
+UINT StSetLinkOnline(ADMIN *a, RPC_LINK *t)
+{
+ UINT i;
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ wchar_t accountname[MAX_ACCOUNT_NAME_LEN + 1];
+ LINK *k;
+
+
+ if (UniIsEmptyStr(t->AccountName))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_cascade") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ UniStrCpy(accountname, sizeof(accountname), t->AccountName);
+ k = NULL;
+
+ // Find specified link
+ LockList(h->LinkList);
+ {
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *kk = LIST_DATA(h->LinkList, i);
+ Lock(kk->lock);
+ {
+ if (UniStrCmpi(kk->Option->AccountName, accountname) == 0)
+ {
+ k = kk;
+ AddRef(kk->ref);
+ }
+ }
+ Unlock(kk->lock);
+
+ if (k != NULL)
+ {
+ break;
+ }
+ }
+ }
+ UnlockList(h->LinkList);
+
+ if (k == NULL)
+ {
+ // Specified link is not found
+ ReleaseHub(h);
+
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ ALog(a, h, "LA_SET_LINK_ONLINE", t->AccountName);
+
+ SetLinkOnline(k);
+
+ ReleaseLink(k);
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ret;
+}
+
+// Get link status
+UINT StGetLinkStatus(ADMIN *a, RPC_LINK_STATUS *t)
+{
+ UINT i;
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ wchar_t accountname[MAX_ACCOUNT_NAME_LEN + 1];
+ LINK *k;
+ SESSION *sess;
+
+ if (UniIsEmptyStr(t->AccountName))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ UniStrCpy(accountname, sizeof(accountname), t->AccountName);
+ FreeRpcLinkStatus(t);
+ Zero(t, sizeof(RPC_LINK_STATUS));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+ UniStrCpy(t->AccountName, sizeof(t->AccountName), accountname);
+
+ k = NULL;
+
+ // Find the link
+ LockList(h->LinkList);
+ {
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *kk = LIST_DATA(h->LinkList, i);
+ Lock(kk->lock);
+ {
+ if (UniStrCmpi(kk->Option->AccountName, accountname) == 0)
+ {
+ k = kk;
+ AddRef(kk->ref);
+ }
+ }
+ Unlock(kk->lock);
+
+ if (k != NULL)
+ {
+ break;
+ }
+ }
+ }
+ UnlockList(h->LinkList);
+
+ if (k == NULL)
+ {
+ // Specified link is not found
+ ReleaseHub(h);
+
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ // Get status infomation from session
+ Lock(k->lock);
+ {
+ sess = k->ClientSession;
+ if (sess != NULL)
+ {
+ AddRef(sess->ref);
+ }
+ }
+ Unlock(k->lock);
+
+ if (sess != NULL && k->Offline == false)
+ {
+ CiGetSessionStatus(&t->Status, sess);
+ }
+ else
+ {
+ ret = ERR_LINK_IS_OFFLINE;
+ }
+ ReleaseSession(sess);
+
+ ReleaseLink(k);
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Enumerate links
+UINT StEnumLink(ADMIN *a, RPC_ENUM_LINK *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT i;
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ FreeRpcEnumLink(t);
+ Zero(t, sizeof(RPC_ENUM_LINK));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ LockList(h->LinkList);
+ {
+ t->NumLink = LIST_NUM(h->LinkList);
+ t->Links = ZeroMalloc(sizeof(RPC_ENUM_LINK_ITEM) * t->NumLink);
+
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *k = LIST_DATA(h->LinkList, i);
+ RPC_ENUM_LINK_ITEM *e = &t->Links[i];
+
+ Lock(k->lock);
+ {
+ UniStrCpy(e->AccountName, sizeof(e->AccountName), k->Option->AccountName);
+ StrCpy(e->Hostname, sizeof(e->Hostname), k->Option->Hostname);
+ StrCpy(e->HubName, sizeof(e->HubName), k->Option->HubName);
+ e->Online = k->Offline ? false : true;
+
+ if (e->Online)
+ {
+ if (k->ClientSession != NULL)
+ {
+ e->ConnectedTime = TickToTime(k->ClientSession->CurrentConnectionEstablishTime);
+ e->Connected = (k->ClientSession->ClientStatus == CLIENT_STATUS_ESTABLISHED);
+ e->LastError = k->ClientSession->Err;
+ }
+ }
+ }
+ Unlock(k->lock);
+ }
+ }
+ UnlockList(h->LinkList);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Get link configuration
+UINT StGetLink(ADMIN *a, RPC_CREATE_LINK *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ UINT i;
+ char hubname[MAX_SIZE];
+ LINK *k;
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_LINK_CANT_CREATE_ON_FARM;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ k = NULL;
+
+ // Find the link
+ LockList(h->LinkList);
+ {
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *kk = LIST_DATA(h->LinkList, i);
+ Lock(kk->lock);
+ {
+ if (UniStrCmpi(kk->Option->AccountName, t->ClientOption->AccountName) == 0)
+ {
+ k = kk;
+ AddRef(kk->ref);
+ }
+ }
+ Unlock(kk->lock);
+
+ if (k != NULL)
+ {
+ break;
+ }
+ }
+ }
+ UnlockList(h->LinkList);
+
+ if (k == NULL)
+ {
+ // The link is not found
+ ReleaseHub(h);
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ FreeRpcCreateLink(t);
+ Zero(t, sizeof(t));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ Lock(k->lock);
+ {
+ // Get configuration
+ t->Online = k->Offline ? false : true;
+ t->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(t->ClientOption, k->Option, sizeof(CLIENT_OPTION));
+ t->ClientAuth = CopyClientAuth(k->Auth);
+ Copy(&t->Policy, k->Policy, sizeof(POLICY));
+
+ t->CheckServerCert = k->CheckServerCert;
+ t->ServerCert = CloneX(k->ServerCert);
+ }
+ Unlock(k->lock);
+
+ ReleaseLink(k);
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Set link configuration
+UINT StSetLink(ADMIN *a, RPC_CREATE_LINK *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ UINT i;
+ LINK *k;
+
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_LINK_CANT_CREATE_ON_FARM;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_cascade") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ k = NULL;
+
+ // Find the link
+ LockList(h->LinkList);
+ {
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *kk = LIST_DATA(h->LinkList, i);
+ Lock(kk->lock);
+ {
+ if (UniStrCmpi(kk->Option->AccountName, t->ClientOption->AccountName) == 0)
+ {
+ k = kk;
+ AddRef(kk->ref);
+ }
+ }
+ Unlock(kk->lock);
+
+ if (k != NULL)
+ {
+ break;
+ }
+ }
+ }
+ UnlockList(h->LinkList);
+
+ if (k == NULL)
+ {
+ // The link is not found
+ ReleaseHub(h);
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ ALog(a, h, "LA_SET_LINK", t->ClientOption->AccountName);
+
+ Lock(k->lock);
+ {
+ // Update the configuration of the link
+ if (k->ServerCert != NULL)
+ {
+ FreeX(k->ServerCert);
+ k->ServerCert = NULL;
+ }
+
+ Copy(k->Option, t->ClientOption, sizeof(CLIENT_OPTION));
+ StrCpy(k->Option->DeviceName, sizeof(k->Option->DeviceName), LINK_DEVICE_NAME);
+ k->Option->NumRetry = INFINITE;
+ k->Option->RetryInterval = 10;
+ k->Option->NoRoutingTracking = true;
+ CiFreeClientAuth(k->Auth);
+ k->Auth = CopyClientAuth(t->ClientAuth);
+
+ if (t->Policy.Ver3 == false)
+ {
+ Copy(k->Policy, &t->Policy, sizeof(UINT) * NUM_POLICY_ITEM_FOR_VER2);
+ }
+ else
+ {
+ Copy(k->Policy, &t->Policy, sizeof(POLICY));
+ }
+
+ k->Option->RequireBridgeRoutingMode = true; // Enable Bridge / Routing mode
+ k->Option->RequireMonitorMode = false; // Disable monitor mode
+
+ k->CheckServerCert = t->CheckServerCert;
+ k->ServerCert = CloneX(t->ServerCert);
+ }
+ Unlock(k->lock);
+
+ IncrementServerConfigRevision(s);
+
+ ReleaseLink(k);
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Create a new link(cascade)
+UINT StCreateLink(ADMIN *a, RPC_CREATE_LINK *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ UINT i;
+ LINK *k;
+
+ CHECK_RIGHT;
+
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_LINK_CANT_CREATE_ON_FARM;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_cascade") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ k = NULL;
+
+ // Check for existing a link which has same name
+ LockList(h->LinkList);
+ {
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *kk = LIST_DATA(h->LinkList, i);
+ Lock(kk->lock);
+ {
+ if (UniStrCmpi(kk->Option->AccountName, t->ClientOption->AccountName) == 0)
+ {
+ k = kk;
+ AddRef(kk->ref);
+ }
+ }
+ Unlock(kk->lock);
+
+ if (k != NULL)
+ {
+ break;
+ }
+ }
+ }
+ UnlockList(h->LinkList);
+
+ if (k != NULL)
+ {
+ // There is a link which has same name
+ ReleaseLink(k);
+ ReleaseHub(h);
+ return ERR_LINK_ALREADY_EXISTS;
+ }
+
+ ALog(a, h, "LA_CREATE_LINK", t->ClientOption->AccountName);
+
+ // Create a new link
+ k = NewLink(c, h, t->ClientOption, t->ClientAuth, &t->Policy);
+
+ if (k == NULL)
+ {
+ // Link creation failed
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ // setting of verifying server certification
+ //
+ k->CheckServerCert = t->CheckServerCert;
+ k->ServerCert = CloneX(t->ServerCert);
+
+ // stay this off-line
+ k->Offline = false;
+ SetLinkOffline(k);
+ ReleaseLink(k);
+
+ IncrementServerConfigRevision(s);
+ }
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Delete a CA(Certificate Authority) setting from the hub
+UINT StDeleteCa(ADMIN *a, RPC_HUB_DELETE_CA *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_cert_list") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ LockList(h->HubDb->RootCertList);
+ {
+ if (IsInListKey(h->HubDb->RootCertList, t->Key))
+ {
+ X *x = ListKeyToPointer(h->HubDb->RootCertList, t->Key);
+ Delete(h->HubDb->RootCertList, x);
+ FreeX(x);
+
+ ALog(a, h, "LA_DELETE_CA");
+
+ IncrementServerConfigRevision(s);
+ }
+ else
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ }
+ UnlockList(h->HubDb->RootCertList);
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Get CA(Certificate Authority) setting from the hub
+UINT StGetCa(ADMIN *a, RPC_HUB_GET_CA *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT key;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ key = t->Key;
+
+ FreeRpcHubGetCa(t);
+ Zero(t, sizeof(RPC_HUB_GET_CA));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ LockList(h->HubDb->RootCertList);
+ {
+ if (IsInListKey(h->HubDb->RootCertList, key))
+ {
+ X *x = ListKeyToPointer(h->HubDb->RootCertList, key);
+
+ t->Cert = CloneX(x);
+ }
+ else
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ }
+ UnlockList(h->HubDb->RootCertList);
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Enumerate CA(Certificate Authority) in the hub
+UINT StEnumCa(ADMIN *a, RPC_HUB_ENUM_CA *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT i;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ FreeRpcHubEnumCa(t);
+ Zero(t, sizeof(RPC_HUB_ENUM_CA));
+
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, hubname);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ Zero(t, sizeof(RPC_HUB_ENUM_CA));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ if (h->HubDb->RootCertList != NULL)
+ {
+ LockList(h->HubDb->RootCertList);
+ {
+ t->NumCa = LIST_NUM(h->HubDb->RootCertList);
+ t->Ca = ZeroMalloc(sizeof(RPC_HUB_ENUM_CA_ITEM) * t->NumCa);
+
+ for (i = 0;i < t->NumCa;i++)
+ {
+ RPC_HUB_ENUM_CA_ITEM *e = &t->Ca[i];
+ X *x = LIST_DATA(h->HubDb->RootCertList, i);
+
+ e->Key = POINTER_TO_KEY(x);
+ GetAllNameFromNameEx(e->SubjectName, sizeof(e->SubjectName), x->subject_name);
+ GetAllNameFromNameEx(e->IssuerName, sizeof(e->IssuerName), x->issuer_name);
+ e->Expires = x->notAfter;
+ }
+ }
+ UnlockList(h->HubDb->RootCertList);
+ }
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Add CA(Certificate Authority) into the hub
+UINT StAddCa(ADMIN *a, RPC_HUB_ADD_CA *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ if (c->Bridge)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ if (t->Cert == NULL)
+ {
+ ERR_INVALID_PARAMETER;
+ }
+
+ if (t->Cert->is_compatible_bit == false)
+ {
+ return ERR_NOT_RSA_1024;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_cert_list") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ IncrementServerConfigRevision(s);
+
+ ALog(a, h, "LA_ADD_CA");
+
+ AddRootCert(h, t->Cert);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Get logging configuration of the hub
+UINT StGetHubLog(ADMIN *a, RPC_HUB_LOG *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ GetHubLogSetting(h, &t->LogSetting);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Set logging configuration into the hub
+UINT StSetHubLog(ADMIN *a, RPC_HUB_LOG *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ CHECK_RIGHT;
+
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_log_config") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ ALog(a, h, "LA_SET_HUB_LOG");
+
+ SetHubLogSettingEx(h, &t->LogSetting,
+ (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_log_switch_type") != 0));
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get hub status
+UINT StGetHubStatus(ADMIN *a, RPC_HUB_STATUS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ Zero(t, sizeof(RPC_HUB_STATUS));
+
+ Lock(h->lock);
+ {
+ StrCpy(t->HubName, sizeof(t->HubName), h->Name);
+ t->HubType = h->Type;
+ t->Online = h->Offline ? false : true;
+ t->NumSessions = LIST_NUM(h->SessionList);
+ t->NumSessionsClient = Count(h->NumSessionsClient);
+ t->NumSessionsBridge = Count(h->NumSessionsBridge);
+ t->NumAccessLists = LIST_NUM(h->AccessList);
+
+ if (h->HubDb != NULL)
+ {
+ t->NumUsers = LIST_NUM(h->HubDb->UserList);
+ t->NumGroups = LIST_NUM(h->HubDb->GroupList);
+ }
+
+ t->NumMacTables = LIST_NUM(h->MacTable);
+ t->NumIpTables = LIST_NUM(h->IpTable);
+
+ Lock(h->TrafficLock);
+ {
+ Copy(&t->Traffic, h->Traffic, sizeof(TRAFFIC));
+ }
+ Unlock(h->TrafficLock);
+
+ t->NumLogin = h->NumLogin;
+ t->LastCommTime = h->LastCommTime;
+ t->LastLoginTime = h->LastLoginTime;
+ t->CreatedTime = h->CreatedTime;
+ }
+ Unlock(h->lock);
+
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ UINT i;
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ UINT k;
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+
+ if (f->Me == false)
+ {
+ LockList(f->HubList);
+ {
+ for (k = 0;k < LIST_NUM(f->HubList);k++)
+ {
+ HUB_LIST *h = LIST_DATA(f->HubList, k);
+
+ if (StrCmpi(h->Name, t->HubName) == 0)
+ {
+ t->NumSessions += h->NumSessions;
+ t->NumSessionsClient += h->NumSessionsClient;
+ t->NumSessionsBridge += h->NumSessionsBridge;
+ t->NumMacTables += h->NumMacTables;
+ t->NumIpTables += h->NumIpTables;
+ }
+ }
+ }
+ UnlockList(f->HubList);
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+
+ if (h->Type != HUB_TYPE_FARM_STATIC)
+ {
+ t->SecureNATEnabled = h->EnableSecureNAT;
+ }
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Enable SecureNAT function of the hub
+UINT StEnableSecureNAT(ADMIN *a, RPC_HUB *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ CHECK_RIGHT;
+
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_SUPPORTED;
+ }
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_securenat") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ ALog(a, h, "LA_ENABLE_SNAT");
+
+ EnableSecureNAT(h, true);
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+
+ IncrementServerConfigRevision(s);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Disable the SecureNAT function of the hub
+UINT StDisableSecureNAT(ADMIN *a, RPC_HUB *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ CHECK_RIGHT;
+
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_SUPPORTED;
+ }
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_securenat") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ ALog(a, h, "LA_DISABLE_SNAT");
+
+ EnableSecureNAT(h, false);
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+
+ IncrementServerConfigRevision(s);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate NAT entries of the SecureNAT
+UINT StEnumNAT(ADMIN *a, RPC_ENUM_NAT *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT i;
+
+ CHECK_RIGHT;
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_SUPPORTED;
+ }
+
+ Lock(h->lock_online);
+ {
+ if (h->SecureNAT == NULL)
+ {
+ ret = ERR_SNAT_NOT_RUNNING;
+ }
+ else
+ {
+ NtEnumNatList(h->SecureNAT->Nat, t);
+ }
+ }
+ Unlock(h->lock_online);
+
+ if (h->Type == HUB_TYPE_FARM_DYNAMIC)
+ {
+ if (ret == ERR_SNAT_NOT_RUNNING)
+ {
+ // Get status of remote SecureNAT
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ if (f->Me == false)
+ {
+ RPC_ENUM_NAT tmp;
+
+ Zero(&tmp, sizeof(tmp));
+
+ SiCallEnumNat(s, f, hubname, &tmp);
+
+ if (tmp.NumItem >= 1)
+ {
+ FreeRpcEnumNat(t);
+ Copy(t, &tmp, sizeof(RPC_ENUM_NAT));
+ ret = ERR_NO_ERROR;
+ break;
+ }
+ else
+ {
+ FreeRpcEnumNat(&tmp);
+ }
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+ }
+
+ ReleaseHub(h);
+
+ ret = ERR_NO_ERROR;
+
+ return ret;
+}
+
+// Get status of the SecureNAT
+UINT StGetSecureNATStatus(ADMIN *a, RPC_NAT_STATUS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT i;
+
+ CHECK_RIGHT;
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_SUPPORTED;
+ }
+
+ Lock(h->lock_online);
+ {
+ if (h->SecureNAT == NULL)
+ {
+ ret = ERR_SNAT_NOT_RUNNING;
+ }
+ else
+ {
+ NtGetStatus(h->SecureNAT->Nat, t);
+ }
+ }
+ Unlock(h->lock_online);
+
+ if (h->Type == HUB_TYPE_FARM_DYNAMIC)
+ {
+ if (ret == ERR_SNAT_NOT_RUNNING)
+ {
+ // Get status of remote secureNAT
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ if (f->Me == false)
+ {
+ RPC_NAT_STATUS tmp;
+
+ Zero(&tmp, sizeof(tmp));
+
+ SiCallGetNatStatus(s, f, hubname, &tmp);
+
+ if (tmp.NumDhcpClients == 0 && tmp.NumTcpSessions == 0 && tmp.NumUdpSessions == 0)
+ {
+ }
+ else
+ {
+ Copy(t, &tmp, sizeof(RPC_NAT_STATUS));
+ ret = ERR_NO_ERROR;
+ break;
+ }
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+ }
+
+ ReleaseHub(h);
+
+ ret = ERR_NO_ERROR;
+
+ return ret;
+}
+
+// Enumerate DHCP entries
+UINT StEnumDHCP(ADMIN *a, RPC_ENUM_DHCP *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT i;
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_SUPPORTED;
+ }
+
+ Lock(h->lock_online);
+ {
+ if (h->SecureNAT == NULL)
+ {
+ ret = ERR_SNAT_NOT_RUNNING;
+ }
+ else
+ {
+ NtEnumDhcpList(h->SecureNAT->Nat, t);
+ }
+ }
+ Unlock(h->lock_online);
+
+ if (h->Type == HUB_TYPE_FARM_DYNAMIC)
+ {
+ if (ret == ERR_SNAT_NOT_RUNNING)
+ {
+ // Get status of remote DHCP service
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ if (f->Me == false)
+ {
+ RPC_ENUM_DHCP tmp;
+
+ Zero(&tmp, sizeof(tmp));
+
+ SiCallEnumDhcp(s, f, hubname, &tmp);
+
+ if (tmp.NumItem >= 1)
+ {
+ FreeRpcEnumDhcp(t);
+ Copy(t, &tmp, sizeof(RPC_ENUM_DHCP));
+ ret = ERR_NO_ERROR;
+ break;
+ }
+ else
+ {
+ FreeRpcEnumDhcp(&tmp);
+ }
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+ }
+
+ ReleaseHub(h);
+
+ ret = ERR_NO_ERROR;
+
+ return ret;
+}
+
+// Set SecureNAT options
+UINT StSetSecureNATOption(ADMIN *a, VH_OPTION *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+
+ if (IsZero(t->MacAddress, sizeof(t->MacAddress)) ||
+ IsHostIPAddress4(&t->Ip) == false ||
+ IsSubnetMask4(&t->Mask) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ if ((IPToUINT(&t->Ip) & (~(IPToUINT(&t->Mask)))) == 0)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_SUPPORTED;
+ }
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_securenat") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ if (h->SecureNATOption->UseNat == false && t->UseNat)
+ {
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_securenat_enablenat") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+ }
+
+ if (h->SecureNATOption->UseDhcp == false && t->UseDhcp)
+ {
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_securenat_enabledhcp") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+ }
+
+ Copy(h->SecureNATOption, t, sizeof(VH_OPTION));
+
+ if (h->Type != HUB_TYPE_STANDALONE && h->Cedar != NULL && h->Cedar->Server != NULL &&
+ h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ NiClearUnsupportedVhOptionForDynamicHub(h->SecureNATOption, false);
+ }
+
+ Lock(h->lock_online);
+ {
+ if (h->SecureNAT != NULL)
+ {
+ SetVirtualHostOption(h->SecureNAT->Nat->Virtual, t);
+ }
+ }
+ Unlock(h->lock_online);
+
+ ALog(a, h, "LA_SET_SNAT_OPTION");
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+
+ IncrementServerConfigRevision(s);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Get SecureNAT options
+UINT StGetSecureNATOption(ADMIN *a, VH_OPTION *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_SUPPORTED;
+ }
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ Zero(t, sizeof(VH_OPTION));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+ Copy(t, h->SecureNATOption, sizeof(VH_OPTION));
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Make a hub on-line or off-line
+UINT StSetHubOnline(ADMIN *a, RPC_SET_HUB_ONLINE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && t->Online && GetHubAdminOption(h, "no_online") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ if (a->ServerAdmin == false && t->Online == false && GetHubAdminOption(h, "no_offline") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ if (t->Online)
+ {
+ ALog(a, h, "LA_SET_HUB_ONLINE");
+ SetHubOnline(h);
+ }
+ else
+ {
+ ALog(a, h, "LA_SET_HUB_OFFLINE");
+ SetHubOffline(h);
+ }
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+
+ IncrementServerConfigRevision(s);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Get connection information
+UINT StGetConnectionInfo(ADMIN *a, RPC_CONNECTION_INFO *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ CONNECTION *connection;
+ char name[MAX_CONNECTION_NAME_LEN + 1];
+
+ if (IsEmptyStr(t->Name))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ SERVER_ADMIN_ONLY;
+
+ LockList(c->ConnectionList);
+ {
+ CONNECTION tt;
+ Zero(&tt, sizeof(tt));
+ tt.Name = t->Name;
+ StrCpy(name, sizeof(name), t->Name);
+
+ connection = Search(c->ConnectionList, &tt);
+
+ if (connection != NULL)
+ {
+ AddRef(connection->ref);
+ }
+ }
+ UnlockList(c->ConnectionList);
+
+ if (connection == NULL)
+ {
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ Zero(t, sizeof(RPC_CONNECTION_INFO));
+ StrCpy(t->Name, sizeof(t->Name), name);
+
+ Lock(connection->lock);
+ {
+ SOCK *s = connection->FirstSock;
+
+ if (s != NULL)
+ {
+ t->Ip = IPToUINT(&s->RemoteIP);
+ t->Port = s->RemotePort;
+ StrCpy(t->Hostname, sizeof(t->Hostname), s->RemoteHostname);
+ }
+
+ StrCpy(t->Name, sizeof(t->Name), connection->Name);
+ t->ConnectedTime = TickToTime(connection->ConnectedTick);
+ t->Type = connection->Type;
+
+ StrCpy(t->ServerStr, sizeof(t->ServerStr), connection->ServerStr);
+ StrCpy(t->ClientStr, sizeof(t->ClientStr), connection->ClientStr);
+ t->ServerVer = connection->ServerVer;
+ t->ServerBuild = connection->ServerBuild;
+ t->ClientVer = connection->ClientVer;
+ t->ClientBuild = connection->ClientBuild;
+ }
+ Unlock(connection->lock);
+
+ ReleaseConnection(connection);
+
+ return ERR_NO_ERROR;
+}
+
+// Disconnect a connection
+UINT StDisconnectConnection(ADMIN *a, RPC_DISCONNECT_CONNECTION *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ CONNECTION *connection;
+
+ if (IsEmptyStr(t->Name))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ SERVER_ADMIN_ONLY;
+
+ LockList(c->ConnectionList);
+ {
+ CONNECTION tt;
+ Zero(&tt, sizeof(tt));
+ tt.Name = t->Name;
+
+ connection = Search(c->ConnectionList, &tt);
+ if (connection != NULL)
+ {
+ AddRef(connection->ref);
+ }
+ }
+ UnlockList(c->ConnectionList);
+
+ if (connection == NULL)
+ {
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ StopConnection(connection, true);
+
+ ReleaseConnection(connection);
+
+ ALog(a, NULL, "LA_DISCONNECT_CONN", t->Name);
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate connections
+UINT StEnumConnection(ADMIN *a, RPC_ENUM_CONNECTION *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+
+ SERVER_ADMIN_ONLY;
+
+ FreeRpcEnumConnetion(t);
+ Zero(t, sizeof(RPC_ENUM_CONNECTION));
+
+ LockList(c->ConnectionList);
+ {
+ UINT i;
+ t->NumConnection = LIST_NUM(c->ConnectionList);
+ t->Connections = ZeroMalloc(sizeof(RPC_ENUM_CONNECTION_ITEM) * t->NumConnection);
+
+ for (i = 0;i < t->NumConnection;i++)
+ {
+ RPC_ENUM_CONNECTION_ITEM *e = &t->Connections[i];
+ CONNECTION *connection = LIST_DATA(c->ConnectionList, i);
+
+ Lock(connection->lock);
+ {
+ SOCK *s = connection->FirstSock;
+
+ if (s != NULL)
+ {
+ e->Ip = IPToUINT(&s->RemoteIP);
+ e->Port = s->RemotePort;
+ StrCpy(e->Hostname, sizeof(e->Hostname), s->RemoteHostname);
+ }
+
+ StrCpy(e->Name, sizeof(e->Name), connection->Name);
+ e->ConnectedTime = TickToTime(connection->ConnectedTick);
+ e->Type = connection->Type;
+ }
+ Unlock(connection->lock);
+ }
+ }
+ UnlockList(c->ConnectionList);
+
+ return ERR_NO_ERROR;
+}
+
+// Set Radius options of the hub
+UINT StSetHubRadius(ADMIN *a, RPC_RADIUS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ //SetRadiusServer(h, t->RadiusServerName, t->RadiusPort, t->RadiusSecret);
+ SetRadiusServerEx(h, t->RadiusServerName, t->RadiusPort, t->RadiusSecret, t->RadiusRetryInterval);
+
+ ALog(a, h, "LA_SET_HUB_RADIUS");
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get Radius options of the hub
+UINT StGetHubRadius(ADMIN *a, RPC_RADIUS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+
+ CHECK_RIGHT;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ Zero(t, sizeof(t));
+ //GetRadiusServer(h, t->RadiusServerName, sizeof(t->RadiusServerName),
+ // &t->RadiusPort, t->RadiusSecret, sizeof(t->RadiusSecret));
+ GetRadiusServerEx(h, t->RadiusServerName, sizeof(t->RadiusServerName),
+ &t->RadiusPort, t->RadiusSecret, sizeof(t->RadiusSecret), &t->RadiusRetryInterval);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Delete a hub
+UINT StDeleteHub(ADMIN *a, RPC_DELETE_HUB *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+
+ if (IsEmptyStr(t->HubName) || IsSafeStr(t->HubName) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ SERVER_ADMIN_ONLY;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ StopHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ DelHub(c, h);
+ ReleaseHub(h);
+
+ ALog(a, NULL, "LA_DELETE_HUB", t->HubName);
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate hubs
+UINT StEnumHub(ADMIN *a, RPC_ENUM_HUB *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+
+ FreeRpcEnumHub(t);
+
+ Zero(t, sizeof(RPC_ENUM_HUB));
+
+ LockHubList(c);
+ {
+ UINT i, num, j;
+
+ num = 0;
+
+ for (i = 0;i < LIST_NUM(c->HubList);i++)
+ {
+ HUB *h = LIST_DATA(c->HubList, i);
+
+ Lock(h->lock);
+
+ if (a->ServerAdmin == false &&
+ h->Option != NULL &&
+ StrCmpi(h->Name, a->HubName) != 0)
+ {
+ // This hub is not listed
+ }
+ else
+ {
+ // This hub is listed
+ num++;
+ }
+ }
+
+ t->NumHub = num;
+
+ t->Hubs = ZeroMalloc(sizeof(RPC_ENUM_HUB_ITEM) * num);
+
+ i = 0;
+ for (j = 0;j < LIST_NUM(c->HubList);j++)
+ {
+ HUB *h = LIST_DATA(c->HubList, j);
+
+ if (a->ServerAdmin == false &&
+ h->Option != NULL &&
+ StrCmpi(h->Name, a->HubName) != 0)
+ {
+ // This hub is not listed
+ }
+ else
+ {
+ // This hub is listed
+ RPC_ENUM_HUB_ITEM *e = &t->Hubs[i++];
+
+ StrCpy(e->HubName, sizeof(e->HubName), h->Name);
+ e->Online = h->Offline ? false : true;
+ e->HubType = h->Type;
+
+ e->NumSessions = LIST_NUM(h->SessionList);
+
+ LockList(h->MacTable);
+ {
+ e->NumMacTables = LIST_NUM(h->MacTable);
+ }
+ UnlockList(h->MacTable);
+
+ LockList(h->IpTable);
+ {
+ e->NumIpTables = LIST_NUM(h->IpTable);
+ }
+ UnlockList(h->IpTable);
+
+ if (h->HubDb != NULL)
+ {
+ LockList(h->HubDb->UserList);
+ {
+ e->NumUsers = LIST_NUM(h->HubDb->UserList);
+ }
+ UnlockList(h->HubDb->UserList);
+
+ LockList(h->HubDb->GroupList);
+ {
+ e->NumGroups = LIST_NUM(h->HubDb->GroupList);
+ }
+ UnlockList(h->HubDb->GroupList);
+ }
+
+ e->LastCommTime = h->LastCommTime;
+ e->LastLoginTime = h->LastLoginTime;
+ e->NumLogin = h->NumLogin;
+ e->CreatedTime = h->CreatedTime;
+
+ Lock(h->TrafficLock);
+ {
+ Copy(&e->Traffic, h->Traffic, sizeof(TRAFFIC));
+ }
+ Unlock(h->TrafficLock);
+
+ e->IsTrafficFilled = true;
+ }
+
+ Unlock(h->lock);
+ }
+ }
+ UnlockHubList(c);
+
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ UINT i, j, k;
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+
+ LockList(f->HubList);
+ {
+ if (f->Me == false)
+ {
+ for (j = 0;j < LIST_NUM(f->HubList);j++)
+ {
+ HUB_LIST *o = LIST_DATA(f->HubList, j);
+
+ for (k = 0;k < t->NumHub;k++)
+ {
+ RPC_ENUM_HUB_ITEM *e = &t->Hubs[k];
+
+ if (StrCmpi(e->HubName, o->Name) == 0)
+ {
+ e->NumIpTables += o->NumIpTables;
+ e->NumMacTables += o->NumMacTables;
+ e->NumSessions += o->NumSessions;
+ }
+ }
+ }
+ }
+ }
+ UnlockList(f->HubList);
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+
+ return ERR_NO_ERROR;
+}
+
+// Get hub configuration
+UINT StGetHub(ADMIN *a, RPC_CREATE_HUB *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ HUB *h;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ if (IsEmptyStr(t->HubName) || IsSafeStr(t->HubName) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ Zero(t, sizeof(RPC_CREATE_HUB));
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ Lock(h->lock);
+ {
+ StrCpy(t->HubName, sizeof(t->HubName), h->Name);
+ t->Online = h->Offline ? false : true;
+ t->HubOption.MaxSession = h->Option->MaxSession;
+ t->HubOption.NoEnum = h->Option->NoEnum;
+ t->HubType = h->Type;
+ }
+ Unlock(h->lock);
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Set hub configuration
+UINT StSetHub(ADMIN *a, RPC_CREATE_HUB *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ if (IsEmptyStr(t->HubName) || IsSafeStr(t->HubName) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ if (s->ServerType == SERVER_TYPE_STANDALONE)
+ {
+ if (t->HubType != HUB_TYPE_STANDALONE)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ if (t->HubType == HUB_TYPE_STANDALONE)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (h->Type != t->HubType)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_SUPPORTED;
+ }
+
+ if (IsZero(t->HashedPassword, sizeof(t->HashedPassword)) == false &&
+ IsZero(t->SecurePassword, sizeof(t->SecurePassword)) == false)
+ {
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_admin_password") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+ }
+
+ // Is the password to be set blank
+ {
+ UCHAR hash1[SHA1_SIZE], hash2[SHA1_SIZE];
+ HashPassword(hash1, ADMINISTRATOR_USERNAME, "");
+ Hash(hash2, "", 0, true);
+
+ if (Cmp(t->HashedPassword, hash2, SHA1_SIZE) == 0 || Cmp(t->SecurePassword, hash1, SHA1_SIZE) == 0)
+ {
+ if (a->ServerAdmin == false && a->Rpc->Sock->RemoteIP.addr[0] != 127)
+ {
+ // Refuse to set a blank password to hub admin from remote host
+ ReleaseHub(h);
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ Lock(h->lock);
+ {
+ if (a->ServerAdmin == false && h->Type != t->HubType)
+ {
+ ret = ERR_NOT_ENOUGH_RIGHT;
+ }
+ else
+ {
+ h->Type = t->HubType;
+ h->Option->MaxSession = t->HubOption.MaxSession;
+ h->Option->NoEnum = t->HubOption.NoEnum;
+ if (IsZero(t->HashedPassword, sizeof(t->HashedPassword)) == false &&
+ IsZero(t->SecurePassword, sizeof(t->SecurePassword)) == false)
+ {
+ Copy(h->HashedPassword, t->HashedPassword, SHA1_SIZE);
+ Copy(h->SecurePassword, t->SecurePassword, SHA1_SIZE);
+ }
+ }
+ }
+ Unlock(h->lock);
+
+ if (t->Online)
+ {
+ if (a->ServerAdmin || GetHubAdminOption(h, "no_online") == 0)
+ {
+ SetHubOnline(h);
+ }
+ }
+ else
+ {
+ if (a->ServerAdmin || GetHubAdminOption(h, "no_offline") == 0)
+ {
+ SetHubOffline(h);
+ }
+ }
+
+ if (h->Type == HUB_TYPE_FARM_STATIC)
+ {
+ EnableSecureNAT(h, false);
+ }
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+
+ IncrementServerConfigRevision(s);
+
+ ALog(a, h, "LA_SET_HUB");
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Create a hub
+UINT StCreateHub(ADMIN *a, RPC_CREATE_HUB *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ HUB_OPTION o;
+ UINT current_hub_num;
+ bool b;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+
+
+ if (IsEmptyStr(t->HubName) || IsSafeStr(t->HubName) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ SERVER_ADMIN_ONLY;
+
+ Trim(t->HubName);
+ if (StrLen(t->HubName) == 0)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ if (StartWith(t->HubName, ".") || EndWith(t->HubName, "."))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ if (s->ServerType == SERVER_TYPE_STANDALONE)
+ {
+ if (t->HubType != HUB_TYPE_STANDALONE)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+ else if (t->HubType != HUB_TYPE_FARM_DYNAMIC && t->HubType != HUB_TYPE_FARM_STATIC)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Create a hub object
+ Zero(&o, sizeof(o));
+ o.MaxSession = t->HubOption.MaxSession;
+ o.NoEnum = t->HubOption.NoEnum;
+
+ // Default setting for hub admin options
+ SiSetDefaultHubOption(&o);
+
+ LockList(c->HubList);
+ {
+ current_hub_num = LIST_NUM(c->HubList);
+ }
+ UnlockList(c->HubList);
+
+ if (current_hub_num > GetServerCapsInt(a->Server, "i_max_hubs"))
+ {
+ return ERR_TOO_MANY_HUBS;
+ }
+
+ LockList(c->HubList);
+ {
+ b = IsHub(c, t->HubName);
+ }
+ UnlockList(c->HubList);
+
+ if (b)
+ {
+ return ERR_HUB_ALREADY_EXISTS;
+ }
+
+ ALog(a, NULL, "LA_CREATE_HUB", t->HubName);
+
+ h = NewHub(c, t->HubName, &o);
+ Copy(h->HashedPassword, t->HashedPassword, SHA1_SIZE);
+ Copy(h->SecurePassword, t->SecurePassword, SHA1_SIZE);
+
+ h->Type = t->HubType;
+
+ AddHub(c, h);
+
+ if (t->Online)
+ {
+ h->Offline = true;
+ SetHubOnline(h);
+ }
+ else
+ {
+ h->Offline = false;
+ SetHubOffline(h);
+ }
+
+ h->CreatedTime = SystemTime64();
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Set cipher for SSL to the server
+UINT StSetServerCipher(ADMIN *a, RPC_STR *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+
+ if (IsEmptyStr(t->String))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ SERVER_ADMIN_ONLY;
+
+ StrUpper(t->String);
+
+ if (CheckCipherListName(t->String) == false)
+ {
+ return ERR_CIPHER_NOT_SUPPORTED;
+ }
+ else
+ {
+ ALog(a, NULL, "LA_SET_SERVER_CIPHER", t->String);
+ }
+
+ Lock(c->lock);
+ {
+ SetCedarCipherList(c, t->String);
+ }
+ Unlock(c->lock);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get cipher for SSL
+UINT StGetServerCipher(ADMIN *a, RPC_STR *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+
+ FreeRpcStr(t);
+ Zero(t, sizeof(RPC_STR));
+
+ Lock(c->lock);
+ {
+ t->String = CopyStr(c->CipherList);
+ }
+ Unlock(c->lock);
+
+ return ERR_NO_ERROR;
+}
+
+// Get the server certification
+UINT StGetServerCert(ADMIN *a, RPC_KEY_PAIR *t)
+{
+ bool admin;
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ bool is_vgs_cert = false;
+
+ admin = a->ServerAdmin;
+
+ FreeRpcKeyPair(t);
+ Zero(t, sizeof(RPC_KEY_PAIR));
+
+ Lock(c->lock);
+ {
+
+ t->Cert = CloneX(c->ServerX);
+ if (admin && is_vgs_cert == false)
+ {
+ t->Key = CloneK(c->ServerK);
+ }
+ }
+ Unlock(c->lock);
+
+ return ERR_NO_ERROR;
+}
+
+// Set the server certification
+UINT StSetServerCert(ADMIN *a, RPC_KEY_PAIR *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+
+ SERVER_ADMIN_ONLY;
+
+ if (t->Cert == NULL || t->Key == NULL)
+ {
+ return ERR_PROTOCOL_ERROR;
+ }
+
+ if (t->Cert->is_compatible_bit == false)
+ {
+ return ERR_NOT_RSA_1024;
+ }
+
+ if (CheckXandK(t->Cert, t->Key) == false)
+ {
+ return ERR_PROTOCOL_ERROR;
+ }
+
+ SetCedarCert(c, t->Cert, t->Key);
+
+ ALog(a, NULL, "LA_SET_SERVER_CERT");
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get status of connection to cluster controller
+UINT StGetFarmConnectionStatus(ADMIN *a, RPC_FARM_CONNECTION_STATUS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ FARM_CONTROLLER *fc;
+
+ if (s->ServerType != SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_MEMBER;
+ }
+
+ Zero(t, sizeof(RPC_FARM_CONNECTION_STATUS));
+
+ fc = s->FarmController;
+
+ Lock(fc->lock);
+ {
+ if (fc->Sock != NULL)
+ {
+ t->Ip = IPToUINT(&fc->Sock->RemoteIP);
+ t->Port = fc->Sock->RemotePort;
+ }
+
+ t->Online = fc->Online;
+ t->LastError = ERR_NO_ERROR;
+
+ if (t->Online == false)
+ {
+ t->LastError = fc->LastError;
+ }
+ else
+ {
+ t->CurrentConnectedTime = fc->CurrentConnectedTime;
+ }
+
+ t->StartedTime = fc->StartedTime;
+ t->FirstConnectedTime = fc->FirstConnectedTime;
+
+ t->NumConnected = fc->NumConnected;
+ t->NumTry = fc->NumTry;
+ t->NumFailed = fc->NumFailed;
+ }
+ Unlock(fc->lock);
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate cluster members
+UINT StEnumFarmMember(ADMIN *a, RPC_ENUM_FARM *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT i;
+
+ FreeRpcEnumFarm(t);
+ Zero(t, sizeof(RPC_ENUM_FARM));
+
+ if (s->ServerType != SERVER_TYPE_FARM_CONTROLLER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_FARM));
+
+ LockList(s->FarmMemberList);
+ {
+ t->NumFarm = LIST_NUM(s->FarmMemberList);
+ t->Farms = ZeroMalloc(sizeof(RPC_ENUM_FARM_ITEM) * t->NumFarm);
+
+ for (i = 0;i < t->NumFarm;i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ RPC_ENUM_FARM_ITEM *e = &t->Farms[i];
+
+ e->Id = POINTER_TO_KEY(f);
+ e->Controller = f->Me;
+
+ if (e->Controller)
+ {
+ e->ConnectedTime = TickToTime(c->CreatedTick);
+ e->Ip = 0x0100007f;
+ GetMachineName(e->Hostname, sizeof(e->Hostname));
+ e->Point = f->Point;
+ e->NumSessions = Count(c->CurrentSessions);
+ e->NumTcpConnections = Count(c->CurrentTcpConnections);
+
+ e->AssignedBridgeLicense = Count(c->AssignedBridgeLicense);
+ e->AssignedClientLicense = Count(c->AssignedClientLicense);
+ }
+ else
+ {
+ e->ConnectedTime = f->ConnectedTime;
+ e->Ip = f->Ip;
+ StrCpy(e->Hostname, sizeof(e->Hostname), f->hostname);
+ e->Point = f->Point;
+ e->NumSessions = f->NumSessions;
+ e->NumTcpConnections = f->NumTcpConnections;
+
+ e->AssignedBridgeLicense = f->AssignedBridgeLicense;
+ e->AssignedClientLicense = f->AssignedClientLicense;
+ }
+ e->NumHubs = LIST_NUM(f->HubList);
+ }
+ }
+ UnlockList(s->FarmMemberList);
+
+ return ERR_NO_ERROR;
+}
+
+// Get cluster member information
+UINT StGetFarmInfo(ADMIN *a, RPC_FARM_INFO *t)
+{
+ SERVER *s = a->Server;
+ UINT id = t->Id;
+ UINT i;
+ UINT ret = ERR_NO_ERROR;
+
+ FreeRpcFarmInfo(t);
+ Zero(t, sizeof(RPC_FARM_INFO));
+
+ if (s->ServerType != SERVER_TYPE_FARM_CONTROLLER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ LockList(s->FarmMemberList);
+ {
+ if (IsInListKey(s->FarmMemberList, id))
+ {
+ FARM_MEMBER *f = ListKeyToPointer(s->FarmMemberList, id);
+
+ t->Id = id;
+ t->Controller = f->Me;
+ t->Weight = f->Weight;
+
+ LockList(f->HubList);
+ {
+ t->NumFarmHub = LIST_NUM(f->HubList);
+ t->FarmHubs = ZeroMalloc(sizeof(RPC_FARM_HUB) * t->NumFarmHub);
+
+ for (i = 0;i < t->NumFarmHub;i++)
+ {
+ RPC_FARM_HUB *h = &t->FarmHubs[i];
+ HUB_LIST *hh = LIST_DATA(f->HubList, i);
+
+ h->DynamicHub = hh->DynamicHub;
+ StrCpy(h->HubName, sizeof(h->HubName), hh->Name);
+ }
+ }
+ UnlockList(f->HubList);
+
+ if (t->Controller)
+ {
+ t->ConnectedTime = TickToTime(s->Cedar->CreatedTick);
+ t->Ip = 0x0100007f;
+ GetMachineName(t->Hostname, sizeof(t->Hostname));
+ t->Point = f->Point;
+
+ LockList(s->ServerListenerList);
+ {
+ UINT i, n;
+ t->NumPort = 0;
+ for (i = 0;i < LIST_NUM(s->ServerListenerList);i++)
+ {
+ SERVER_LISTENER *o = LIST_DATA(s->ServerListenerList, i);
+ if (o->Enabled)
+ {
+ t->NumPort++;
+ }
+ }
+ t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+ n = 0;
+ for (i = 0;i < LIST_NUM(s->ServerListenerList);i++)
+ {
+ SERVER_LISTENER *o = LIST_DATA(s->ServerListenerList, i);
+ if (o->Enabled)
+ {
+ t->Ports[n++] = o->Port;
+ }
+ }
+ }
+ UnlockList(s->ServerListenerList);
+
+ t->ServerCert = CloneX(s->Cedar->ServerX);
+ t->NumSessions = Count(s->Cedar->CurrentSessions);
+ t->NumTcpConnections = Count(s->Cedar->CurrentTcpConnections);
+ }
+ else
+ {
+ t->ConnectedTime = f->ConnectedTime;
+ t->Ip = f->Ip;
+ StrCpy(t->Hostname, sizeof(t->Hostname), f->hostname);
+ t->Point = f->Point;
+ t->NumPort = f->NumPort;
+ t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+ Copy(t->Ports, f->Ports, sizeof(UINT) * t->NumPort);
+ t->ServerCert = CloneX(f->ServerCert);
+ t->NumSessions = f->NumSessions;
+ t->NumTcpConnections = f->NumTcpConnections;
+ }
+ }
+ else
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ }
+ UnlockList(s->FarmMemberList);
+
+ return ret;
+}
+
+// Get clustering configuration
+UINT StGetFarmSetting(ADMIN *a, RPC_FARM *t)
+{
+ SERVER *s;
+ FreeRpcFarm(t);
+ Zero(t, sizeof(RPC_FARM));
+
+ s = a->Server;
+ t->ServerType = s->ServerType;
+ t->ControllerOnly = s->ControllerOnly;
+ t->Weight = s->Weight;
+
+ if (t->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ t->NumPort = s->NumPublicPort;
+ t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+ Copy(t->Ports, s->PublicPorts, sizeof(UINT) * t->NumPort);
+ t->PublicIp = s->PublicIp;
+ StrCpy(t->ControllerName, sizeof(t->ControllerName), s->ControllerName);
+ t->ControllerPort = s->ControllerPort;
+ }
+ else
+ {
+ t->NumPort = 0;
+ t->Ports = ZeroMalloc(0);
+ }
+
+ return ERR_NO_ERROR;
+}
+
+// Set clustering configuration
+UINT StSetFarmSetting(ADMIN *a, RPC_FARM *t)
+{
+ bool cluster_allowed = false;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+
+
+ cluster_allowed = GetServerCapsInt(a->Server, "b_support_cluster");
+
+ if (t->ServerType != SERVER_TYPE_STANDALONE && cluster_allowed == false)
+ {
+ // When clustering function is disabled, deny turning into clustering mode
+ return ERR_NOT_SUPPORTED;
+ }
+
+ ALog(a, NULL, "LA_SET_FARM_SETTING");
+
+ IncrementServerConfigRevision(a->Server);
+
+ SiSetServerType(a->Server, t->ServerType, t->PublicIp, t->NumPort, t->Ports,
+ t->ControllerName, t->ControllerPort, t->MemberPassword, t->Weight, t->ControllerOnly);
+
+ return ERR_NO_ERROR;
+}
+
+// Set server password
+UINT StSetServerPassword(ADMIN *a, RPC_SET_PASSWORD *t)
+{
+ SERVER_ADMIN_ONLY;
+
+
+ Copy(a->Server->HashedPassword, t->HashedPassword, SHA1_SIZE);
+
+ ALog(a, NULL, "LA_SET_SERVER_PASSWORD");
+
+ IncrementServerConfigRevision(a->Server);
+
+ return ERR_NO_ERROR;
+}
+
+// Enable / Disable listener
+UINT StEnableListener(ADMIN *a, RPC_LISTENER *t)
+{
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+
+
+ LockList(a->Server->ServerListenerList);
+ {
+ if (t->Enable)
+ {
+ if (SiEnableListener(a->Server, t->Port) == false)
+ {
+ ret = ERR_LISTENER_NOT_FOUND;
+ }
+ else
+ {
+ ALog(a, NULL, "LA_ENABLE_LISTENER", t->Port);
+ }
+ }
+ else
+ {
+ if (SiDisableListener(a->Server, t->Port) == false)
+ {
+ ret = ERR_LISTENER_NOT_FOUND;
+ }
+ else
+ {
+ ALog(a, NULL, "LA_DISABLE_LISTENER", t->Port);
+ }
+ }
+ }
+ UnlockList(a->Server->ServerListenerList);
+
+ IncrementServerConfigRevision(a->Server);
+
+ SleepThread(250);
+
+ return ret;
+}
+
+// Delete a listener
+UINT StDeleteListener(ADMIN *a, RPC_LISTENER *t)
+{
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+
+
+ LockList(a->Server->ServerListenerList);
+ {
+ if (SiDeleteListener(a->Server, t->Port) == false)
+ {
+ ret = ERR_LISTENER_NOT_FOUND;
+ }
+ else
+ {
+ ALog(a, NULL, "LA_DELETE_LISTENER", t->Port);
+
+ IncrementServerConfigRevision(a->Server);
+ }
+ }
+ UnlockList(a->Server->ServerListenerList);
+
+ return ret;
+}
+
+// Enumerating listeners
+UINT StEnumListener(ADMIN *a, RPC_LISTENER_LIST *t)
+{
+ CEDAR *c = a->Server->Cedar;
+ UINT i;
+
+ FreeRpcListenerList(t);
+ Zero(t, sizeof(RPC_LISTENER_LIST));
+
+ LockList(a->Server->ServerListenerList);
+ {
+ t->NumPort = LIST_NUM(a->Server->ServerListenerList);
+ t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+ t->Enables = ZeroMalloc(sizeof(bool) * t->NumPort);
+ t->Errors = ZeroMalloc(sizeof(bool) * t->NumPort);
+
+ for (i = 0;i < t->NumPort;i++)
+ {
+ SERVER_LISTENER *o = LIST_DATA(a->Server->ServerListenerList, i);
+
+ t->Ports[i] = o->Port;
+ t->Enables[i] = o->Enabled;
+ if (t->Enables[i])
+ {
+ if (o->Listener->Status == LISTENER_STATUS_TRYING)
+ {
+ t->Errors[i] = true;
+ }
+ }
+ }
+ }
+ UnlockList(a->Server->ServerListenerList);
+
+ return ERR_NO_ERROR;
+}
+
+// Create a listener
+UINT StCreateListener(ADMIN *a, RPC_LISTENER *t)
+{
+ UINT ret = ERR_NO_ERROR;
+ CEDAR *c = a->Server->Cedar;
+
+ if (t->Port == 0 || t->Port > 65535)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ SERVER_ADMIN_ONLY;
+
+ LockList(a->Server->ServerListenerList);
+ {
+ if (SiAddListener(a->Server, t->Port, t->Enable) == false)
+ {
+ ret = ERR_LISTENER_ALREADY_EXISTS;
+ }
+ else
+ {
+ ALog(a, NULL, "LA_CREATE_LISTENER", t->Port);
+
+ IncrementServerConfigRevision(a->Server);
+ }
+ }
+ UnlockList(a->Server->ServerListenerList);
+
+ SleepThread(250);
+
+ return ret;
+}
+
+// Get server status
+UINT StGetServerStatus(ADMIN *a, RPC_SERVER_STATUS *t)
+{
+ CEDAR *c;
+ UINT i;
+
+ c = a->Server->Cedar;
+
+ Zero(t, sizeof(RPC_SERVER_STATUS));
+
+ Lock(c->TrafficLock);
+ {
+ Copy(&t->Traffic, c->Traffic, sizeof(TRAFFIC));
+ }
+ Unlock(c->TrafficLock);
+
+ GetMemInfo(&t->MemInfo);
+
+ t->ServerType = a->Server->ServerType;
+ t->NumTcpConnections = t->NumTcpConnectionsLocal = t->NumTcpConnectionsRemote = 0;
+ t->NumSessionsTotal = t->NumSessionsLocal = t->NumSessionsRemote = 0;
+
+ t->NumTcpConnectionsLocal = Count(c->CurrentTcpConnections);
+
+ if (a->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ LockList(a->Server->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(a->Server->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(a->Server->FarmMemberList, i);
+
+ if (f->Me == false)
+ {
+ t->NumTcpConnectionsRemote += f->NumTcpConnections;
+ t->NumSessionsRemote += f->NumSessions;
+ AddTraffic(&t->Traffic, &f->Traffic);
+ }
+ }
+ }
+ UnlockList(a->Server->FarmMemberList);
+ }
+
+ t->NumMacTables = t->NumIpTables = t->NumUsers = t->NumGroups = 0;
+
+ // The number of hubs
+ LockList(c->HubList);
+ {
+ t->NumHubTotal = LIST_NUM(c->HubList);
+
+ t->NumHubStandalone = t->NumHubDynamic = t->NumHubStatic = 0;
+
+ for (i = 0;i < LIST_NUM(c->HubList);i++)
+ {
+ HUB *h = LIST_DATA(c->HubList, i);
+ Lock(h->lock);
+ {
+ switch (h->Type)
+ {
+ case HUB_TYPE_STANDALONE:
+ t->NumHubStandalone++;
+ break;
+
+ case HUB_TYPE_FARM_STATIC:
+ t->NumHubStatic++;
+ break;
+
+ case HUB_TYPE_FARM_DYNAMIC:
+ t->NumHubDynamic++;
+ break;
+ }
+ }
+
+ t->NumMacTables += LIST_NUM(h->MacTable);
+ t->NumIpTables += LIST_NUM(h->IpTable);
+
+ if (h->HubDb != NULL)
+ {
+ t->NumUsers += LIST_NUM(h->HubDb->UserList);
+ t->NumGroups += LIST_NUM(h->HubDb->GroupList);
+ }
+
+ Unlock(h->lock);
+ }
+ }
+ UnlockList(c->HubList);
+
+ // The number of sessions
+ t->NumSessionsLocal = Count(c->CurrentSessions);
+ t->NumSessionsTotal = t->NumSessionsLocal + t->NumSessionsRemote;
+ t->NumTcpConnections = t->NumTcpConnectionsLocal + t->NumTcpConnectionsRemote;
+
+ t->AssignedBridgeLicenses = Count(c->AssignedBridgeLicense);
+ t->AssignedClientLicenses = Count(c->AssignedClientLicense);
+
+ t->AssignedBridgeLicensesTotal = a->Server->CurrentAssignedBridgeLicense;
+ t->AssignedClientLicensesTotal = a->Server->CurrentAssignedClientLicense;
+
+ t->CurrentTick = Tick64();
+ t->CurrentTime = SystemTime64();
+
+ t->StartTime = a->Server->StartTime;
+
+ return ERR_NO_ERROR;
+}
+
+// Get server information
+UINT StGetServerInfo(ADMIN *a, RPC_SERVER_INFO *t)
+{
+ CEDAR *c;
+ OS_INFO *info;
+ SYSTEMTIME st;
+ // Validate arguments
+ if (a == NULL || t == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ FreeRpcServerInfo(t);
+ Zero(t, sizeof(RPC_SERVER_INFO));
+
+ c = a->Server->Cedar;
+
+ GetServerProductName(a->Server, t->ServerProductName, sizeof(t->ServerProductName));
+
+ StrCpy(t->ServerVersionString, sizeof(t->ServerVersionString), c->VerString);
+ StrCpy(t->ServerBuildInfoString, sizeof(t->ServerBuildInfoString), c->BuildInfo);
+ t->ServerVerInt = c->Version;
+ t->ServerBuildInt = c->Build;
+ GetMachineName(t->ServerHostName, sizeof(t->ServerHostName));
+ t->ServerType = c->Server->ServerType;
+
+ Zero(&st, sizeof(st));
+ st.wYear = BUILD_DATE_Y;
+ st.wMonth = BUILD_DATE_M;
+ st.wDay = BUILD_DATE_D;
+ st.wHour = BUILD_DATE_HO;
+ st.wMinute = BUILD_DATE_MI;
+ st.wSecond = BUILD_DATE_SE;
+
+ t->ServerBuildDate = SystemToUINT64(&st);
+ StrCpy(t->ServerFamilyName, sizeof(t->ServerFamilyName), UPDATE_FAMILY_NAME);
+
+ info = GetOsInfo();
+ if (info != NULL)
+ {
+ CopyOsInfo(&t->OsInfo, info);
+ }
+
+ return ERR_NO_ERROR;
+}
+
+// Copy OS_INFO
+void CopyOsInfo(OS_INFO *dst, OS_INFO *info)
+{
+ // Validate arguments
+ if (info == NULL || dst == NULL)
+ {
+ return;
+ }
+
+ dst->OsType = info->OsType;
+ dst->OsServicePack = info->OsServicePack;
+ dst->OsSystemName = CopyStr(info->OsSystemName);
+ dst->OsProductName = CopyStr(info->OsProductName);
+ dst->OsVendorName = CopyStr(info->OsVendorName);
+ dst->OsVersion = CopyStr(info->OsVersion);
+ dst->KernelName = CopyStr(info->KernelName);
+ dst->KernelVersion = CopyStr(info->KernelVersion);
+}
+
+// OPENVPN_SSTP_CONFIG
+void InOpenVpnSstpConfig(OPENVPN_SSTP_CONFIG *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(OPENVPN_SSTP_CONFIG));
+
+ t->EnableOpenVPN = PackGetBool(p, "EnableOpenVPN");
+ t->EnableSSTP = PackGetBool(p, "EnableSSTP");
+ PackGetStr(p, "OpenVPNPortList", t->OpenVPNPortList, sizeof(t->OpenVPNPortList));
+}
+void OutOpenVpnSstpConfig(PACK *p, OPENVPN_SSTP_CONFIG *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "EnableOpenVPN", t->EnableOpenVPN);
+ PackAddBool(p, "EnableSSTP", t->EnableSSTP);
+ PackAddStr(p, "OpenVPNPortList", t->OpenVPNPortList);
+}
+
+// DDNS_CLIENT_STATUS
+void InDDnsClientStatus(DDNS_CLIENT_STATUS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(DDNS_CLIENT_STATUS));
+
+ t->Err_IPv4 = PackGetInt(p, "Err_IPv4");
+ t->Err_IPv6 = PackGetInt(p, "Err_IPv6");
+
+ PackGetStr(p, "CurrentHostName", t->CurrentHostName, sizeof(t->CurrentHostName));
+ PackGetStr(p, "CurrentFqdn", t->CurrentFqdn, sizeof(t->CurrentFqdn));
+ PackGetStr(p, "DnsSuffix", t->DnsSuffix, sizeof(t->DnsSuffix));
+ PackGetStr(p, "CurrentIPv4", t->CurrentIPv4, sizeof(t->CurrentIPv4));
+ PackGetStr(p, "CurrentIPv6", t->CurrentIPv6, sizeof(t->CurrentIPv6));
+}
+void OutDDnsClientStatus(PACK *p, DDNS_CLIENT_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "Err_IPv4", t->Err_IPv4);
+ PackAddInt(p, "Err_IPv6", t->Err_IPv6);
+ PackAddStr(p, "CurrentHostName", t->CurrentHostName);
+ PackAddStr(p, "CurrentFqdn", t->CurrentFqdn);
+ PackAddStr(p, "DnsSuffix", t->DnsSuffix);
+ PackAddStr(p, "CurrentIPv4", t->CurrentIPv4);
+ PackAddStr(p, "CurrentIPv6", t->CurrentIPv6);
+}
+
+// INTERNET_SETTING
+void InRpcInternetSetting(INTERNET_SETTING *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ t->ProxyType = PackGetInt(p, "ProxyType");
+ PackGetStr(p, "ProxyHostName", t->ProxyHostName, sizeof(t->ProxyHostName));
+ t->ProxyPort = PackGetInt(p, "ProxyPort");
+ PackGetStr(p, "ProxyUsername", t->ProxyUsername, sizeof(t->ProxyUsername));
+ PackGetStr(p, "ProxyPassword", t->ProxyPassword, sizeof(t->ProxyPassword));
+}
+void OutRpcInternetSetting(PACK *p, INTERNET_SETTING *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "ProxyType", t->ProxyType);
+ PackAddStr(p, "ProxyHostName", t->ProxyHostName);
+ PackAddInt(p, "ProxyPort", t->ProxyPort);
+ PackAddStr(p, "ProxyUsername", t->ProxyUsername);
+ PackAddStr(p, "ProxyPassword", t->ProxyPassword);
+}
+
+// RPC_AZURE_STATUS
+void InRpcAzureStatus(RPC_AZURE_STATUS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_AZURE_STATUS));
+
+ t->IsConnected = PackGetBool(p, "IsConnected");
+ t->IsEnabled = PackGetBool(p, "IsEnabled");
+}
+void OutRpcAzureStatus(PACK *p, RPC_AZURE_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "IsConnected", t->IsConnected);
+ PackAddBool(p, "IsEnabled", t->IsEnabled);
+}
+
+// RPC_SPECIAL_LISTENER
+void InRpcSpecialListener(RPC_SPECIAL_LISTENER *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_SPECIAL_LISTENER));
+
+ t->VpnOverIcmpListener = PackGetBool(p, "VpnOverIcmpListener");
+ t->VpnOverDnsListener = PackGetBool(p, "VpnOverDnsListener");
+}
+void OutRpcSpecialListener(PACK *p, RPC_SPECIAL_LISTENER *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "VpnOverIcmpListener", t->VpnOverIcmpListener);
+ PackAddBool(p, "VpnOverDnsListener", t->VpnOverDnsListener);
+}
+
+
+// ETHERIP_ID
+void InEtherIpId(ETHERIP_ID *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(ETHERIP_ID));
+
+ PackGetStr(p, "Id", t->Id, sizeof(t->Id));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetStr(p, "UserName", t->UserName, sizeof(t->UserName));
+ PackGetStr(p, "Password", t->Password, sizeof(t->Password));
+}
+void OutEtherIpId(PACK *p, ETHERIP_ID *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "Id", t->Id);
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddStr(p, "UserName", t->UserName);
+ PackAddStr(p, "Password", t->Password);
+}
+
+// RPC_ENUM_ETHERIP_ID
+void InRpcEnumEtherIpId(RPC_ENUM_ETHERIP_ID *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_ETHERIP_ID));
+
+ t->NumItem = PackGetInt(p, "NumItem");
+ t->IdList = ZeroMalloc(sizeof(ETHERIP_ID) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ ETHERIP_ID *e = &t->IdList[i];
+
+ PackGetStrEx(p, "Id", e->Id, sizeof(e->Id), i);
+ PackGetStrEx(p, "HubName", e->HubName, sizeof(e->HubName), i);
+ PackGetStrEx(p, "UserName", e->UserName, sizeof(e->UserName), i);
+ PackGetStrEx(p, "Password", e->Password, sizeof(e->Password), i);
+ }
+}
+void OutRpcEnumEtherIpId(PACK *p, RPC_ENUM_ETHERIP_ID *t)
+{
+ UINT i;
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ ETHERIP_ID *e = &t->IdList[i];
+
+ PackAddStrEx(p, "Id", e->Id, i, t->NumItem);
+ PackAddStrEx(p, "HubName", e->HubName, i, t->NumItem);
+ PackAddStrEx(p, "UserName", e->UserName, i, t->NumItem);
+ PackAddStrEx(p, "Password", e->Password, i, t->NumItem);
+ }
+}
+void FreeRpcEnumEtherIpId(RPC_ENUM_ETHERIP_ID *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->IdList);
+}
+
+// IPSEC_SERVICES
+void InIPsecServices(IPSEC_SERVICES *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(IPSEC_SERVICES));
+
+ t->L2TP_Raw = PackGetBool(p, "L2TP_Raw");
+ t->L2TP_IPsec = PackGetBool(p, "L2TP_IPsec");
+ t->EtherIP_IPsec = PackGetBool(p, "EtherIP_IPsec");
+
+ PackGetStr(p, "IPsec_Secret", t->IPsec_Secret, sizeof(t->IPsec_Secret));
+ PackGetStr(p, "L2TP_DefaultHub", t->L2TP_DefaultHub, sizeof(t->L2TP_DefaultHub));
+}
+void OutIPsecServices(PACK *p, IPSEC_SERVICES *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "L2TP_Raw", t->L2TP_Raw);
+ PackAddBool(p, "L2TP_IPsec", t->L2TP_IPsec);
+ PackAddBool(p, "EtherIP_IPsec", t->EtherIP_IPsec);
+
+ PackAddStr(p, "IPsec_Secret", t->IPsec_Secret);
+ PackAddStr(p, "L2TP_DefaultHub", t->L2TP_DefaultHub);
+}
+
+// RPC_WINVER
+void InRpcWinVer(RPC_WINVER *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_WINVER));
+
+ t->IsWindows = PackGetBool(p, "V_IsWindows");
+ t->IsNT = PackGetBool(p, "V_IsNT");
+ t->IsServer = PackGetBool(p, "V_IsServer");
+ t->IsBeta = PackGetBool(p, "V_IsBeta");
+ t->VerMajor = PackGetInt(p, "V_VerMajor");
+ t->VerMinor = PackGetInt(p, "V_VerMinor");
+ t->Build = PackGetInt(p, "V_Build");
+ t->ServicePack = PackGetInt(p, "V_ServicePack");
+ PackGetStr(p, "V_Title", t->Title, sizeof(t->Title));
+}
+void OutRpcWinVer(PACK *p, RPC_WINVER *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "V_IsWindows", t->IsWindows);
+ PackAddBool(p, "V_IsNT", t->IsNT);
+ PackAddBool(p, "V_IsServer", t->IsServer);
+ PackAddBool(p, "V_IsBeta", t->IsBeta);
+ PackAddInt(p, "V_VerMajor", t->VerMajor);
+ PackAddInt(p, "V_VerMinor", t->VerMinor);
+ PackAddInt(p, "V_Build", t->Build);
+ PackAddInt(p, "V_ServicePack", t->ServicePack);
+ PackAddStr(p, "V_Title", t->Title);
+}
+
+// RPC_MSG
+void InRpcMsg(RPC_MSG *t, PACK *p)
+{
+ UINT size;
+ char *utf8;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_MSG));
+
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ size = PackGetDataSize(p, "Msg");
+ utf8 = ZeroMalloc(size + 8);
+ PackGetData(p, "Msg", utf8);
+ t->Msg = CopyUtfToUni(utf8);
+ Free(utf8);
+}
+void OutRpcMsg(PACK *p, RPC_MSG *t)
+{
+ UINT size;
+ char *utf8;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ utf8 = CopyUniToUtf(t->Msg);
+ size = StrLen(utf8);
+ PackAddData(p, "Msg", utf8, size);
+ Free(utf8);
+}
+void FreeRpcMsg(RPC_MSG *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Msg);
+}
+
+// RPC_ENUM_ETH_VLAN
+void InRpcEnumEthVLan(RPC_ENUM_ETH_VLAN *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_ETH_VLAN));
+
+ t->NumItem = PackGetIndexCount(p, "DeviceName");
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_ETH_VLAN_ITEM) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_ETH_VLAN_ITEM *e = &t->Items[i];
+
+ PackGetStrEx(p, "DeviceName", e->DeviceName, sizeof(e->DeviceName), i);
+ PackGetStrEx(p, "Guid", e->Guid, sizeof(e->Guid), i);
+ PackGetStrEx(p, "DeviceInstanceId", e->DeviceInstanceId, sizeof(e->DeviceInstanceId), i);
+ PackGetStrEx(p, "DriverName", e->DriverName, sizeof(e->DriverName), i);
+ PackGetStrEx(p, "DriverType", e->DriverType, sizeof(e->DriverType), i);
+ e->Support = PackGetBoolEx(p, "Support", i);
+ e->Enabled = PackGetBoolEx(p, "Enabled", i);
+ }
+}
+void OutRpcEnumEthVLan(PACK *p, RPC_ENUM_ETH_VLAN *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_ETH_VLAN_ITEM *e = &t->Items[i];
+
+ PackAddStrEx(p, "DeviceName", e->DeviceName, i, t->NumItem);
+ PackAddStrEx(p, "Guid", e->Guid, i, t->NumItem);
+ PackAddStrEx(p, "DeviceInstanceId", e->DeviceInstanceId, i, t->NumItem);
+ PackAddStrEx(p, "DriverName", e->DriverName, i, t->NumItem);
+ PackAddStrEx(p, "DriverType", e->DriverType, i, t->NumItem);
+ PackAddBoolEx(p, "Support", e->Support, i, t->NumItem);
+ PackAddBoolEx(p, "Enabled", e->Enabled, i, t->NumItem);
+ }
+}
+void FreeRpcEnumEthVLan(RPC_ENUM_ETH_VLAN *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_ENUM_LOG_FILE
+void InRpcEnumLogFile(RPC_ENUM_LOG_FILE *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_LOG_FILE));
+ t->NumItem = PackGetInt(p, "NumItem");
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_LOG_FILE_ITEM) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_LOG_FILE_ITEM *e = &t->Items[i];
+
+ PackGetStrEx(p, "FilePath", e->FilePath, sizeof(e->FilePath), i);
+ PackGetStrEx(p, "ServerName", e->ServerName, sizeof(e->ServerName), i);
+ e->FileSize = PackGetIntEx(p, "FileSize", i);
+ e->UpdatedTime = PackGetInt64Ex(p, "UpdatedTime", i);
+ }
+}
+void OutRpcEnumLogFile(PACK *p, RPC_ENUM_LOG_FILE *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_LOG_FILE_ITEM *e = &t->Items[i];
+
+ PackAddStrEx(p, "FilePath", e->FilePath, i, t->NumItem);
+ PackAddStrEx(p, "ServerName", e->ServerName, i, t->NumItem);
+ PackAddIntEx(p, "FileSize", e->FileSize, i, t->NumItem);
+ PackAddInt64Ex(p, "UpdatedTime", e->UpdatedTime, i, t->NumItem);
+ }
+}
+void FreeRpcEnumLogFile(RPC_ENUM_LOG_FILE *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+void AdjoinRpcEnumLogFile(RPC_ENUM_LOG_FILE *t, RPC_ENUM_LOG_FILE *src)
+{
+ LIST *o;
+ UINT i;
+ // Validate arguments
+ if (t == NULL || src == NULL)
+ {
+ return;
+ }
+
+ o = NewListFast(CmpLogFile);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_LOG_FILE_ITEM *e = &t->Items[i];
+ LOG_FILE *f = ZeroMalloc(sizeof(LOG_FILE));
+
+ f->FileSize = e->FileSize;
+ StrCpy(f->Path, sizeof(f->Path), e->FilePath);
+ StrCpy(f->ServerName, sizeof(f->ServerName), e->ServerName);
+ f->UpdatedTime = e->UpdatedTime;
+
+ Add(o, f);
+ }
+
+ for (i = 0;i < src->NumItem;i++)
+ {
+ RPC_ENUM_LOG_FILE_ITEM *e = &src->Items[i];
+ LOG_FILE *f = ZeroMalloc(sizeof(LOG_FILE));
+
+ f->FileSize = e->FileSize;
+ StrCpy(f->Path, sizeof(f->Path), e->FilePath);
+ StrCpy(f->ServerName, sizeof(f->ServerName), e->ServerName);
+ f->UpdatedTime = e->UpdatedTime;
+
+ Add(o, f);
+ }
+
+ FreeRpcEnumLogFile(t);
+
+ Sort(o);
+
+ Zero(t, sizeof(RPC_ENUM_LOG_FILE));
+ t->NumItem = LIST_NUM(o);
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_LOG_FILE_ITEM) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ LOG_FILE *f = LIST_DATA(o, i);
+ RPC_ENUM_LOG_FILE_ITEM *e = &t->Items[i];
+
+ StrCpy(e->FilePath, sizeof(e->FilePath), f->Path);
+ StrCpy(e->ServerName, sizeof(e->ServerName), f->ServerName);
+ e->FileSize = f->FileSize;
+ e->UpdatedTime = f->UpdatedTime;
+ }
+
+ FreeEnumLogFile(o);
+}
+
+// RPC_READ_LOG_FILE
+void InRpcReadLogFile(RPC_READ_LOG_FILE *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_READ_LOG_FILE));
+ PackGetStr(p, "FilePath", t->FilePath, sizeof(t->FilePath));
+ PackGetStr(p, "ServerName", t->ServerName, sizeof(t->ServerName));
+ t->Offset = PackGetInt(p, "Offset");
+
+ t->Buffer = PackGetBuf(p, "Buffer");
+}
+void OutRpcReadLogFile(PACK *p, RPC_READ_LOG_FILE *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "FilePath", t->FilePath);
+ PackAddStr(p, "ServerName", t->ServerName);
+ PackAddInt(p, "Offset", t->Offset);
+
+ if (t->Buffer != NULL)
+ {
+ PackAddBuf(p, "Buffer", t->Buffer);
+ }
+}
+void FreeRpcReadLogFile(RPC_READ_LOG_FILE *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->Buffer != NULL)
+ {
+ FreeBuf(t->Buffer);
+ }
+}
+
+// RPC_AC_LIST
+void InRpcAcList(RPC_AC_LIST *t, PACK *p)
+{
+ UINT i;
+ LIST *o;
+ UINT num;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_AC_LIST));
+ o = NewAcList();
+
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ num = PackGetInt(p, "NumItem");
+
+ for (i = 0;i < num;i++)
+ {
+ AC *ac = ZeroMalloc(sizeof(AC));
+
+ ac->Deny = PackGetBoolEx(p, "Deny", i);
+ PackGetIpEx(p, "IpAddress", &ac->IpAddress, i);
+ ac->Masked = PackGetBoolEx(p, "Masked", i);
+
+ if (ac->Masked)
+ {
+ PackGetIpEx(p, "SubnetMask", &ac->SubnetMask, i);
+ }
+
+ ac->Priority = PackGetIntEx(p, "Priority", i);
+
+ AddAc(o, ac);
+
+ Free(ac);
+ }
+
+ t->o = o;
+}
+void OutRpcAcList(PACK *p, RPC_AC_LIST *t)
+{
+ UINT i, num;
+ LIST *o;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ o = t->o;
+ num = LIST_NUM(o);
+
+ PackAddInt(p, "NumItem", num);
+
+ PackAddStr(p, "HubName", t->HubName);
+
+ for (i = 0;i < num;i++)
+ {
+ AC *ac = LIST_DATA(o, i);
+
+ PackAddBoolEx(p, "Deny", ac->Deny, i, num);
+ PackAddIpEx(p, "IpAddress", &ac->IpAddress, i, num);
+ PackAddBoolEx(p, "Masked", ac->Masked, i, num);
+
+ PackAddIpEx(p, "SubnetMask", &ac->SubnetMask, i, num);
+
+ PackAddIntEx(p, "Priority", ac->Priority, i, num);
+ }
+}
+void FreeRpcAcList(RPC_AC_LIST *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FreeAcList(t->o);
+}
+
+// RPC_INT
+void InRpcInt(RPC_INT *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_INT));
+ t->IntValue = PackGetInt(p, "IntValue");
+}
+void OutRpcInt(PACK *p, RPC_INT *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "IntValue", t->IntValue);
+}
+
+// RPC_ENUM_CRL
+void InRpcEnumCrl(RPC_ENUM_CRL *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_CRL));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->NumItem = PackGetInt(p, "NumItem");
+
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_CRL_ITEM) * t->NumItem);
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_CRL_ITEM *e = &t->Items[i];
+
+ e->Key = PackGetIntEx(p, "Key", i);
+ PackGetUniStrEx(p, "CrlInfo", e->CrlInfo, sizeof(e->CrlInfo), i);
+ }
+}
+void OutRpcEnumCrl(PACK *p, RPC_ENUM_CRL *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddInt(p, "NumItem", t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_CRL_ITEM *e = &t->Items[i];
+
+ PackAddIntEx(p, "Key", e->Key, i, t->NumItem);
+ PackAddUniStrEx(p, "CrlInfo", e->CrlInfo, i, t->NumItem);
+ }
+}
+void FreeRpcEnumCrl(RPC_ENUM_CRL *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_CRL
+void InRpcCrl(RPC_CRL *t, PACK *p)
+{
+ BUF *b;
+ NAME *n;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_CRL));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->Key = PackGetInt(p, "Key");
+ b = PackGetBuf(p, "Serial");
+ t->Crl = ZeroMalloc(sizeof(CRL));
+ if (b != NULL)
+ {
+ t->Crl->Serial = NewXSerial(b->Buf, b->Size);
+ FreeBuf(b);
+ }
+ t->Crl->Name = ZeroMalloc(sizeof(NAME));
+ n = t->Crl->Name;
+ if (PackGetUniStr(p, "CommonName", tmp, sizeof(tmp)))
+ {
+ n->CommonName = CopyUniStr(tmp);
+ }
+ if (PackGetUniStr(p, "Organization", tmp, sizeof(tmp)))
+ {
+ n->Organization = CopyUniStr(tmp);
+ }
+ if (PackGetUniStr(p, "Unit", tmp, sizeof(tmp)))
+ {
+ n->Unit = CopyUniStr(tmp);
+ }
+ if (PackGetUniStr(p, "Country", tmp, sizeof(tmp)))
+ {
+ n->Country = CopyUniStr(tmp);
+ }
+ if (PackGetUniStr(p, "State", tmp, sizeof(tmp)))
+ {
+ n->State = CopyUniStr(tmp);
+ }
+ if (PackGetUniStr(p, "Local", tmp, sizeof(tmp)))
+ {
+ n->Local = CopyUniStr(tmp);
+ }
+ if (PackGetDataSize(p, "DigestMD5") == MD5_SIZE)
+ {
+ PackGetData(p, "DigestMD5", t->Crl->DigestMD5);
+ }
+ if (PackGetDataSize(p, "DigestSHA1") == SHA1_SIZE)
+ {
+ PackGetData(p, "DigestSHA1", t->Crl->DigestSHA1);
+ }
+}
+void OutRpcCrl(PACK *p, RPC_CRL *t)
+{
+ NAME *n;
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddInt(p, "Key", t->Key);
+
+ if (t->Crl == NULL)
+ {
+ return;
+ }
+
+ if (t->Crl->Serial != NULL)
+ {
+ PackAddData(p, "Serial", t->Crl->Serial->data, t->Crl->Serial->size);
+ }
+ n = t->Crl->Name;
+ if (n->CommonName != NULL)
+ {
+ PackAddUniStr(p, "CommonName", n->CommonName);
+ }
+ if (n->Organization != NULL)
+ {
+ PackAddUniStr(p, "Organization", n->Organization);
+ }
+ if (n->Unit != NULL)
+ {
+ PackAddUniStr(p, "Unit", n->Unit);
+ }
+ if (n->Country != NULL)
+ {
+ PackAddUniStr(p, "Country", n->Country);
+ }
+ if (n->State != NULL)
+ {
+ PackAddUniStr(p, "State", n->State);
+ }
+ if (n->Local != NULL)
+ {
+ PackAddUniStr(p, "Local", n->Local);
+ }
+ if (IsZero(t->Crl->DigestMD5, MD5_SIZE) == false)
+ {
+ PackAddData(p, "DigestMD5", t->Crl->DigestMD5, MD5_SIZE);
+ }
+ if (IsZero(t->Crl->DigestSHA1, SHA1_SIZE) == false)
+ {
+ PackAddData(p, "DigestSHA1", t->Crl->DigestSHA1, SHA1_SIZE);
+ }
+}
+void FreeRpcCrl(RPC_CRL *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FreeCrl(t->Crl);
+}
+
+// RPC_ENUM_L3TABLE
+void InRpcEnumL3Table(RPC_ENUM_L3TABLE *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_L3TABLE));
+ t->NumItem = PackGetInt(p, "NumItem");
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+ t->Items = ZeroMalloc(sizeof(RPC_L3TABLE) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_L3TABLE *e = &t->Items[i];
+
+ e->NetworkAddress = PackGetIp32Ex(p, "NetworkAddress", i);
+ e->SubnetMask = PackGetIp32Ex(p, "SubnetMask", i);
+ e->GatewayAddress = PackGetIp32Ex(p, "GatewayAddress", i);
+ e->Metric = PackGetIntEx(p, "Metric", i);
+ }
+}
+void OutRpcEnumL3Table(PACK *p, RPC_ENUM_L3TABLE *t)
+{
+ UINT i;
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+ PackAddStr(p, "Name", t->Name);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_L3TABLE *e = &t->Items[i];
+
+ PackAddIp32Ex(p, "NetworkAddress", e->NetworkAddress, i, t->NumItem);
+ PackAddIp32Ex(p, "SubnetMask", e->SubnetMask, i, t->NumItem);
+ PackAddIp32Ex(p, "GatewayAddress", e->GatewayAddress, i, t->NumItem);
+ PackAddIntEx(p, "Metric", e->Metric, i, t->NumItem);
+ }
+}
+void FreeRpcEnumL3Table(RPC_ENUM_L3TABLE *t)
+{
+ Free(t->Items);
+}
+
+// RPC_L3TABLE
+void InRpcL3Table(RPC_L3TABLE *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_L3TABLE));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+ t->NetworkAddress = PackGetIp32(p, "NetworkAddress");
+ t->SubnetMask = PackGetIp32(p, "SubnetMask");
+ t->GatewayAddress = PackGetIp32(p, "GatewayAddress");
+ t->Metric = PackGetInt(p, "Metric");
+}
+void OutRpcL3Table(PACK *p, RPC_L3TABLE *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "Name", t->Name);
+ PackAddIp32(p, "NetworkAddress", t->NetworkAddress);
+ PackAddIp32(p, "SubnetMask", t->SubnetMask);
+ PackAddIp32(p, "GatewayAddress", t->GatewayAddress);
+ PackAddInt(p, "Metric", t->Metric);
+}
+
+// RPC_ENUM_L3IF
+void InRpcEnumL3If(RPC_ENUM_L3IF *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_L3IF));
+ t->NumItem = PackGetInt(p, "NumItem");
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+ t->Items = ZeroMalloc(sizeof(RPC_L3IF) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_L3IF *f = &t->Items[i];
+
+ PackGetStrEx(p, "HubName", f->HubName, sizeof(f->HubName), i);
+ f->IpAddress = PackGetIp32Ex(p, "IpAddress", i);
+ f->SubnetMask = PackGetIp32Ex(p, "SubnetMask", i);
+ }
+}
+void OutRpcEnumL3If(PACK *p, RPC_ENUM_L3IF *t)
+{
+ UINT i;
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+ PackAddStr(p, "Name", t->Name);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_L3IF *f = &t->Items[i];
+
+ PackAddStrEx(p, "HubName", f->HubName, i, t->NumItem);
+ PackAddIp32Ex(p, "IpAddress", f->IpAddress, i, t->NumItem);
+ PackAddIp32Ex(p, "SubnetMask", f->SubnetMask, i, t->NumItem);
+ }
+}
+void FreeRpcEnumL3If(RPC_ENUM_L3IF *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_L3IF
+void InRpcL3If(RPC_L3IF *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_L3IF));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->IpAddress = PackGetIp32(p, "IpAddress");
+ t->SubnetMask = PackGetIp32(p, "SubnetMask");
+}
+void OutRpcL3If(PACK *p, RPC_L3IF *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "Name", t->Name);
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddIp32(p, "IpAddress", t->IpAddress);
+ PackAddIp32(p, "SubnetMask", t->SubnetMask);
+}
+
+// RPC_L3SW
+void InRpcL3Sw(RPC_L3SW *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_L3SW));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+}
+void OutRpcL3Sw(PACK *p, RPC_L3SW *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "Name", t->Name);
+}
+
+// RPC_ENUM_L3SW
+void InRpcEnumL3Sw(RPC_ENUM_L3SW *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_L3SW));
+ t->NumItem = PackGetInt(p, "NumItem");
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_L3SW_ITEM) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_L3SW_ITEM *s = &t->Items[i];
+
+ PackGetStrEx(p, "Name", s->Name, sizeof(s->Name), i);
+ s->NumInterfaces = PackGetIntEx(p, "NumInterfaces", i);
+ s->NumTables = PackGetIntEx(p, "NumTables", i);
+ s->Active = PackGetBoolEx(p, "Active", i);
+ s->Online = PackGetBoolEx(p, "Online", i);
+ }
+}
+void OutRpcEnumL3Sw(PACK *p, RPC_ENUM_L3SW *t)
+{
+ UINT i;
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_L3SW_ITEM *s = &t->Items[i];
+
+ PackAddStrEx(p, "Name", s->Name, i, t->NumItem);
+ PackAddIntEx(p, "NumInterfaces", s->NumInterfaces, i, t->NumItem);
+ PackAddIntEx(p, "NumTables", s->NumTables, i, t->NumItem);
+ PackAddBoolEx(p, "Active", s->Active, i, t->NumItem);
+ PackAddBoolEx(p, "Online", s->Online, i, t->NumItem);
+ }
+}
+void FreeRpcEnumL3Sw(RPC_ENUM_L3SW *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_ENUM_ETH
+void InRpcEnumEth(RPC_ENUM_ETH *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_ETH));
+ t->NumItem = PackGetInt(p, "NumItem");
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_ETH_ITEM) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_ETH_ITEM *e = &t->Items[i];
+ PackGetStrEx(p, "DeviceName", e->DeviceName, sizeof(e->DeviceName), i);
+ PackGetUniStrEx(p, "NetworkConnectionName", e->NetworkConnectionName, sizeof(e->NetworkConnectionName), i);
+ }
+}
+void OutRpcEnumEth(PACK *p, RPC_ENUM_ETH *t)
+{
+ UINT i;
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_ETH_ITEM *e = &t->Items[i];
+ PackAddStrEx(p, "DeviceName", e->DeviceName, i, t->NumItem);
+ PackAddUniStrEx(p, "NetworkConnectionName", e->NetworkConnectionName, i, t->NumItem);
+ }
+}
+void FreeRpcEnumEth(RPC_ENUM_ETH *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_LOCALBRIDGE
+void InRpcLocalBridge(RPC_LOCALBRIDGE *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_LOCALBRIDGE));
+ PackGetStr(p, "DeviceName", t->DeviceName, sizeof(t->DeviceName));
+ PackGetStr(p, "HubNameLB", t->HubName, sizeof(t->HubName));
+ t->TapMode = PackGetBool(p, "TapMode");
+}
+void OutRpcLocalBridge(PACK *p, RPC_LOCALBRIDGE *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "DeviceName", t->DeviceName);
+ PackAddStr(p, "HubNameLB", t->HubName);
+ PackAddBool(p, "TapMode", t->TapMode);
+}
+
+// RPC_ENUM_LOCALBRIDGE
+void InRpcEnumLocalBridge(RPC_ENUM_LOCALBRIDGE *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_LOCALBRIDGE));
+ t->NumItem = PackGetInt(p, "NumItem");
+ t->Items = ZeroMalloc(sizeof(RPC_LOCALBRIDGE) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_LOCALBRIDGE *e = &t->Items[i];
+
+ PackGetStrEx(p, "DeviceName", e->DeviceName, sizeof(e->DeviceName), i);
+ PackGetStrEx(p, "HubNameLB", e->HubName, sizeof(e->HubName), i);
+ e->Online = PackGetBoolEx(p, "Online", i);
+ e->Active = PackGetBoolEx(p, "Active", i);
+ e->TapMode = PackGetBoolEx(p, "TapMode", i);
+ }
+}
+void OutRpcEnumLocalBridge(PACK *p, RPC_ENUM_LOCALBRIDGE *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_LOCALBRIDGE *e = &t->Items[i];
+
+ PackAddStrEx(p, "DeviceName", e->DeviceName, i, t->NumItem);
+ PackAddStrEx(p, "HubNameLB", e->HubName, i, t->NumItem);
+ PackAddBoolEx(p, "Online", e->Online, i, t->NumItem);
+ PackAddBoolEx(p, "Active", e->Active, i, t->NumItem);
+ PackAddBoolEx(p, "TapMode", e->TapMode, i, t->NumItem);
+ }
+}
+void FreeRpcEnumLocalBridge(RPC_ENUM_LOCALBRIDGE *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+ Free(t->Items);
+}
+
+// MEMINFO
+void InRpcMemInfo(MEMINFO *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(MEMINFO));
+ t->TotalMemory = PackGetInt64(p, "TotalMemory");
+ t->UsedMemory = PackGetInt64(p, "UsedMemory");
+ t->FreeMemory = PackGetInt64(p, "FreeMemory");
+ t->TotalPhys = PackGetInt64(p, "TotalPhys");
+ t->UsedPhys = PackGetInt64(p, "UsedPhys");
+ t->FreePhys = PackGetInt64(p, "FreePhys");
+}
+void OutRpcMemInfo(PACK *p, MEMINFO *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt64(p, "TotalMemory", t->TotalMemory);
+ PackAddInt64(p, "UsedMemory", t->UsedMemory);
+ PackAddInt64(p, "FreeMemory", t->FreeMemory);
+ PackAddInt64(p, "TotalPhys", t->TotalPhys);
+ PackAddInt64(p, "UsedPhys", t->UsedPhys);
+ PackAddInt64(p, "FreePhys", t->FreePhys);
+}
+
+// OS_INFO
+void InRpcOsInfo(OS_INFO *t, PACK *p)
+{
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(OS_INFO));
+ t->OsType = PackGetInt(p, "OsType");
+ t->OsServicePack = PackGetInt(p, "OsServicePack");
+ if (PackGetStr(p, "OsSystemName", tmp, sizeof(tmp)))
+ {
+ t->OsSystemName = CopyStr(tmp);
+ }
+ if (PackGetStr(p, "OsProductName", tmp, sizeof(tmp)))
+ {
+ t->OsProductName = CopyStr(tmp);
+ }
+ if (PackGetStr(p, "OsVendorName", tmp, sizeof(tmp)))
+ {
+ t->OsVendorName = CopyStr(tmp);
+ }
+ if (PackGetStr(p, "OsVersion", tmp, sizeof(tmp)))
+ {
+ t->OsVersion = CopyStr(tmp);
+ }
+ if (PackGetStr(p, "KernelName", tmp, sizeof(tmp)))
+ {
+ t->KernelName = CopyStr(tmp);
+ }
+ if (PackGetStr(p, "KernelVersion", tmp, sizeof(tmp)))
+ {
+ t->KernelVersion = CopyStr(tmp);
+ }
+}
+void OutRpcOsInfo(PACK *p, OS_INFO *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "OsType", t->OsType);
+ PackAddInt(p, "OsServicePack", t->OsServicePack);
+ PackAddStr(p, "OsSystemName", t->OsSystemName);
+ PackAddStr(p, "OsProductName", t->OsProductName);
+ PackAddStr(p, "OsVendorName", t->OsVendorName);
+ PackAddStr(p, "OsVersion", t->OsVersion);
+ PackAddStr(p, "KernelName", t->KernelName);
+ PackAddStr(p, "KernelVersion", t->KernelVersion);
+}
+void FreeRpcOsInfo(OS_INFO *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->OsSystemName);
+ Free(t->OsProductName);
+ Free(t->OsVendorName);
+ Free(t->OsVersion);
+ Free(t->KernelName);
+ Free(t->KernelVersion);
+}
+
+// Read a local log file
+void SiReadLocalLogFile(SERVER *s, char *filepath, UINT offset, RPC_READ_LOG_FILE *t)
+{
+ char exe_dir[MAX_PATH], full_path[MAX_PATH];
+ IO *o;
+ // Validate arguments
+ if (s == NULL || t == NULL || filepath == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_READ_LOG_FILE));
+
+ GetExeDir(exe_dir, sizeof(exe_dir));
+ Format(full_path, sizeof(full_path), "%s/%s", exe_dir, filepath);
+
+ // Read file
+ o = FileOpenEx(full_path, false, false);
+ if (o != NULL)
+ {
+ UINT filesize = FileSize(o);
+
+ if (offset < filesize)
+ {
+ UINT readsize = MIN(filesize - offset, FTP_BLOCK_SIZE);
+ void *buf = ZeroMalloc(readsize);
+
+ FileSeek(o, FILE_BEGIN, offset);
+ FileRead(o, buf, readsize);
+
+ t->Buffer = NewBuf();
+ WriteBuf(t->Buffer, buf, readsize);
+ Free(buf);
+ }
+
+ FileClose(o);
+ }
+}
+
+// Enumerate local log files
+void SiEnumLocalLogFileList(SERVER *s, char *hubname, RPC_ENUM_LOG_FILE *t)
+{
+ LIST *o;
+ UINT i;
+ // Validate arguments
+ if (s == NULL || t == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_LOG_FILE));
+
+ o = EnumLogFile(hubname);
+
+ t->NumItem = LIST_NUM(o);
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_LOG_FILE_ITEM) * t->NumItem);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ LOG_FILE *f = LIST_DATA(o, i);
+ RPC_ENUM_LOG_FILE_ITEM *e = &t->Items[i];
+
+ StrCpy(e->FilePath, sizeof(e->FilePath), f->Path);
+ StrCpy(e->ServerName, sizeof(e->ServerName), f->ServerName);
+ e->FileSize = f->FileSize;
+ e->UpdatedTime = f->UpdatedTime;
+ }
+
+ FreeEnumLogFile(o);
+}
+
+// Enumerate local sessions
+void SiEnumLocalSession(SERVER *s, char *hubname, RPC_ENUM_SESSION *t)
+{
+ HUB *h;
+ // Validate arguments
+ if (s == NULL || hubname == NULL || t == NULL)
+ {
+ return;
+ }
+
+ LockHubList(s->Cedar);
+ h = GetHub(s->Cedar, hubname);
+ UnlockHubList(s->Cedar);
+
+ if (h == NULL)
+ {
+ t->NumSession = 0;
+ t->Sessions = ZeroMalloc(0);
+ return;
+ }
+
+ LockList(h->SessionList);
+ {
+ UINT i;
+ t->NumSession = LIST_NUM(h->SessionList);
+ t->Sessions = ZeroMalloc(sizeof(RPC_ENUM_SESSION_ITEM) * t->NumSession);
+
+ for (i = 0;i < t->NumSession;i++)
+ {
+ SESSION *s = LIST_DATA(h->SessionList, i);
+ RPC_ENUM_SESSION_ITEM *e = &t->Sessions[i];
+ Lock(s->lock);
+ {
+ StrCpy(e->Name, sizeof(e->Name), s->Name);
+ StrCpy(e->Username, sizeof(e->Username), s->Username);
+ e->Ip = IPToUINT(&s->Connection->ClientIp);
+ StrCpy(e->Hostname, sizeof(e->Hostname), s->Connection->ClientHostname);
+ e->MaxNumTcp = s->MaxConnection;
+ e->LinkMode = s->LinkModeServer;
+ e->SecureNATMode = s->SecureNATMode;
+ e->BridgeMode = s->BridgeMode;
+ e->Layer3Mode = s->L3SwitchMode;
+ e->VLanId = s->VLanId;
+ LockList(s->Connection->Tcp->TcpSockList);
+ {
+ e->CurrentNumTcp = s->Connection->Tcp->TcpSockList->num_item;
+ }
+ UnlockList(s->Connection->Tcp->TcpSockList);
+ Lock(s->TrafficLock);
+ {
+ e->PacketSize = GetTrafficPacketSize(s->Traffic);
+ e->PacketNum = GetTrafficPacketNum(s->Traffic);
+ }
+ Unlock(s->TrafficLock);
+ e->Client_BridgeMode = s->IsBridgeMode;
+ e->Client_MonitorMode = s->IsMonitorMode;
+ Copy(e->UniqueId, s->NodeInfo.UniqueId, 16);
+ }
+ Unlock(s->lock);
+ GetMachineName(e->RemoteHostname, sizeof(e->RemoteHostname));
+ }
+ }
+ UnlockList(h->SessionList);
+
+ ReleaseHub(h);
+}
+
+// RPC_ENUM_LICENSE_KEY
+void InRpcEnumLicenseKey(RPC_ENUM_LICENSE_KEY *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_LICENSE_KEY));
+ t->NumItem = PackGetInt(p, "NumItem");
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_LICENSE_KEY_ITEM) * t->NumItem);
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_LICENSE_KEY_ITEM *e = &t->Items[i];
+
+ e->Id = PackGetIntEx(p, "Id", i);
+ PackGetStrEx(p, "LicenseKey", e->LicenseKey, sizeof(e->LicenseKey), i);
+ PackGetStrEx(p, "LicenseId", e->LicenseId, sizeof(e->LicenseId), i);
+ PackGetStrEx(p, "LicenseName", e->LicenseName, sizeof(e->LicenseName), i);
+ e->Expires = PackGetInt64Ex(p, "Expires", i);
+ e->Status = PackGetIntEx(p, "Status", i);
+ e->ProductId = PackGetIntEx(p, "ProductId", i);
+ e->SystemId = PackGetInt64Ex(p, "SystemId", i);
+ e->SerialId = PackGetIntEx(p, "SerialId", i);
+ }
+}
+void OutRpcEnumLicenseKey(PACK *p, RPC_ENUM_LICENSE_KEY *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_LICENSE_KEY_ITEM *e = &t->Items[i];
+
+ PackAddIntEx(p, "Id", e->Id, i, t->NumItem);
+ PackAddStrEx(p, "LicenseKey", e->LicenseKey, i, t->NumItem);
+ PackAddStrEx(p, "LicenseId", e->LicenseId, i, t->NumItem);
+ PackAddStrEx(p, "LicenseName", e->LicenseName, i, t->NumItem);
+ PackAddInt64Ex(p, "Expires", e->Expires, i, t->NumItem);
+ PackAddIntEx(p, "Status", e->Status, i, t->NumItem);
+ PackAddIntEx(p, "ProductId", e->ProductId, i, t->NumItem);
+ PackAddInt64Ex(p, "SystemId", e->SystemId, i, t->NumItem);
+ PackAddIntEx(p, "SerialId", e->SerialId, i, t->NumItem);
+ }
+}
+void FreeRpcEnumLicenseKey(RPC_ENUM_LICENSE_KEY *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_LICENSE_STATUS
+void InRpcLicenseStatus(RPC_LICENSE_STATUS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_LICENSE_STATUS));
+
+ t->EditionId = PackGetInt(p, "EditionId");
+ PackGetStr(p, "EditionStr", t->EditionStr, sizeof(t->EditionStr) );
+ t->SystemId = PackGetInt64(p, "SystemId");
+ t->SystemExpires = PackGetInt64(p, "SystemExpires");
+ t->NumClientConnectLicense = PackGetInt(p, "NumClientConnectLicense");
+ t->NumBridgeConnectLicense = PackGetInt(p, "NumBridgeConnectLicense");
+
+ // v3.0
+ t->NeedSubscription = PackGetBool(p, "NeedSubscription");
+ t->AllowEnterpriseFunction = PackGetBool(p, "AllowEnterpriseFunction");
+ t->SubscriptionExpires = PackGetInt64(p, "SubscriptionExpires");
+ t->IsSubscriptionExpired = PackGetBool(p, "IsSubscriptionExpired");
+ t->NumUserCreationLicense = PackGetInt(p, "NumUserCreationLicense");
+ t->ReleaseDate = PackGetInt64(p, "ReleaseDate");
+}
+void OutRpcLicenseStatus(PACK *p, RPC_LICENSE_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "EditionId", t->EditionId);
+ PackAddStr(p, "EditionStr", t->EditionStr);
+ PackAddInt64(p, "SystemId", t->SystemId);
+ PackAddInt64(p, "SystemExpires", t->SystemExpires);
+ PackAddInt(p, "NumClientConnectLicense", t->NumClientConnectLicense);
+ PackAddInt(p, "NumBridgeConnectLicense", t->NumBridgeConnectLicense);
+
+ // v3.0
+ PackAddBool(p, "NeedSubscription", t->NeedSubscription);
+ PackAddBool(p, "AllowEnterpriseFunction", t->AllowEnterpriseFunction);
+ PackAddInt64(p, "SubscriptionExpires", t->SubscriptionExpires);
+ PackAddBool(p, "IsSubscriptionExpired", t->IsSubscriptionExpired);
+ PackAddInt(p, "NumUserCreationLicense", t->NumUserCreationLicense);
+ PackAddInt64(p, "ReleaseDate", t->ReleaseDate);
+}
+
+// RPC_ADMIN_OPTION
+void InRpcAdminOption(RPC_ADMIN_OPTION *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ADMIN_OPTION));
+ t->NumItem = PackGetInt(p, "NumItem");
+ t->Items = ZeroMalloc(sizeof(ADMIN_OPTION) * t->NumItem);
+
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ ADMIN_OPTION *o = &t->Items[i];
+
+ PackGetStrEx(p, "Name", o->Name, sizeof(o->Name), i);
+ o->Value = PackGetIntEx(p, "Value", i);
+ }
+}
+void OutRpcAdminOption(PACK *p, RPC_ADMIN_OPTION *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+
+ PackAddStr(p, "HubName", t->HubName);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ ADMIN_OPTION *o = &t->Items[i];
+
+ PackAddStrEx(p, "Name", o->Name, i, t->NumItem);
+ PackAddIntEx(p, "Value", o->Value, i, t->NumItem);
+ }
+}
+void FreeRpcAdminOption(RPC_ADMIN_OPTION *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_CONFIG
+void InRpcConfig(RPC_CONFIG *t, PACK *p)
+{
+ UINT size;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_CONFIG));
+ PackGetStr(p, "FileName", t->FileName, sizeof(t->FileName));
+ size = PackGetDataSize(p, "FileData");
+ t->FileData = ZeroMalloc(size + 1);
+ PackGetData(p, "FileData", t->FileData);
+}
+void OutRpcConfig(PACK *p, RPC_CONFIG *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "FileName", t->FileName);
+ PackAddData(p, "FileData", t->FileData, StrLen(t->FileData));
+}
+void FreeRpcConfig(RPC_CONFIG *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->FileData);
+}
+
+// RPC_BRIDGE_SUPPORT
+void InRpcBridgeSupport(RPC_BRIDGE_SUPPORT *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_BRIDGE_SUPPORT));
+
+ t->IsBridgeSupportedOs = PackGetBool(p, "IsBridgeSupportedOs");
+ t->IsWinPcapNeeded = PackGetBool(p, "IsWinPcapNeeded");
+}
+void OutRpcBridgeSupport(PACK *p, RPC_BRIDGE_SUPPORT *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "IsBridgeSupportedOs", t->IsBridgeSupportedOs);
+ PackAddBool(p, "IsWinPcapNeeded",t->IsWinPcapNeeded);
+}
+
+// RPC_ADD_ACCESS
+void InRpcAddAccess(RPC_ADD_ACCESS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ADD_ACCESS));
+
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ InRpcAccess(&t->Access, p);
+}
+void OutRpcAddAccess(PACK *p, RPC_ADD_ACCESS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ OutRpcAccess(p, &t->Access);
+}
+
+// RPC_DELETE_ACCESS
+void InRpcDeleteAccess(RPC_DELETE_ACCESS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_DELETE_ACCESS));
+
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->Id = PackGetInt(p, "Id");
+}
+void OutRpcDeleteAccess(PACK *p, RPC_DELETE_ACCESS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddInt(p, "Id", t->Id);
+}
+
+
+// RPC_SERVER_INFO
+void InRpcServerInfo(RPC_SERVER_INFO *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_SERVER_INFO));
+
+ PackGetStr(p, "ServerProductName", t->ServerProductName, sizeof(t->ServerProductName));
+ PackGetStr(p, "ServerVersionString", t->ServerVersionString, sizeof(t->ServerVersionString));
+ PackGetStr(p, "ServerBuildInfoString", t->ServerBuildInfoString, sizeof(t->ServerBuildInfoString));
+ t->ServerVerInt = PackGetInt(p, "ServerVerInt");
+ t->ServerBuildInt = PackGetInt(p, "ServerBuildInt");
+ PackGetStr(p, "ServerHostName", t->ServerHostName, sizeof(t->ServerHostName));
+ t->ServerType = PackGetInt(p, "ServerType");
+ t->ServerBuildDate = PackGetInt64(p, "ServerBuildDate");
+ PackGetStr(p, "ServerFamilyName", t->ServerFamilyName, sizeof(t->ServerFamilyName));
+ InRpcOsInfo(&t->OsInfo, p);
+}
+void OutRpcServerInfo(PACK *p, RPC_SERVER_INFO *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "ServerProductName", t->ServerProductName);
+ PackAddStr(p, "ServerVersionString", t->ServerVersionString);
+ PackAddStr(p, "ServerBuildInfoString", t->ServerBuildInfoString);
+ PackAddInt(p, "ServerVerInt", t->ServerVerInt);
+ PackAddInt(p, "ServerBuildInt", t->ServerBuildInt);
+ PackAddStr(p, "ServerHostName", t->ServerHostName);
+ PackAddInt(p, "ServerType", t->ServerType);
+ PackAddInt64(p, "ServerBuildDate", t->ServerBuildDate);
+ PackAddStr(p, "ServerFamilyName", t->ServerFamilyName);
+ OutRpcOsInfo(p, &t->OsInfo);
+}
+void FreeRpcServerInfo(RPC_SERVER_INFO *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FreeRpcOsInfo(&t->OsInfo);
+}
+
+// RPC_SERVER_STATUS
+void InRpcServerStatus(RPC_SERVER_STATUS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_SERVER_STATUS));
+ t->ServerType = PackGetInt(p, "ServerType");
+ t->NumTcpConnections = PackGetInt(p, "NumTcpConnections");
+ t->NumTcpConnectionsLocal = PackGetInt(p, "NumTcpConnectionsLocal");
+ t->NumTcpConnectionsRemote = PackGetInt(p, "NumTcpConnectionsRemote");
+ t->NumHubTotal = PackGetInt(p, "NumHubTotal");
+ t->NumHubStandalone = PackGetInt(p, "NumHubStandalone");
+ t->NumHubStatic = PackGetInt(p, "NumHubStatic");
+ t->NumHubDynamic = PackGetInt(p, "NumHubDynamic");
+ t->NumSessionsTotal = PackGetInt(p, "NumSessionsTotal");
+ t->NumSessionsLocal = PackGetInt(p, "NumSessionsLocal");
+ t->NumSessionsRemote = PackGetInt(p, "NumSessionsRemote");
+ t->NumMacTables = PackGetInt(p, "NumMacTables");
+ t->NumIpTables = PackGetInt(p, "NumIpTables");
+ t->NumUsers = PackGetInt(p, "NumUsers");
+ t->NumGroups = PackGetInt(p, "NumGroups");
+ t->CurrentTime = PackGetInt64(p, "CurrentTime");
+ t->CurrentTick = PackGetInt64(p, "CurrentTick");
+ t->AssignedBridgeLicenses = PackGetInt(p, "AssignedBridgeLicenses");
+ t->AssignedClientLicenses = PackGetInt(p, "AssignedClientLicenses");
+ t->AssignedBridgeLicensesTotal = PackGetInt(p, "AssignedBridgeLicensesTotal");
+ t->AssignedClientLicensesTotal = PackGetInt(p, "AssignedClientLicensesTotal");
+ t->StartTime = PackGetInt64(p, "StartTime");
+
+ InRpcTraffic(&t->Traffic, p);
+
+ InRpcMemInfo(&t->MemInfo, p);
+}
+void OutRpcServerStatus(PACK *p, RPC_SERVER_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "ServerType", t->ServerType);
+ PackAddInt(p, "NumHubTotal", t->NumHubTotal);
+ PackAddInt(p, "NumHubStandalone", t->NumHubStandalone);
+ PackAddInt(p, "NumHubStatic", t->NumHubStatic);
+ PackAddInt(p, "NumHubDynamic", t->NumHubDynamic);
+ PackAddInt(p, "NumSessionsTotal", t->NumSessionsTotal);
+ PackAddInt(p, "NumSessionsLocal", t->NumSessionsLocal);
+ PackAddInt(p, "NumSessionsRemote", t->NumSessionsRemote);
+ PackAddInt(p, "NumTcpConnections", t->NumTcpConnections);
+ PackAddInt(p, "NumTcpConnectionsLocal", t->NumTcpConnectionsLocal);
+ PackAddInt(p, "NumTcpConnectionsRemote", t->NumTcpConnectionsRemote);
+ PackAddInt(p, "NumMacTables", t->NumMacTables);
+ PackAddInt(p, "NumIpTables", t->NumIpTables);
+ PackAddInt(p, "NumUsers", t->NumUsers);
+ PackAddInt(p, "NumGroups", t->NumGroups);
+ PackAddInt64(p, "CurrentTime", t->CurrentTime);
+ PackAddInt64(p, "CurrentTick", t->CurrentTick);
+ PackAddInt(p, "AssignedBridgeLicenses", t->AssignedBridgeLicenses);
+ PackAddInt(p, "AssignedClientLicenses", t->AssignedClientLicenses);
+ PackAddInt(p, "AssignedBridgeLicensesTotal", t->AssignedBridgeLicensesTotal);
+ PackAddInt(p, "AssignedClientLicensesTotal", t->AssignedClientLicensesTotal);
+ PackAddInt64(p, "StartTime", t->StartTime);
+
+ OutRpcTraffic(p, &t->Traffic);
+
+ OutRpcMemInfo(p, &t->MemInfo);
+}
+
+// RPC_LISTENER
+void InRpcListener(RPC_LISTENER *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_LISTENER));
+ t->Port = PackGetInt(p, "Port");
+ t->Enable = PackGetBool(p, "Enable");
+}
+void OutRpcListener(PACK *p, RPC_LISTENER *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "Port", t->Port);
+ PackAddBool(p, "Enable", t->Enable);
+}
+
+// RPC_LISTENER_LIST
+void InRpcListenerList(RPC_LISTENER_LIST *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_LISTENER_LIST));
+ t->NumPort = PackGetIndexCount(p, "Ports");
+ t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+ t->Enables = ZeroMalloc(sizeof(UINT) * t->NumPort);
+ t->Errors = ZeroMalloc(sizeof(UINT) * t->NumPort);
+ for (i = 0;i < t->NumPort;i++)
+ {
+ t->Ports[i] = PackGetIntEx(p, "Ports", i);
+ t->Enables[i] = PackGetBoolEx(p, "Enables", i);
+ t->Errors[i] = PackGetBoolEx(p, "Errors", i);
+ }
+}
+void OutRpcListenerList(PACK *p, RPC_LISTENER_LIST *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < t->NumPort;i++)
+ {
+ PackAddIntEx(p, "Ports", t->Ports[i], i, t->NumPort);
+ PackAddBoolEx(p, "Enables", t->Enables[i], i, t->NumPort);
+ PackAddBoolEx(p, "Errors", t->Errors[i], i, t->NumPort);
+ }
+}
+void FreeRpcListenerList(RPC_LISTENER_LIST *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Ports);
+ Free(t->Enables);
+ Free(t->Errors);
+}
+
+// RPC_STR
+void InRpcStr(RPC_STR *t, PACK *p)
+{
+ UINT size = 65536;
+ char *tmp = Malloc(size);
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_STR));
+ if (PackGetStr(p, "String", tmp, size) == false)
+ {
+ t->String = CopyStr("");
+ }
+ else
+ {
+ t->String = CopyStr(tmp);
+ }
+ Free(tmp);
+}
+void OutRpcStr(PACK *p, RPC_STR *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "String", t->String);
+}
+void FreeRpcStr(RPC_STR *t)
+{
+ // Validate arguments
+ if (t == NULL )
+ {
+ return;
+ }
+
+ Free(t->String);
+}
+
+// RPC_SET_PASSWORD
+void InRpcSetPassword(RPC_SET_PASSWORD *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_SET_PASSWORD));
+ PackGetData2(p, "HashedPassword", t->HashedPassword, sizeof(t->HashedPassword));
+}
+void OutRpcSetPassword(PACK *p, RPC_SET_PASSWORD *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddData(p, "HashedPassword", t->HashedPassword, sizeof(t->HashedPassword));
+}
+
+// RPC_FARM
+void InRpcFarm(RPC_FARM *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_FARM));
+ t->ServerType = PackGetInt(p, "ServerType");
+ t->NumPort = PackGetIndexCount(p, "Ports");
+ t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+ for (i = 0;i < t->NumPort;i++)
+ {
+ t->Ports[i] = PackGetIntEx(p, "Ports", i);
+ }
+ t->PublicIp = PackGetIp32(p, "PublicIp");
+ PackGetStr(p, "ControllerName", t->ControllerName, sizeof(t->ControllerName));
+ t->ControllerPort = PackGetInt(p, "ControllerPort");
+ PackGetData2(p, "MemberPassword", t->MemberPassword, sizeof(t->MemberPassword));
+ t->Weight = PackGetInt(p, "Weight");
+ t->ControllerOnly = PackGetBool(p, "ControllerOnly");
+}
+void OutRpcFarm(PACK *p, RPC_FARM *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "ServerType", t->ServerType);
+ for (i = 0;i < t->NumPort;i++)
+ {
+ PackAddIntEx(p, "Ports", t->Ports[i], i, t->NumPort);
+ }
+ PackAddIp32(p, "PublicIp", t->PublicIp);
+ PackAddStr(p, "ControllerName", t->ControllerName);
+ PackAddInt(p, "ControllerPort", t->ControllerPort);
+ PackAddData(p, "MemberPassword", t->MemberPassword, sizeof(t->MemberPassword));
+ PackAddInt(p, "Weight", t->Weight);
+ PackAddBool(p, "ControllerOnly", t->ControllerOnly);
+}
+void FreeRpcFarm(RPC_FARM *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Ports);
+}
+
+// RPC_FARM_HUB
+void InRpcFarmHub(RPC_FARM_HUB *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_FARM_HUB));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->DynamicHub = PackGetBool(p, "DynamicHub");
+}
+void OutRpcFarmHub(PACK *p, RPC_FARM_HUB *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddBool(p, "DynamicHub", t->DynamicHub);
+}
+
+// RPC_FARM_INFO
+void InRpcFarmInfo(RPC_FARM_INFO *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_FARM_INFO));
+ t->Id = PackGetInt(p, "Id");
+ t->Controller = PackGetBool(p, "Controller");
+ t->ConnectedTime = PackGetInt64(p, "ConnectedTime");
+ t->Ip = PackGetIp32(p, "Ip");
+ PackGetStr(p, "Hostname", t->Hostname, sizeof(t->Hostname));
+ t->Point = PackGetInt(p, "Point");
+ t->NumPort = PackGetIndexCount(p, "Ports");
+ t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+ for (i = 0;i < t->NumPort;i++)
+ {
+ t->Ports[i] = PackGetIntEx(p, "Ports", i);
+ }
+ t->ServerCert = PackGetX(p, "ServerCert");
+ t->NumFarmHub = PackGetIndexCount(p, "HubName");
+ t->FarmHubs = ZeroMalloc(sizeof(RPC_FARM_HUB) * t->NumFarmHub);
+ for (i = 0;i < t->NumFarmHub;i++)
+ {
+ PackGetStrEx(p, "HubName", t->FarmHubs[i].HubName, sizeof(t->FarmHubs[i].HubName), i);
+ t->FarmHubs[i].DynamicHub = PackGetBoolEx(p, "DynamicHub", i);
+ }
+ t->NumSessions = PackGetInt(p, "NumSessions");
+ t->NumTcpConnections = PackGetInt(p, "NumTcpConnections");
+ t->Weight = PackGetInt(p, "Weight");
+}
+void OutRpcFarmInfo(PACK *p, RPC_FARM_INFO *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "Id", t->Id);
+ PackAddBool(p, "Controller", t->Controller);
+ PackAddInt64(p, "ConnectedTime", t->ConnectedTime);
+ PackAddIp32(p, "Ip", t->Ip);
+ PackAddStr(p, "Hostname", t->Hostname);
+ PackAddInt(p, "Point", t->Point);
+ for (i = 0;i < t->NumPort;i++)
+ {
+ PackAddIntEx(p, "Ports", t->Ports[i], i, t->NumPort);
+ }
+ PackAddX(p, "ServerCert", t->ServerCert);
+ for (i = 0;i < t->NumFarmHub;i++)
+ {
+ PackAddStrEx(p, "HubName", t->FarmHubs[i].HubName, i, t->NumFarmHub);
+ PackAddBoolEx(p, "DynamicHub", t->FarmHubs[i].DynamicHub, i, t->NumFarmHub);
+ }
+ PackAddInt(p, "NumSessions", t->NumSessions);
+ PackAddInt(p, "NumTcpConnections", t->NumTcpConnections);
+ PackAddInt(p, "Weight", t->Weight);
+}
+void FreeRpcFarmInfo(RPC_FARM_INFO *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Ports);
+ Free(t->FarmHubs);
+ FreeX(t->ServerCert);
+}
+
+void InRpcEnumFarm(RPC_ENUM_FARM *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_FARM));
+ t->NumFarm = PackGetIndexCount(p, "Id");
+ t->Farms = ZeroMalloc(sizeof(RPC_ENUM_FARM_ITEM) * t->NumFarm);
+
+ for (i = 0;i < t->NumFarm;i++)
+ {
+ RPC_ENUM_FARM_ITEM *e = &t->Farms[i];
+
+ e->Id = PackGetIntEx(p, "Id", i);
+ e->Controller = PackGetBoolEx(p, "Controller", i);
+ e->ConnectedTime = PackGetInt64Ex(p, "ConnectedTime", i);
+ e->Ip = PackGetIp32Ex(p, "Ip", i);
+ PackGetStrEx(p, "Hostname", e->Hostname, sizeof(e->Hostname), i);
+ e->Point = PackGetIntEx(p, "Point", i);
+ e->NumSessions = PackGetIntEx(p, "NumSessions", i);
+ e->NumTcpConnections = PackGetIntEx(p, "NumTcpConnections", i);
+ e->NumHubs = PackGetIntEx(p, "NumHubs", i);
+ e->AssignedClientLicense = PackGetIntEx(p, "AssignedClientLicense", i);
+ e->AssignedBridgeLicense = PackGetIntEx(p, "AssignedBridgeLicense", i);
+ }
+}
+void OutRpcEnumFarm(PACK *p, RPC_ENUM_FARM *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < t->NumFarm;i++)
+ {
+ RPC_ENUM_FARM_ITEM *e = &t->Farms[i];
+
+ PackAddIntEx(p, "Id", e->Id, i, t->NumFarm);
+ PackAddBoolEx(p, "Controller", e->Controller, i, t->NumFarm);
+ PackAddInt64Ex(p, "ConnectedTime", e->ConnectedTime, i, t->NumFarm);
+ PackAddIp32Ex(p, "Ip", e->Ip, i, t->NumFarm);
+ PackAddStrEx(p, "Hostname", e->Hostname, i, t->NumFarm);
+ PackAddIntEx(p, "Point", e->Point, i, t->NumFarm);
+ PackAddIntEx(p, "NumSessions", e->NumSessions, i, t->NumFarm);
+ PackAddIntEx(p, "NumTcpConnections", e->NumTcpConnections, i, t->NumFarm);
+ PackAddIntEx(p, "NumHubs", e->NumHubs, i, t->NumFarm);
+ PackAddIntEx(p, "AssignedClientLicense", e->AssignedClientLicense, i, t->NumFarm);
+ PackAddIntEx(p, "AssignedBridgeLicense", e->AssignedBridgeLicense, i, t->NumFarm);
+ }
+}
+void FreeRpcEnumFarm(RPC_ENUM_FARM *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Farms);
+}
+
+// RPC_FARM_CONNECTION_STATUS
+void InRpcFarmConnectionStatus(RPC_FARM_CONNECTION_STATUS *t, PACK *p)
+{
+ Zero(t, sizeof(RPC_FARM_CONNECTION_STATUS));
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ t->Ip = PackGetIp32(p, "Ip");
+ t->Port = PackGetInt(p, "Port");
+ t->Online = PackGetBool(p, "Online");
+ t->LastError = PackGetInt(p, "LastError");
+ t->StartedTime = PackGetInt64(p, "StartedTime");
+ t->CurrentConnectedTime = PackGetInt64(p, "CurrentConnectedTime");
+ t->FirstConnectedTime = PackGetInt64(p, "FirstConnectedTime");
+ t->NumConnected = PackGetInt(p, "NumConnected");
+ t->NumTry = PackGetInt(p, "NumTry");
+ t->NumFailed = PackGetInt(p, "NumFailed");
+}
+void OutRpcFarmConnectionStatus(PACK *p, RPC_FARM_CONNECTION_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddIp32(p, "Ip", t->Ip);
+ PackAddInt(p, "Port", t->Port);
+ PackAddBool(p, "Online", t->Online);
+ PackAddInt(p, "LastError", t->LastError);
+ PackAddInt64(p, "StartedTime", t->StartedTime);
+ PackAddInt64(p, "CurrentConnectedTime", t->CurrentConnectedTime);
+ PackAddInt64(p, "FirstConnectedTime", t->FirstConnectedTime);
+ PackAddInt(p, "NumConnected", t->NumConnected);
+ PackAddInt(p, "NumTry", t->NumTry);
+ PackAddInt(p, "NumFailed", t->NumFailed);
+}
+
+// RPC_HUB_OPTION
+void InRpcHubOption(RPC_HUB_OPTION *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_HUB_OPTION));
+ t->MaxSession = PackGetInt(p, "MaxSession");
+ t->NoEnum = PackGetBool(p, "NoEnum");
+}
+void OutRpcHubOption(PACK *p, RPC_HUB_OPTION *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "MaxSession", t->MaxSession);
+ PackAddBool(p, "NoEnum", t->NoEnum);
+}
+
+// RPC_RADIUS
+void InRpcRadius(RPC_RADIUS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_RADIUS));
+ PackGetStr(p, "RadiusServerName", t->RadiusServerName, sizeof(t->RadiusServerName));
+ t->RadiusPort = PackGetInt(p, "RadiusPort");
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetStr(p, "RadiusSecret", t->RadiusSecret, sizeof(t->RadiusSecret));
+ t->RadiusRetryInterval = PackGetInt(p, "RadiusRetryInterval");
+}
+void OutRpcRadius(PACK *p, RPC_RADIUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "RadiusServerName", t->RadiusServerName);
+ PackAddInt(p, "RadiusPort", t->RadiusPort);
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddStr(p, "RadiusSecret", t->RadiusSecret);
+ PackAddInt(p, "RadiusRetryInterval", t->RadiusRetryInterval);
+}
+
+// RPC_HUB
+void InRpcHub(RPC_HUB *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_HUB));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+}
+void OutRpcHub(PACK *p, RPC_HUB *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+}
+
+// RPC_CREATE_HUB
+void InRpcCreateHub(RPC_CREATE_HUB *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_CREATE_HUB));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetData2(p, "HashedPassword", t->HashedPassword, sizeof(t->HashedPassword));
+ PackGetData2(p, "SecurePassword", t->SecurePassword, sizeof(t->SecurePassword));
+ t->Online = PackGetBool(p, "Online");
+ InRpcHubOption(&t->HubOption, p);
+ t->HubType = PackGetInt(p, "HubType");
+}
+void OutRpcCreateHub(PACK *p, RPC_CREATE_HUB *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddData(p, "HashedPassword", t->HashedPassword, sizeof(t->HashedPassword));
+ PackAddData(p, "SecurePassword", t->SecurePassword, sizeof(t->SecurePassword));
+ PackAddBool(p, "Online", t->Online);
+ OutRpcHubOption(p, &t->HubOption);
+ PackAddInt(p, "HubType", t->HubType);
+}
+
+// RPC_ENUM_HUB
+void InRpcEnumHub(RPC_ENUM_HUB *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_HUB));
+ t->NumHub = PackGetIndexCount(p, "HubName");
+ t->Hubs = ZeroMalloc(sizeof(RPC_ENUM_HUB_ITEM) * t->NumHub);
+
+ for (i = 0;i < t->NumHub;i++)
+ {
+ RPC_ENUM_HUB_ITEM *e = &t->Hubs[i];
+
+ PackGetStrEx(p, "HubName", e->HubName, sizeof(e->HubName), i);
+ e->Online = PackGetBoolEx(p, "Online", i);
+ e->HubType = PackGetIntEx(p, "HubType", i);
+ e->NumSessions = PackGetIntEx(p, "NumSessions", i);
+ e->NumUsers = PackGetIntEx(p, "NumUsers", i);
+ e->NumGroups = PackGetIntEx(p, "NumGroups", i);
+ e->NumMacTables = PackGetIntEx(p, "NumMacTables", i);
+ e->NumIpTables = PackGetIntEx(p, "NumIpTables", i);
+ e->LastCommTime = PackGetInt64Ex(p, "LastCommTime", i);
+ e->CreatedTime = PackGetInt64Ex(p, "CreatedTime", i);
+ e->LastLoginTime = PackGetInt64Ex(p, "LastLoginTime", i);
+ e->NumLogin = PackGetIntEx(p, "NumLogin", i);
+ e->IsTrafficFilled = PackGetBoolEx(p, "IsTrafficFilled", i);
+
+ InRpcTrafficEx(&e->Traffic, p, i);
+ }
+}
+void OutRpcEnumHub(PACK *p, RPC_ENUM_HUB *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < t->NumHub;i++)
+ {
+ RPC_ENUM_HUB_ITEM *e = &t->Hubs[i];
+
+ PackAddStrEx(p, "HubName", e->HubName, i, t->NumHub);
+ PackAddBoolEx(p, "Online", e->Online, i, t->NumHub);
+ PackAddIntEx(p, "HubType", e->HubType, i, t->NumHub);
+ PackAddIntEx(p, "NumSessions", e->NumSessions, i, t->NumHub);
+ PackAddIntEx(p, "NumUsers", e->NumUsers, i, t->NumHub);
+ PackAddIntEx(p, "NumGroups", e->NumGroups, i, t->NumHub);
+ PackAddIntEx(p, "NumMacTables", e->NumMacTables, i, t->NumHub);
+ PackAddIntEx(p, "NumIpTables", e->NumIpTables, i, t->NumHub);
+ PackAddInt64Ex(p, "LastCommTime", e->LastCommTime, i, t->NumHub);
+ PackAddInt64Ex(p, "CreatedTime", e->CreatedTime, i, t->NumHub);
+ PackAddInt64Ex(p, "LastLoginTime", e->LastLoginTime, i, t->NumHub);
+ PackAddIntEx(p, "NumLogin", e->NumLogin, i, t->NumHub);
+ PackAddBoolEx(p, "IsTrafficFilled", e->IsTrafficFilled, i, t->NumHub);
+
+ OutRpcTrafficEx(&e->Traffic, p, i, t->NumHub);
+ }
+}
+void FreeRpcEnumHub(RPC_ENUM_HUB *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Hubs);
+}
+
+// RPC_DELETE_HUB
+void InRpcDeleteHub(RPC_DELETE_HUB *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_DELETE_HUB));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+}
+void OutRpcDeleteHub(PACK *p, RPC_DELETE_HUB *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+}
+
+// RPC_ENUM_CONNECTION
+void InRpcEnumConnection(RPC_ENUM_CONNECTION *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_CONNECTION));
+ t->NumConnection = PackGetIndexCount(p, "Name");
+ t->Connections = ZeroMalloc(sizeof(RPC_ENUM_CONNECTION_ITEM) * t->NumConnection);
+
+ for (i = 0;i < t->NumConnection;i++)
+ {
+ RPC_ENUM_CONNECTION_ITEM *e = &t->Connections[i];
+
+ e->Ip = PackGetIp32Ex(p, "Ip", i);
+ e->Port = PackGetIntEx(p, "Port", i);
+ PackGetStrEx(p, "Name", e->Name, sizeof(e->Name), i);
+ PackGetStrEx(p, "Hostname", e->Hostname, sizeof(e->Hostname), i);
+ e->ConnectedTime = PackGetInt64Ex(p, "ConnectedTime", i);
+ e->Type = PackGetIntEx(p, "Type", i);
+ }
+}
+void OutRpcEnumConnection(PACK *p, RPC_ENUM_CONNECTION *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < t->NumConnection;i++)
+ {
+ RPC_ENUM_CONNECTION_ITEM *e = &t->Connections[i];
+
+ PackAddIp32Ex(p, "Ip", e->Ip, i, t->NumConnection);
+ PackAddIntEx(p, "Port", e->Port, i, t->NumConnection);
+ PackAddStrEx(p, "Name", e->Name, i, t->NumConnection);
+ PackAddStrEx(p, "Hostname", e->Hostname, i, t->NumConnection);
+ PackAddInt64Ex(p, "ConnectedTime", e->ConnectedTime, i, t->NumConnection);
+ PackAddIntEx(p, "Type", e->Type, i, t->NumConnection);
+ }
+}
+void FreeRpcEnumConnetion(RPC_ENUM_CONNECTION *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Connections);
+}
+
+// RPC_DISCONNECT_CONNECTION
+void InRpcDisconnectConnection(RPC_DISCONNECT_CONNECTION *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_DISCONNECT_CONNECTION));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+}
+void OutRpcDisconnectConnection(PACK *p, RPC_DISCONNECT_CONNECTION *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "Name", t->Name);
+}
+
+// RPC_CONNECTION_INFO
+void InRpcConnectionInfo(RPC_CONNECTION_INFO *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_CONNECTION_INFO));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+ t->Ip = PackGetIp32(p, "Ip");
+ t->Port = PackGetInt(p, "Port");
+ t->ConnectedTime = PackGetInt64(p, "ConnectedTime");
+ PackGetStr(p, "Hostname", t->Hostname, sizeof(t->Hostname));
+ PackGetStr(p, "ServerStr", t->ServerStr, sizeof(t->ServerStr));
+ PackGetStr(p, "ClientStr", t->ClientStr, sizeof(t->ClientStr));
+ t->ServerVer = PackGetInt(p, "ServerVer");
+ t->ServerBuild = PackGetInt(p, "ServerBuild");
+ t->ClientVer = PackGetInt(p, "ClientVer");
+ t->ClientBuild = PackGetInt(p, "ClientBuild");
+ t->Type = PackGetInt(p, "Type");
+}
+void OutRpcConnectionInfo(PACK *p, RPC_CONNECTION_INFO *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "Name", t->Name);
+ PackAddIp32(p, "Ip", t->Ip);
+ PackAddInt(p, "Port", t->Port);
+ PackAddInt64(p, "ConnectedTime", t->ConnectedTime);
+ PackAddStr(p, "Hostname", t->Hostname);
+ PackAddStr(p, "ServerStr", t->ServerStr);
+ PackAddStr(p, "ClientStr", t->ClientStr);
+ PackAddInt(p, "ServerVer", t->ServerVer);
+ PackAddInt(p, "ServerBuild", t->ServerBuild);
+ PackAddInt(p, "ClientVer", t->ClientVer);
+ PackAddInt(p, "ClientBuild", t->ClientBuild);
+ PackAddInt(p, "Type", t->Type);
+}
+
+// RPC_SET_HUB_ONLINE
+void InRpcSetHubOnline(RPC_SET_HUB_ONLINE *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_SET_HUB_ONLINE));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->Online = PackGetBool(p, "Online");
+}
+void OutRpcSetHubOnline(PACK *p, RPC_SET_HUB_ONLINE *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddBool(p, "Online", t->Online);
+}
+
+// RPC_HUB_STATUS
+void InRpcHubStatus(RPC_HUB_STATUS *t, PACK *p)
+{
+ Zero(t, sizeof(RPC_HUB_STATUS));
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->Online = PackGetBool(p, "Online");
+ t->HubType = PackGetInt(p, "HubType");
+ t->NumSessions = PackGetInt(p, "NumSessions");
+ t->NumSessionsClient = PackGetInt(p, "NumSessionsClient");
+ t->NumSessionsBridge = PackGetInt(p, "NumSessionsBridge");
+ t->NumAccessLists = PackGetInt(p, "NumAccessLists");
+ t->NumUsers = PackGetInt(p, "NumUsers");
+ t->NumGroups = PackGetInt(p, "NumGroups");
+ t->NumMacTables = PackGetInt(p, "NumMacTables");
+ t->NumIpTables = PackGetInt(p, "NumIpTables");
+ t->SecureNATEnabled = PackGetBool(p, "SecureNATEnabled");
+ InRpcTraffic(&t->Traffic, p);
+ t->LastCommTime = PackGetInt64(p, "LastCommTime");
+ t->CreatedTime = PackGetInt64(p, "CreatedTime");
+ t->LastLoginTime = PackGetInt64(p, "LastLoginTime");
+ t->NumLogin = PackGetInt(p, "NumLogin");
+}
+void OutRpcHubStatus(PACK *p, RPC_HUB_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddBool(p, "Online", t->Online);
+ PackAddInt(p, "HubType", t->HubType);
+ PackAddInt(p, "NumSessions", t->NumSessions);
+ PackAddInt(p, "NumSessionsClient", t->NumSessionsClient);
+ PackAddInt(p, "NumSessionsBridge", t->NumSessionsBridge);
+ PackAddInt(p, "NumAccessLists", t->NumAccessLists);
+ PackAddInt(p, "NumUsers", t->NumUsers);
+ PackAddInt(p, "NumGroups", t->NumGroups);
+ PackAddInt(p, "NumMacTables", t->NumMacTables);
+ PackAddInt(p, "NumIpTables", t->NumIpTables);
+ PackAddBool(p, "SecureNATEnabled", t->SecureNATEnabled);
+ OutRpcTraffic(p, &t->Traffic);
+ PackAddInt64(p, "LastCommTime", t->LastCommTime);
+ PackAddInt64(p, "CreatedTime", t->CreatedTime);
+ PackAddInt64(p, "LastLoginTime", t->LastLoginTime);
+ PackAddInt(p, "NumLogin", t->NumLogin);
+}
+
+// RPC_HUB_LOG
+void InRpcHubLog(RPC_HUB_LOG *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_HUB_LOG));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->LogSetting.SaveSecurityLog = PackGetBool(p, "SaveSecurityLog");
+ t->LogSetting.SecurityLogSwitchType = PackGetInt(p, "SecurityLogSwitchType");
+ t->LogSetting.SavePacketLog = PackGetBool(p, "SavePacketLog");
+ t->LogSetting.PacketLogSwitchType = PackGetInt(p, "PacketLogSwitchType");
+ for (i = 0;i < NUM_PACKET_LOG;i++)
+ {
+ t->LogSetting.PacketLogConfig[i] = PackGetIntEx(p, "PacketLogConfig", i);
+ }
+}
+void OutRpcHubLog(PACK *p, RPC_HUB_LOG *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddBool(p, "SaveSecurityLog", t->LogSetting.SaveSecurityLog);
+ PackAddInt(p, "SecurityLogSwitchType", t->LogSetting.SecurityLogSwitchType);
+ PackAddBool(p, "SavePacketLog", t->LogSetting.SavePacketLog);
+ PackAddInt(p, "PacketLogSwitchType", t->LogSetting.PacketLogSwitchType);
+ for (i = 0;i < NUM_PACKET_LOG;i++)
+ {
+ PackAddIntEx(p, "PacketLogConfig", t->LogSetting.PacketLogConfig[i], i, NUM_PACKET_LOG);
+ }
+}
+
+// RPC_HUB_ADD_CA
+void InRpcHubAddCa(RPC_HUB_ADD_CA *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_HUB_ADD_CA));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->Cert = PackGetX(p, "Cert");
+}
+void OutRpcHubAddCa(PACK *p, RPC_HUB_ADD_CA *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddX(p, "Cert", t->Cert);
+}
+void FreeRpcHubAddCa(RPC_HUB_ADD_CA *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FreeX(t->Cert);
+}
+
+// RPC_HUB_ENUM_CA
+void InRpcHubEnumCa(RPC_HUB_ENUM_CA *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_HUB_ENUM_CA));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->NumCa = PackGetIndexCount(p, "Key");
+ t->Ca = ZeroMalloc(sizeof(RPC_HUB_ENUM_CA_ITEM) * t->NumCa);
+
+ for (i = 0;i < t->NumCa;i++)
+ {
+ RPC_HUB_ENUM_CA_ITEM *e = &t->Ca[i];
+
+ e->Key = PackGetIntEx(p, "Key", i);
+ PackGetUniStrEx(p, "SubjectName", e->SubjectName, sizeof(e->SubjectName), i);
+ PackGetUniStrEx(p, "IssuerName", e->IssuerName, sizeof(e->IssuerName), i);
+ e->Expires = PackGetInt64Ex(p, "Expires", i);
+ }
+}
+void OutRpcHubEnumCa(PACK *p, RPC_HUB_ENUM_CA *t)
+{
+ UINT i;
+ PackAddStr(p, "HubName", t->HubName);
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < t->NumCa;i++)
+ {
+ RPC_HUB_ENUM_CA_ITEM *e = &t->Ca[i];
+
+ PackAddIntEx(p, "Key", e->Key, i, t->NumCa);
+ PackAddUniStrEx(p, "SubjectName", e->SubjectName, i, t->NumCa);
+ PackAddUniStrEx(p, "IssuerName", e->IssuerName, i, t->NumCa);
+ PackAddInt64Ex(p, "Expires", e->Expires, i, t->NumCa);
+ }
+}
+void FreeRpcHubEnumCa(RPC_HUB_ENUM_CA *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Ca);
+}
+
+// RPC_HUB_GET_CA
+void InRpcHubGetCa(RPC_HUB_GET_CA *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_HUB_GET_CA));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->Key = PackGetInt(p, "Key");
+ t->Cert = PackGetX(p, "Cert");
+}
+void OutRpcHubGetCa(PACK *p, RPC_HUB_GET_CA *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddInt(p, "Key", t->Key);
+ PackAddX(p, "Cert", t->Cert);
+}
+void FreeRpcHubGetCa(RPC_HUB_GET_CA *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FreeX(t->Cert);
+}
+
+// RPC_HUB_DELETE_CA
+void InRpcHubDeleteCa(RPC_HUB_DELETE_CA *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_HUB_DELETE_CA));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->Key = PackGetInt(p, "Key");
+}
+void OutRpcHubDeleteCa(PACK *p, RPC_HUB_DELETE_CA *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddInt(p, "Key", t->Key);
+}
+
+// RPC_CREATE_LINK
+void InRpcCreateLink(RPC_CREATE_LINK *t, PACK *p)
+{
+ BUF *b;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_CREATE_LINK));
+ PackGetStr(p, "HubName_Ex", t->HubName, sizeof(t->HubName));
+ t->Online = PackGetBool(p, "Online");
+ t->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ InRpcClientOption(t->ClientOption, p);
+ t->ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+ InRpcClientAuth(t->ClientAuth, p);
+ InRpcPolicy(&t->Policy, p);
+
+ t->CheckServerCert = PackGetBool(p, "CheckServerCert");
+ b = PackGetBuf(p, "ServerCert");
+ if (b != NULL)
+ {
+ t->ServerCert = BufToX(b, false);
+ FreeBuf(b);
+ }
+}
+void OutRpcCreateLink(PACK *p, RPC_CREATE_LINK *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName_Ex",t->HubName);
+ PackAddBool(p, "Online", t->Online);
+ OutRpcClientOption(p, t->ClientOption);
+ OutRpcClientAuth(p, t->ClientAuth);
+ OutRpcPolicy(p, &t->Policy);
+
+ PackAddBool(p, "CheckServerCert", t->CheckServerCert);
+ if (t->ServerCert != NULL)
+ {
+ BUF *b;
+ b = XToBuf(t->ServerCert, false);
+ PackAddBuf(p, "ServerCert", b);
+ FreeBuf(b);
+ }
+}
+void FreeRpcCreateLink(RPC_CREATE_LINK *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->ServerCert != NULL)
+ {
+ FreeX(t->ServerCert);
+ }
+ Free(t->ClientOption);
+ CiFreeClientAuth(t->ClientAuth);
+}
+
+// RPC_ENUM_LINK
+void InRpcEnumLink(RPC_ENUM_LINK *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_LINK));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->NumLink = PackGetIndexCount(p, "AccountName");
+ t->Links = ZeroMalloc(sizeof(RPC_ENUM_LINK_ITEM) * t->NumLink);
+
+ for (i = 0;i < t->NumLink;i++)
+ {
+ RPC_ENUM_LINK_ITEM *e = &t->Links[i];
+
+ PackGetUniStrEx(p, "AccountName", e->AccountName, sizeof(e->AccountName), i);
+ PackGetStrEx(p, "Hostname", e->Hostname, sizeof(e->Hostname), i);
+ PackGetStrEx(p, "ConnectedHubName", e->HubName, sizeof(e->HubName), i);
+ e->Online = PackGetBoolEx(p, "Online", i);
+ e->ConnectedTime = PackGetInt64Ex(p, "ConnectedTime", i);
+ e->Connected = PackGetBoolEx(p, "Connected", i);
+ e->LastError = PackGetIntEx(p, "LastError", i);
+ }
+}
+void OutRpcEnumLink(PACK *p, RPC_ENUM_LINK *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+
+ for (i = 0;i < t->NumLink;i++)
+ {
+ RPC_ENUM_LINK_ITEM *e = &t->Links[i];
+
+ PackAddUniStrEx(p, "AccountName", e->AccountName, i, t->NumLink);
+ PackAddStrEx(p, "ConnectedHubName", e->HubName, i, t->NumLink);
+ PackAddStrEx(p, "Hostname", e->Hostname, i, t->NumLink);
+ PackAddBoolEx(p, "Online", e->Online, i, t->NumLink);
+ PackAddInt64Ex(p, "ConnectedTime", e->ConnectedTime, i, t->NumLink);
+ PackAddBoolEx(p, "Connected", e->Connected, i, t->NumLink);
+ PackAddIntEx(p, "LastError", e->LastError, i, t->NumLink);
+ }
+}
+void FreeRpcEnumLink(RPC_ENUM_LINK *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Links);
+}
+
+// RPC_LINK_STATUS
+void InRpcLinkStatus(RPC_LINK_STATUS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_LINK_STATUS));
+ PackGetStr(p, "HubName_Ex", t->HubName, sizeof(t->HubName));
+ PackGetUniStr(p, "AccountName", t->AccountName, sizeof(t->AccountName));
+ InRpcClientGetConnectionStatus(&t->Status, p);
+}
+void OutRpcLinkStatus(PACK *p, RPC_LINK_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName_Ex", t->HubName);
+ PackAddUniStr(p, "AccountName", t->AccountName);
+ OutRpcClientGetConnectionStatus(p, &t->Status);
+}
+void FreeRpcLinkStatus(RPC_LINK_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ CiFreeClientGetConnectionStatus(&t->Status);
+}
+
+// RPC_LINK
+void InRpcLink(RPC_LINK *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_LINK));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetUniStr(p, "AccountName", t->AccountName, sizeof(t->AccountName));
+}
+void OutRpcLink(PACK *p, RPC_LINK *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddUniStr(p, "AccountName", t->AccountName);
+}
+
+// RPC_RENAME_LINK
+void InRpcRenameLink(RPC_RENAME_LINK *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_RENAME_LINK));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetUniStr(p, "OldAccountName", t->OldAccountName, sizeof(t->OldAccountName));
+ PackGetUniStr(p, "NewAccountName", t->NewAccountName, sizeof(t->NewAccountName));
+}
+void OutRpcRenameLink(PACK *p, RPC_RENAME_LINK *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddUniStr(p, "OldAccountName", t->OldAccountName);
+ PackAddUniStr(p, "NewAccountName", t->NewAccountName);
+}
+
+// ACCESS
+void InRpcAccessEx(ACCESS *a, PACK *p, UINT index)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(a, sizeof(ACCESS));
+ a->Id = PackGetIntEx(p, "Id", index);
+ PackGetUniStrEx(p, "Note", a->Note, sizeof(a->Note), index);
+ a->Active = PackGetBoolEx(p, "Active", index);
+ a->Priority = PackGetIntEx(p, "Priority", index);
+ a->Discard = PackGetBoolEx(p, "Discard", index);
+ a->SrcIpAddress = PackGetIp32Ex(p, "SrcIpAddress", index);
+ a->SrcSubnetMask = PackGetIp32Ex(p, "SrcSubnetMask", index);
+ a->DestIpAddress = PackGetIp32Ex(p, "DestIpAddress", index);
+ a->DestSubnetMask = PackGetIp32Ex(p, "DestSubnetMask", index);
+ a->Protocol = PackGetIntEx(p, "Protocol", index);
+ a->SrcPortStart = PackGetIntEx(p, "SrcPortStart", index);
+ a->SrcPortEnd = PackGetIntEx(p, "SrcPortEnd", index);
+ a->DestPortStart = PackGetIntEx(p, "DestPortStart", index);
+ a->DestPortEnd = PackGetIntEx(p, "DestPortEnd", index);
+ //a->SrcUsernameHash = PackGetIntEx(p, "SrcUsernameHash", index);
+ PackGetStrEx(p, "SrcUsername", a->SrcUsername, sizeof(a->SrcUsername), index);
+ //a->DestUsernameHash = PackGetIntEx(p, "DestUsernameHash", index);
+ PackGetStrEx(p, "DestUsername", a->DestUsername, sizeof(a->DestUsername), index);
+ a->CheckSrcMac = PackGetBoolEx(p, "CheckSrcMac", index);
+ PackGetDataEx2(p, "SrcMacAddress", a->SrcMacAddress, sizeof(a->SrcMacAddress), index);
+ PackGetDataEx2(p, "SrcMacMask", a->SrcMacMask, sizeof(a->SrcMacMask), index);
+ a->CheckDstMac = PackGetBoolEx(p, "CheckDstMac", index);
+ PackGetDataEx2(p, "DstMacAddress", a->DstMacAddress, sizeof(a->DstMacAddress), index);
+ PackGetDataEx2(p, "DstMacMask", a->DstMacMask, sizeof(a->DstMacMask), index);
+ a->CheckTcpState = PackGetBoolEx(p, "CheckTcpState", index);
+ a->Established = PackGetBoolEx(p, "Established", index);
+ a->Delay = PackGetIntEx(p, "Delay", index);
+ a->Jitter = PackGetIntEx(p, "Jitter", index);
+ a->Loss = PackGetIntEx(p, "Loss", index);
+ a->IsIPv6 = PackGetBoolEx(p, "IsIPv6", index);
+ a->UniqueId = PackGetIntEx(p, "UniqueId", index);
+ PackGetStrEx(p, "RedirectUrl", a->RedirectUrl, sizeof(a->RedirectUrl), index);
+ if (a->IsIPv6)
+ {
+ PackGetIp6AddrEx(p, "SrcIpAddress6", &a->SrcIpAddress6, index);
+ PackGetIp6AddrEx(p, "SrcSubnetMask6", &a->SrcSubnetMask6, index);
+ PackGetIp6AddrEx(p, "DestIpAddress6", &a->DestIpAddress6, index);
+ PackGetIp6AddrEx(p, "DestSubnetMask6", &a->DestSubnetMask6, index);
+ }
+}
+void InRpcAccess(ACCESS *a, PACK *p)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ InRpcAccessEx(a, p, 0);
+}
+void OutRpcAccessEx(PACK *p, ACCESS *a, UINT index, UINT total)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddIntEx(p, "Id", a->Id, index, total);
+ PackAddUniStrEx(p, "Note", a->Note, index, total);
+ PackAddBoolEx(p, "Active", a->Active, index, total);
+ PackAddIntEx(p, "Priority", a->Priority, index, total);
+ PackAddBoolEx(p, "Discard", a->Discard, index, total);
+ if (a->IsIPv6)
+ {
+ PackAddIp32Ex(p, "SrcIpAddress", 0xFDFFFFDF, index, total);
+ PackAddIp32Ex(p, "SrcSubnetMask", 0xFFFFFFFF, index, total);
+ PackAddIp32Ex(p, "DestIpAddress", 0xFDFFFFDF, index, total);
+ PackAddIp32Ex(p, "DestSubnetMask", 0xFFFFFFFF, index, total);
+ }
+ else
+ {
+ PackAddIp32Ex(p, "SrcIpAddress", a->SrcIpAddress, index, total);
+ PackAddIp32Ex(p, "SrcSubnetMask", a->SrcSubnetMask, index, total);
+ PackAddIp32Ex(p, "DestIpAddress", a->DestIpAddress, index, total);
+ PackAddIp32Ex(p, "DestSubnetMask", a->DestSubnetMask, index, total);
+ }
+ PackAddIntEx(p, "Protocol", a->Protocol, index, total);
+ PackAddIntEx(p, "SrcPortStart", a->SrcPortStart, index, total);
+ PackAddIntEx(p, "SrcPortEnd", a->SrcPortEnd, index, total);
+ PackAddIntEx(p, "DestPortStart", a->DestPortStart, index, total);
+ PackAddIntEx(p, "DestPortEnd", a->DestPortEnd, index, total);
+ //PackAddIntEx(p, "SrcUsernameHash", a->SrcUsernameHash, index, total);
+ PackAddStrEx(p, "SrcUsername", a->SrcUsername, index, total);
+ //PackAddIntEx(p, "DestUsernameHash", a->DestUsernameHash, index, total);
+ PackAddStrEx(p, "DestUsername", a->DestUsername, index, total);
+ PackAddBoolEx(p, "CheckSrcMac", a->CheckSrcMac, index, total);
+ PackAddDataEx(p, "SrcMacAddress", a->SrcMacAddress, sizeof(a->SrcMacAddress), index, total);
+ PackAddDataEx(p, "SrcMacMask", a->SrcMacMask, sizeof(a->SrcMacMask), index, total);
+ PackAddBoolEx(p, "CheckDstMac", a->CheckDstMac, index, total);
+ PackAddDataEx(p, "DstMacAddress", a->DstMacAddress, sizeof(a->DstMacAddress), index, total);
+ PackAddDataEx(p, "DstMacMask", a->DstMacMask, sizeof(a->DstMacMask), index, total);
+ PackAddBoolEx(p, "CheckTcpState", a->CheckTcpState, index, total);
+ PackAddBoolEx(p, "Established", a->Established, index, total);
+ PackAddIntEx(p, "Delay", a->Delay, index, total);
+ PackAddIntEx(p, "Jitter", a->Jitter, index, total);
+ PackAddIntEx(p, "Loss", a->Loss, index, total);
+ PackAddBoolEx(p, "IsIPv6", a->IsIPv6, index, total);
+ PackAddIntEx(p, "UniqueId", a->UniqueId, index, total);
+ PackAddStrEx(p, "RedirectUrl", a->RedirectUrl, index, total);
+ if (a->IsIPv6)
+ {
+ PackAddIp6AddrEx(p, "SrcIpAddress6", &a->SrcIpAddress6, index, total);
+ PackAddIp6AddrEx(p, "SrcSubnetMask6", &a->SrcSubnetMask6, index, total);
+ PackAddIp6AddrEx(p, "DestIpAddress6", &a->DestIpAddress6, index, total);
+ PackAddIp6AddrEx(p, "DestSubnetMask6", &a->DestSubnetMask6, index, total);
+ }
+ else
+ {
+ IPV6_ADDR zero;
+
+ Zero(&zero, sizeof(zero));
+
+ PackAddIp6AddrEx(p, "SrcIpAddress6", &zero, index, total);
+ PackAddIp6AddrEx(p, "SrcSubnetMask6", &zero, index, total);
+ PackAddIp6AddrEx(p, "DestIpAddress6", &zero, index, total);
+ PackAddIp6AddrEx(p, "DestSubnetMask6", &zero, index, total);
+ }
+}
+void OutRpcAccess(PACK *p, ACCESS *a)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ OutRpcAccessEx(p, a, 0, 1);
+}
+
+// RPC_ENUM_ACCESS_LIST
+void InRpcEnumAccessList(RPC_ENUM_ACCESS_LIST *a, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(a, sizeof(RPC_ENUM_ACCESS_LIST));
+ PackGetStr(p, "HubName", a->HubName, sizeof(a->HubName));
+ a->NumAccess = PackGetIndexCount(p, "Protocol");
+ a->Accesses = ZeroMalloc(sizeof(ACCESS) * a->NumAccess);
+
+ for (i = 0;i < a->NumAccess;i++)
+ {
+ ACCESS *e = &a->Accesses[i];
+
+ InRpcAccessEx(e, p, i);
+ }
+}
+void OutRpcEnumAccessList(PACK *p, RPC_ENUM_ACCESS_LIST *a)
+{
+ UINT i;
+ PackAddStr(p, "HubName", a->HubName);
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < a->NumAccess;i++)
+ {
+ ACCESS *e = &a->Accesses[i];
+
+ OutRpcAccessEx(p, e, i, a->NumAccess);
+ }
+}
+void FreeRpcEnumAccessList(RPC_ENUM_ACCESS_LIST *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ Free(a->Accesses);
+}
+
+// AUTHDATA
+void *InRpcAuthData(PACK *p, UINT *authtype)
+{
+ wchar_t tmp[MAX_SIZE];
+ AUTHPASSWORD *pw;
+ AUTHUSERCERT *usercert;
+ AUTHROOTCERT *rootcert;
+ AUTHRADIUS *radius;
+ AUTHNT *nt;
+ BUF *b;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+ if (authtype == NULL)
+ {
+ return NULL;
+ }
+
+ *authtype = PackGetInt(p, "AuthType");
+
+ switch (*authtype)
+ {
+ case AUTHTYPE_PASSWORD:
+ pw = ZeroMalloc(sizeof(AUTHPASSWORD));
+ PackGetData2(p, "HashedKey", pw->HashedKey, sizeof(pw->HashedKey));
+ PackGetData2(p, "NtLmSecureHash", pw->NtLmSecureHash, sizeof(pw->NtLmSecureHash));
+ return pw;
+
+ case AUTHTYPE_USERCERT:
+ usercert = ZeroMalloc(sizeof(AUTHUSERCERT));
+ usercert->UserX = PackGetX(p, "UserX");
+ return usercert;
+
+ case AUTHTYPE_ROOTCERT:
+ rootcert = ZeroMalloc(sizeof(AUTHROOTCERT));
+ b = PackGetBuf(p, "Serial");
+ if (b != NULL)
+ {
+ rootcert->Serial = NewXSerial(b->Buf, b->Size);
+ FreeBuf(b);
+ }
+ if (PackGetUniStr(p, "CommonName", tmp, sizeof(tmp)))
+ {
+ rootcert->CommonName = CopyUniStr(tmp);
+ }
+ return rootcert;
+
+ case AUTHTYPE_RADIUS:
+ radius = ZeroMalloc(sizeof(AUTHRADIUS));
+ if (PackGetUniStr(p, "RadiusUsername", tmp, sizeof(tmp)))
+ {
+ radius->RadiusUsername = CopyUniStr(tmp);
+ }
+ else
+ {
+ radius->RadiusUsername = CopyUniStr(L"");
+ }
+ return radius;
+
+ case AUTHTYPE_NT:
+ nt = ZeroMalloc(sizeof(AUTHNT));
+ if (PackGetUniStr(p, "NtUsername", tmp, sizeof(tmp)))
+ {
+ nt->NtUsername = CopyUniStr(tmp);
+ }
+ else
+ {
+ nt->NtUsername = CopyUniStr(L"");
+ }
+ return nt;
+ }
+
+ return NULL;
+}
+void OutRpcAuthData(PACK *p, void *authdata, UINT authtype)
+{
+ AUTHPASSWORD *pw = authdata;
+ AUTHUSERCERT *usercert = authdata;
+ AUTHROOTCERT *rootcert = authdata;
+ AUTHRADIUS *radius = authdata;
+ AUTHNT *nt = authdata;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "AuthType", authtype);
+
+ switch (authtype)
+ {
+ case AUTHTYPE_PASSWORD:
+ PackAddData(p, "HashedKey", pw->HashedKey, sizeof(pw->HashedKey));
+ PackAddData(p, "NtLmSecureHash", pw->NtLmSecureHash, sizeof(pw->NtLmSecureHash));
+ break;
+
+ case AUTHTYPE_USERCERT:
+ PackAddX(p, "UserX", usercert->UserX);
+ break;
+
+ case AUTHTYPE_ROOTCERT:
+ if (rootcert->Serial != NULL)
+ {
+ PackAddData(p, "Serial", rootcert->Serial->data, rootcert->Serial->size);
+ }
+ if (rootcert->CommonName != NULL)
+ {
+ PackAddUniStr(p, "CommonName", rootcert->CommonName);
+ }
+ break;
+
+ case AUTHTYPE_RADIUS:
+ PackAddUniStr(p, "RadiusUsername", radius->RadiusUsername);
+ break;
+
+ case AUTHTYPE_NT:
+ PackAddUniStr(p, "NtUsername", nt->NtUsername);
+ break;
+ }
+}
+void FreeRpcAuthData(void *authdata, UINT authtype)
+{
+ FreeAuthData(authtype, authdata);
+}
+
+// RPC_SET_USER
+void InRpcSetUser(RPC_SET_USER *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_SET_USER));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+ PackGetStr(p, "GroupName", t->GroupName, sizeof(t->GroupName));
+ PackGetUniStr(p, "Realname", t->Realname, sizeof(t->Realname));
+ PackGetUniStr(p, "Note", t->Note, sizeof(t->Note));
+ t->CreatedTime = PackGetInt64(p, "CreatedTime");
+ t->UpdatedTime = PackGetInt64(p, "UpdatedTime");
+ t->ExpireTime = PackGetInt64(p, "ExpireTime");
+ t->AuthData = InRpcAuthData(p, &t->AuthType);
+ t->NumLogin = PackGetInt(p, "NumLogin");
+ InRpcTraffic(&t->Traffic, p);
+
+ if (PackGetBool(p, "UsePolicy"))
+ {
+ t->Policy = ZeroMalloc(sizeof(POLICY));
+ InRpcPolicy(t->Policy, p);
+ }
+}
+
+void OutRpcSetUser(PACK *p, RPC_SET_USER *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddStr(p, "Name", t->Name);
+ PackAddStr(p, "GroupName", t->GroupName);
+ PackAddUniStr(p, "Realname", t->Realname);
+ PackAddUniStr(p, "Note", t->Note);
+ PackAddInt64(p, "CreatedTime", t->CreatedTime);
+ PackAddInt64(p, "UpdatedTime", t->UpdatedTime);
+ PackAddInt64(p, "ExpireTime", t->ExpireTime);
+ OutRpcAuthData(p, t->AuthData, t->AuthType);
+ PackAddInt(p, "NumLogin", t->NumLogin);
+ OutRpcTraffic(p, &t->Traffic);
+
+ if (t->Policy != NULL)
+ {
+ PackAddBool(p, "UsePolicy", true);
+ OutRpcPolicy(p, t->Policy);
+ }
+}
+void FreeRpcSetUser(RPC_SET_USER *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FreeRpcAuthData(t->AuthData, t->AuthType);
+ if (t->Policy)
+ {
+ Free(t->Policy);
+ }
+}
+
+// RPC_ENUM_USER
+void InRpcEnumUser(RPC_ENUM_USER *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_USER));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->NumUser = PackGetIndexCount(p, "Name");
+ t->Users = ZeroMalloc(sizeof(RPC_ENUM_USER_ITEM) * t->NumUser);
+
+ for (i = 0;i < t->NumUser;i++)
+ {
+ RPC_ENUM_USER_ITEM *e = &t->Users[i];
+
+ PackGetStrEx(p, "Name", e->Name, sizeof(e->Name), i);
+ PackGetStrEx(p, "GroupName", e->GroupName, sizeof(e->GroupName), i);
+ PackGetUniStrEx(p, "Realname", e->Realname, sizeof(e->Realname), i);
+ PackGetUniStrEx(p, "Note", e->Note, sizeof(e->Note), i);
+ e->AuthType = PackGetIntEx(p, "AuthType", i);
+ e->LastLoginTime = PackGetInt64Ex(p, "LastLoginTime", i);
+ e->NumLogin = PackGetIntEx(p, "NumLogin", i);
+ e->DenyAccess = PackGetBoolEx(p, "DenyAccess", i);
+
+ e->IsTrafficFilled = PackGetBoolEx(p, "IsTrafficFilled", i);
+ InRpcTrafficEx(&e->Traffic, p, i);
+
+ e->IsExpiresFilled = PackGetBoolEx(p, "IsExpiresFilled", i);
+ e->Expires = PackGetInt64Ex(p, "Expires", i);
+ }
+}
+void OutRpcEnumUser(PACK *p, RPC_ENUM_USER *t)
+{
+ UINT i;
+ PackAddStr(p, "HubName", t->HubName);
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < t->NumUser;i++)
+ {
+ RPC_ENUM_USER_ITEM *e = &t->Users[i];
+
+ PackAddStrEx(p, "Name", e->Name, i, t->NumUser);
+ PackAddStrEx(p, "GroupName", e->GroupName, i, t->NumUser);
+ PackAddUniStrEx(p, "Realname", e->Realname, i, t->NumUser);
+ PackAddUniStrEx(p, "Note", e->Note, i, t->NumUser);
+ PackAddIntEx(p, "AuthType", e->AuthType, i, t->NumUser);
+ PackAddInt64Ex(p, "LastLoginTime", e->LastLoginTime, i, t->NumUser);
+ PackAddIntEx(p, "NumLogin", e->NumLogin, i, t->NumUser);
+ PackAddBoolEx(p, "DenyAccess", e->DenyAccess, i, t->NumUser);
+
+ PackAddBoolEx(p, "IsTrafficFilled", e->IsTrafficFilled, i, t->NumUser);
+ OutRpcTrafficEx(&e->Traffic, p, i, t->NumUser);
+
+ PackAddBoolEx(p, "IsExpiresFilled", e->IsExpiresFilled, i, t->NumUser);
+ PackAddInt64Ex(p, "Expires", e->Expires, i, t->NumUser);
+ }
+}
+void FreeRpcEnumUser(RPC_ENUM_USER *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Users);
+}
+
+// RPC_SET_GROUP
+void InRpcSetGroup(RPC_SET_GROUP *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_SET_GROUP));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+ PackGetUniStr(p, "Realname", t->Realname, sizeof(t->Realname));
+ PackGetUniStr(p, "Note", t->Note, sizeof(t->Note));
+ InRpcTraffic(&t->Traffic, p);
+
+ if (PackGetBool(p, "UsePolicy"))
+ {
+ t->Policy = ZeroMalloc(sizeof(POLICY));
+ InRpcPolicy(t->Policy, p);
+ }
+}
+void OutRpcSetGroup(PACK *p, RPC_SET_GROUP *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddStr(p, "Name", t->Name);
+ PackAddUniStr(p, "Realname", t->Realname);
+ PackAddUniStr(p, "Note", t->Note);
+ OutRpcTraffic(p, &t->Traffic);
+
+ if (t->Policy != NULL)
+ {
+ PackAddBool(p, "UsePolicy", true);
+ OutRpcPolicy(p, t->Policy);
+ }
+}
+void FreeRpcSetGroup(RPC_SET_GROUP *t)
+{
+ Free(t->Policy);
+}
+
+// RPC_ENUM_GROUP
+void InRpcEnumGroup(RPC_ENUM_GROUP *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_GROUP));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->NumGroup = PackGetIndexCount(p, "Name");
+ t->Groups = ZeroMalloc(sizeof(RPC_ENUM_GROUP_ITEM) * t->NumGroup);
+
+ for (i = 0;i < t->NumGroup;i++)
+ {
+ RPC_ENUM_GROUP_ITEM *e = &t->Groups[i];
+
+ PackGetStrEx(p, "Name", e->Name, sizeof(e->Name), i);
+ PackGetUniStrEx(p, "Realname", e->Realname, sizeof(e->Realname), i);
+ PackGetUniStrEx(p, "Note", e->Note, sizeof(e->Note), i);
+ e->NumUsers = PackGetIntEx(p, "NumUsers", i);
+ e->DenyAccess = PackGetBoolEx(p, "DenyAccess", i);
+ }
+}
+void OutRpcEnumGroup(PACK *p, RPC_ENUM_GROUP *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+
+ for (i = 0;i < t->NumGroup;i++)
+ {
+ RPC_ENUM_GROUP_ITEM *e = &t->Groups[i];
+
+ PackAddStrEx(p, "Name", e->Name, i, t->NumGroup);
+ PackAddUniStrEx(p, "Realname", e->Realname, i, t->NumGroup);
+ PackAddUniStrEx(p, "Note", e->Note, i, t->NumGroup);
+ PackAddIntEx(p, "NumUsers", e->NumUsers, i, t->NumGroup);
+ PackAddBoolEx(p, "DenyAccess", e->DenyAccess, i, t->NumGroup);
+ }
+}
+void FreeRpcEnumGroup(RPC_ENUM_GROUP *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Groups);
+}
+
+// RPC_DELETE_USER
+void InRpcDeleteUser(RPC_DELETE_USER *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_DELETE_USER));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+}
+void OutRpcDeleteUser(PACK *p, RPC_DELETE_USER *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddStr(p, "Name", t->Name);
+}
+
+// RPC_ENUM_SESSION
+void InRpcEnumSession(RPC_ENUM_SESSION *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_SESSION));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->NumSession = PackGetIndexCount(p, "Name");
+ t->Sessions = ZeroMalloc(sizeof(RPC_ENUM_SESSION_ITEM) * t->NumSession);
+
+ for (i = 0;i < t->NumSession;i++)
+ {
+ RPC_ENUM_SESSION_ITEM *e = &t->Sessions[i];
+
+ PackGetStrEx(p, "Name", e->Name, sizeof(e->Name), i);
+ PackGetStrEx(p, "Username", e->Username, sizeof(e->Username), i);
+ e->Ip = PackGetIntEx(p, "Ip", i);
+ PackGetStrEx(p, "Hostname", e->Hostname, sizeof(e->Hostname), i);
+ e->MaxNumTcp = PackGetIntEx(p, "MaxNumTcp", i);
+ e->CurrentNumTcp = PackGetIntEx(p, "CurrentNumTcp", i);
+ e->PacketSize = PackGetInt64Ex(p, "PacketSize", i);
+ e->PacketNum = PackGetInt64Ex(p, "PacketNum", i);
+ e->RemoteSession = PackGetBoolEx(p, "RemoteSession", i);
+ e->LinkMode = PackGetBoolEx(p, "LinkMode", i);
+ e->SecureNATMode = PackGetBoolEx(p, "SecureNATMode", i);
+ e->BridgeMode = PackGetBoolEx(p, "BridgeMode", i);
+ e->Layer3Mode = PackGetBoolEx(p, "Layer3Mode", i);
+ e->Client_BridgeMode = PackGetBoolEx(p, "Client_BridgeMode", i);
+ e->Client_MonitorMode = PackGetBoolEx(p, "Client_MonitorMode", i);
+ PackGetStrEx(p, "RemoteHostname", e->RemoteHostname, sizeof(e->RemoteHostname), i);
+ e->VLanId = PackGetIntEx(p, "VLanId", i);
+ PackGetDataEx2(p, "UniqueId", e->UniqueId, sizeof(e->UniqueId), i);
+ }
+}
+void OutRpcEnumSession(PACK *p, RPC_ENUM_SESSION *t)
+{
+ UINT i;
+ PackAddStr(p, "HubName", t->HubName);
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < t->NumSession;i++)
+ {
+ RPC_ENUM_SESSION_ITEM *e = &t->Sessions[i];
+
+ PackAddStrEx(p, "Name", e->Name, i, t->NumSession);
+ PackAddStrEx(p, "Username", e->Username, i, t->NumSession);
+ PackAddIp32Ex(p, "Ip", e->Ip, i, t->NumSession);
+ PackAddStrEx(p, "Hostname", e->Hostname, i, t->NumSession);
+ PackAddIntEx(p, "MaxNumTcp", e->MaxNumTcp, i, t->NumSession);
+ PackAddIntEx(p, "CurrentNumTcp", e->CurrentNumTcp, i, t->NumSession);
+ PackAddInt64Ex(p, "PacketSize", e->PacketSize, i, t->NumSession);
+ PackAddInt64Ex(p, "PacketNum", e->PacketNum, i, t->NumSession);
+ PackAddBoolEx(p, "RemoteSession", e->RemoteSession, i, t->NumSession);
+ PackAddStrEx(p, "RemoteHostname", e->RemoteHostname, i, t->NumSession);
+ PackAddBoolEx(p, "LinkMode", e->LinkMode, i, t->NumSession);
+ PackAddBoolEx(p, "SecureNATMode", e->SecureNATMode, i, t->NumSession);
+ PackAddBoolEx(p, "BridgeMode", e->BridgeMode, i, t->NumSession);
+ PackAddBoolEx(p, "Layer3Mode", e->Layer3Mode, i, t->NumSession);
+ PackAddBoolEx(p, "Client_BridgeMode", e->Client_BridgeMode, i, t->NumSession);
+ PackAddBoolEx(p, "Client_MonitorMode", e->Client_MonitorMode, i, t->NumSession);
+ PackAddIntEx(p, "VLanId", e->VLanId, i, t->NumSession);
+ PackAddDataEx(p, "UniqueId", e->UniqueId, sizeof(e->UniqueId), i, t->NumSession);
+ }
+}
+void FreeRpcEnumSession(RPC_ENUM_SESSION *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Sessions);
+}
+
+// RPC_KEY_PAIR
+void InRpcKeyPair(RPC_KEY_PAIR *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ t->Cert = PackGetX(p, "Cert");
+ t->Key = PackGetK(p, "Key");
+}
+void OutRpcKeyPair(PACK *p, RPC_KEY_PAIR *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddX(p, "Cert", t->Cert);
+ PackAddK(p, "Key", t->Key);
+}
+void FreeRpcKeyPair(RPC_KEY_PAIR *t)
+{
+ FreeX(t->Cert);
+ FreeK(t->Key);
+}
+
+// NODE_INFO
+void InRpcNodeInfo(NODE_INFO *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(NODE_INFO));
+ PackGetStr(p, "ClientProductName", t->ClientProductName, sizeof(t->ClientProductName));
+ PackGetStr(p, "ServerProductName", t->ServerProductName, sizeof(t->ServerProductName));
+ PackGetStr(p, "ClientOsName", t->ClientOsName, sizeof(t->ClientOsName));
+ PackGetStr(p, "ClientOsVer", t->ClientOsVer, sizeof(t->ClientOsVer));
+ PackGetStr(p, "ClientOsProductId", t->ClientOsProductId, sizeof(t->ClientOsProductId));
+ PackGetStr(p, "ClientHostname", t->ClientHostname, sizeof(t->ClientHostname));
+ PackGetStr(p, "ServerHostname", t->ServerHostname, sizeof(t->ServerHostname));
+ PackGetStr(p, "ProxyHostname", t->ProxyHostname, sizeof(t->ProxyHostname));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetData2(p, "UniqueId", t->UniqueId, sizeof(t->UniqueId));
+
+ t->ClientProductVer = PackGetInt(p, "ClientProductVer");
+ t->ClientProductBuild = PackGetInt(p, "ClientProductBuild");
+ t->ServerProductVer = PackGetInt(p, "ServerProductVer");
+ t->ServerProductBuild = PackGetInt(p, "ServerProductBuild");
+ t->ClientIpAddress = PackGetIp32(p, "ClientIpAddress");
+ PackGetData2(p, "ClientIpAddress6", t->ClientIpAddress6, sizeof(t->ClientIpAddress6));
+ t->ClientPort = PackGetInt(p, "ClientPort");
+ t->ServerIpAddress = PackGetIp32(p, "ServerIpAddress");
+ PackGetData2(p, "ServerIpAddress6", t->ServerIpAddress6, sizeof(t->ServerIpAddress6));
+ t->ServerPort = PackGetInt(p, "ServerPort2");
+ t->ProxyIpAddress = PackGetIp32(p, "ProxyIpAddress");
+ PackGetData2(p, "ProxyIpAddress6", t->ProxyIpAddress6, sizeof(t->ProxyIpAddress6));
+ t->ProxyPort = PackGetInt(p, "ProxyPort");
+}
+void OutRpcNodeInfo(PACK *p, NODE_INFO *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "ClientProductName", t->ClientProductName);
+ PackAddStr(p, "ServerProductName", t->ServerProductName);
+ PackAddStr(p, "ClientOsName", t->ClientOsName);
+ PackAddStr(p, "ClientOsVer", t->ClientOsVer);
+ PackAddStr(p, "ClientOsProductId", t->ClientOsProductId);
+ PackAddStr(p, "ClientHostname", t->ClientHostname);
+ PackAddStr(p, "ServerHostname", t->ServerHostname);
+ PackAddStr(p, "ProxyHostname", t->ProxyHostname);
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddData(p, "UniqueId", t->UniqueId, sizeof(t->UniqueId));
+
+ PackAddInt(p, "ClientProductVer", t->ClientProductVer);
+ PackAddInt(p, "ClientProductBuild", t->ClientProductBuild);
+ PackAddInt(p, "ServerProductVer", t->ServerProductVer);
+ PackAddInt(p, "ServerProductBuild", t->ServerProductBuild);
+ PackAddIp32(p, "ClientIpAddress", t->ClientIpAddress);
+ PackAddData(p, "ClientIpAddress6", t->ClientIpAddress6, sizeof(t->ClientIpAddress6));
+ PackAddInt(p, "ClientPort", t->ClientPort);
+ PackAddIp32(p, "ServerIpAddress", t->ServerIpAddress);
+ PackAddData(p, "ServerIpAddress6", t->ServerIpAddress6, sizeof(t->ServerIpAddress6));
+ PackAddInt(p, "ServerPort2", t->ServerPort);
+ PackAddIp32(p, "ProxyIpAddress", t->ProxyIpAddress);
+ PackAddData(p, "ProxyIpAddress6", t->ProxyIpAddress6, sizeof(t->ProxyIpAddress6));
+ PackAddInt(p, "ProxyPort", t->ProxyPort);
+}
+
+// RPC_SESSION_STATUS
+void InRpcSessionStatus(RPC_SESSION_STATUS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_SESSION_STATUS));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+ PackGetStr(p, "Username", t->Username, sizeof(t->Username));
+ PackGetStr(p, "GroupName", t->GroupName, sizeof(t->GroupName));
+ PackGetStr(p, "RealUsername", t->RealUsername, sizeof(t->RealUsername));
+ t->ClientIp = PackGetIp32(p, "SessionStatus_ClientIp");
+ PackGetData2(p, "SessionStatus_ClientIp6", t->ClientIp6, sizeof(t->ClientIp6));
+ PackGetStr(p, "SessionStatus_ClientHostName", t->ClientHostName, sizeof(t->ClientHostName));
+
+ InRpcClientGetConnectionStatus(&t->Status, p);
+ InRpcNodeInfo(&t->NodeInfo, p);
+}
+void OutRpcSessionStatus(PACK *p, RPC_SESSION_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddStr(p, "Name", t->Name);
+ PackAddStr(p, "Username", t->Username);
+ PackAddStr(p, "GroupName", t->GroupName);
+ PackAddStr(p, "RealUsername", t->RealUsername);
+ PackAddIp32(p, "SessionStatus_ClientIp", t->ClientIp);
+ PackAddData(p, "SessionStatus_ClientIp6", t->ClientIp6, sizeof(t->ClientIp6));
+ PackAddStr(p, "SessionStatus_ClientHostName", t->ClientHostName);
+
+ OutRpcClientGetConnectionStatus(p, &t->Status);
+ OutRpcNodeInfo(p, &t->NodeInfo);
+}
+void FreeRpcSessionStatus(RPC_SESSION_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ CiFreeClientGetConnectionStatus(&t->Status);
+}
+
+// RPC_DELETE_SESSION
+void InRpcDeleteSession(RPC_DELETE_SESSION *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_DELETE_SESSION));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+}
+void OutRpcDeleteSession(PACK *p, RPC_DELETE_SESSION *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddStr(p, "Name", t->Name);
+}
+
+// RPC_ENUM_MAC_TABLE
+void InRpcEnumMacTable(RPC_ENUM_MAC_TABLE *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_MAC_TABLE));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->NumMacTable = PackGetIndexCount(p, "SessionName");
+ t->MacTables = ZeroMalloc(sizeof(RPC_ENUM_MAC_TABLE_ITEM) * t->NumMacTable);
+
+ for (i = 0;i < t->NumMacTable;i++)
+ {
+ RPC_ENUM_MAC_TABLE_ITEM *e = &t->MacTables[i];
+
+ e->Key = PackGetIntEx(p, "Key", i);
+ PackGetStrEx(p, "SessionName", e->SessionName, sizeof(e->SessionName), i);
+ PackGetDataEx2(p, "MacAddress", e->MacAddress, sizeof(e->MacAddress), i);
+ e->VlanId = PackGetIntEx(p, "VlanId", i);
+ e->CreatedTime = PackGetInt64Ex(p, "CreatedTime", i);
+ e->UpdatedTime = PackGetInt64Ex(p, "UpdatedTime", i);
+ e->RemoteItem = PackGetBoolEx(p, "RemoteItem", i);
+ PackGetStrEx(p, "RemoteHostname", e->RemoteHostname, sizeof(e->RemoteHostname), i);
+ }
+}
+void OutRpcEnumMacTable(PACK *p, RPC_ENUM_MAC_TABLE *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+
+ for (i = 0;i < t->NumMacTable;i++)
+ {
+ RPC_ENUM_MAC_TABLE_ITEM *e = &t->MacTables[i];
+
+ PackAddIntEx(p, "Key", e->Key, i, t->NumMacTable);
+ PackAddStrEx(p, "SessionName", e->SessionName, i, t->NumMacTable);
+ PackAddDataEx(p, "MacAddress", e->MacAddress, sizeof(e->MacAddress), i, t->NumMacTable);
+ PackAddIntEx(p, "VlanId", e->VlanId, i, t->NumMacTable);
+ PackAddInt64Ex(p, "CreatedTime", e->CreatedTime, i, t->NumMacTable);
+ PackAddInt64Ex(p, "UpdatedTime", e->UpdatedTime, i, t->NumMacTable);
+ PackAddBoolEx(p, "RemoteItem", e->RemoteItem, i, t->NumMacTable);
+ PackAddStrEx(p, "RemoteHostname", e->RemoteHostname, i, t->NumMacTable);
+ }
+}
+void FreeRpcEnumMacTable(RPC_ENUM_MAC_TABLE *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->MacTables);
+}
+
+// RPC_ENUM_IP_TABLE
+void InRpcEnumIpTable(RPC_ENUM_IP_TABLE *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_IP_TABLE));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->NumIpTable = PackGetIndexCount(p, "SessionName");
+ t->IpTables = ZeroMalloc(sizeof(RPC_ENUM_IP_TABLE_ITEM) * t->NumIpTable);
+
+ for (i = 0;i < t->NumIpTable;i++)
+ {
+ RPC_ENUM_IP_TABLE_ITEM *e = &t->IpTables[i];
+
+ e->Key = PackGetIntEx(p, "Key", i);
+ PackGetStrEx(p, "SessionName", e->SessionName, sizeof(e->SessionName), i);
+ e->Ip = PackGetIp32Ex(p, "Ip", i);
+ if (PackGetIpEx(p, "IpV6", &e->IpV6, i) == false)
+ {
+ UINTToIP(&e->IpV6, e->Ip);
+ }
+ e->DhcpAllocated = PackGetBoolEx(p, "DhcpAllocated", i);
+ e->CreatedTime = PackGetInt64Ex(p, "CreatedTime", i);
+ e->UpdatedTime = PackGetInt64Ex(p, "UpdatedTime", i);
+ e->RemoteItem = PackGetBoolEx(p, "RemoteItem", i);
+ PackGetStrEx(p, "RemoteHostname", e->RemoteHostname, sizeof(e->RemoteHostname), i);
+ }
+}
+void OutRpcEnumIpTable(PACK *p, RPC_ENUM_IP_TABLE *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+
+ for (i = 0;i < t->NumIpTable;i++)
+ {
+ RPC_ENUM_IP_TABLE_ITEM *e = &t->IpTables[i];
+
+ PackAddIntEx(p, "Key", e->Key, i, t->NumIpTable);
+ PackAddStrEx(p, "SessionName", e->SessionName, i, t->NumIpTable);
+ PackAddIp32Ex(p, "Ip", e->Ip, i, t->NumIpTable);
+ PackAddIpEx(p, "IpV6", &e->IpV6, i, t->NumIpTable);
+ PackAddBoolEx(p, "DhcpAllocated", e->DhcpAllocated, i, t->NumIpTable);
+ PackAddInt64Ex(p, "CreatedTime", e->CreatedTime, i, t->NumIpTable);
+ PackAddInt64Ex(p, "UpdatedTime", e->UpdatedTime, i, t->NumIpTable);
+ PackAddBoolEx(p, "RemoteItem", e->RemoteItem, i, t->NumIpTable);
+ PackAddStrEx(p, "RemoteHostname", e->RemoteHostname, i, t->NumIpTable);
+ }
+}
+void FreeRpcEnumIpTable(RPC_ENUM_IP_TABLE *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->IpTables);
+}
+
+// RPC_DELETE_TABLE
+void InRpcDeleteTable(RPC_DELETE_TABLE *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_DELETE_TABLE));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->Key = PackGetInt(p, "Key");
+}
+void OutRpcDeleteTable(PACK *p, RPC_DELETE_TABLE *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddInt(p, "Key", t->Key);
+}
+
+// Adjoin RPC_ENUM_IP_TABLE
+void AdjoinRpcEnumIpTable(RPC_ENUM_IP_TABLE *dest, RPC_ENUM_IP_TABLE *src)
+{
+ UINT old_num;
+ UINT i, n;
+ if (dest == NULL || src == NULL)
+ {
+ return;
+ }
+
+ if (src->NumIpTable == 0)
+ {
+ return;
+ }
+
+ old_num = dest->NumIpTable;
+ dest->NumIpTable += src->NumIpTable;
+ dest->IpTables = ReAlloc(dest->IpTables, sizeof(RPC_ENUM_IP_TABLE_ITEM) * dest->NumIpTable);
+
+ n = 0;
+ for (i = old_num;i < dest->NumIpTable;i++)
+ {
+ Copy(&dest->IpTables[i], &src->IpTables[n++], sizeof(RPC_ENUM_IP_TABLE_ITEM));
+ }
+}
+
+// Adjoin RPC_ENUM_MAC_TABLE
+void AdjoinRpcEnumMacTable(RPC_ENUM_MAC_TABLE *dest, RPC_ENUM_MAC_TABLE *src)
+{
+ UINT old_num;
+ UINT i, n;
+ if (dest == NULL || src == NULL)
+ {
+ return;
+ }
+
+ if (src->NumMacTable == 0)
+ {
+ return;
+ }
+
+ old_num = dest->NumMacTable;
+ dest->NumMacTable += src->NumMacTable;
+ dest->MacTables = ReAlloc(dest->MacTables, sizeof(RPC_ENUM_MAC_TABLE_ITEM) * dest->NumMacTable);
+
+ n = 0;
+ for (i = old_num;i < dest->NumMacTable;i++)
+ {
+ Copy(&dest->MacTables[i], &src->MacTables[n++], sizeof(RPC_ENUM_MAC_TABLE_ITEM));
+ }
+}
+
+// Adjoin RPC_ENUM_SESSION
+void AdjoinRpcEnumSession(RPC_ENUM_SESSION *dest, RPC_ENUM_SESSION *src)
+{
+ UINT old_num;
+ UINT i, n;
+ if (dest == NULL || src == NULL)
+ {
+ return;
+ }
+
+ if (src->NumSession == 0)
+ {
+ return;
+ }
+
+ old_num = dest->NumSession;
+ dest->NumSession += src->NumSession;
+ dest->Sessions = ReAlloc(dest->Sessions, sizeof(RPC_ENUM_SESSION_ITEM) * dest->NumSession);
+
+ n = 0;
+ for (i = old_num;i < dest->NumSession;i++)
+ {
+ Copy(&dest->Sessions[i], &src->Sessions[n++], sizeof(RPC_ENUM_SESSION_ITEM));
+ }
+}
+
+// RPC_KEEP
+void InRpcKeep(RPC_KEEP *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_KEEP));
+ t->UseKeepConnect = PackGetBool(p, "UseKeepConnect");
+ PackGetStr(p, "KeepConnectHost", t->KeepConnectHost, sizeof(t->KeepConnectHost));
+ t->KeepConnectPort = PackGetInt(p, "KeepConnectPort");
+ t->KeepConnectProtocol = PackGetInt(p, "KeepConnectProtocol");
+ t->KeepConnectInterval = PackGetInt(p, "KeepConnectInterval");
+}
+void OutRpcKeep(PACK *p, RPC_KEEP *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "UseKeepConnect", t->UseKeepConnect);
+ PackAddStr(p, "KeepConnectHost", t->KeepConnectHost);
+ PackAddInt(p, "KeepConnectPort", t->KeepConnectPort);
+ PackAddInt(p, "KeepConnectProtocol", t->KeepConnectProtocol);
+ PackAddInt(p, "KeepConnectInterval", t->KeepConnectInterval);
+}
+
+// test RPC function
+UINT StTest(ADMIN *a, RPC_TEST *t)
+{
+ Format(t->StrValue, sizeof(t->StrValue), "%u", t->IntValue);
+
+ return ERR_NO_ERROR;
+}
+
+// RPC_TEST
+void InRpcTest(RPC_TEST *t, PACK *p)
+{
+ Zero(t, sizeof(RPC_TEST));
+ t->IntValue = PackGetInt(p, "IntValue");
+ t->Int64Value = PackGetInt64(p, "Int64Value");
+ PackGetStr(p, "StrValue", t->StrValue, sizeof(t->StrValue));
+ PackGetUniStr(p, "UniStrValue", t->UniStrValue, sizeof(t->UniStrValue));
+}
+void OutRpcTest(PACK *p, RPC_TEST *t)
+{
+ PackAddInt(p, "IntValue", t->IntValue);
+ PackAddInt64(p, "Int64Value", t->Int64Value);
+ PackAddStr(p, "StrValue", t->StrValue);
+ PackAddUniStr(p, "UniStrValue", t->UniStrValue);
+}
+void FreeRpcTest(RPC_TEST *t)
+{
+}
+
+// Admin RPC call
+PACK *AdminCall(RPC *rpc, char *function_name, PACK *p)
+{
+ // Validate arguments
+ if (rpc == NULL || function_name == NULL)
+ {
+ return NULL;
+ }
+ if (p == NULL)
+ {
+ p = NewPack();
+ }
+
+// Debug("Admin RPC Call: %s\n", function_name);
+
+ return RpcCall(rpc, function_name, p);
+}
+
+// Check whether the source IP address is permitted to admin connection
+bool CheckAdminSourceAddress(SOCK *sock, char *hubname)
+{
+ BUF *b;
+ char *s;
+ bool ok = false;
+ // Validate arguments
+ if (sock == NULL)
+ {
+ return false;
+ }
+
+ b = ReadDump(ADMINIP_TXT);
+ if (b == NULL)
+ {
+ return true;
+ }
+
+ while (true)
+ {
+ UINT i;
+ TOKEN_LIST *t;
+ IP ip;
+ s = CfgReadNextLine(b);
+
+ if (s == NULL)
+ {
+ break;
+ }
+
+ Trim(s);
+
+ i = SearchStrEx(s, "//", 0, false);
+ if (i != INFINITE)
+ {
+ s[i] = 0;
+ }
+
+ i = SearchStrEx(s, "#", 0, false);
+ if (i != INFINITE)
+ {
+ s[i] = 0;
+ }
+
+ Trim(s);
+
+ t = ParseToken(s, " \t");
+ if (t != NULL)
+ {
+ if (t->NumTokens >= 1)
+ {
+ if (t->NumTokens == 1 || StrCmpi(hubname, t->Token[1]) == 0)
+ {
+ if (StrToIP(&ip, t->Token[0]))
+ {
+ if (CmpIpAddr(&sock->RemoteIP, &ip) == 0)
+ {
+ ok = true;
+ }
+ }
+
+ if (StrCmpi(t->Token[0], "*") == 0)
+ {
+ ok = true;
+ }
+ }
+ }
+
+ FreeToken(t);
+ }
+
+ Free(s);
+ }
+
+ FreeBuf(b);
+
+ return ok;
+}
+
+// Accept admin connection
+UINT AdminAccept(CONNECTION *c, PACK *p)
+{
+ ADMIN *a;
+ UCHAR secure_password[SHA1_SIZE];
+ UCHAR null_password[SHA1_SIZE];
+ UCHAR secure_null_password[SHA1_SIZE];
+ char hubname[MAX_HUBNAME_LEN + 1];
+ CEDAR *cedar;
+ SOCK *sock;
+ RPC *rpc;
+ UINT err;
+ SERVER *server = NULL;
+ RPC_WINVER ver;
+ bool accept_empty_password;
+ bool is_empty_password = false;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ cedar = c->Cedar;
+ sock = c->FirstSock;
+
+ if (cedar != NULL)
+ {
+ server = cedar->Server;
+ }
+
+ accept_empty_password = PackGetBool(p, "accept_empty_password");
+
+ // Get client OS version
+ InRpcWinVer(&ver, p);
+
+ // Get hub name
+ if (PackGetStr(p, "hubname", hubname, sizeof(hubname)) == false)
+ {
+ // without hub name
+ StrCpy(hubname, sizeof(hubname), "");
+ }
+
+ // Cehck source IP address
+ if (CheckAdminSourceAddress(sock, hubname) == false)
+ {
+ SLog(c->Cedar, "LA_IP_DENIED", c->Name);
+ return ERR_IP_ADDRESS_DENIED;
+ }
+
+ // Get password information
+ if (PackGetDataSize(p, "secure_password") != SHA1_SIZE)
+ {
+ // Malformed information
+ return ERR_PROTOCOL_ERROR;
+ }
+ PackGetData(p, "secure_password", secure_password);
+
+ if (StrLen(hubname) == 0)
+ {
+ // Server admin mode
+ SLog(c->Cedar, "LA_CONNECTED_1", c->Name);
+ }
+ else
+ {
+ // Hub admin mode
+ if (cedar->Server != NULL && cedar->Server->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ // Connection with hub admin mode to cluster member is not permitted
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+ SLog(c->Cedar, "LA_CONNECTED_2", c->Name, hubname);
+ }
+
+ // Check password
+ err = AdminCheckPassword(cedar, c->Random, secure_password,
+ StrLen(hubname) != 0 ? hubname : NULL, accept_empty_password, &is_empty_password);
+
+ if (err != ERR_NO_ERROR)
+ {
+ // Error occured
+ SLog(c->Cedar, "LA_ERROR", c->Name, GetUniErrorStr(err), err);
+ return err;
+ }
+
+ SLog(c->Cedar, "LA_OK", c->Name);
+
+ HashAdminPassword(null_password, "");
+ SecurePassword(secure_null_password, null_password, c->Random);
+
+ if (Cmp(secure_null_password, secure_password, SHA1_SIZE) == 0)
+ {
+ if (sock->RemoteIP.addr[0] != 127)
+ {
+ // The client tried to use blank password for hub admin mode from remote
+ if (StrLen(hubname) != 0)
+ {
+ return ERR_NULL_PASSWORD_LOCAL_ONLY;
+ }
+ }
+ }
+
+
+ // Reply success result
+ p = NewPack();
+ if (accept_empty_password && is_empty_password)
+ {
+ PackAddBool(p, "empty_password", true);
+ }
+ HttpServerSend(sock, p);
+ FreePack(p);
+
+ // Construct ADMIN object
+ a = ZeroMalloc(sizeof(ADMIN));
+ a->ServerAdmin = ((StrLen(hubname) == 0) ? true : false);
+ a->HubName = (StrLen(hubname) != 0 ? hubname : NULL);
+ a->Server = c->Cedar->Server;
+ a->ClientBuild = c->ClientBuild;
+
+ Copy(&a->ClientWinVer, &ver, sizeof(RPC_WINVER));
+
+ // Timeout setting
+ SetTimeout(sock, INFINITE);
+
+ // RPC Server
+ rpc = StartRpcServer(sock, AdminDispatch, a);
+
+ a->Rpc = rpc;
+
+ SLog(c->Cedar, "LA_RPC_START", c->Name, rpc->Name);
+
+ RpcServer(rpc);
+ RpcFree(rpc);
+
+ if (a->LogFileList != NULL)
+ {
+ // Free cached log file list, if it exists
+ FreeEnumLogFile(a->LogFileList);
+ }
+
+ // Free ADMIN object
+ Free(a);
+
+ return ERR_NO_ERROR;
+}
+
+// Check for admin password
+UINT AdminCheckPassword(CEDAR *c, void *random, void *secure_password, char *hubname,
+ bool accept_empty_password, bool *is_password_empty)
+{
+ UCHAR check[SHA1_SIZE];
+ bool b_dummy;
+ // Validate arguments
+ if (c == NULL || random == NULL || secure_password == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+ if (is_password_empty == NULL)
+ {
+ is_password_empty = &b_dummy;
+ }
+
+ *is_password_empty = false;
+
+ if (hubname == NULL || StrLen(hubname) == 0)
+ {
+ // Server admin mode
+ Lock(c->lock);
+ {
+ if (accept_empty_password && SiIsEmptyPassword(c->Server->HashedPassword))
+ {
+ // blank password
+ *is_password_empty = true;
+ }
+
+ SecurePassword(check, c->Server->HashedPassword, random);
+ }
+ Unlock(c->lock);
+
+ if (Cmp(check, secure_password, SHA1_SIZE) != 0)
+ {
+ // Password incorrect
+ return ERR_ACCESS_DENIED;
+ }
+ }
+ else
+ {
+ HUB *h;
+
+#if 0
+ if (c->Server->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ // In cluster member mode, hub admin mode is disabled
+ return ERR_FARM_MEMBER_HUB_ADMIN;
+ }
+#endif
+
+ // Hub admin mode
+ LockHubList(c);
+ {
+ h = GetHub(c, hubname);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ // Specified hub is not found
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ Lock(h->lock);
+ {
+ if (accept_empty_password && SiIsEmptyPassword(h->HashedPassword))
+ {
+ // User specified blank password
+ *is_password_empty = true;
+ }
+
+ SecurePassword(check, h->HashedPassword, random);
+ }
+ Unlock(h->lock);
+
+ ReleaseHub(h);
+
+ if (Cmp(check, secure_password, SHA1_SIZE) != 0)
+ {
+ // Incorrect password
+ return ERR_ACCESS_DENIED;
+ }
+ }
+
+ return ERR_NO_ERROR;
+}
+
+// Hash admin password
+void HashAdminPassword(void *hash, char *password)
+{
+ // Validate arguments
+ if (hash == NULL || password == NULL)
+ {
+ return;
+ }
+
+ Hash(hash, password, StrLen(password), true);
+}
+
+// Disconnect admin connection
+void AdminDisconnect(RPC *rpc)
+{
+ SESSION *s;
+ SOCK *sock;
+ // Validate arguments
+ if (rpc == NULL)
+ {
+ return;
+ }
+
+ s = (SESSION *)rpc->Param;
+ sock = rpc->Sock;
+
+ EndRpc(rpc);
+
+ Disconnect(sock);
+ ReleaseSession(s);
+}
+
+// Admin connection main routine
+SESSION *AdminConnectMain(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err, char *client_name, void *hWnd, bool *empty_password)
+{
+ UCHAR secure_password[SHA1_SIZE];
+ SESSION *s;
+ SOCK *sock;
+ PACK *p;
+ RPC_WINVER ver;
+ // connect
+ s = NewRpcSessionEx2(cedar, o, err, client_name, hWnd);
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ // Get socket
+ sock = s->Connection->FirstSock;
+
+ // Generate connect method
+ p = NewPack();
+
+ PackAddClientVersion(p, s->Connection);
+
+ PackAddStr(p, "method", "admin");
+ PackAddBool(p, "accept_empty_password", true);
+
+ // Windows version on client
+ GetWinVer(&ver);
+ OutRpcWinVer(p, &ver);
+
+ // Secure Password
+ SecurePassword(secure_password, hashed_password, s->Connection->Random);
+
+ PackAddData(p, "secure_password", secure_password, sizeof(secure_password));
+
+ // HUB name
+ if (hubname != NULL)
+ {
+ PackAddStr(p, "hubname", hubname);
+ }
+
+ if (HttpClientSend(sock, p) == false)
+ {
+ // disconnect
+ FreePack(p);
+ ReleaseSession(s);
+ *err = ERR_DISCONNECTED;
+ return NULL;
+ }
+
+ FreePack(p);
+
+ p = HttpClientRecv(sock);
+ if (p == NULL)
+ {
+ // disconnect
+ ReleaseSession(s);
+ *err = ERR_DISCONNECTED;
+ return NULL;
+ }
+
+ if (GetErrorFromPack(p) != 0)
+ {
+ // error
+ ReleaseSession(s);
+ *err = GetErrorFromPack(p);
+ FreePack(p);
+ return NULL;
+ }
+
+ if (empty_password != NULL)
+ {
+ *empty_password = PackGetBool(p, "empty_password");
+ }
+
+ FreePack(p);
+
+ return s;
+}
+
+// Admin connection
+RPC *AdminConnect(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err)
+{
+ return AdminConnectEx(cedar, o, hubname, hashed_password, err, NULL);
+}
+RPC *AdminConnectEx(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err, char *client_name)
+{
+ return AdminConnectEx2(cedar, o, hubname, hashed_password, err, client_name, NULL);
+}
+RPC *AdminConnectEx2(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err, char *client_name, void *hWnd)
+{
+ SESSION *s;
+ SOCK *sock;
+ RPC *rpc;
+ UCHAR hashed_password_2[SHA1_SIZE];
+ bool empty_password = false;
+ // Validate arguments
+ if (cedar == NULL || o == NULL || hashed_password == NULL || err == NULL)
+ {
+ return NULL;
+ }
+
+ if (client_name == NULL)
+ {
+ client_name = CEDAR_MANAGER_STR;
+ }
+
+ Copy(hashed_password_2, hashed_password, SHA1_SIZE);
+
+ s = AdminConnectMain(cedar, o, hubname, hashed_password_2, err, client_name, hWnd, &empty_password);
+
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ sock = s->Connection->FirstSock;
+
+ // RPC start
+ rpc = StartRpcClient(sock, s);
+
+ rpc->IsVpnServer = true;
+ Copy(&rpc->VpnServerClientOption, o, sizeof(CLIENT_OPTION));
+ StrCpy(rpc->VpnServerHubName, sizeof(rpc->VpnServerHubName), hubname);
+ StrCpy(rpc->VpnServerClientName, sizeof(rpc->VpnServerClientName), client_name);
+
+ if (empty_password == false)
+ {
+ Copy(rpc->VpnServerHashedPassword, hashed_password_2, SHA1_SIZE);
+ }
+ else
+ {
+ HashAdminPassword(rpc->VpnServerHashedPassword, "");
+ }
+
+ // timeout setting
+ SetTimeout(sock, INFINITE);
+
+ return rpc;
+}
+
+// Reconnect admin connection
+UINT AdminReconnect(RPC *rpc)
+{
+ SESSION *s;
+ SOCK *sock;
+ CEDAR *cedar;
+ UINT err;
+ bool empty_password = false;
+ // Validate arguments
+ if (rpc == NULL || rpc->IsVpnServer == false)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ s = (SESSION *)rpc->Param;
+ cedar = s->Cedar;
+ AddRef(cedar->ref);
+
+ sock = rpc->Sock;
+ Disconnect(sock);
+ ReleaseSock(sock);
+ ReleaseSession(s);
+ rpc->Param = NULL;
+
+ rpc->Sock = NULL;
+
+ s = AdminConnectMain(cedar, &rpc->VpnServerClientOption,
+ rpc->VpnServerHubName,
+ rpc->VpnServerHashedPassword,
+ &err,
+ rpc->VpnServerClientName, NULL, &empty_password);
+
+ ReleaseCedar(cedar);
+
+ if (s == NULL)
+ {
+ return err;
+ }
+
+ if (empty_password)
+ {
+ HashAdminPassword(rpc->VpnServerHashedPassword, "");
+ }
+
+ rpc->Param = s;
+ rpc->Sock = s->Connection->FirstSock;
+ AddRef(rpc->Sock->ref);
+
+ return ERR_NO_ERROR;
+}
+
+// Identify blank password
+bool SiIsEmptyPassword(void *hash_password)
+{
+ UCHAR hash[SHA1_SIZE];
+ // Validate arguments
+ if (hash_password == NULL)
+ {
+ return false;
+ }
+
+ Hash(hash, "", 0, true);
+
+ if (Cmp(hash_password, hash, SHA1_SIZE) == 0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Admin.h b/src/Cedar/Admin.h
new file mode 100644
index 00000000..b667f609
--- /dev/null
+++ b/src/Cedar/Admin.h
@@ -0,0 +1,1505 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Admin.h
+// Header of Admin.c
+
+#ifndef ADMIN_H
+#define ADMIN_H
+
+// Windows version
+struct RPC_WINVER
+{
+ bool IsWindows;
+ bool IsNT;
+ bool IsServer;
+ bool IsBeta;
+ UINT VerMajor;
+ UINT VerMinor;
+ UINT Build;
+ UINT ServicePack;
+ char Title[128];
+};
+
+// Server-side structure
+struct ADMIN
+{
+ SERVER *Server; // Server
+ bool ServerAdmin; // Server Administrator
+ char *HubName; // HUB name that can be managed
+ RPC *Rpc; // RPC
+ LIST *LogFileList; // Accessible log file list
+ UINT ClientBuild; // Build number of the client
+ RPC_WINVER ClientWinVer; // Windows version of client
+};
+
+// Test
+struct RPC_TEST
+{
+ UINT IntValue;
+ UINT64 Int64Value;
+ char StrValue[1024];
+ wchar_t UniStrValue[1024];
+};
+
+// Server Information *
+struct RPC_SERVER_INFO
+{
+ char ServerProductName[128]; // Server product name
+ char ServerVersionString[128]; // Server version string
+ char ServerBuildInfoString[128]; // Server build information string
+ UINT ServerVerInt; // Server version integer value
+ UINT ServerBuildInt; // Server build number integer value
+ char ServerHostName[MAX_HOST_NAME_LEN + 1]; // Server host name
+ UINT ServerType; // Type of server
+ UINT64 ServerBuildDate; // Build date and time of the server
+ char ServerFamilyName[128]; // Family name
+ OS_INFO OsInfo; // OS information
+};
+
+// Server status
+struct RPC_SERVER_STATUS
+{
+ UINT ServerType; // Type of server
+ UINT NumTcpConnections; // Total number of TCP connections
+ UINT NumTcpConnectionsLocal; // Number of Local TCP connections
+ UINT NumTcpConnectionsRemote; // Number of remote TCP connections
+ UINT NumHubTotal; // Total number of HUBs
+ UINT NumHubStandalone; // Nymber of stand-alone HUB
+ UINT NumHubStatic; // Number of static HUBs
+ UINT NumHubDynamic; // Number of Dynamic HUBs
+ UINT NumSessionsTotal; // Total number of sessions
+ UINT NumSessionsLocal; // Number of Local sessions (only controller)
+ UINT NumSessionsRemote; // The number of remote sessions (other than the controller)
+ UINT NumMacTables; // Number of MAC table entries
+ UINT NumIpTables; // Number of IP table entries
+ UINT NumUsers; // Number of users
+ UINT NumGroups; // Number of groups
+ UINT AssignedBridgeLicenses; // Number of assigned bridge licenses
+ UINT AssignedClientLicenses; // Number of assigned client licenses
+ UINT AssignedBridgeLicensesTotal; // Number of Assigned bridge license (cluster-wide)
+ UINT AssignedClientLicensesTotal; // Number of assigned client licenses (cluster-wide)
+ TRAFFIC Traffic; // Traffic information
+ UINT64 CurrentTime; // Current time
+ UINT64 CurrentTick; // Current tick
+ UINT64 StartTime; // Start-up time
+ MEMINFO MemInfo; // Memory information
+};
+
+// Listener
+struct RPC_LISTENER
+{
+ UINT Port; // Port number
+ bool Enable; // Active state
+};
+
+// List of listeners *
+struct RPC_LISTENER_LIST
+{
+ UINT NumPort; // Number of ports
+ UINT *Ports; // Port List
+ bool *Enables; // Effective state
+ bool *Errors; // An error occurred
+};
+
+// String *
+struct RPC_STR
+{
+ char *String; // String
+};
+
+// Integer
+struct RPC_INT
+{
+ UINT IntValue; // Integer
+};
+
+// Set Password
+struct RPC_SET_PASSWORD
+{
+ UCHAR HashedPassword[SHA1_SIZE]; // Hashed password
+};
+
+// Server farm configuration *
+struct RPC_FARM
+{
+ UINT ServerType; // Type of server
+ UINT NumPort; // Number of public ports
+ UINT *Ports; // Public port list
+ UINT PublicIp; // Public IP
+ char ControllerName[MAX_HOST_NAME_LEN + 1]; // Controller name
+ UINT ControllerPort; // Controller port
+ UCHAR MemberPassword[SHA1_SIZE]; // Member password
+ UINT Weight; // Performance ratio
+ bool ControllerOnly; // Only controller function
+};
+
+// HUB item of each farm member
+struct RPC_FARM_HUB
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ bool DynamicHub; // Dynamic HUB
+};
+
+// Server farm member information acquisition *
+struct RPC_FARM_INFO
+{
+ UINT Id; // ID
+ bool Controller; // Controller
+ UINT64 ConnectedTime; // Connection time
+ UINT Ip; // IP address
+ char Hostname[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT Point; // Point
+ UINT NumPort; // Number of ports
+ UINT *Ports; // Port
+ X *ServerCert; // Server certificate
+ UINT NumFarmHub; // Number of farm HUB
+ RPC_FARM_HUB *FarmHubs; // Farm HUB
+ UINT NumSessions; // Number of sessions
+ UINT NumTcpConnections; // Number of TCP connections
+ UINT Weight; // Performance ratio
+};
+
+// Server farm members enumeration items
+struct RPC_ENUM_FARM_ITEM
+{
+ UINT Id; // ID
+ bool Controller; // Controller
+ UINT64 ConnectedTime; // Connection time
+ UINT Ip; // IP address
+ char Hostname[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT Point; // Point
+ UINT NumSessions; // Number of sessions
+ UINT NumTcpConnections; // Number of TCP connections
+ UINT NumHubs; // Number of HUBs
+ UINT AssignedClientLicense; // Number of assigned client licenses
+ UINT AssignedBridgeLicense; // Number of assigned bridge licenses
+};
+
+// Server farm member enumeration *
+struct RPC_ENUM_FARM
+{
+ UINT NumFarm; // Number of farm members
+ RPC_ENUM_FARM_ITEM *Farms; // Farm member list
+};
+
+// Connection state to the controller
+struct RPC_FARM_CONNECTION_STATUS
+{
+ UINT Ip; // IP address
+ UINT Port; // Port number
+ bool Online; // Online state
+ UINT LastError; // Last error
+ UINT64 StartedTime; // Connection start time
+ UINT64 FirstConnectedTime; // First connection time
+ UINT64 CurrentConnectedTime; // Connection time of this time
+ UINT NumTry; // Number of trials
+ UINT NumConnected; // Number of connection count
+ UINT NumFailed; // Connection failure count
+};
+
+// Key pair
+struct RPC_KEY_PAIR
+{
+ X *Cert; // Certificate
+ K *Key; // Secret key
+};
+
+// HUB option
+struct RPC_HUB_OPTION
+{
+ UINT MaxSession; // Maximum number of sessions
+ bool NoEnum; // Not listed
+};
+
+// Radius server options
+struct RPC_RADIUS
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ char RadiusServerName[MAX_HOST_NAME_LEN + 1]; // Radius server name
+ UINT RadiusPort; // Radius port number
+ char RadiusSecret[MAX_PASSWORD_LEN + 1]; // Secret key
+ UINT RadiusRetryInterval; // Radius retry interval
+};
+
+// Specify the HUB
+struct RPC_HUB
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+};
+
+// Create a HUB
+struct RPC_CREATE_HUB
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UCHAR HashedPassword[SHA1_SIZE]; // Administrative password
+ UCHAR SecurePassword[SHA1_SIZE]; // Administrator password
+ bool Online; // Online flag
+ RPC_HUB_OPTION HubOption; // HUB options
+ UINT HubType; // Type of HUB
+};
+
+// Enumeration items of HUB
+struct RPC_ENUM_HUB_ITEM
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ bool Online; // Online
+ UINT HubType; // Type of HUB
+ UINT NumUsers; // Number of users
+ UINT NumGroups; // Number of groups
+ UINT NumSessions; // Number of sessions
+ UINT NumMacTables; // Number of MAC table entries
+ UINT NumIpTables; // Number of IP table entries
+ UINT64 LastCommTime; // Last communication date and time
+ UINT64 LastLoginTime; // Last login date and time
+ UINT64 CreatedTime; // Creation date and time
+ UINT NumLogin; // Number of logins
+ bool IsTrafficFilled; // Whether the traffic information exists
+ TRAFFIC Traffic; // Traffic
+};
+
+// Enumeration of HUB
+struct RPC_ENUM_HUB
+{
+ UINT NumHub; // Number of HUBs
+ RPC_ENUM_HUB_ITEM *Hubs; // HUB
+};
+
+// Delete the HUB
+struct RPC_DELETE_HUB
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+};
+
+// Connection enumeration items
+struct RPC_ENUM_CONNECTION_ITEM
+{
+ char Name[MAX_SIZE]; // Connection name
+ char Hostname[MAX_SIZE]; // Host name
+ UINT Ip; // IP address
+ UINT Port; // Port number
+ UINT64 ConnectedTime; // Connected time
+ UINT Type; // Type
+};
+
+// Connection enumeration
+struct RPC_ENUM_CONNECTION
+{
+ UINT NumConnection; // Number of connections
+ RPC_ENUM_CONNECTION_ITEM *Connections; // Connection list
+};
+
+// Disconnection
+struct RPC_DISCONNECT_CONNECTION
+{
+ char Name[MAX_SIZE]; // Connection name
+};
+
+// Connection information
+struct RPC_CONNECTION_INFO
+{
+ char Name[MAX_SIZE]; // Connection name
+ UINT Type; // Type
+ char Hostname[MAX_SIZE]; // Host name
+ UINT Ip; // IP address
+ UINT Port; // Port number
+ UINT64 ConnectedTime; // Connected time
+ char ServerStr[MAX_SERVER_STR_LEN + 1]; // Server string
+ UINT ServerVer; // Server version
+ UINT ServerBuild; // Server build number
+ char ClientStr[MAX_CLIENT_STR_LEN + 1]; // Client string
+ UINT ClientVer; // Client version
+ UINT ClientBuild; // Client build number
+};
+
+// Online or offline the HUB
+struct RPC_SET_HUB_ONLINE
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ bool Online; // Online / offline flag
+};
+
+// Get the state HUB
+struct RPC_HUB_STATUS
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ bool Online; // Online
+ UINT HubType; // Type of HUB
+ UINT NumSessions; // Number of sessions
+ UINT NumSessionsClient; // Number of sessions (client)
+ UINT NumSessionsBridge; // Number of sessions (bridge)
+ UINT NumAccessLists; // Number of Access list entries
+ UINT NumUsers; // Number of users
+ UINT NumGroups; // Number of groups
+ UINT NumMacTables; // Number of MAC table entries
+ UINT NumIpTables; // Number of IP table entries
+ TRAFFIC Traffic; // Traffic
+ bool SecureNATEnabled; // Whether SecureNAT is enabled
+ UINT64 LastCommTime; // Last communication date and time
+ UINT64 LastLoginTime; // Last login date and time
+ UINT64 CreatedTime; // Creation date and time
+ UINT NumLogin; // Number of logins
+};
+
+// HUB log settings
+struct RPC_HUB_LOG
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ HUB_LOG LogSetting; // Log Settings
+};
+
+// Add CA to HUB *
+struct RPC_HUB_ADD_CA
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ X *Cert; // Certificate
+};
+
+// CA enumeration items of HUB
+struct RPC_HUB_ENUM_CA_ITEM
+{
+ UINT Key; // Certificate key
+ wchar_t SubjectName[MAX_SIZE]; // Issued to
+ wchar_t IssuerName[MAX_SIZE]; // Issuer
+ UINT64 Expires; // Expiration date
+};
+
+// CA enumeration of HUB *
+struct RPC_HUB_ENUM_CA
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT NumCa; // CA number
+ RPC_HUB_ENUM_CA_ITEM *Ca; // CA
+};
+
+// Get the CA of HUB *
+struct RPC_HUB_GET_CA
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT Key; // Certificate key
+ X *Cert; // Certificate
+};
+
+// Delete the CA of HUB
+struct RPC_HUB_DELETE_CA
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT Key; // Certificate key to be deleted
+};
+
+// Create and set of link *
+struct RPC_CREATE_LINK
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ bool Online; // Online flag
+ CLIENT_OPTION *ClientOption; // Client Option
+ CLIENT_AUTH *ClientAuth; // Client authentication data
+ POLICY Policy; // Policy
+ bool CheckServerCert; // Validate the server certificate
+ X *ServerCert; // Server certificate
+};
+
+// Enumeration items of link
+struct RPC_ENUM_LINK_ITEM
+{
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+ bool Online; // Online flag
+ bool Connected; // Connection completion flag
+ UINT LastError; // The error that last occurred
+ UINT64 ConnectedTime; // Connection completion time
+ char Hostname[MAX_HOST_NAME_LEN + 1]; // Host name
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+};
+
+// Enumeration of the link *
+struct RPC_ENUM_LINK
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT NumLink; // Number of links
+ RPC_ENUM_LINK_ITEM *Links; // Link List
+};
+
+// Get the link state *
+struct RPC_LINK_STATUS
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+ RPC_CLIENT_GET_CONNECTION_STATUS Status; // Status
+};
+
+// Specify the Link
+struct RPC_LINK
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+};
+
+// Rename link
+struct RPC_RENAME_LINK
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ wchar_t OldAccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Old account name
+ wchar_t NewAccountName[MAX_ACCOUNT_NAME_LEN + 1]; // New account name
+};
+
+// Enumeration of the access list *
+struct RPC_ENUM_ACCESS_LIST
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT NumAccess; // Number of Access list entries
+ ACCESS *Accesses; // Access list
+};
+
+// Add to Access List
+struct RPC_ADD_ACCESS
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ ACCESS Access; // Access list
+};
+
+// Delete the access list
+struct RPC_DELETE_ACCESS
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT Id; // ID
+};
+
+// Create, configure, and get the user *
+struct RPC_SET_USER
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ char Name[MAX_USERNAME_LEN + 1]; // User name
+ char GroupName[MAX_USERNAME_LEN + 1]; // Group name
+ wchar_t Realname[MAX_SIZE]; // Real name
+ wchar_t Note[MAX_SIZE]; // Note
+ UINT64 CreatedTime; // Creation date and time
+ UINT64 UpdatedTime; // Updating date
+ UINT64 ExpireTime; // Expiration date
+ UINT AuthType; // Authentication method
+ void *AuthData; // Authentication data
+ UINT NumLogin; // Number of logins
+ TRAFFIC Traffic; // Traffic data
+ POLICY *Policy; // Policy
+};
+
+// Enumeration item of user
+struct RPC_ENUM_USER_ITEM
+{
+ char Name[MAX_USERNAME_LEN + 1]; // User name
+ char GroupName[MAX_USERNAME_LEN + 1]; // Group name
+ wchar_t Realname[MAX_SIZE]; // Real name
+ wchar_t Note[MAX_SIZE]; // Note
+ UINT AuthType; // Authentication method
+ UINT NumLogin; // Number of logins
+ UINT64 LastLoginTime; // Last login date and time
+ bool DenyAccess; // Access denied
+ bool IsTrafficFilled; // Flag of whether the traffic variable is set
+ TRAFFIC Traffic; // Traffic
+ bool IsExpiresFilled; // Flag of whether expiration date variable is set
+ UINT64 Expires; // Expiration date
+};
+
+// Enumeration of user
+struct RPC_ENUM_USER
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT NumUser; // Number of users
+ RPC_ENUM_USER_ITEM *Users; // User
+};
+
+// Create, configure, and get the group *
+struct RPC_SET_GROUP
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ char Name[MAX_USERNAME_LEN + 1]; // User name
+ wchar_t Realname[MAX_SIZE]; // Real name
+ wchar_t Note[MAX_SIZE]; // Note
+ TRAFFIC Traffic; // Traffic data
+ POLICY *Policy; // Policy
+};
+
+// Enumeration items in the group
+struct RPC_ENUM_GROUP_ITEM
+{
+ char Name[MAX_USERNAME_LEN + 1]; // User name
+ wchar_t Realname[MAX_SIZE]; // Real name
+ wchar_t Note[MAX_SIZE]; // Note
+ UINT NumUsers; // Number of users
+ bool DenyAccess; // Access denied
+};
+
+// Group enumeration
+struct RPC_ENUM_GROUP
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT NumGroup; // Number of groups
+ RPC_ENUM_GROUP_ITEM *Groups; // Group
+};
+
+// Deleting a user or group
+struct RPC_DELETE_USER
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ char Name[MAX_USERNAME_LEN + 1]; // User or group name
+};
+
+// Enumeration items of session
+struct RPC_ENUM_SESSION_ITEM
+{
+ char Name[MAX_SESSION_NAME_LEN + 1]; // Session name
+ bool RemoteSession; // Remote session
+ char RemoteHostname[MAX_HOST_NAME_LEN + 1]; // Remote server name
+ char Username[MAX_USERNAME_LEN + 1]; // User name
+ UINT Ip; // IP address (IPv4)
+ char Hostname[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT MaxNumTcp; // Maximum number of TCP connections
+ UINT CurrentNumTcp; // Number of currentl TCP connections
+ UINT64 PacketSize; // Packet size
+ UINT64 PacketNum; // Number of packets
+ bool LinkMode; // Link mode
+ bool SecureNATMode; // SecureNAT mode
+ bool BridgeMode; // Bridge mode
+ bool Layer3Mode; // Layer 3 mode
+ bool Client_BridgeMode; // Client is bridge mode
+ bool Client_MonitorMode; // Client is monitoring mode
+ UINT VLanId; // VLAN ID
+ UCHAR UniqueId[16]; // Unique ID
+};
+
+// Disconnect the session
+struct RPC_DELETE_SESSION
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ char Name[MAX_SESSION_NAME_LEN + 1]; // Session name
+};
+
+// Enumeration items of the MAC table
+struct RPC_ENUM_MAC_TABLE_ITEM
+{
+ UINT Key; // Key
+ char SessionName[MAX_SESSION_NAME_LEN + 1]; // Session name
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2];
+ UINT64 CreatedTime; // Creation date and time
+ UINT64 UpdatedTime; // Updating date
+ bool RemoteItem; // Remote items
+ char RemoteHostname[MAX_HOST_NAME_LEN + 1]; // Remote host name
+ UINT VlanId; // VLAN ID
+};
+
+// Enumeration of the MAC table
+struct RPC_ENUM_MAC_TABLE
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT NumMacTable; // Number of tables
+ RPC_ENUM_MAC_TABLE_ITEM *MacTables; // MAC table
+};
+
+// Enumeration items of IP table
+struct RPC_ENUM_IP_TABLE_ITEM
+{
+ UINT Key; // Key
+ char SessionName[MAX_SESSION_NAME_LEN + 1]; // Session name
+ UINT Ip; // IP address
+ IP IpV6; // IPv6 address
+ bool DhcpAllocated; // Assigned by the DHCP
+ UINT64 CreatedTime; // Creation date and time
+ UINT64 UpdatedTime; // Updating date
+ bool RemoteItem; // Remote items
+ char RemoteHostname[MAX_HOST_NAME_LEN + 1]; // Remote host name
+};
+
+// Enumeration of IP table
+struct RPC_ENUM_IP_TABLE
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT NumIpTable; // Number of tables
+ RPC_ENUM_IP_TABLE_ITEM *IpTables; // MAC table
+};
+
+// Delete the table
+struct RPC_DELETE_TABLE
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT Key; // Key
+};
+
+// KEEP setting
+struct RPC_KEEP
+{
+ bool UseKeepConnect; // Keep connected to the Internet
+ char KeepConnectHost[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT KeepConnectPort; // Port number
+ UINT KeepConnectProtocol; // Protocol
+ UINT KeepConnectInterval; // Interval
+};
+
+// Ethernet enumeration item
+struct RPC_ENUM_ETH_ITEM
+{
+ char DeviceName[MAX_SIZE]; // Device name
+ wchar_t NetworkConnectionName[MAX_SIZE];// Network connection name
+};
+
+// Ethernet enumeration
+struct RPC_ENUM_ETH
+{
+ UINT NumItem; // Number of items
+ RPC_ENUM_ETH_ITEM *Items; // Item
+};
+
+// Bridge item
+struct RPC_LOCALBRIDGE
+{
+ char DeviceName[MAX_SIZE]; // Device name
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ bool Online; // Online flag
+ bool Active; // Running flag
+ bool TapMode; // Tap mode
+};
+
+// Bridge enumeration
+struct RPC_ENUM_LOCALBRIDGE
+{
+ UINT NumItem; // Number of items
+ RPC_LOCALBRIDGE *Items; // Item
+};
+
+// Bridge support information
+struct RPC_BRIDGE_SUPPORT
+{
+ bool IsBridgeSupportedOs; // Whether the OS supports the bridge
+ bool IsWinPcapNeeded; // Whether WinPcap is necessary
+};
+
+// Config operation
+struct RPC_CONFIG
+{
+ char FileName[MAX_PATH]; // File name
+ char *FileData; // File data
+};
+
+// Administration options list
+struct RPC_ADMIN_OPTION
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // Virtual HUB name
+ UINT NumItem; // Count
+ ADMIN_OPTION *Items; // Data
+};
+
+// Layer-3 switch
+struct RPC_L3SW
+{
+ char Name[MAX_HUBNAME_LEN + 1]; // L3 switch name
+};
+
+// Layer-3 switch enumeration
+struct RPC_ENUM_L3SW_ITEM
+{
+ char Name[MAX_HUBNAME_LEN + 1]; // Name
+ UINT NumInterfaces; // Number of interfaces
+ UINT NumTables; // Routing table number
+ bool Active; // In operation
+ bool Online; // Online
+};
+struct RPC_ENUM_L3SW
+{
+ UINT NumItem;
+ RPC_ENUM_L3SW_ITEM *Items;
+};
+
+// Layer-3 interface
+struct RPC_L3IF
+{
+ char Name[MAX_HUBNAME_LEN + 1]; // L3 switch name
+ char HubName[MAX_HUBNAME_LEN + 1]; // Virtual HUB name
+ UINT IpAddress; // IP address
+ UINT SubnetMask; // Subnet mask
+};
+
+// Layer-3 interface enumeration
+struct RPC_ENUM_L3IF
+{
+ char Name[MAX_HUBNAME_LEN + 1]; // L3 switch name
+ UINT NumItem;
+ RPC_L3IF *Items;
+};
+
+// Routing table
+struct RPC_L3TABLE
+{
+ char Name[MAX_HUBNAME_LEN + 1]; // L3 switch name
+ UINT NetworkAddress; // Network address
+ UINT SubnetMask; // Subnet mask
+ UINT GatewayAddress; // Gateway address
+ UINT Metric; // Metric
+};
+
+// Routing table enumeration
+struct RPC_ENUM_L3TABLE
+{
+ char Name[MAX_HUBNAME_LEN + 1]; // L3 switch name
+ UINT NumItem;
+ RPC_L3TABLE *Items;
+};
+
+// CRL entry
+struct RPC_CRL
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT Key; // Key
+ CRL *Crl; // CRL body
+};
+
+// CRL enumeration
+struct RPC_ENUM_CRL_ITEM
+{
+ UINT Key; // Key
+ wchar_t CrlInfo[MAX_SIZE]; // Information
+};
+struct RPC_ENUM_CRL
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT NumItem; // Number of items
+ RPC_ENUM_CRL_ITEM *Items; // List
+};
+
+// AC list
+struct RPC_AC_LIST
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ LIST *o; // List body
+ bool InternalFlag1;
+};
+
+// Log file enumeration
+struct RPC_ENUM_LOG_FILE_ITEM
+{
+ char ServerName[MAX_HOST_NAME_LEN + 1]; // Server name
+ char FilePath[MAX_PATH]; // File Path
+ UINT FileSize; // File size
+ UINT64 UpdatedTime; // Updating date
+};
+struct RPC_ENUM_LOG_FILE
+{
+ UINT NumItem; // Number of items
+ RPC_ENUM_LOG_FILE_ITEM *Items; // List
+};
+
+// Read a Log file
+struct RPC_READ_LOG_FILE
+{
+ char ServerName[MAX_HOST_NAME_LEN + 1]; // Server name
+ char FilePath[MAX_PATH]; // File Path
+ UINT Offset; // Offset
+ BUF *Buffer; // Buffer
+};
+
+// Download information
+struct DOWNLOAD_PROGRESS
+{
+ void *Param; // User define data
+ UINT TotalSize; // The total file size
+ UINT CurrentSize; // Size which has loaded
+ UINT ProgressPercent; // Percent Complete
+};
+
+// Enumerate the license keys
+struct RPC_ENUM_LICENSE_KEY_ITEM
+{
+ UINT Id; // ID
+ char LicenseKey[LICENSE_KEYSTR_LEN + 1]; // License key
+ char LicenseId[LICENSE_LICENSEID_STR_LEN + 1]; // License ID
+ char LicenseName[LICENSE_MAX_PRODUCT_NAME_LEN + 1]; // License name
+ UINT64 Expires; // Expiration date
+ UINT Status; // Situation
+ UINT ProductId; // Product ID
+ UINT64 SystemId; // System ID
+ UINT SerialId; // Serial ID
+};
+struct RPC_ENUM_LICENSE_KEY
+{
+ UINT NumItem; // Number of items
+ RPC_ENUM_LICENSE_KEY_ITEM *Items; // List
+};
+
+// License status of the server
+struct RPC_LICENSE_STATUS
+{
+ UINT EditionId; // Edition ID
+ char EditionStr[LICENSE_MAX_PRODUCT_NAME_LEN + 1]; // Edition name
+ UINT64 SystemId; // System ID
+ UINT64 SystemExpires; // System expiration date
+ UINT NumClientConnectLicense; // Maximum number of concurrent client connections
+ UINT NumBridgeConnectLicense; // Available number of concurrent bridge connections
+
+ // v3.0
+ bool NeedSubscription; // Subscription system is enabled
+ UINT64 SubscriptionExpires; // Subscription expiration date
+ bool IsSubscriptionExpired; // Whether the subscription is expired
+ UINT NumUserCreationLicense; // Maximum number of users
+ bool AllowEnterpriseFunction; // Operation of the enterprise function
+ UINT64 ReleaseDate; // Release date
+};
+
+// Enumeration of VLAN support status of physical LAN card
+struct RPC_ENUM_ETH_VLAN_ITEM
+{
+ char DeviceName[MAX_SIZE]; // Device name
+ char Guid[MAX_SIZE]; // GUID
+ char DeviceInstanceId[MAX_SIZE]; // Device Instance ID
+ char DriverName[MAX_SIZE]; // Driver file name
+ char DriverType[MAX_SIZE]; // Type of driver
+ bool Support; // Check whether it is supported
+ bool Enabled; // Whether it is enabled
+};
+struct RPC_ENUM_ETH_VLAN
+{
+ UINT NumItem; // Number of items
+ RPC_ENUM_ETH_VLAN_ITEM *Items; // List
+};
+
+// Message
+struct RPC_MSG
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ wchar_t *Msg; // Message
+};
+
+// EtherIP setting list
+struct RPC_ENUM_ETHERIP_ID
+{
+ UINT NumItem;
+ ETHERIP_ID *IdList;
+};
+
+// Set the special listener
+struct RPC_SPECIAL_LISTENER
+{
+ bool VpnOverIcmpListener; // VPN over ICMP
+ bool VpnOverDnsListener; // VPN over DNS
+};
+
+// Get / Set the Azure state
+struct RPC_AZURE_STATUS
+{
+ bool IsEnabled; // Whether enabled
+ bool IsConnected; // Whether it's connected
+};
+
+
+// Function prototype
+UINT AdminAccept(CONNECTION *c, PACK *p);
+void HashAdminPassword(void *hash, char *password);
+SESSION *AdminConnectMain(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err, char *client_name, void *hWnd, bool *empty_password);
+RPC *AdminConnect(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err);
+RPC *AdminConnectEx(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err, char *client_name);
+RPC *AdminConnectEx2(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err, char *client_name, void *hWnd);
+void AdminDisconnect(RPC *rpc);
+UINT AdminReconnect(RPC *rpc);
+UINT AdminCheckPassword(CEDAR *c, void *random, void *secure_password, char *hubname, bool accept_empty_password, bool *is_password_empty);
+PACK *AdminDispatch(RPC *rpc, char *name, PACK *p);
+PACK *AdminCall(RPC *rpc, char *function_name, PACK *p);
+void SiEnumLocalSession(SERVER *s, char *hubname, RPC_ENUM_SESSION *t);
+void CopyOsInfo(OS_INFO *dst, OS_INFO *info);
+CAPSLIST *ScGetCapsEx(RPC *rpc);
+UINT SiEnumMacTable(SERVER *s, char *hubname, RPC_ENUM_MAC_TABLE *t);
+UINT SiEnumIpTable(SERVER *s, char *hubname, RPC_ENUM_IP_TABLE *t);
+void SiEnumLocalLogFileList(SERVER *s, char *hubname, RPC_ENUM_LOG_FILE *t);
+void SiReadLocalLogFile(SERVER *s, char *filepath, UINT offset, RPC_READ_LOG_FILE *t);
+typedef bool (DOWNLOAD_PROC)(DOWNLOAD_PROGRESS *progress);
+BUF *DownloadFileFromServer(RPC *r, char *server_name, char *filepath, UINT total_size, DOWNLOAD_PROC *proc, void *param);
+bool CheckAdminSourceAddress(SOCK *sock, char *hubname);
+void SiEnumSessionMain(SERVER *s, RPC_ENUM_SESSION *t);
+bool SiIsEmptyPassword(void *hash_password);
+
+UINT StTest(ADMIN *a, RPC_TEST *t);
+UINT StGetServerInfo(ADMIN *a, RPC_SERVER_INFO *t);
+UINT StGetServerStatus(ADMIN *a, RPC_SERVER_STATUS *t);
+UINT StCreateListener(ADMIN *a, RPC_LISTENER *t);
+UINT StEnumListener(ADMIN *a, RPC_LISTENER_LIST *t);
+UINT StDeleteListener(ADMIN *a, RPC_LISTENER *t);
+UINT StEnableListener(ADMIN *a, RPC_LISTENER *t);
+UINT StSetServerPassword(ADMIN *a, RPC_SET_PASSWORD *t);
+UINT StSetFarmSetting(ADMIN *a, RPC_FARM *t);
+UINT StGetFarmSetting(ADMIN *a, RPC_FARM *t);
+UINT StGetFarmInfo(ADMIN *a, RPC_FARM_INFO *t);
+UINT StEnumFarmMember(ADMIN *a, RPC_ENUM_FARM *t);
+UINT StGetFarmConnectionStatus(ADMIN *a, RPC_FARM_CONNECTION_STATUS *t);
+UINT StSetServerCert(ADMIN *a, RPC_KEY_PAIR *t);
+UINT StGetServerCert(ADMIN *a, RPC_KEY_PAIR *t);
+UINT StGetServerCipher(ADMIN *a, RPC_STR *t);
+UINT StSetServerCipher(ADMIN *a, RPC_STR *t);
+UINT StCreateHub(ADMIN *a, RPC_CREATE_HUB *t);
+UINT StSetHub(ADMIN *a, RPC_CREATE_HUB *t);
+UINT StGetHub(ADMIN *a, RPC_CREATE_HUB *t);
+UINT StEnumHub(ADMIN *a, RPC_ENUM_HUB *t);
+UINT StDeleteHub(ADMIN *a, RPC_DELETE_HUB *t);
+UINT StGetHubRadius(ADMIN *a, RPC_RADIUS *t);
+UINT StSetHubRadius(ADMIN *a, RPC_RADIUS *t);
+UINT StEnumConnection(ADMIN *a, RPC_ENUM_CONNECTION *t);
+UINT StDisconnectConnection(ADMIN *a, RPC_DISCONNECT_CONNECTION *t);
+UINT StGetConnectionInfo(ADMIN *a, RPC_CONNECTION_INFO *t);
+UINT StSetHubOnline(ADMIN *a, RPC_SET_HUB_ONLINE *t);
+UINT StGetHubStatus(ADMIN *a, RPC_HUB_STATUS *t);
+UINT StSetHubLog(ADMIN *a, RPC_HUB_LOG *t);
+UINT StGetHubLog(ADMIN *a, RPC_HUB_LOG *t);
+UINT StAddCa(ADMIN *a, RPC_HUB_ADD_CA *t);
+UINT StEnumCa(ADMIN *a, RPC_HUB_ENUM_CA *t);
+UINT StGetCa(ADMIN *a, RPC_HUB_GET_CA *t);
+UINT StDeleteCa(ADMIN *a, RPC_HUB_DELETE_CA *t);
+UINT StCreateLink(ADMIN *a, RPC_CREATE_LINK *t);
+UINT StEnumLink(ADMIN *a, RPC_ENUM_LINK *t);
+UINT StGetLinkStatus(ADMIN *a, RPC_LINK_STATUS *t);
+UINT StSetLinkOnline(ADMIN *a, RPC_LINK *t);
+UINT StSetLinkOffline(ADMIN *a, RPC_LINK *t);
+UINT StDeleteLink(ADMIN *a, RPC_LINK *t);
+UINT StRenameLink(ADMIN *a, RPC_RENAME_LINK *t);
+UINT StAddAccess(ADMIN *a, RPC_ADD_ACCESS *t);
+UINT StDeleteAccess(ADMIN *a, RPC_DELETE_ACCESS *t);
+UINT StEnumAccess(ADMIN *a, RPC_ENUM_ACCESS_LIST *t);
+UINT StCreateUser(ADMIN *a, RPC_SET_USER *t);
+UINT StSetUser(ADMIN *a, RPC_SET_USER *t);
+UINT StGetUser(ADMIN *a, RPC_SET_USER *t);
+UINT StDeleteUser(ADMIN *a, RPC_DELETE_USER *t);
+UINT StEnumUser(ADMIN *a, RPC_ENUM_USER *t);
+UINT StCreateGroup(ADMIN *a, RPC_SET_GROUP *t);
+UINT StSetGroup(ADMIN *a, RPC_SET_GROUP *t);
+UINT StGetGroup(ADMIN *a, RPC_SET_GROUP *t);
+UINT StDeleteGroup(ADMIN *a, RPC_DELETE_USER *t);
+UINT StEnumGroup(ADMIN *a, RPC_ENUM_GROUP *t);
+UINT StEnumSession(ADMIN *a, RPC_ENUM_SESSION *t);
+UINT StGetSessionStatus(ADMIN *a, RPC_SESSION_STATUS *t);
+UINT StDeleteSession(ADMIN *a, RPC_DELETE_SESSION *t);
+UINT StEnumMacTable(ADMIN *a, RPC_ENUM_MAC_TABLE *t);
+UINT StDeleteMacTable(ADMIN *a, RPC_DELETE_TABLE *t);
+UINT StEnumIpTable(ADMIN *a, RPC_ENUM_IP_TABLE *t);
+UINT StDeleteIpTable(ADMIN *a, RPC_DELETE_TABLE *t);
+UINT StGetLink(ADMIN *a, RPC_CREATE_LINK *t);
+UINT StSetLink(ADMIN *a, RPC_CREATE_LINK *t);
+UINT StSetAccessList(ADMIN *a, RPC_ENUM_ACCESS_LIST *t);
+UINT StSetKeep(ADMIN *a, RPC_KEEP *t);
+UINT StGetKeep(ADMIN *a, RPC_KEEP *t);
+UINT StEnableSecureNAT(ADMIN *a, RPC_HUB *t);
+UINT StDisableSecureNAT(ADMIN *a, RPC_HUB *t);
+UINT StSetSecureNATOption(ADMIN *a, VH_OPTION *t);
+UINT StGetSecureNATOption(ADMIN *a, VH_OPTION *t);
+UINT StEnumNAT(ADMIN *a, RPC_ENUM_NAT *t);
+UINT StEnumDHCP(ADMIN *a, RPC_ENUM_DHCP *t);
+UINT StGetSecureNATStatus(ADMIN *a, RPC_NAT_STATUS *t);
+UINT StEnumEthernet(ADMIN *a, RPC_ENUM_ETH *t);
+UINT StAddLocalBridge(ADMIN *a, RPC_LOCALBRIDGE *t);
+UINT StDeleteLocalBridge(ADMIN *a, RPC_LOCALBRIDGE *t);
+UINT StEnumLocalBridge(ADMIN *a, RPC_ENUM_LOCALBRIDGE *t);
+UINT StGetBridgeSupport(ADMIN *a, RPC_BRIDGE_SUPPORT *t);
+UINT StRebootServer(ADMIN *a, RPC_TEST *t);
+UINT StGetCaps(ADMIN *a, CAPSLIST *t);
+UINT StGetConfig(ADMIN *a, RPC_CONFIG *t);
+UINT StSetConfig(ADMIN *a, RPC_CONFIG *t);
+UINT StGetDefaultHubAdminOptions(ADMIN *a, RPC_ADMIN_OPTION *t);
+UINT StGetHubAdminOptions(ADMIN *a, RPC_ADMIN_OPTION *t);
+UINT StSetHubAdminOptions(ADMIN *a, RPC_ADMIN_OPTION *t);
+UINT StGetHubExtOptions(ADMIN *a, RPC_ADMIN_OPTION *t);
+UINT StSetHubExtOptions(ADMIN *a, RPC_ADMIN_OPTION *t);
+UINT StAddL3Switch(ADMIN *a, RPC_L3SW *t);
+UINT StDelL3Switch(ADMIN *a, RPC_L3SW *t);
+UINT StEnumL3Switch(ADMIN *a, RPC_ENUM_L3SW *t);
+UINT StStartL3Switch(ADMIN *a, RPC_L3SW *t);
+UINT StStopL3Switch(ADMIN *a, RPC_L3SW *t);
+UINT StAddL3If(ADMIN *a, RPC_L3IF *t);
+UINT StDelL3If(ADMIN *a, RPC_L3IF *t);
+UINT StEnumL3If(ADMIN *a, RPC_ENUM_L3IF *t);
+UINT StAddL3Table(ADMIN *a, RPC_L3TABLE *t);
+UINT StDelL3Table(ADMIN *a, RPC_L3TABLE *t);
+UINT StEnumL3Table(ADMIN *a, RPC_ENUM_L3TABLE *t);
+UINT StEnumCrl(ADMIN *a, RPC_ENUM_CRL *t);
+UINT StAddCrl(ADMIN *a, RPC_CRL *t);
+UINT StDelCrl(ADMIN *a, RPC_CRL *t);
+UINT StGetCrl(ADMIN *a, RPC_CRL *t);
+UINT StSetCrl(ADMIN *a, RPC_CRL *t);
+UINT StSetAcList(ADMIN *a, RPC_AC_LIST *t);
+UINT StGetAcList(ADMIN *a, RPC_AC_LIST *t);
+UINT StEnumLogFile(ADMIN *a, RPC_ENUM_LOG_FILE *t);
+UINT StReadLogFile(ADMIN *a, RPC_READ_LOG_FILE *t);
+UINT StAddLicenseKey(ADMIN *a, RPC_TEST *t);
+UINT StDelLicenseKey(ADMIN *a, RPC_TEST *t);
+UINT StEnumLicenseKey(ADMIN *a, RPC_ENUM_LICENSE_KEY *t);
+UINT StGetLicenseStatus(ADMIN *a, RPC_LICENSE_STATUS *t);
+UINT StSetSysLog(ADMIN *a, SYSLOG_SETTING *t);
+UINT StGetSysLog(ADMIN *a, SYSLOG_SETTING *t);
+UINT StEnumEthVLan(ADMIN *a, RPC_ENUM_ETH_VLAN *t);
+UINT StSetEnableEthVLan(ADMIN *a, RPC_TEST *t);
+UINT StSetHubMsg(ADMIN *a, RPC_MSG *t);
+UINT StGetHubMsg(ADMIN *a, RPC_MSG *t);
+UINT StCrash(ADMIN *a, RPC_TEST *t);
+UINT StGetAdminMsg(ADMIN *a, RPC_MSG *t);
+UINT StFlush(ADMIN *a, RPC_TEST *t);
+UINT StDebug(ADMIN *a, RPC_TEST *t);
+UINT StSetIPsecServices(ADMIN *a, IPSEC_SERVICES *t);
+UINT StGetIPsecServices(ADMIN *a, IPSEC_SERVICES *t);
+UINT StAddEtherIpId(ADMIN *a, ETHERIP_ID *t);
+UINT StGetEtherIpId(ADMIN *a, ETHERIP_ID *t);
+UINT StDeleteEtherIpId(ADMIN *a, ETHERIP_ID *t);
+UINT StEnumEtherIpId(ADMIN *a, RPC_ENUM_ETHERIP_ID *t);
+UINT StSetOpenVpnSstpConfig(ADMIN *a, OPENVPN_SSTP_CONFIG *t);
+UINT StGetOpenVpnSstpConfig(ADMIN *a, OPENVPN_SSTP_CONFIG *t);
+UINT StGetDDnsClientStatus(ADMIN *a, DDNS_CLIENT_STATUS *t);
+UINT StChangeDDnsClientHostname(ADMIN *a, RPC_TEST *t);
+UINT StRegenerateServerCert(ADMIN *a, RPC_TEST *t);
+UINT StMakeOpenVpnConfigFile(ADMIN *a, RPC_READ_LOG_FILE *t);
+UINT StSetSpecialListener(ADMIN *a, RPC_SPECIAL_LISTENER *t);
+UINT StGetSpecialListener(ADMIN *a, RPC_SPECIAL_LISTENER *t);
+UINT StGetAzureStatus(ADMIN *a, RPC_AZURE_STATUS *t);
+UINT StSetAzureStatus(ADMIN *a, RPC_AZURE_STATUS *t);
+UINT StGetDDnsInternetSetting(ADMIN *a, INTERNET_SETTING *t);
+UINT StSetDDnsInternetSetting(ADMIN *a, INTERNET_SETTING *t);
+UINT StSetVgsConfig(ADMIN *a, VGS_CONFIG *t);
+UINT StGetVgsConfig(ADMIN *a, VGS_CONFIG *t);
+
+UINT ScTest(RPC *r, RPC_TEST *t);
+UINT ScGetServerInfo(RPC *r, RPC_SERVER_INFO *t);
+UINT ScGetServerStatus(RPC *r, RPC_SERVER_STATUS *t);
+UINT ScCreateListener(RPC *r, RPC_LISTENER *t);
+UINT ScEnumListener(RPC *r, RPC_LISTENER_LIST *t);
+UINT ScDeleteListener(RPC *r, RPC_LISTENER *t);
+UINT ScEnableListener(RPC *r, RPC_LISTENER *t);
+UINT ScSetServerPassword(RPC *r, RPC_SET_PASSWORD *t);
+UINT ScSetFarmSetting(RPC *r, RPC_FARM *t);
+UINT ScGetFarmSetting(RPC *r, RPC_FARM *t);
+UINT ScGetFarmInfo(RPC *r, RPC_FARM_INFO *t);
+UINT ScEnumFarmMember(RPC *r, RPC_ENUM_FARM *t);
+UINT ScGetFarmConnectionStatus(RPC *r, RPC_FARM_CONNECTION_STATUS *t);
+UINT ScSetServerCert(RPC *r, RPC_KEY_PAIR *t);
+UINT ScGetServerCert(RPC *r, RPC_KEY_PAIR *t);
+UINT ScGetServerCipher(RPC *r, RPC_STR *t);
+UINT ScSetServerCipher(RPC *r, RPC_STR *t);
+UINT ScCreateHub(RPC *r, RPC_CREATE_HUB *t);
+UINT ScSetHub(RPC *r, RPC_CREATE_HUB *t);
+UINT ScGetHub(RPC *r, RPC_CREATE_HUB *t);
+UINT ScEnumHub(RPC *r, RPC_ENUM_HUB *t);
+UINT ScDeleteHub(RPC *r, RPC_DELETE_HUB *t);
+UINT ScGetHubRadius(RPC *r, RPC_RADIUS *t);
+UINT ScSetHubRadius(RPC *r, RPC_RADIUS *t);
+UINT ScEnumConnection(RPC *r, RPC_ENUM_CONNECTION *t);
+UINT ScDisconnectConnection(RPC *r, RPC_DISCONNECT_CONNECTION *t);
+UINT ScGetConnectionInfo(RPC *r, RPC_CONNECTION_INFO *t);
+UINT ScSetHubOnline(RPC *r, RPC_SET_HUB_ONLINE *t);
+UINT ScGetHubStatus(RPC *r, RPC_HUB_STATUS *t);
+UINT ScSetHubLog(RPC *r, RPC_HUB_LOG *t);
+UINT ScGetHubLog(RPC *r, RPC_HUB_LOG *t);
+UINT ScAddCa(RPC *r, RPC_HUB_ADD_CA *t);
+UINT ScEnumCa(RPC *r, RPC_HUB_ENUM_CA *t);
+UINT ScGetCa(RPC *r, RPC_HUB_GET_CA *t);
+UINT ScDeleteCa(RPC *r, RPC_HUB_DELETE_CA *t);
+UINT ScCreateLink(RPC *r, RPC_CREATE_LINK *t);
+UINT ScEnumLink(RPC *r, RPC_ENUM_LINK *t);
+UINT ScGetLinkStatus(RPC *r, RPC_LINK_STATUS *t);
+UINT ScSetLinkOnline(RPC *r, RPC_LINK *t);
+UINT ScSetLinkOffline(RPC *r, RPC_LINK *t);
+UINT ScDeleteLink(RPC *r, RPC_LINK *t);
+UINT ScRenameLink(RPC *r, RPC_RENAME_LINK *t);
+UINT ScAddAccess(RPC *r, RPC_ADD_ACCESS *t);
+UINT ScDeleteAccess(RPC *r, RPC_DELETE_ACCESS *t);
+UINT ScEnumAccess(RPC *r, RPC_ENUM_ACCESS_LIST *t);
+UINT ScCreateUser(RPC *r, RPC_SET_USER *t);
+UINT ScSetUser(RPC *r, RPC_SET_USER *t);
+UINT ScGetUser(RPC *r, RPC_SET_USER *t);
+UINT ScDeleteUser(RPC *r, RPC_DELETE_USER *t);
+UINT ScEnumUser(RPC *r, RPC_ENUM_USER *t);
+UINT ScCreateGroup(RPC *r, RPC_SET_GROUP *t);
+UINT ScSetGroup(RPC *r, RPC_SET_GROUP *t);
+UINT ScGetGroup(RPC *r, RPC_SET_GROUP *t);
+UINT ScDeleteGroup(RPC *r, RPC_DELETE_USER *t);
+UINT ScEnumGroup(RPC *r, RPC_ENUM_GROUP *t);
+UINT ScEnumSession(RPC *r, RPC_ENUM_SESSION *t);
+UINT ScGetSessionStatus(RPC *r, RPC_SESSION_STATUS *t);
+UINT ScDeleteSession(RPC *r, RPC_DELETE_SESSION *t);
+UINT ScEnumMacTable(RPC *r, RPC_ENUM_MAC_TABLE *t);
+UINT ScDeleteMacTable(RPC *r, RPC_DELETE_TABLE *t);
+UINT ScEnumIpTable(RPC *r, RPC_ENUM_IP_TABLE *t);
+UINT ScDeleteIpTable(RPC *r, RPC_DELETE_TABLE *t);
+UINT ScGetLink(RPC *a, RPC_CREATE_LINK *t);
+UINT ScSetLink(RPC *a, RPC_CREATE_LINK *t);
+UINT ScSetAccessList(RPC *r, RPC_ENUM_ACCESS_LIST *t);
+UINT ScSetKeep(RPC *r, RPC_KEEP *t);
+UINT ScGetKeep(RPC *r, RPC_KEEP *t);
+UINT ScEnableSecureNAT(RPC *r, RPC_HUB *t);
+UINT ScDisableSecureNAT(RPC *r, RPC_HUB *t);
+UINT ScSetSecureNATOption(RPC *r, VH_OPTION *t);
+UINT ScGetSecureNATOption(RPC *r, VH_OPTION *t);
+UINT ScEnumNAT(RPC *r, RPC_ENUM_NAT *t);
+UINT ScEnumDHCP(RPC *r, RPC_ENUM_DHCP *t);
+UINT ScGetSecureNATStatus(RPC *r, RPC_NAT_STATUS *t);
+UINT ScEnumEthernet(RPC *r, RPC_ENUM_ETH *t);
+UINT ScAddLocalBridge(RPC *r, RPC_LOCALBRIDGE *t);
+UINT ScDeleteLocalBridge(RPC *r, RPC_LOCALBRIDGE *t);
+UINT ScEnumLocalBridge(RPC *r, RPC_ENUM_LOCALBRIDGE *t);
+UINT ScGetBridgeSupport(RPC *r, RPC_BRIDGE_SUPPORT *t);
+UINT ScRebootServer(RPC *r, RPC_TEST *t);
+UINT ScGetCaps(RPC *r, CAPSLIST *t);
+UINT ScGetConfig(RPC *r, RPC_CONFIG *t);
+UINT ScSetConfig(RPC *r, RPC_CONFIG *t);
+UINT ScGetDefaultHubAdminOptions(RPC *r, RPC_ADMIN_OPTION *t);
+UINT ScGetHubAdminOptions(RPC *r, RPC_ADMIN_OPTION *t);
+UINT ScSetHubAdminOptions(RPC *r, RPC_ADMIN_OPTION *t);
+UINT ScGetHubExtOptions(RPC *r, RPC_ADMIN_OPTION *t);
+UINT ScSetHubExtOptions(RPC *r, RPC_ADMIN_OPTION *t);
+UINT ScAddL3Switch(RPC *r, RPC_L3SW *t);
+UINT ScDelL3Switch(RPC *r, RPC_L3SW *t);
+UINT ScEnumL3Switch(RPC *r, RPC_ENUM_L3SW *t);
+UINT ScStartL3Switch(RPC *r, RPC_L3SW *t);
+UINT ScStopL3Switch(RPC *r, RPC_L3SW *t);
+UINT ScAddL3If(RPC *r, RPC_L3IF *t);
+UINT ScDelL3If(RPC *r, RPC_L3IF *t);
+UINT ScEnumL3If(RPC *r, RPC_ENUM_L3IF *t);
+UINT ScAddL3Table(RPC *r, RPC_L3TABLE *t);
+UINT ScDelL3Table(RPC *r, RPC_L3TABLE *t);
+UINT ScEnumL3Table(RPC *r, RPC_ENUM_L3TABLE *t);
+UINT ScEnumCrl(RPC *r, RPC_ENUM_CRL *t);
+UINT ScAddCrl(RPC *r, RPC_CRL *t);
+UINT ScDelCrl(RPC *r, RPC_CRL *t);
+UINT ScGetCrl(RPC *r, RPC_CRL *t);
+UINT ScSetCrl(RPC *r, RPC_CRL *t);
+UINT ScSetAcList(RPC *r, RPC_AC_LIST *t);
+UINT ScGetAcList(RPC *r, RPC_AC_LIST *t);
+UINT ScEnumLogFile(RPC *r, RPC_ENUM_LOG_FILE *t);
+UINT ScReadLogFile(RPC *r, RPC_READ_LOG_FILE *t);
+UINT ScAddLicenseKey(RPC *r, RPC_TEST *t);
+UINT ScDelLicenseKey(RPC *r, RPC_TEST *t);
+UINT ScEnumLicenseKey(RPC *r, RPC_ENUM_LICENSE_KEY *t);
+UINT ScGetLicenseStatus(RPC *r, RPC_LICENSE_STATUS *t);
+UINT ScSetSysLog(RPC *r, SYSLOG_SETTING *t);
+UINT ScGetSysLog(RPC *r, SYSLOG_SETTING *t);
+UINT ScEnumEthVLan(RPC *r, RPC_ENUM_ETH_VLAN *t);
+UINT ScSetEnableEthVLan(RPC *r, RPC_TEST *t);
+UINT ScSetHubMsg(RPC *r, RPC_MSG *t);
+UINT ScGetHubMsg(RPC *r, RPC_MSG *t);
+UINT ScCrash(RPC *r, RPC_TEST *t);
+UINT ScGetAdminMsg(RPC *r, RPC_MSG *t);
+UINT ScFlush(RPC *r, RPC_TEST *t);
+UINT ScDebug(RPC *r, RPC_TEST *t);
+UINT ScSetIPsecServices(RPC *r, IPSEC_SERVICES *t);
+UINT ScGetIPsecServices(RPC *r, IPSEC_SERVICES *t);
+UINT ScAddEtherIpId(RPC *r, ETHERIP_ID *t);
+UINT ScGetEtherIpId(RPC *r, ETHERIP_ID *t);
+UINT ScDeleteEtherIpId(RPC *r, ETHERIP_ID *t);
+UINT ScEnumEtherIpId(RPC *r, RPC_ENUM_ETHERIP_ID *t);
+UINT ScSetOpenVpnSstpConfig(RPC *r, OPENVPN_SSTP_CONFIG *t);
+UINT ScGetOpenVpnSstpConfig(RPC *r, OPENVPN_SSTP_CONFIG *t);
+UINT ScGetDDnsClientStatus(RPC *r, DDNS_CLIENT_STATUS *t);
+UINT ScChangeDDnsClientHostname(RPC *r, RPC_TEST *t);
+UINT ScRegenerateServerCert(RPC *r, RPC_TEST *t);
+UINT ScMakeOpenVpnConfigFile(RPC *r, RPC_READ_LOG_FILE *t);
+UINT ScSetSpecialListener(RPC *r, RPC_SPECIAL_LISTENER *t);
+UINT ScGetSpecialListener(RPC *r, RPC_SPECIAL_LISTENER *t);
+UINT ScGetAzureStatus(RPC *r, RPC_AZURE_STATUS *t);
+UINT ScSetAzureStatus(RPC *r, RPC_AZURE_STATUS *t);
+UINT ScGetDDnsInternetSetting(RPC *r, INTERNET_SETTING *t);
+UINT ScSetDDnsInternetSetting(RPC *r, INTERNET_SETTING *t);
+UINT ScSetVgsConfig(RPC *r, VGS_CONFIG *t);
+UINT ScGetVgsConfig(RPC *r, VGS_CONFIG *t);
+
+void InRpcTest(RPC_TEST *t, PACK *p);
+void OutRpcTest(PACK *p, RPC_TEST *t);
+void FreeRpcTest(RPC_TEST *t);
+void InRpcServerInfo(RPC_SERVER_INFO *t, PACK *p);
+void OutRpcServerInfo(PACK *p, RPC_SERVER_INFO *t);
+void FreeRpcServerInfo(RPC_SERVER_INFO *t);
+void InRpcServerStatus(RPC_SERVER_STATUS *t, PACK *p);
+void OutRpcServerStatus(PACK *p, RPC_SERVER_STATUS *t);
+void InRpcListener(RPC_LISTENER *t, PACK *p);
+void OutRpcListener(PACK *p, RPC_LISTENER *t);
+void InRpcListenerList(RPC_LISTENER_LIST *t, PACK *p);
+void OutRpcListenerList(PACK *p, RPC_LISTENER_LIST *t);
+void FreeRpcListenerList(RPC_LISTENER_LIST *t);
+void InRpcStr(RPC_STR *t, PACK *p);
+void OutRpcStr(PACK *p, RPC_STR *t);
+void FreeRpcStr(RPC_STR *t);
+void InRpcSetPassword(RPC_SET_PASSWORD *t, PACK *p);
+void OutRpcSetPassword(PACK *p, RPC_SET_PASSWORD *t);
+void InRpcFarm(RPC_FARM *t, PACK *p);
+void OutRpcFarm(PACK *p, RPC_FARM *t);
+void FreeRpcFarm(RPC_FARM *t);
+void InRpcFarmHub(RPC_FARM_HUB *t, PACK *p);
+void OutRpcFarmHub(PACK *p, RPC_FARM_HUB *t);
+void InRpcFarmInfo(RPC_FARM_INFO *t, PACK *p);
+void OutRpcFarmInfo(PACK *p, RPC_FARM_INFO *t);
+void FreeRpcFarmInfo(RPC_FARM_INFO *t);
+void InRpcEnumFarm(RPC_ENUM_FARM *t, PACK *p);
+void OutRpcEnumFarm(PACK *p, RPC_ENUM_FARM *t);
+void FreeRpcEnumFarm(RPC_ENUM_FARM *t);
+void InRpcFarmConnectionStatus(RPC_FARM_CONNECTION_STATUS *t, PACK *p);
+void OutRpcFarmConnectionStatus(PACK *p, RPC_FARM_CONNECTION_STATUS *t);
+void InRpcHubOption(RPC_HUB_OPTION *t, PACK *p);
+void OutRpcHubOption(PACK *p, RPC_HUB_OPTION *t);
+void InRpcRadius(RPC_RADIUS *t, PACK *p);
+void OutRpcRadius(PACK *p, RPC_RADIUS *t);
+void InRpcHub(RPC_HUB *t, PACK *p);
+void OutRpcHub(PACK *p, RPC_HUB *t);
+void InRpcCreateHub(RPC_CREATE_HUB *t, PACK *p);
+void OutRpcCreateHub(PACK *p, RPC_CREATE_HUB *t);
+void InRpcEnumHub(RPC_ENUM_HUB *t, PACK *p);
+void OutRpcEnumHub(PACK *p, RPC_ENUM_HUB *t);
+void FreeRpcEnumHub(RPC_ENUM_HUB *t);
+void InRpcDeleteHub(RPC_DELETE_HUB *t, PACK *p);
+void OutRpcDeleteHub(PACK *p, RPC_DELETE_HUB *t);
+void InRpcEnumConnection(RPC_ENUM_CONNECTION *t, PACK *p);
+void OutRpcEnumConnection(PACK *p, RPC_ENUM_CONNECTION *t);
+void FreeRpcEnumConnetion(RPC_ENUM_CONNECTION *t);
+void InRpcDisconnectConnection(RPC_DISCONNECT_CONNECTION *t, PACK *p);
+void OutRpcDisconnectConnection(PACK *p, RPC_DISCONNECT_CONNECTION *t);
+void InRpcConnectionInfo(RPC_CONNECTION_INFO *t, PACK *p);
+void OutRpcConnectionInfo(PACK *p, RPC_CONNECTION_INFO *t);
+void InRpcSetHubOnline(RPC_SET_HUB_ONLINE *t, PACK *p);
+void OutRpcSetHubOnline(PACK *p, RPC_SET_HUB_ONLINE *t);
+void InRpcHubStatus(RPC_HUB_STATUS *t, PACK *p);
+void OutRpcHubStatus(PACK *p, RPC_HUB_STATUS *t);
+void InRpcHubLog(RPC_HUB_LOG *t, PACK *p);
+void OutRpcHubLog(PACK *p, RPC_HUB_LOG *t);
+void InRpcHubAddCa(RPC_HUB_ADD_CA *t, PACK *p);
+void OutRpcHubAddCa(PACK *p, RPC_HUB_ADD_CA *t);
+void FreeRpcHubAddCa(RPC_HUB_ADD_CA *t);
+void InRpcHubEnumCa(RPC_HUB_ENUM_CA *t, PACK *p);
+void OutRpcHubEnumCa(PACK *p, RPC_HUB_ENUM_CA *t);
+void FreeRpcHubEnumCa(RPC_HUB_ENUM_CA *t);
+void InRpcHubGetCa(RPC_HUB_GET_CA *t, PACK *p);
+void OutRpcHubGetCa(PACK *p, RPC_HUB_GET_CA *t);
+void FreeRpcHubGetCa(RPC_HUB_GET_CA *t);
+void InRpcHubDeleteCa(RPC_HUB_DELETE_CA *t, PACK *p);
+void OutRpcHubDeleteCa(PACK *p, RPC_HUB_DELETE_CA *t);
+void InRpcCreateLink(RPC_CREATE_LINK *t, PACK *p);
+void OutRpcCreateLink(PACK *p, RPC_CREATE_LINK *t);
+void FreeRpcCreateLink(RPC_CREATE_LINK *t);
+void InRpcEnumLink(RPC_ENUM_LINK *t, PACK *p);
+void OutRpcEnumLink(PACK *p, RPC_ENUM_LINK *t);
+void FreeRpcEnumLink(RPC_ENUM_LINK *t);
+void InRpcLinkStatus(RPC_LINK_STATUS *t, PACK *p);
+void OutRpcLinkStatus(PACK *p, RPC_LINK_STATUS *t);
+void FreeRpcLinkStatus(RPC_LINK_STATUS *t);
+void InRpcLink(RPC_LINK *t, PACK *p);
+void OutRpcLink(PACK *p, RPC_LINK *t);
+void InRpcAccessEx(ACCESS *a, PACK *p, UINT index);
+void InRpcAccess(ACCESS *a, PACK *p);
+void OutRpcAccessEx(PACK *p, ACCESS *a, UINT index, UINT total);
+void OutRpcAccess(PACK *p, ACCESS *a);
+void InRpcEnumAccessList(RPC_ENUM_ACCESS_LIST *a, PACK *p);
+void OutRpcEnumAccessList(PACK *p, RPC_ENUM_ACCESS_LIST *a);
+void FreeRpcEnumAccessList(RPC_ENUM_ACCESS_LIST *a);
+void *InRpcAuthData(PACK *p, UINT *authtype);
+void OutRpcAuthData(PACK *p, void *authdata, UINT authtype);
+void FreeRpcAuthData(void *authdata, UINT authtype);
+void InRpcSetUser(RPC_SET_USER *t, PACK *p);
+void OutRpcSetUser(PACK *p, RPC_SET_USER *t);
+void FreeRpcSetUser(RPC_SET_USER *t);
+void InRpcEnumUser(RPC_ENUM_USER *t, PACK *p);
+void OutRpcEnumUser(PACK *p, RPC_ENUM_USER *t);
+void FreeRpcEnumUser(RPC_ENUM_USER *t);
+void InRpcSetGroup(RPC_SET_GROUP *t, PACK *p);
+void OutRpcSetGroup(PACK *p, RPC_SET_GROUP *t);
+void InRpcEnumGroup(RPC_ENUM_GROUP *t, PACK *p);
+void OutRpcEnumGroup(PACK *p, RPC_ENUM_GROUP *t);
+void FreeRpcEnumGroup(RPC_ENUM_GROUP *t);
+void InRpcDeleteUser(RPC_DELETE_USER *t, PACK *p);
+void OutRpcDeleteUser(PACK *p, RPC_DELETE_USER *t);
+void InRpcEnumSession(RPC_ENUM_SESSION *t, PACK *p);
+void OutRpcEnumSession(PACK *p, RPC_ENUM_SESSION *t);
+void FreeRpcEnumSession(RPC_ENUM_SESSION *t);
+void InRpcNodeInfo(NODE_INFO *t, PACK *p);
+void OutRpcNodeInfo(PACK *p, NODE_INFO *t);
+void InRpcSessionStatus(RPC_SESSION_STATUS *t, PACK *p);
+void OutRpcSessionStatus(PACK *p, RPC_SESSION_STATUS *t);
+void FreeRpcSessionStatus(RPC_SESSION_STATUS *t);
+void InRpcDeleteSession(RPC_DELETE_SESSION *t, PACK *p);
+void OutRpcDeleteSession(PACK *p, RPC_DELETE_SESSION *t);
+void InRpcEnumMacTable(RPC_ENUM_MAC_TABLE *t, PACK *p);
+void OutRpcEnumMacTable(PACK *p, RPC_ENUM_MAC_TABLE *t);
+void FreeRpcEnumMacTable(RPC_ENUM_MAC_TABLE *t);
+void InRpcEnumIpTable(RPC_ENUM_IP_TABLE *t, PACK *p);
+void OutRpcEnumIpTable(PACK *p, RPC_ENUM_IP_TABLE *t);
+void FreeRpcEnumIpTable(RPC_ENUM_IP_TABLE *t);
+void InRpcDeleteTable(RPC_DELETE_TABLE *t, PACK *p);
+void OutRpcDeleteTable(PACK *p, RPC_DELETE_TABLE *t);
+void InRpcMemInfo(MEMINFO *t, PACK *p);
+void OutRpcMemInfo(PACK *p, MEMINFO *t);
+void InRpcKeyPair(RPC_KEY_PAIR *t, PACK *p);
+void OutRpcKeyPair(PACK *p, RPC_KEY_PAIR *t);
+void FreeRpcKeyPair(RPC_KEY_PAIR *t);
+void InRpcAddAccess(RPC_ADD_ACCESS *t, PACK *p);
+void OutRpcAddAccess(PACK *p, RPC_ADD_ACCESS *t);
+void InRpcDeleteAccess(RPC_DELETE_ACCESS *t, PACK *p);
+void OutRpcDeleteAccess(PACK *p, RPC_DELETE_ACCESS *t);
+void FreeRpcSetGroup(RPC_SET_GROUP *t);
+void AdjoinRpcEnumSession(RPC_ENUM_SESSION *dest, RPC_ENUM_SESSION *src);
+void AdjoinRpcEnumMacTable(RPC_ENUM_MAC_TABLE *dest, RPC_ENUM_MAC_TABLE *src);
+void AdjoinRpcEnumIpTable(RPC_ENUM_IP_TABLE *dest, RPC_ENUM_IP_TABLE *src);
+void InRpcKeep(RPC_KEEP *t, PACK *p);
+void OutRpcKeep(PACK *p, RPC_KEEP *t);
+void InRpcOsInfo(OS_INFO *t, PACK *p);
+void OutRpcOsInfo(PACK *p, OS_INFO *t);
+void FreeRpcOsInfo(OS_INFO *t);
+void InRpcEnumEth(RPC_ENUM_ETH *t, PACK *p);
+void OutRpcEnumEth(PACK *p, RPC_ENUM_ETH *t);
+void FreeRpcEnumEth(RPC_ENUM_ETH *t);
+void InRpcLocalBridge(RPC_LOCALBRIDGE *t, PACK *p);
+void OutRpcLocalBridge(PACK *p, RPC_LOCALBRIDGE *t);
+void InRpcEnumLocalBridge(RPC_ENUM_LOCALBRIDGE *t, PACK *p);
+void OutRpcEnumLocalBridge(PACK *p, RPC_ENUM_LOCALBRIDGE *t);
+void FreeRpcEnumLocalBridge(RPC_ENUM_LOCALBRIDGE *t);
+void InRpcBridgeSupport(RPC_BRIDGE_SUPPORT *t, PACK *p);
+void OutRpcBridgeSupport(PACK *p, RPC_BRIDGE_SUPPORT *t);
+void InRpcConfig(RPC_CONFIG *t, PACK *p);
+void OutRpcConfig(PACK *p, RPC_CONFIG *t);
+void FreeRpcConfig(RPC_CONFIG *t);
+void InRpcAdminOption(RPC_ADMIN_OPTION *t, PACK *p);
+void OutRpcAdminOption(PACK *p, RPC_ADMIN_OPTION *t);
+void FreeRpcAdminOption(RPC_ADMIN_OPTION *t);
+void InRpcEnumL3Table(RPC_ENUM_L3TABLE *t, PACK *p);
+void OutRpcEnumL3Table(PACK *p, RPC_ENUM_L3TABLE *t);
+void FreeRpcEnumL3Table(RPC_ENUM_L3TABLE *t);
+void InRpcL3Table(RPC_L3TABLE *t, PACK *p);
+void OutRpcL3Table(PACK *p, RPC_L3TABLE *t);
+void InRpcEnumL3If(RPC_ENUM_L3IF *t, PACK *p);
+void OutRpcEnumL3If(PACK *p, RPC_ENUM_L3IF *t);
+void FreeRpcEnumL3If(RPC_ENUM_L3IF *t);
+void InRpcL3If(RPC_L3IF *t, PACK *p);
+void OutRpcL3If(PACK *p, RPC_L3IF *t);
+void InRpcL3Sw(RPC_L3SW *t, PACK *p);
+void OutRpcL3Sw(PACK *p, RPC_L3SW *t);
+void InRpcEnumL3Sw(RPC_ENUM_L3SW *t, PACK *p);
+void OutRpcEnumL3Sw(PACK *p, RPC_ENUM_L3SW *t);
+void FreeRpcEnumL3Sw(RPC_ENUM_L3SW *t);
+void InRpcCrl(RPC_CRL *t, PACK *p);
+void OutRpcCrl(PACK *p, RPC_CRL *t);
+void FreeRpcCrl(RPC_CRL *t);
+void InRpcEnumCrl(RPC_ENUM_CRL *t, PACK *p);
+void OutRpcEnumCrl(PACK *p, RPC_ENUM_CRL *t);
+void FreeRpcEnumCrl(RPC_ENUM_CRL *t);
+void InRpcInt(RPC_INT *t, PACK *p);
+void OutRpcInt(PACK *p, RPC_INT *t);
+void InRpcAcList(RPC_AC_LIST *t, PACK *p);
+void OutRpcAcList(PACK *p, RPC_AC_LIST *t);
+void FreeRpcAcList(RPC_AC_LIST *t);
+void InRpcEnumLogFile(RPC_ENUM_LOG_FILE *t, PACK *p);
+void OutRpcEnumLogFile(PACK *p, RPC_ENUM_LOG_FILE *t);
+void FreeRpcEnumLogFile(RPC_ENUM_LOG_FILE *t);
+void AdjoinRpcEnumLogFile(RPC_ENUM_LOG_FILE *t, RPC_ENUM_LOG_FILE *src);
+void InRpcReadLogFile(RPC_READ_LOG_FILE *t, PACK *p);
+void OutRpcReadLogFile(PACK *p, RPC_READ_LOG_FILE *t);
+void FreeRpcReadLogFile(RPC_READ_LOG_FILE *t);
+void InRpcRenameLink(RPC_RENAME_LINK *t, PACK *p);
+void OutRpcRenameLink(PACK *p, RPC_RENAME_LINK *t);
+void InRpcEnumLicenseKey(RPC_ENUM_LICENSE_KEY *t, PACK *p);
+void OutRpcEnumLicenseKey(PACK *p, RPC_ENUM_LICENSE_KEY *t);
+void FreeRpcEnumLicenseKey(RPC_ENUM_LICENSE_KEY *t);
+void InRpcLicenseStatus(RPC_LICENSE_STATUS *t, PACK *p);
+void OutRpcLicenseStatus(PACK *p, RPC_LICENSE_STATUS *t);
+void InRpcEnumEthVLan(RPC_ENUM_ETH_VLAN *t, PACK *p);
+void OutRpcEnumEthVLan(PACK *p, RPC_ENUM_ETH_VLAN *t);
+void FreeRpcEnumEthVLan(RPC_ENUM_ETH_VLAN *t);
+void InRpcMsg(RPC_MSG *t, PACK *p);
+void OutRpcMsg(PACK *p, RPC_MSG *t);
+void FreeRpcMsg(RPC_MSG *t);
+void InRpcWinVer(RPC_WINVER *t, PACK *p);
+void OutRpcWinVer(PACK *p, RPC_WINVER *t);
+void InIPsecServices(IPSEC_SERVICES *t, PACK *p);
+void OutIPsecServices(PACK *p, IPSEC_SERVICES *t);
+void InRpcEnumEtherIpId(RPC_ENUM_ETHERIP_ID *t, PACK *p);
+void OutRpcEnumEtherIpId(PACK *p, RPC_ENUM_ETHERIP_ID *t);
+void FreeRpcEnumEtherIpId(RPC_ENUM_ETHERIP_ID *t);
+void InEtherIpId(ETHERIP_ID *t, PACK *p);
+void OutEtherIpId(PACK *p, ETHERIP_ID *t);
+void InOpenVpnSstpConfig(OPENVPN_SSTP_CONFIG *t, PACK *p);
+void OutOpenVpnSstpConfig(PACK *p, OPENVPN_SSTP_CONFIG *t);
+void InDDnsClientStatus(DDNS_CLIENT_STATUS *t, PACK *p);
+void OutDDnsClientStatus(PACK *p, DDNS_CLIENT_STATUS *t);
+void InRpcSpecialListener(RPC_SPECIAL_LISTENER *t, PACK *p);
+void OutRpcSpecialListener(PACK *p, RPC_SPECIAL_LISTENER *t);
+void InRpcAzureStatus(RPC_AZURE_STATUS *t, PACK *p);
+void OutRpcAzureStatus(PACK *p, RPC_AZURE_STATUS *t);
+void InRpcInternetSetting(INTERNET_SETTING *t, PACK *p);
+void OutRpcInternetSetting(PACK *p, INTERNET_SETTING *t);
+
+#endif // ADMIN_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/AzureClient.c b/src/Cedar/AzureClient.c
new file mode 100644
index 00000000..7bf2e183
--- /dev/null
+++ b/src/Cedar/AzureClient.c
@@ -0,0 +1,658 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// AzureClient.c
+// VPN Azure Client
+
+#include "CedarPch.h"
+
+// Wait for connection request
+void AcWaitForRequest(AZURE_CLIENT *ac, SOCK *s, AZURE_PARAM *param)
+{
+ // Validate arguments
+ if (ac == NULL || s == NULL || param == NULL)
+ {
+ return;
+ }
+
+ while (ac->Halt == false)
+ {
+ UCHAR uc;
+
+ // Receive 1 byte
+ if (RecvAll(s, &uc, 1, false) == 0)
+ {
+ break;
+ }
+
+ if (uc != 0)
+ {
+ // Receive a Pack
+ PACK *p = RecvPackWithHash(s);
+
+ if (p == NULL)
+ {
+ break;
+ }
+ else
+ {
+ // Verify contents of Pack
+ char opcode[MAX_SIZE];
+ char cipher_name[MAX_SIZE];
+ char hostname[MAX_SIZE];
+
+ PackGetStr(p, "opcode", opcode, sizeof(opcode));
+ PackGetStr(p, "cipher_name", cipher_name, sizeof(cipher_name));
+ PackGetStr(p, "hostname", hostname, sizeof(hostname));
+
+ if (StrCmpi(opcode, "relay") == 0)
+ {
+ IP client_ip, server_ip;
+ UINT client_port;
+ UINT server_port;
+ UCHAR session_id[SHA1_SIZE];
+
+ if (PackGetIp(p, "client_ip", &client_ip) &&
+ PackGetIp(p, "server_ip", &server_ip) &&
+ PackGetData2(p, "session_id", session_id, sizeof(session_id)))
+ {
+ client_port = PackGetInt(p, "client_port");
+ server_port = PackGetInt(p, "server_port");
+
+ if (client_port != 0 && server_port != 0)
+ {
+ SOCK *ns;
+ Debug("Connect Request from %r:%u\n", &client_ip, client_port);
+
+ // Create new socket and connect VPN Azure Server
+ if (ac->DDnsStatusCopy.InternetSetting.ProxyType == PROXY_DIRECT)
+ {
+ ns = ConnectEx2(ac->DDnsStatusCopy.CurrentAzureIp, AZURE_SERVER_PORT,
+ 0, (bool *)&ac->Halt);
+ }
+ else
+ {
+ ns = WpcSockConnect2(ac->DDnsStatusCopy.CurrentAzureIp, AZURE_SERVER_PORT,
+ &ac->DDnsStatusCopy.InternetSetting, NULL, AZURE_VIA_PROXY_TIMEOUT);
+ }
+
+ if (ns == NULL)
+ {
+ Debug("Connect Error.\n");
+ }
+ else
+ {
+ Debug("Connected to the relay server.\n");
+
+ SetTimeout(ns, param->DataTimeout);
+
+ if (StartSSLEx(ns, NULL, NULL, true, 0, NULL))
+ {
+ // Check certification
+ char server_cert_hash_str[MAX_SIZE];
+ UCHAR server_cert_hash[SHA1_SIZE];
+
+ Zero(server_cert_hash, sizeof(server_cert_hash));
+ GetXDigest(ns->RemoteX, server_cert_hash, true);
+
+ BinToStr(server_cert_hash_str, sizeof(server_cert_hash_str),
+ server_cert_hash, SHA1_SIZE);
+
+ if (IsEmptyStr(ac->DDnsStatusCopy.AzureCertHash) || StrCmpi(server_cert_hash_str, ac->DDnsStatusCopy.AzureCertHash) == 0)
+ {
+ if (SendAll(ns, AZURE_PROTOCOL_DATA_SIANGTURE, 24, true))
+ {
+ PACK *p2 = NewPack();
+
+ PackAddStr(p2, "hostname", hostname);
+ PackAddData(p2, "session_id", session_id, sizeof(session_id));
+
+ if (SendPackWithHash(ns, p2))
+ {
+ UCHAR uc;
+
+ if (RecvAll(ns, &uc, 1, true) != false)
+ {
+ if (uc != 0)
+ {
+ SOCK *accept_sock = GetReverseListeningSock(ac->Cedar);
+
+ if (accept_sock != NULL)
+ {
+ AddRef(ns->ref);
+
+ SetTimeout(ns, INFINITE);
+
+ Copy(&ns->Reverse_MyServerGlobalIp, &server_ip, sizeof(IP));
+ ns->Reverse_MyServerPort = server_port;
+
+ InjectNewReverseSocketToAccept(accept_sock, ns,
+ &client_ip, client_port);
+
+ ReleaseSock(accept_sock);
+ }
+ }
+ }
+ }
+
+ FreePack(p2);
+ }
+ }
+ }
+
+ ReleaseSock(ns);
+ }
+ }
+ }
+ }
+
+ FreePack(p);
+ }
+ }
+
+ // Send 1 byte
+ uc = 0;
+ if (SendAll(s, &uc, 1, false) == 0)
+ {
+ break;
+ }
+ }
+}
+
+// VPN Azure client main thread
+void AcMainThread(THREAD *thread, void *param)
+{
+ AZURE_CLIENT *ac = (AZURE_CLIENT *)param;
+ UINT last_ip_revision = INFINITE;
+ UINT64 last_reconnect_tick = 0;
+ UINT64 next_reconnect_interval = AZURE_CONNECT_INITIAL_RETRY_INTERVAL;
+ UINT num_reconnect_retry = 0;
+ UINT64 next_ddns_retry_tick = 0;
+ bool last_connect_ok = false;
+ // Validate arguments
+ if (ac == NULL || thread == NULL)
+ {
+ return;
+ }
+
+ while (ac->Halt == false)
+ {
+ UINT64 now = Tick64();
+ bool connect_was_ok = false;
+ // Wait for enabling VPN Azure function
+ if (ac->IsEnabled)
+ {
+ // VPN Azure is enabled
+ DDNS_CLIENT_STATUS st;
+ bool connect_now = false;
+ bool azure_ip_changed = false;
+
+ Lock(ac->Lock);
+ {
+ Copy(&st, &ac->DDnsStatus, sizeof(DDNS_CLIENT_STATUS));
+
+ if (StrCmpi(st.CurrentAzureIp, ac->DDnsStatusCopy.CurrentAzureIp) != 0)
+ {
+ if (IsEmptyStr(st.CurrentAzureIp) == false)
+ {
+ // Destination IP address is changed
+ connect_now = true;
+ num_reconnect_retry = 0;
+ }
+ }
+
+ if (StrCmpi(st.CurrentHostName, ac->DDnsStatusCopy.CurrentHostName) != 0)
+ {
+ // DDNS host name is changed
+ connect_now = true;
+ num_reconnect_retry = 0;
+ }
+
+ Copy(&ac->DDnsStatusCopy, &st, sizeof(DDNS_CLIENT_STATUS));
+ }
+ Unlock(ac->Lock);
+
+ if (last_ip_revision != ac->IpStatusRevision)
+ {
+ last_ip_revision = ac->IpStatusRevision;
+
+ connect_now = true;
+
+ num_reconnect_retry = 0;
+ }
+
+ if (last_reconnect_tick == 0 || (now >= (last_reconnect_tick + next_reconnect_interval)))
+ {
+ UINT r;
+
+ last_reconnect_tick = now;
+ num_reconnect_retry++;
+ next_reconnect_interval = (UINT64)num_reconnect_retry * AZURE_CONNECT_INITIAL_RETRY_INTERVAL;
+ next_reconnect_interval = MIN(next_reconnect_interval, AZURE_CONNECT_MAX_RETRY_INTERVAL);
+
+ r = (UINT)next_reconnect_interval;
+
+ r = GenRandInterval(r / 2, r);
+
+ next_reconnect_interval = r;
+
+ connect_now = true;
+ }
+
+ if (IsEmptyStr(st.CurrentAzureIp) == false && IsEmptyStr(st.CurrentHostName) == false)
+ {
+ if (connect_now)
+ {
+ SOCK *s;
+ char *host = NULL;
+ UINT port = AZURE_SERVER_PORT;
+
+ Debug("VPN Azure: Connecting to %s...\n", st.CurrentAzureIp);
+
+ if (ParseHostPort(st.CurrentAzureIp, &host, &port, AZURE_SERVER_PORT))
+ {
+ if (st.InternetSetting.ProxyType == PROXY_DIRECT)
+ {
+ s = ConnectEx2(host, port, 0, (bool *)&ac->Halt);
+ }
+ else
+ {
+ s = WpcSockConnect2(host, port, &st.InternetSetting, NULL, AZURE_VIA_PROXY_TIMEOUT);
+ }
+
+ if (s != NULL)
+ {
+ PACK *p;
+ UINT64 established_tick = 0;
+
+ Debug("VPN Azure: Connected.\n");
+
+ SetTimeout(s, AZURE_PROTOCOL_CONTROL_TIMEOUT_DEFAULT);
+
+ Lock(ac->Lock);
+ {
+ ac->CurrentSock = s;
+ ac->IsConnected = true;
+ StrCpy(ac->ConnectingAzureIp, sizeof(ac->ConnectingAzureIp), st.CurrentAzureIp);
+ }
+ Unlock(ac->Lock);
+
+ SendAll(s, AZURE_PROTOCOL_CONTROL_SIGNATURE, StrLen(AZURE_PROTOCOL_CONTROL_SIGNATURE), false);
+
+ // Receive parameter
+ p = RecvPackWithHash(s);
+ if (p != NULL)
+ {
+ UCHAR c;
+ AZURE_PARAM param;
+ bool hostname_changed = false;
+
+ Zero(¶m, sizeof(param));
+
+ param.ControlKeepAlive = PackGetInt(p, "ControlKeepAlive");
+ param.ControlTimeout = PackGetInt(p, "ControlTimeout");
+ param.DataTimeout = PackGetInt(p, "DataTimeout");
+ param.SslTimeout = PackGetInt(p, "SslTimeout");
+
+ FreePack(p);
+
+ param.ControlKeepAlive = MAKESURE(param.ControlKeepAlive, 1000, AZURE_SERVER_MAX_KEEPALIVE);
+ param.ControlTimeout = MAKESURE(param.ControlTimeout, 1000, AZURE_SERVER_MAX_TIMEOUT);
+ param.DataTimeout = MAKESURE(param.DataTimeout, 1000, AZURE_SERVER_MAX_TIMEOUT);
+ param.SslTimeout = MAKESURE(param.SslTimeout, 1000, AZURE_SERVER_MAX_TIMEOUT);
+
+ Lock(ac->Lock);
+ {
+ Copy(&ac->AzureParam, ¶m, sizeof(AZURE_PARAM));
+ }
+ Unlock(ac->Lock);
+
+ SetTimeout(s, param.ControlTimeout);
+
+ // Send parameter
+ p = NewPack();
+ PackAddStr(p, "CurrentHostName", st.CurrentHostName);
+ PackAddStr(p, "CurrentAzureIp", st.CurrentAzureIp);
+ PackAddInt64(p, "CurrentAzureTimestamp", st.CurrentAzureTimestamp);
+ PackAddStr(p, "CurrentAzureSignature", st.CurrentAzureSignature);
+
+ Lock(ac->Lock);
+ {
+ if (StrCmpi(st.CurrentHostName, ac->DDnsStatus.CurrentHostName) != 0)
+ {
+ hostname_changed = true;
+ }
+ }
+ Unlock(ac->Lock);
+
+ if (hostname_changed == false)
+ {
+ if (SendPackWithHash(s, p))
+ {
+ // Receive result
+ if (RecvAll(s, &c, 1, false))
+ {
+ if (c && ac->Halt == false)
+ {
+ connect_was_ok = true;
+
+ established_tick = Tick64();
+
+ AcWaitForRequest(ac, s, ¶m);
+ }
+ }
+ }
+ }
+
+ FreePack(p);
+ }
+ else
+ {
+ WHERE;
+ }
+
+ Debug("VPN Azure: Disconnected.\n");
+
+ Lock(ac->Lock);
+ {
+ ac->IsConnected = false;
+ ac->CurrentSock = NULL;
+ ClearStr(ac->ConnectingAzureIp, sizeof(ac->ConnectingAzureIp));
+ }
+ Unlock(ac->Lock);
+
+ if (established_tick != 0)
+ {
+ if ((established_tick + (UINT64)AZURE_CONNECT_MAX_RETRY_INTERVAL) <= Tick64())
+ {
+ // If the connected time exceeds the AZURE_CONNECT_MAX_RETRY_INTERVAL, reset the retry counter.
+ last_reconnect_tick = 0;
+ num_reconnect_retry = 0;
+ next_reconnect_interval = AZURE_CONNECT_INITIAL_RETRY_INTERVAL;
+ }
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+ }
+ else
+ {
+ Debug("VPN Azure: Error: Connect Failed.\n");
+ }
+
+ Free(host);
+ }
+ }
+ }
+ }
+ else
+ {
+ last_reconnect_tick = 0;
+ num_reconnect_retry = 0;
+ next_reconnect_interval = AZURE_CONNECT_INITIAL_RETRY_INTERVAL;
+ }
+
+ if (ac->Halt)
+ {
+ break;
+ }
+
+ if (connect_was_ok)
+ {
+ // If connection goes out after connected, increment connection success count to urge DDNS client query
+ next_ddns_retry_tick = Tick64() + MIN((UINT64)DDNS_VPN_AZURE_CONNECT_ERROR_DDNS_RETRY_TIME_DIFF * (UINT64)(num_reconnect_retry + 1), (UINT64)DDNS_VPN_AZURE_CONNECT_ERROR_DDNS_RETRY_TIME_DIFF_MAX);
+ }
+
+ if ((next_ddns_retry_tick != 0) && (Tick64() >= next_ddns_retry_tick))
+ {
+ next_ddns_retry_tick = 0;
+
+ ac->DDnsTriggerInt++;
+ }
+
+ Wait(ac->Event, rand() % 1000);
+ }
+}
+
+// Get enabled or disabled VPN Azure client
+bool AcGetEnable(AZURE_CLIENT *ac)
+{
+ // Validate arguments
+ if (ac == NULL)
+ {
+ return false;
+ }
+
+ return ac->IsEnabled;
+}
+
+// Enable or disable VPN Azure client
+void AcSetEnable(AZURE_CLIENT *ac, bool enabled)
+{
+ bool old_status;
+ // Validate arguments
+ if (ac == NULL)
+ {
+ return;
+ }
+
+ old_status = ac->IsEnabled;
+
+ ac->IsEnabled = enabled;
+
+ if (ac->IsEnabled && (ac->IsEnabled != old_status))
+ {
+ ac->DDnsTriggerInt++;
+ }
+
+ AcApplyCurrentConfig(ac, NULL);
+}
+
+// Set current configuration to VPN Azure client
+void AcApplyCurrentConfig(AZURE_CLIENT *ac, DDNS_CLIENT_STATUS *ddns_status)
+{
+ bool disconnect_now = false;
+ SOCK *disconnect_sock = NULL;
+ // Validate arguments
+ if (ac == NULL)
+ {
+ return;
+ }
+
+ // Get current DDNS configuration
+ Lock(ac->Lock);
+ {
+ if (ddns_status != NULL)
+ {
+ if (StrCmpi(ac->DDnsStatus.CurrentHostName, ddns_status->CurrentHostName) != 0)
+ {
+ // If host name is changed, disconnect current data connection
+ disconnect_now = true;
+ }
+
+ if (Cmp(&ac->DDnsStatus.InternetSetting, &ddns_status->InternetSetting, sizeof(INTERNET_SETTING)) != 0)
+ {
+ // If proxy setting is changed, disconnect current data connection
+ disconnect_now = true;
+ }
+
+ Copy(&ac->DDnsStatus, ddns_status, sizeof(DDNS_CLIENT_STATUS));
+ }
+
+ if (ac->IsEnabled == false)
+ {
+ // If VPN Azure client is disabled, disconnect current data connection
+ disconnect_now = true;
+ }
+
+ if (disconnect_now)
+ {
+ if (ac->CurrentSock != NULL)
+ {
+ disconnect_sock = ac->CurrentSock;
+ AddRef(disconnect_sock->ref);
+ }
+ }
+ }
+ Unlock(ac->Lock);
+
+ if (disconnect_sock != NULL)
+ {
+ Disconnect(disconnect_sock);
+ ReleaseSock(disconnect_sock);
+ }
+
+ Set(ac->Event);
+}
+
+// Free VPN Azure client
+void FreeAzureClient(AZURE_CLIENT *ac)
+{
+ SOCK *disconnect_sock = NULL;
+ // Validate arguments
+ if (ac == NULL)
+ {
+ return;
+ }
+
+ ac->Halt = true;
+
+ Lock(ac->Lock);
+ {
+ if (ac->CurrentSock != NULL)
+ {
+ disconnect_sock = ac->CurrentSock;
+
+ AddRef(disconnect_sock->ref);
+ }
+ }
+ Unlock(ac->Lock);
+
+ if (disconnect_sock != NULL)
+ {
+ Disconnect(disconnect_sock);
+ ReleaseSock(disconnect_sock);
+ }
+
+ Set(ac->Event);
+
+ // Stop main thread
+ WaitThread(ac->MainThread, INFINITE);
+ ReleaseThread(ac->MainThread);
+
+ ReleaseEvent(ac->Event);
+
+ DeleteLock(ac->Lock);
+
+ Free(ac);
+}
+
+// Create new VPN Azure client
+AZURE_CLIENT *NewAzureClient(CEDAR *cedar, SERVER *server)
+{
+ AZURE_CLIENT *ac;
+ // Validate arguments
+ if (cedar == NULL || server == NULL)
+ {
+ return NULL;
+ }
+
+ ac = ZeroMalloc(sizeof(AZURE_CLIENT));
+
+ ac->Cedar = cedar;
+
+ ac->Server = server;
+
+ ac->Lock = NewLock();
+
+ ac->IsEnabled = false;
+
+ ac->Event = NewEvent();
+
+ // Start main thread
+ ac->MainThread = NewThread(AcMainThread, ac);
+
+ return ac;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/AzureClient.h b/src/Cedar/AzureClient.h
new file mode 100644
index 00000000..1a55a9ca
--- /dev/null
+++ b/src/Cedar/AzureClient.h
@@ -0,0 +1,149 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// AzureClient.h
+// Header of AzureClient.c
+
+#ifndef AZURE_CLIENT_H
+#define AZURE_CLIENT_H
+
+// Constants
+#define AZURE_SERVER_PORT 443
+#define AZURE_PROTOCOL_CONTROL_SIGNATURE "ACTL"
+#define AZURE_PROTOCOL_DATA_SIANGTURE "AZURE_CONNECT_SIGNATURE!"
+#define AZURE_PROTOCOL_CONTROL_TIMEOUT_DEFAULT (5 * 1000) // Default timeout
+#define AZURE_CONNECT_INITIAL_RETRY_INTERVAL (1 * 1000) // Initial re-connection interval (15 * 1000)
+#define AZURE_CONNECT_MAX_RETRY_INTERVAL (60 * 60 * 1000) // Maximum re-connection interval
+
+#define AZURE_DOMAIN_SUFFIX ".vpnazure.net"
+
+#define AZURE_SERVER_MAX_KEEPALIVE (5 * 60 * 1000)
+#define AZURE_SERVER_MAX_TIMEOUT (10 * 60 * 1000)
+
+#define AZURE_VIA_PROXY_TIMEOUT 5000
+
+
+// Communications parameter
+struct AZURE_PARAM
+{
+ UINT ControlKeepAlive;
+ UINT ControlTimeout;
+ UINT DataTimeout;
+ UINT SslTimeout;
+};
+
+// VPN Azure Client
+struct AZURE_CLIENT
+{
+ CEDAR *Cedar;
+ SERVER *Server;
+ LOCK *Lock;
+ DDNS_CLIENT_STATUS DDnsStatus;
+ volatile bool IsEnabled;
+ EVENT *Event;
+ volatile bool Halt;
+ THREAD *MainThread;
+ volatile UINT IpStatusRevision;
+ DDNS_CLIENT_STATUS DDnsStatusCopy;
+ SOCK *CurrentSock;
+ char ConnectingAzureIp[MAX_SIZE];
+ AZURE_PARAM AzureParam;
+ volatile UINT DDnsTriggerInt;
+ volatile bool IsConnected;
+};
+
+
+// Function prototype
+AZURE_CLIENT *NewAzureClient(CEDAR *cedar, SERVER *server);
+void FreeAzureClient(AZURE_CLIENT *ac);
+void AcApplyCurrentConfig(AZURE_CLIENT *ac, DDNS_CLIENT_STATUS *ddns_status);
+void AcMainThread(THREAD *thread, void *param);
+void AcSetEnable(AZURE_CLIENT *ac, bool enabled);
+bool AcGetEnable(AZURE_CLIENT *ac);
+void AcWaitForRequest(AZURE_CLIENT *ac, SOCK *s, AZURE_PARAM *param);
+
+
+#endif // AZURE_CLIENT_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/AzureServer.c b/src/Cedar/AzureServer.c
new file mode 100644
index 00000000..caea4c30
--- /dev/null
+++ b/src/Cedar/AzureServer.c
@@ -0,0 +1,90 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// AzureServer.c
+// VPN Azure Server
+
+#include "CedarPch.h"
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/AzureServer.h b/src/Cedar/AzureServer.h
new file mode 100644
index 00000000..c6389c35
--- /dev/null
+++ b/src/Cedar/AzureServer.h
@@ -0,0 +1,94 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// AzureServer.h
+// Header of AzureServer.c
+
+#ifndef AZURE_SERVER_H
+#define AZURE_SERVER_H
+
+
+#endif // AZURE_SERVER_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Bridge.c b/src/Cedar/Bridge.c
new file mode 100644
index 00000000..a2434995
--- /dev/null
+++ b/src/Cedar/Bridge.c
@@ -0,0 +1,532 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Bridge.c
+// Ethernet Bridge Program (Local Bridge)
+
+#include
+
+#define BRIDGE_C
+
+#ifdef WIN32
+#define OS_WIN32
+#endif
+
+#ifdef OS_WIN32
+
+// Win32
+#include "BridgeWin32.c"
+
+#else
+
+// Unix
+#include "BridgeUnix.c"
+
+#endif // OS_WIN32
+
+// Hash the list of current Ethernet devices
+UINT GetEthDeviceHash()
+{
+#ifdef OS_UNIX
+ // UNIX
+ UINT num;
+ UINT i;
+ char tmp[4096];
+ UCHAR hash[SHA1_SIZE];
+ TOKEN_LIST *t = GetEthList();
+
+ num = t->NumTokens;
+ tmp[0] = 0;
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ StrCat(tmp, sizeof(tmp), t->Token[i]);
+ }
+ FreeToken(t);
+
+ Hash(hash, tmp, StrLen(tmp), true);
+
+ Copy(&num, hash, sizeof(UINT));
+
+ return num;
+#else // OS_UNIX
+ // Win32
+ UINT ret = 0;
+ MS_ADAPTER_LIST *a = MsCreateAdapterListEx(true);
+ UINT num;
+ UINT i;
+ char tmp[4096];
+ UCHAR hash[SHA1_SIZE];
+
+ tmp[0] = 0;
+ if (a != NULL)
+ {
+ for (i = 0;i < a->Num;i++)
+ {
+ StrCat(tmp, sizeof(tmp), a->Adapters[i]->Title);
+ }
+ }
+ MsFreeAdapterList(a);
+
+ Hash(hash, tmp, StrLen(tmp), true);
+
+ Copy(&num, hash, sizeof(UINT));
+
+ return num;
+#endif // OS_UNIX
+}
+
+// Get whether WinPcap is needed
+bool IsNeedWinPcap()
+{
+ if (IsBridgeSupported() == false)
+ {
+ // Not in Windows
+ return false;
+ }
+ else
+ {
+ // Windows
+ if (IsEthSupported())
+ {
+ // Already success to access the Ethernet device
+ return false;
+ }
+ else
+ {
+ // Failed to access the Ethernet device
+ return true;
+ }
+ }
+}
+
+// Get whether the local-bridging is supported by current OS
+bool IsBridgeSupported()
+{
+ UINT type = GetOsInfo()->OsType;
+
+ if (OS_IS_WINDOWS(type))
+ {
+ if (IsEthSupported())
+ {
+ return true;
+ }
+ else
+ {
+ bool ret = false;
+
+#ifdef OS_WIN32
+ ret = MsIsAdmin();
+#endif // OS_WIN32
+
+ return ret;
+ }
+ }
+ else
+ {
+ return IsEthSupported();
+ }
+}
+
+// Delete a local-bridge
+bool DeleteLocalBridge(CEDAR *c, char *hubname, char *devicename)
+{
+ bool ret = false;
+ // Validate arguments
+ if (c == NULL || hubname == NULL || devicename == NULL)
+ {
+ return false;
+ }
+
+ LockList(c->HubList);
+ {
+ LockList(c->LocalBridgeList);
+ {
+ UINT i;
+
+ for (i = 0;i < LIST_NUM(c->LocalBridgeList);i++)
+ {
+ LOCALBRIDGE *br = LIST_DATA(c->LocalBridgeList, i);
+
+ if (StrCmpi(br->HubName, hubname) == 0)
+ {
+ if (StrCmpi(br->DeviceName, devicename) == 0)
+ {
+ if (br->Bridge != NULL)
+ {
+ BrFreeBridge(br->Bridge);
+ br->Bridge = NULL;
+ }
+
+ Delete(c->LocalBridgeList, br);
+ Free(br);
+
+ ret = true;
+ break;
+ }
+ }
+ }
+ }
+ UnlockList(c->LocalBridgeList);
+ }
+ UnlockList(c->HubList);
+
+ return ret;
+}
+
+// Add a local-bridge
+void AddLocalBridge(CEDAR *c, char *hubname, char *devicename, bool local, bool monitor, bool tapmode, char *tapaddr, bool limit_broadcast)
+{
+ UINT i;
+ HUB *h = NULL;
+ LOCALBRIDGE *br = NULL;
+ // Validate arguments
+ if (c == NULL || hubname == NULL || devicename == NULL)
+ {
+ return;
+ }
+
+ if (OS_IS_UNIX(GetOsInfo()->OsType) == false)
+ {
+ tapmode = false;
+ }
+
+ LockList(c->HubList);
+ {
+ LockList(c->LocalBridgeList);
+ {
+ bool exists = false;
+
+ // Ensure that the same configuration local-bridge doesn't exist already
+ for (i = 0;i < LIST_NUM(c->LocalBridgeList);i++)
+ {
+ LOCALBRIDGE *br = LIST_DATA(c->LocalBridgeList, i);
+ if (StrCmpi(br->DeviceName, devicename) == 0)
+ {
+ if (StrCmpi(br->HubName, hubname) == 0)
+ {
+ if (br->TapMode == tapmode)
+ {
+ exists = true;
+ }
+ }
+ }
+ }
+
+ if (exists == false)
+ {
+ // Add configuration
+ br = ZeroMalloc(sizeof(LOCALBRIDGE));
+ StrCpy(br->HubName, sizeof(br->HubName), hubname);
+ StrCpy(br->DeviceName, sizeof(br->DeviceName), devicename);
+ br->Bridge = NULL;
+ br->Local = local;
+ br->TapMode = tapmode;
+ br->LimitBroadcast = limit_broadcast;
+ br->Monitor = monitor;
+ if (br->TapMode)
+ {
+ if (tapaddr != NULL && IsZero(tapaddr, 6) == false)
+ {
+ Copy(br->TapMacAddress, tapaddr, 6);
+ }
+ else
+ {
+ GenMacAddress(br->TapMacAddress);
+ }
+ }
+
+ Add(c->LocalBridgeList, br);
+
+ // Find the hub
+ for (i = 0;i < LIST_NUM(c->HubList);i++)
+ {
+ HUB *hub = LIST_DATA(c->HubList, i);
+ if (StrCmpi(hub->Name, br->HubName) == 0)
+ {
+ h = hub;
+ AddRef(h->ref);
+ break;
+ }
+ }
+ }
+ }
+ UnlockList(c->LocalBridgeList);
+ }
+ UnlockList(c->HubList);
+
+ // Start the local-bridge immediately
+ if (h != NULL && br != NULL && h->Type != HUB_TYPE_FARM_DYNAMIC)
+ {
+ Lock(h->lock_online);
+ {
+ if (h->Offline == false)
+ {
+ LockList(c->LocalBridgeList);
+ {
+ if (IsInList(c->LocalBridgeList, br))
+ {
+ if (br->Bridge == NULL)
+ {
+ br->Bridge = BrNewBridge(h, br->DeviceName, NULL, br->Local, br->Monitor, br->TapMode, br->TapMacAddress, br->LimitBroadcast, br);
+ }
+ }
+ }
+ UnlockList(c->LocalBridgeList);
+ }
+ }
+ Unlock(h->lock_online);
+ }
+
+ ReleaseHub(h);
+}
+
+// Initialize the local-bridge list
+void InitLocalBridgeList(CEDAR *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->LocalBridgeList = NewList(NULL);
+}
+
+// Free the local-bridge list
+void FreeLocalBridgeList(CEDAR *c)
+{
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(c->LocalBridgeList);i++)
+ {
+ LOCALBRIDGE *br = LIST_DATA(c->LocalBridgeList, i);
+ Free(br);
+ }
+
+ ReleaseList(c->LocalBridgeList);
+ c->LocalBridgeList = NULL;
+}
+
+// Bridging thread
+void BrBridgeThread(THREAD *thread, void *param)
+{
+ BRIDGE *b;
+ CONNECTION *c;
+ SESSION *s;
+ HUB *h;
+ char name[MAX_SIZE];
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ b = (BRIDGE *)param;
+
+ // Create a connection object
+ c = NewServerConnection(b->Cedar, NULL, thread);
+ c->Protocol = CONNECTION_HUB_BRIDGE;
+
+ // Create a session object
+ s = NewServerSession(b->Cedar, c, b->Hub, BRIDGE_USER_NAME, b->Policy);
+ HLog(b->Hub, "LH_START_BRIDGE", b->Name, s->Name);
+ StrCpy(name, sizeof(name), b->Name);
+ h = b->Hub;
+ AddRef(h->ref);
+ s->BridgeMode = true;
+ s->Bridge = b;
+ c->Session = s;
+ ReleaseConnection(c);
+
+ // Dummy user name for local-bridge
+ s->Username = CopyStr(BRIDGE_USER_NAME_PRINT);
+
+ b->Session = s;
+ AddRef(s->ref);
+
+ // Notify completion
+ NoticeThreadInit(thread);
+
+ // Main procedure of the session
+ Debug("Bridge %s Start.\n", b->Name);
+ SessionMain(s);
+ Debug("Bridge %s Stop.\n", b->Name);
+
+ HLog(h, "LH_STOP_BRIDGE", name);
+
+ ReleaseHub(h);
+
+ ReleaseSession(s);
+}
+
+// Free the local-bridge object
+void BrFreeBridge(BRIDGE *b)
+{
+ // Validate arguments
+ if (b == NULL)
+ {
+ return;
+ }
+
+ if (b->ParentLocalBridge != NULL)
+ {
+ b->ParentLocalBridge = NULL;
+ }
+
+ // Stop session thread
+ StopSession(b->Session);
+ ReleaseSession(b->Session);
+
+ Free(b);
+}
+
+// Create new local-bridge
+BRIDGE *BrNewBridge(HUB *h, char *name, POLICY *p, bool local, bool monitor, bool tapmode, char *tapaddr, bool limit_broadcast, LOCALBRIDGE *parent_local_bridge)
+{
+ BRIDGE *b;
+ POLICY *policy;
+ THREAD *t;
+ // Validate arguments
+ if (h == NULL || name == NULL || parent_local_bridge == NULL)
+ {
+ return NULL;
+ }
+
+ if (p == NULL)
+ {
+ policy = ClonePolicy(GetDefaultPolicy());
+ }
+ else
+ {
+ policy = ClonePolicy(p);
+ }
+
+ b = ZeroMalloc(sizeof(BRIDGE));
+ b->Cedar = h->Cedar;
+ b->Hub = h;
+ StrCpy(b->Name, sizeof(b->Name), name);
+ b->Policy = policy;
+ b->Local = local;
+ b->Monitor = monitor;
+ b->TapMode = tapmode;
+ b->LimitBroadcast = limit_broadcast;
+ b->ParentLocalBridge = parent_local_bridge;
+
+ if (b->TapMode)
+ {
+ if (tapaddr != NULL && IsZero(tapaddr, 6) == false)
+ {
+ Copy(b->TapMacAddress, tapaddr, 6);
+ }
+ else
+ {
+ GenMacAddress(b->TapMacAddress);
+ }
+ }
+
+ if (monitor)
+ {
+ // Enabling monitoring mode
+ policy->MonitorPort = true;
+ }
+
+ if (b->LimitBroadcast == false)
+ {
+ // Disable broadcast limiter
+ policy->NoBroadcastLimiter = true;
+ }
+
+ // Start thread
+ t = NewThread(BrBridgeThread, b);
+ WaitThreadInit(t);
+ ReleaseThread(t);
+
+ return b;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Bridge.h b/src/Cedar/Bridge.h
new file mode 100644
index 00000000..771ef4ef
--- /dev/null
+++ b/src/Cedar/Bridge.h
@@ -0,0 +1,152 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Bridge.h
+// Header of Bridge.c
+
+#ifndef BRIDGE_H
+#define BRIDGE_H
+
+#ifdef OS_WIN32
+
+// For Win32
+#include
+
+#else
+
+// For Unix
+#include
+
+#endif // OS_WIN32
+
+// Bridge
+struct BRIDGE
+{
+ bool Active; // Status
+ CEDAR *Cedar; // Cedar
+ HUB *Hub; // HUB
+ SESSION *Session; // Session
+ POLICY *Policy; // Policy
+ ETH *Eth; // Ethernet
+ char Name[MAX_SIZE]; // Device name
+ UINT64 LastBridgeTry; // Time to try to bridge at last
+ bool Local; // Local mode
+ bool Monitor; // Monitor mode
+ bool TapMode; // Tap mode
+ bool LimitBroadcast; // Broadcasts limiting mode
+ UCHAR TapMacAddress[6]; // MAC address of the tap
+ UINT LastNumDevice; // Number of device (Number of last checked)
+ UINT64 LastNumDeviceCheck; // Time at which to check the number of devices at last
+ UINT64 LastChangeMtuError; // Time that recorded the error to change the MTU at last
+ LOCALBRIDGE *ParentLocalBridge; // Parent Local Bridge
+};
+
+// Local bridge
+struct LOCALBRIDGE
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // Virtual HUB name
+ char DeviceName[MAX_SIZE]; // Device name
+ bool Local; // Local mode
+ bool Monitor; // Monitor mode
+ bool TapMode; // Tap mode
+ bool LimitBroadcast; // Broadcast packets limiting mode
+ UCHAR TapMacAddress[6]; // MAC address of the tap
+ BRIDGE *Bridge; // Bridge
+};
+
+BRIDGE *BrNewBridge(HUB *h, char *name, POLICY *p, bool local, bool monitor, bool tapmode, char *tapaddr, bool limit_broadcast, LOCALBRIDGE *parent_local_bridge);
+void BrBridgeThread(THREAD *thread, void *param);
+void BrFreeBridge(BRIDGE *b);
+void InitLocalBridgeList(CEDAR *c);
+void FreeLocalBridgeList(CEDAR *c);
+void AddLocalBridge(CEDAR *c, char *hubname, char *devicename, bool local, bool monitor, bool tapmode, char *tapaddr, bool limit_broadcast);
+bool DeleteLocalBridge(CEDAR *c, char *hubname, char *devicename);
+bool IsBridgeSupported();
+bool IsNeedWinPcap();
+UINT GetEthDeviceHash();
+
+#endif // BRIDGE_H
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/BridgeUnix.c b/src/Cedar/BridgeUnix.c
new file mode 100644
index 00000000..ee8c93a2
--- /dev/null
+++ b/src/Cedar/BridgeUnix.c
@@ -0,0 +1,1813 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// BridgeUnix.c
+// Ethernet Bridge Program (for UNIX)
+//#define BRIDGE_C
+//#define UNIX_LINUX
+
+#include
+
+#ifdef BRIDGE_C
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef UNIX_SOLARIS
+#include
+#endif
+
+#ifdef BRIDGE_PCAP
+#include
+#endif // BRIDGE_PCAP
+
+#ifdef BRIDGE_BPF
+#include
+#include
+#include
+#include
+#include
+#endif // BRIDGE_BPF
+
+// Initialize
+void InitEth()
+{
+}
+
+// Free
+void FreeEth()
+{
+}
+
+// Check whether interface description string of Ethernet device can be retrieved in this system
+bool EthIsInterfaceDescriptionSupportedUnix()
+{
+ bool ret = false;
+ DIRLIST *d = EnumDir("/etc/sysconfig/networking/devices/");
+
+ if (d == NULL)
+ {
+ return false;
+ }
+
+ if (d->NumFiles >= 1)
+ {
+ ret = true;
+ }
+
+ FreeDir(d);
+
+ return ret;
+}
+
+// Get interface description string
+bool EthGetInterfaceDescriptionUnix(char *name, char *str, UINT size)
+{
+ char tmp[MAX_SIZE];
+ bool ret = false;
+ BUF *b;
+ // Validate arguments
+ if (name == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ StrCpy(str, size, name);
+
+ Format(tmp, sizeof(tmp), "/etc/sysconfig/networking/devices/ifcfg-%s", name);
+
+ b = ReadDump(tmp);
+ if (b != NULL)
+ {
+ char *line = CfgReadNextLine(b);
+
+ if (IsEmptyStr(line) == false)
+ {
+ if (StartWith(line, "#"))
+ {
+ char tmp[MAX_SIZE];
+
+ StrCpy(tmp, sizeof(tmp), line + 1);
+
+ Trim(tmp);
+ tmp[60] = 0;
+
+ StrCpy(str, size, tmp);
+
+ ret = true;
+ }
+ }
+
+ Free(line);
+
+ FreeBuf(b);
+ }
+
+ return ret;
+}
+
+// Open raw socket
+int UnixEthOpenRawSocket()
+{
+#ifdef UNIX_LINUX
+ int s;
+
+ s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (s < 0)
+ {
+ return INVALID_SOCKET;
+ }
+ else
+ {
+ return s;
+ }
+#else // UNIX_LINUX
+ return -1;
+#endif // UNIX_LINUX
+}
+
+// Is Ethernet device control supported?
+bool IsEthSupported()
+{
+ bool ret = false;
+
+#if defined(UNIX_LINUX)
+ ret = IsEthSupportedLinux();
+#elif defined(UNIX_SOLARIS)
+ ret = IsEthSupportedSolaris();
+#elif defined(BRIDGE_PCAP)
+ ret = true;
+#elif defined(BRIDGE_BPF)
+ ret = true;
+#endif
+ return ret;
+}
+
+#ifdef UNIX_LINUX
+bool IsEthSupportedLinux()
+{
+ int s;
+
+ // Try to open a raw socket
+ s = UnixEthOpenRawSocket();
+ if (s == INVALID_SOCKET)
+ {
+ // fail
+ return false;
+ }
+
+ // success
+ closesocket(s);
+
+ return true;
+}
+#endif // UNIX_LINUX
+
+#ifdef UNIX_SOLARIS
+bool IsEthSupportedSolaris()
+{
+ return true;
+}
+#endif // UNIX_SOLARIS
+
+#ifdef UNIX_SOLARIS
+// Get Ethernet device list on Solaris
+TOKEN_LIST *GetEthListSolaris()
+{
+ TOKEN_LIST *t;
+ int i, s;
+ LIST *o;
+
+
+ o = NewListFast(CompareStr);
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s != INVALID_SOCKET)
+ {
+ struct lifnum lifn;
+ lifn.lifn_family = AF_INET;
+ lifn.lifn_flags = 0;
+ if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) >= 0)
+ {
+ struct lifconf lifc;
+ struct lifreq *buf;
+ UINT numifs;
+ UINT bufsize;
+
+ numifs = lifn.lifn_count;
+ Debug("NumIFs:%d\n",numifs);
+ bufsize = numifs * sizeof(struct lifreq);
+ buf = Malloc(bufsize);
+
+ lifc.lifc_family = AF_INET;
+ lifc.lifc_flags = 0;
+ lifc.lifc_len = bufsize;
+ lifc.lifc_buf = (char*) buf;
+ if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) >= 0)
+ {
+ for (i = 0; iNumTokens = LIST_NUM(o);
+ t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ char *name = LIST_DATA(o, i);
+ t->Token[i] = name;
+ }
+
+ ReleaseList(o);
+
+ return t;
+}
+#endif // UNIX_SOLARIS
+
+#ifdef UNIX_LINUX
+// Get Ethernet device list on Linux
+TOKEN_LIST *GetEthListLinux()
+{
+ struct ifreq ifr;
+ TOKEN_LIST *t;
+ UINT i, n;
+ int s;
+ LIST *o;
+ char name[MAX_SIZE];
+
+ o = NewListFast(CompareStr);
+
+ s = UnixEthOpenRawSocket();
+ if (s != INVALID_SOCKET)
+ {
+ n = 0;
+ for (i = 0;;i++)
+ {
+ Zero(&ifr, sizeof(ifr));
+ ifr.ifr_ifindex = i;
+
+ if (ioctl(s, SIOCGIFNAME, &ifr) >= 0)
+ {
+ n = 0;
+ StrCpy(name, sizeof(name), ifr.ifr_name);
+
+ Zero(&ifr, sizeof(ifr));
+ StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);
+ if (ioctl(s, SIOCGIFHWADDR, &ifr) >= 0)
+ {
+ UINT type = ifr.ifr_hwaddr.sa_family;
+ if (type == 1 || type == 2 || type == 6 || type == 800 || type == 801)
+ {
+ if (IsInListStr(o, name) == false)
+ {
+ if (StartWith(name, "tap_") == false)
+ {
+ Add(o, CopyStr(name));
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ n++;
+ if (n >= 64)
+ {
+ break;
+ }
+ }
+ }
+ closesocket(s);
+ }
+
+ Sort(o);
+
+ t = ZeroMalloc(sizeof(TOKEN_LIST));
+ t->NumTokens = LIST_NUM(o);
+ t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ char *name = LIST_DATA(o, i);
+ t->Token[i] = name;
+ }
+
+ ReleaseList(o);
+
+ return t;
+}
+#endif // UNIX_LINUX
+
+#ifdef BRIDGE_PCAP
+// Ethernet device list by Pcap API
+TOKEN_LIST *GetEthListPcap()
+{
+ pcap_if_t *alldevs;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ LIST *o;
+ TOKEN_LIST *t;
+ int i;
+
+ o = NewListFast(CompareStr);
+
+ if( pcap_findalldevs(&alldevs,errbuf) != -1)
+ {
+ pcap_if_t *dev = alldevs;
+ while(dev != NULL)
+ {
+ pcap_t *p;
+ // Device type will be unknown until open the device?
+ p = pcap_open_live(dev->name, 0, false, 0, errbuf);
+ if(p != NULL)
+ {
+ int datalink = pcap_datalink(p);
+ // Debug("type:%s\n",pcap_datalink_val_to_name(datalink));
+ pcap_close(p);
+ if(datalink == DLT_EN10MB){
+ // Enumerate only Ethernet type device
+ Add(o, CopyStr(dev->name));
+ }
+ }
+ dev = dev->next;
+ }
+ pcap_freealldevs(alldevs);
+ }
+
+ Sort(o);
+ t = ZeroMalloc(sizeof(TOKEN_LIST));
+ t->NumTokens = LIST_NUM(o);
+ t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ t->Token[i] = LIST_DATA(o, i);
+ }
+ ReleaseList(o);
+ return t;
+}
+#endif // BRIDGE_PCAP
+
+#ifdef BRIDGE_BPF
+// Ethernet device list by BPF API
+TOKEN_LIST *GetEthListBpf()
+{
+ struct ifaddrs *ifadrs;
+ struct sockaddr_dl *sockadr;
+ LIST *o;
+ TOKEN_LIST *t;
+ int i;
+
+ o = NewListFast(CompareStr);
+
+ // Enumerate network devices
+ if(getifaddrs( &ifadrs ) == 0)
+ {
+ struct ifaddrs *ifadr = ifadrs;
+ while(ifadr)
+ {
+ sockadr = (struct sockaddr_dl*)ifadr->ifa_addr;
+ if(sockadr->sdl_family == AF_LINK && sockadr->sdl_type == IFT_ETHER)
+ {
+ // Is this Ethernet device?
+ if(!IsInListStr(o,ifadr->ifa_name))
+ {
+ // Ignore the foregoing device (for device which have multiple MAC address)
+ Add(o, CopyStr(ifadr->ifa_name));
+ }
+ }
+ ifadr = ifadr -> ifa_next;
+ }
+ freeifaddrs(ifadrs);
+ }
+
+ Sort(o);
+ t = ZeroMalloc(sizeof(TOKEN_LIST));
+ t->NumTokens = LIST_NUM(o);
+ t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ t->Token[i] = LIST_DATA(o, i);
+ }
+ ReleaseList(o);
+ return t;
+}
+#endif // BRIDGE_BPF
+
+// Enumerate Ethernet devices
+TOKEN_LIST *GetEthList()
+{
+ TOKEN_LIST *t = NULL;
+
+#if defined(UNIX_LINUX)
+ t = GetEthListLinux();
+#elif defined(UNIX_SOLARIS)
+ t = GetEthListSolaris();
+#elif defined(BRIDGE_PCAP)
+ t = GetEthListPcap();
+#elif defined(BRIDGE_BPF)
+ t = GetEthListBpf();
+#endif
+
+ return t;
+}
+
+#ifdef UNIX_LINUX
+// Open Ethernet device (Linux)
+ETH *OpenEthLinux(char *name, bool local, bool tapmode, char *tapaddr)
+{
+ ETH *e;
+ struct ifreq ifr;
+ struct sockaddr_ll addr;
+ int s;
+ int index;
+ CANCEL *c;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return NULL;
+ }
+
+ if (tapmode)
+ {
+#ifndef NO_VLAN
+ // In tap mode
+ VLAN *v = NewTap(name, tapaddr);
+ if (v == NULL)
+ {
+ return NULL;
+ }
+
+ e = ZeroMalloc(sizeof(ETH));
+ e->Name = CopyStr(name);
+ e->Title = CopyStr(name);
+ e->Cancel = VLanGetCancel(v);
+ e->IfIndex = 0;
+ e->Socket = INVALID_SOCKET;
+ e->Tap = v;
+
+ return e;
+#else // NO_VLAN
+ return NULL;
+#endif // NO_VLAN
+ }
+
+ s = UnixEthOpenRawSocket();
+ if (s == INVALID_SOCKET)
+ {
+ return NULL;
+ }
+
+ Zero(&ifr, sizeof(ifr));
+ StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);
+
+ if (ioctl(s, SIOCGIFINDEX, &ifr) < 0)
+ {
+ closesocket(s);
+ return NULL;
+ }
+
+ index = ifr.ifr_ifindex;
+
+ Zero(&addr, sizeof(addr));
+ addr.sll_family = PF_PACKET;
+ addr.sll_protocol = htons(ETH_P_ALL);
+ addr.sll_ifindex = index;
+
+ if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+ {
+ closesocket(s);
+ return NULL;
+ }
+
+ if (local == false)
+ {
+ // Enable promiscious mode
+ Zero(&ifr, sizeof(ifr));
+ StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);
+ if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
+ {
+ // Failed
+ closesocket(s);
+ return NULL;
+ }
+
+ ifr.ifr_flags |= IFF_PROMISC;
+
+ if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0)
+ {
+ // Failed
+ closesocket(s);
+ return NULL;
+ }
+ }
+
+ e = ZeroMalloc(sizeof(ETH));
+ e->Name = CopyStr(name);
+ e->Title = CopyStr(name);
+ e->IfIndex = index;
+ e->Socket = s;
+
+ c = NewCancel();
+ UnixDeletePipe(c->pipe_read, c->pipe_write);
+ c->pipe_read = c->pipe_write = -1;
+
+ UnixSetSocketNonBlockingMode(s, true);
+
+ c->SpecialFlag = true;
+ c->pipe_read = s;
+
+ e->Cancel = c;
+
+ // Get MTU
+ e->InitialMtu = EthGetMtu(e);
+
+ if (tapmode == false)
+ {
+ // Disable hardware offloading
+ UnixDisableInterfaceOffload(name);
+ }
+
+ return e;
+}
+#endif // UNIX_LINUX
+
+// Get the MTU value
+UINT EthGetMtu(ETH *e)
+{
+#if defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ UINT ret = 0;
+#ifdef UNIX_SOLARIS
+ struct lifreq ifr;
+#else // UNIX_SOLARIS
+ struct ifreq ifr;
+#endif // UNIX_SOLARIS
+ int s;
+ // Validate arguments
+ if (e == NULL || e->Tap != NULL)
+ {
+ return 0;
+ }
+
+ if (e->CurrentMtu != 0)
+ {
+ return e->CurrentMtu;
+ }
+
+#if defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ s = e->SocketBsdIf;
+#else // defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ s = e->Socket;
+#endif // defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+
+ Zero(&ifr, sizeof(ifr));
+
+#ifdef UNIX_SOLARIS
+ StrCpy(ifr.lifr_name, sizeof(ifr.lifr_name), e->Name);
+#else // UNIX_SOLARIS
+ StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), e->Name);
+#endif // UNIX_SOLARIS
+
+#ifdef UNIX_SOLARIS
+ if (ioctl(s, SIOCGLIFMTU, &ifr) < 0)
+ {
+ // failed
+ return 0;
+ }
+#else // UNIX_SOLARIS
+ if (ioctl(s, SIOCGIFMTU, &ifr) < 0)
+ {
+ // failed
+ return 0;
+ }
+#endif // UNIX_SOLARIS
+
+#ifdef UNIX_SOLARIS
+ ret = ifr.lifr_mtu + 14;
+#else // UNIX_SOLARIS
+ ret = ifr.ifr_mtu + 14;
+#endif // UNIX_SOLARIS
+
+ e->CurrentMtu = ret;
+
+ Debug("%s: GetMtu: %u\n", e->Name, ret);
+
+ return ret;
+#else // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ return 0;
+#endif // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+}
+
+// Set the MTU value
+bool EthSetMtu(ETH *e, UINT mtu)
+{
+#if defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ UINT ret = 0;
+#ifdef UNIX_SOLARIS
+ struct lifreq ifr;
+#else // UNIX_SOLARIS
+ struct ifreq ifr;
+#endif // UNIX_SOLARIS
+ int s;
+ // Validate arguments
+ if (e == NULL || e->Tap != NULL || (mtu > 1 && mtu < 1514))
+ {
+ return false;
+ }
+ if (mtu == 0 && e->InitialMtu == 0)
+ {
+ return false;
+ }
+
+ if (mtu == 0)
+ {
+ // Restore initial MTU value when parameter mtu == 0
+ mtu = e->InitialMtu;
+ }
+
+#if defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ s = e->SocketBsdIf;
+#else // defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ s = e->Socket;
+#endif // defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+
+ if (e->CurrentMtu == mtu)
+ {
+ // No need to change
+ return true;
+ }
+
+ Zero(&ifr, sizeof(ifr));
+
+#ifdef UNIX_SOLARIS
+ StrCpy(ifr.lifr_name, sizeof(ifr.lifr_name), e->Name);
+ ifr.lifr_mtu = mtu - 14;
+#else // UNIX_SOLARIS
+ StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), e->Name);
+ ifr.ifr_mtu = mtu - 14;
+#endif // UNIX_SOLARIS
+
+#ifdef UNIX_SOLARIS
+ if (ioctl(s, SIOCSLIFMTU, &ifr) < 0)
+ {
+ // Failed
+ return false;
+ }
+#else // UNIX_SOLARIS
+ if (ioctl(s, SIOCSIFMTU, &ifr) < 0)
+ {
+ // Failed
+ return false;
+ }
+#endif // UNIX_SOLARIS
+
+ e->CurrentMtu = mtu;
+
+ Debug("%s: SetMtu: %u\n", e->Name, mtu);
+
+ return true;
+#else // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ return false;
+#endif // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+}
+
+// Is changing MTU supported?
+bool EthIsChangeMtuSupported(ETH *e)
+{
+#if defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ // Validate arguments
+ if (e == NULL || e->Tap != NULL)
+ {
+ return false;
+ }
+
+ return true;
+#else // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ return false;
+#endif // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+}
+
+#ifdef UNIX_SOLARIS
+// Open Ethernet adapter (Solaris)
+ETH *OpenEthSolaris(char *name, bool local, bool tapmode, char *tapaddr)
+{
+ char devname[MAX_SIZE];
+ UINT devid;
+ int fd;
+ ETH *e;
+ CANCEL *c;
+ struct strioctl sioc;
+
+ // Validate arguments
+ if (name == NULL || tapmode != false)
+ {
+ return NULL;
+ }
+
+ // Parse device name
+ if (ParseUnixEthDeviceName(devname, sizeof(devname), &devid, name) == false)
+ {
+ return NULL;
+ }
+
+ // Open the device
+ fd = open(devname, O_RDWR);
+ if (fd == -1)
+ {
+ // Failed
+ return NULL;
+ }
+
+ // Attach to the device
+ if (DlipAttatchRequest(fd, devid) == false)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ // Verify ACK message
+ if (DlipReceiveAck(fd) == false)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ // Bind to SAP
+ if (DlipBindRequest(fd) == false)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ // Verify ACK message
+ if (DlipReceiveAck(fd) == false)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ // Set to ignore SAP and promiscuous mode
+ if (DlipPromiscuous(fd, DL_PROMISC_SAP) == false)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ // Verify ACK message
+ if (DlipReceiveAck(fd) == false)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ // Set to the mode to receive self sending packet
+ if (DlipPromiscuous(fd, DL_PROMISC_PHYS) == false)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ // Verify ACK message
+ if (DlipReceiveAck(fd) == false)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ // Set to raw mode
+ sioc.ic_cmd = DLIOCRAW;
+ sioc.ic_timout = -1;
+ sioc.ic_len = 0;
+ sioc.ic_dp = NULL;
+ if (ioctl(fd, I_STR, &sioc) < 0)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ if (ioctl(fd, I_FLUSH, FLUSHR) < 0)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ e = ZeroMalloc(sizeof(ETH));
+ e->Name = CopyStr(name);
+ e->Title = CopyStr(name);
+
+ c = NewCancel();
+ UnixDeletePipe(c->pipe_read, c->pipe_write);
+ c->pipe_read = c->pipe_write = -1;
+
+ c->SpecialFlag = true;
+ c->pipe_read = fd;
+
+ e->Cancel = c;
+
+ e->IfIndex = -1;
+ e->Socket = fd;
+
+ UnixSetSocketNonBlockingMode(fd, true);
+
+ // Get control interface
+ e->SocketBsdIf = socket(AF_INET, SOCK_DGRAM, 0);
+
+ // Get MTU value
+ e->InitialMtu = EthGetMtu(e);
+
+ return e;
+}
+
+// Set to promiscuous mode
+bool DlipPromiscuous(int fd, UINT level)
+{
+ dl_promiscon_req_t req;
+ struct strbuf ctl;
+ int flags;
+ // Validate arguments
+ if (fd == -1)
+ {
+ return false;
+ }
+
+ Zero(&req, sizeof(req));
+ req.dl_primitive = DL_PROMISCON_REQ;
+ req.dl_level = level;
+
+ Zero(&ctl, sizeof(ctl));
+ ctl.maxlen = 0;
+ ctl.len = sizeof(req);
+ ctl.buf = (char *)&req;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, NULL, flags) < 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Bind to a SAP
+bool DlipBindRequest(int fd)
+{
+ dl_bind_req_t req;
+ struct strbuf ctl;
+
+ if (fd == -1)
+ {
+ return false;
+ }
+
+ Zero(&req, sizeof(req));
+ req.dl_primitive = DL_BIND_REQ;
+ req.dl_service_mode = DL_CLDLS;
+ req.dl_sap = 0;
+
+ Zero(&ctl, sizeof(ctl));
+ ctl.maxlen = 0;
+ ctl.len = sizeof(req);
+ ctl.buf = (char *)&req;
+
+ if (putmsg(fd, &ctl, NULL, 0) < 0)
+ {
+ return false;
+ }
+ return true;
+}
+
+// Attach to the device
+bool DlipAttatchRequest(int fd, UINT devid)
+{
+ dl_attach_req_t req;
+ struct strbuf ctl;
+ int flags;
+ // Validate arguments
+ if (fd == -1)
+ {
+ return false;
+ }
+
+ Zero(&req, sizeof(req));
+ req.dl_primitive = DL_ATTACH_REQ;
+ req.dl_ppa = devid;
+
+ Zero(&ctl, sizeof(ctl));
+ ctl.maxlen = 0;
+ ctl.len = sizeof(req);
+ ctl.buf = (char *)&req;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, NULL, flags) < 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Verify the ACK message
+bool DlipReceiveAck(int fd)
+{
+ union DL_primitives *dlp;
+ struct strbuf ctl;
+ int flags = 0;
+ char *buf;
+ // Validate arguments
+ if (fd == -1)
+ {
+ return false;
+ }
+
+ buf = MallocFast(SOLARIS_MAXDLBUF);
+
+ Zero(&ctl, sizeof(ctl));
+ ctl.maxlen = SOLARIS_MAXDLBUF;
+ ctl.len = 0;
+ ctl.buf = buf;
+
+ if (getmsg(fd, &ctl, NULL, &flags) < 0)
+ {
+ return false;
+ }
+
+ dlp = (union DL_primitives *)ctl.buf;
+ if (dlp->dl_primitive != (UINT)DL_OK_ACK && dlp->dl_primitive != (UINT)DL_BIND_ACK)
+ {
+ Free(buf);
+ return false;
+ }
+
+ Free(buf);
+
+ return true;
+}
+
+#endif // UNIX_SOLARIS
+
+// Separate UNIX device name string into device name and id number
+bool ParseUnixEthDeviceName(char *dst_devname, UINT dst_devname_size, UINT *dst_devid, char *src_name)
+{
+ UINT len, i, j;
+
+ // Validate arguments
+ if (dst_devname == NULL || dst_devid == NULL || src_name == NULL)
+ {
+ return false;
+ }
+
+ len = strlen(src_name);
+ // Check string length
+ if(len == 0)
+ {
+ return false;
+ }
+
+ for (i = len-1; i+1 != 0; i--)
+ {
+ // Find last non-numeric character
+ if (src_name[i] < '0' || '9' < src_name[i])
+ {
+ // last character must be a number
+ if(src_name[i+1]==0)
+ {
+ return false;
+ }
+ *dst_devid = ToInt(src_name + i + 1);
+ StrCpy(dst_devname, dst_devname_size, "/dev/");
+ for (j = 0; jBuf = data;
+ block->Size = size;
+ return block;
+}
+
+// Free captured packet data structure
+void FreeCaptureBlock(struct CAPTUREBLOCK *block){
+ Free(block);
+}
+#endif // BRIDGE_BPF || BRIDGE_PCAP
+
+#ifdef BRIDGE_PCAP
+// Callback function to receive arriving packet (Pcap)
+void PcapHandler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
+{
+ ETH *e = (ETH*) user;
+ struct CAPTUREBLOCK *block;
+ UCHAR *data;
+
+ data = Malloc(h->caplen);
+ Copy(data, bytes, h->caplen);
+ block = NewCaptureBlock(data, h->caplen);
+ LockQueue(e->Queue);
+ // Discard arriving packet when queue filled
+ if(e->QueueSize < BRIDGE_MAX_QUEUE_SIZE){
+ InsertQueue(e->Queue, block);
+ e->QueueSize += h->caplen;
+ }
+ UnlockQueue(e->Queue);
+ Cancel(e->Cancel);
+ return;
+}
+
+// Relay thread for captured packet (Pcap)
+void PcapThread(THREAD *thread, void *param)
+{
+ ETH *e = (ETH*)param;
+ pcap_t *p = e->Pcap;
+ int ret;
+
+ // Notify initialize completed
+ NoticeThreadInit(thread);
+
+ // Return -1:Error -2:Terminated externally
+ ret = pcap_loop(p, -1, PcapHandler, (u_char*) e);
+ if(ret == -1){
+ e->Socket = INVALID_SOCKET;
+ pcap_perror(p, "capture");
+ }
+ return;
+}
+
+
+// Open Ethernet adapter (Pcap)
+ETH *OpenEthPcap(char *name, bool local, bool tapmode, char *tapaddr)
+{
+ char errbuf[PCAP_ERRBUF_SIZE];
+ ETH *e;
+ pcap_t *p;
+ CANCEL *c;
+
+ // Validate arguments
+ if (name == NULL || tapmode != false)
+ {
+ return NULL;
+ }
+
+ // Initialize error message buffer
+ errbuf[0] = 0;
+
+ // Open capturing device
+ p = pcap_open_live(name, 65535, (local == false), 1, errbuf);
+ if(p==NULL)
+ {
+ return NULL;
+ }
+
+ // Set to non-block mode
+ // (In old BSD OSs, 'select(2)' don't block normally for BPF device. To prevent busy loop)
+ /*
+ if(pcap_setnonblock(p, true, errbuf) == -1)
+ {
+ Debug("pcap_setnonblock:%s\n",errbuf);
+ pcap_close(p);
+ return NULL;
+ }
+ */
+
+ e = ZeroMalloc(sizeof(ETH));
+ e->Name = CopyStr(name);
+ e->Title = CopyStr(name);
+ e->Queue = NewQueue();
+ e->QueueSize = 0;
+ e->Cancel = NewCancel();
+ e->IfIndex = -1;
+ e->Socket = pcap_get_selectable_fd(p);
+ e->Pcap = p;
+
+ e->CaptureThread = NewThread(PcapThread, e);
+ WaitThreadInit(e->CaptureThread);
+
+ return e;
+}
+#endif // BRIDGE_PCAP
+
+#ifdef BRIDGE_BPF
+#ifdef BRIDGE_BPF_THREAD
+// Relay thread for captured packet (BPF)
+void BpfThread(THREAD *thread, void *param)
+{
+ ETH *e = (ETH*)param;
+ int fd = e->Socket;
+ int len;
+ int rest; // Rest size in buffer
+ UCHAR *next; // Head of next packet in buffer
+ struct CAPTUREBLOCK *block; // Data to enqueue
+ UCHAR *data;
+ struct bpf_hdr *hdr;
+
+ // Allocate the buffer
+ UCHAR *buf = Malloc(e->BufSize);
+
+ // Notify initialize completed
+ NoticeThreadInit(thread);
+
+ while(1){
+ // Determining to exit loop
+ if(e->Socket == INVALID_SOCKET){
+ break;
+ }
+
+ rest = read(fd, buf, e->BufSize);
+ if(rest < 0 && errno != EAGAIN){
+ // Error
+ close(fd);
+ e->Socket = INVALID_SOCKET;
+ Free(buf);
+ Cancel(e->Cancel);
+ return;
+ }
+ next = buf;
+ LockQueue(e->Queue);
+ while(rest>0){
+ // Cut out a packet
+ hdr = (struct bpf_hdr*)next;
+
+ // Discard arriving packet when queue filled
+ if(e->QueueSize < BRIDGE_MAX_QUEUE_SIZE){
+ data = Malloc(hdr->bh_caplen);
+ Copy(data, next+(hdr->bh_hdrlen), hdr->bh_caplen);
+ block = NewCaptureBlock(data, hdr->bh_caplen);
+ InsertQueue(e->Queue, block);
+ e->QueueSize += hdr->bh_caplen;
+ }
+
+ // Find the head of next packet
+ rest -= BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
+ next += BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
+ }
+ UnlockQueue(e->Queue);
+ Cancel(e->Cancel);
+ }
+ Free(buf);
+ Cancel(e->Cancel);
+ return;
+}
+#endif // BRIDGE_BPF_THREAD
+
+// Open Ethernet adapter (BPF)
+ETH *OpenEthBpf(char *name, bool local, bool tapmode, char *tapaddr)
+{
+ ETH *e;
+ CANCEL *c;
+ char devname[MAX_SIZE];
+ int n = 0;
+ int fd;
+ int ret;
+ UINT bufsize;
+ struct ifreq ifr;
+ struct timeval to;
+
+ // Find unused bpf device and open it
+ do{
+ Format(devname, sizeof(devname), "/dev/bpf%d", n++);
+ fd = open (devname, O_RDWR);
+ if(fd<0){
+ perror("open");
+ }
+ }while(fd < 0 && errno == EBUSY);
+
+ // No free bpf device was found
+ if(fd < 0){
+ Debug("BPF: No minor number are free.\n");
+ return NULL;
+ }
+
+ // Enlarge buffer size
+ n = 524288; // Somehow(In libpcap, this size is 32768)
+ while(true){
+ // Specify buffer size
+ ioctl(fd, BIOCSBLEN, &n);
+
+ // Bind to the network device
+ StrCpy(ifr.ifr_name, IFNAMSIZ, name);
+ ret = ioctl(fd, BIOCSETIF, &ifr);
+ if(ret < 0){
+ if(ret == ENOBUFS && n>1500){
+ // Inappropriate buffer size
+ // Retry with half buffer size
+ // If buffer size is under 1500 bytes, something goes wrong
+ n /= 2;
+ continue;
+ }
+ Debug("bpf: binding network failed.\n");
+ close(fd);
+ return NULL;
+ }else{
+ break;
+ }
+ }
+ bufsize = n;
+
+ // Set to promiscuous mode
+ if(local == false){
+ if (ioctl(fd, BIOCPROMISC, NULL) < 0){
+ printf("bpf: promisc mode failed.\n");
+ close(fd);
+ return NULL;
+ }
+ }
+
+
+ // Set to immediate mode (Return immediately when packet arrives)
+ n = 1;
+ if (ioctl(fd, BIOCIMMEDIATE, &n) < 0){
+ Debug("BPF: non-block mode failed.\n");
+ close(fd);
+ return NULL;
+ }
+
+ // Set receiving self sending packet
+ n = 1;
+ if (ioctl(fd, BIOCGSEESENT, &n) < 0){
+ Debug("BPF: see sent mode failed.\n");
+ close(fd);
+ return NULL;
+ }
+
+ // Header complete mode (Generate whole header of sending packet)
+ n = 1;
+ if (ioctl(fd, BIOCSHDRCMPLT, &n) < 0){
+ Debug("BPF: Header complete mode failed.\n");
+ close(fd);
+ return NULL;
+ }
+
+ // Set timeout delay to 1 second
+ to.tv_sec = 1;
+ to.tv_usec = 0;
+ if (ioctl(fd, BIOCSRTIMEOUT, &to) < 0){
+ Debug("BPF: Read timeout setting failed.\n");
+ close(fd);
+ return NULL;
+ }
+
+ e = ZeroMalloc(sizeof(ETH));
+ e->Name = CopyStr(name);
+ e->Title = CopyStr(name);
+ e->IfIndex = -1;
+ e->Socket = fd;
+ e->BufSize = bufsize;
+
+#ifdef BRIDGE_BPF_THREAD
+ e->Queue = NewQueue();
+ e->QueueSize = 0;
+ e->Cancel = NewCancel();
+
+ // Start capture thread
+ e->CaptureThread = NewThread(BpfThread, e);
+ WaitThreadInit(e->CaptureThread);
+
+#else // BRIDGE_BPF_THREAD
+ c = NewCancel();
+ UnixDeletePipe(c->pipe_read, c->pipe_write);
+ c->pipe_read = c->pipe_write = -1;
+ c->SpecialFlag = true;
+ c->pipe_read = fd;
+ e->Cancel = c;
+ e->Buffer = Malloc(bufsize);
+ e->Next = e->Buffer;
+ e->Rest = 0;
+
+ // Set to non-blocking mode
+ UnixSetSocketNonBlockingMode(fd, true);
+#endif // BRIDGE_BPF_THREAD
+
+ // Open interface control socket for FreeBSD
+ e->SocketBsdIf = socket(AF_LOCAL, SOCK_DGRAM, 0);
+
+ // Get MTU value
+ e->InitialMtu = EthGetMtu(e);
+
+ return e;
+}
+#endif // BRIDGE_BPF
+
+// Open Ethernet adapter
+ETH *OpenEth(char *name, bool local, bool tapmode, char *tapaddr)
+{
+ ETH *ret = NULL;
+
+#if defined(UNIX_LINUX)
+ ret = OpenEthLinux(name, local, tapmode, tapaddr);
+#elif defined(UNIX_SOLARIS)
+ ret = OpenEthSolaris(name, local, tapmode, tapaddr);
+#elif defined(BRIDGE_PCAP)
+ ret = OpenEthPcap(name, local, tapmode, tapaddr);
+#elif defined(BRIDGE_BPF)
+ ret = OpenEthBpf(name, local, tapmode, tapaddr);
+#endif
+
+ return ret;
+}
+
+typedef struct UNIXTHREAD
+{
+ pthread_t thread;
+ bool finished;
+} UNIXTHREAD;
+
+// Close Ethernet adapter
+void CloseEth(ETH *e)
+{
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ if (e->Tap != NULL)
+ {
+#ifndef NO_VLAN
+ FreeTap(e->Tap);
+#endif // NO_VLAN
+ }
+
+#ifdef BRIDGE_PCAP
+ {
+ struct CAPTUREBLOCK *block;
+ pcap_breakloop(e->Pcap);
+ WaitThread(e->CaptureThread, INFINITE);
+ ReleaseThread(e->CaptureThread);
+ pcap_close(e->Pcap);
+ while (block = GetNext(e->Queue)){
+ Free(block->Buf);
+ FreeCaptureBlock(block);
+ }
+ ReleaseQueue(e->Queue);
+ }
+#endif // BRIDGE_PCAP
+
+#ifdef BRIDGE_BPF
+#ifdef BRIDGE_BPF_THREAD
+ {
+ struct CAPTUREBLOCK *block;
+ int fd = e->Socket;
+ e->Socket = INVALID_SOCKET;
+ WaitThread(e->CaptureThread, INFINITE);
+ ReleaseThread(e->CaptureThread);
+ e->Socket = fd; // restore to close after
+ while (block = GetNext(e->Queue)){
+ Free(block->Buf);
+ FreeCaptureBlock(block);
+ }
+ ReleaseQueue(e->Queue);
+ }
+#else // BRIDGE_BPF_THREAD
+ Free(e->Buffer);
+#endif // BRIDGE_BPF_THREAD
+#endif // BRIDGE_BPF
+
+ ReleaseCancel(e->Cancel);
+ Free(e->Name);
+ Free(e->Title);
+
+ // Restore MTU value
+ EthSetMtu(e, 0);
+
+ if (e->Socket != INVALID_SOCKET)
+ {
+#if defined(BRIDGE_BPF) || defined(BRIDGE_PCAP) || defined(UNIX_SOLARIS)
+ close(e->Socket);
+#else // BRIDGE_PCAP
+ closesocket(e->Socket);
+#endif // BRIDGE_PCAP
+#if defined(BRIDGE_BPF) || defined(UNIX_SOLARIS)
+ if (e->SocketBsdIf != INVALID_SOCKET)
+ {
+ close(e->SocketBsdIf);
+ }
+#endif // BRIDGE_BPF || UNIX_SOLARIS
+ }
+
+ Free(e);
+}
+
+// Get cancel object
+CANCEL *EthGetCancel(ETH *e)
+{
+ CANCEL *c;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return NULL;
+ }
+
+ c = e->Cancel;
+ AddRef(c->ref);
+
+ return c;
+}
+
+// Read a packet
+UINT EthGetPacket(ETH *e, void **data)
+{
+ UINT ret = 0;
+
+#if defined(UNIX_LINUX)
+ ret = EthGetPacketLinux(e, data);
+#elif defined(UNIX_SOLARIS)
+ ret = EthGetPacketSolaris(e, data);
+#elif defined(BRIDGE_PCAP)
+ ret = EthGetPacketPcap(e, data);
+#elif defined(BRIDGE_BPF)
+ ret = EthGetPacketBpf(e, data);
+#endif
+
+ return ret;
+}
+
+#ifdef UNIX_LINUX
+UINT EthGetPacketLinux(ETH *e, void **data)
+{
+ int s, ret;
+ UCHAR tmp[UNIX_ETH_TMP_BUFFER_SIZE];
+ // Validate arguments
+ if (e == NULL || data == NULL)
+ {
+ return INFINITE;
+ }
+
+ if (e->Tap != NULL)
+ {
+#ifndef NO_VLAN
+ // tap mode
+ void *buf;
+ UINT size;
+
+ if (VLanGetNextPacket(e->Tap, &buf, &size) == false)
+ {
+ return INFINITE;
+ }
+
+ *data = buf;
+ return size;
+#else // NO_VLAN
+ return INFINITE;
+#endif
+ }
+
+ s = e->Socket;
+
+ if (s == INVALID_SOCKET)
+ {
+ return INFINITE;
+ }
+
+ // Read
+ ret = read(s, tmp, sizeof(tmp));
+ if (ret == 0 || (ret == -1 && errno == EAGAIN))
+ {
+ // No packet
+ *data = NULL;
+ return 0;
+ }
+ else if (ret == -1 || ret > sizeof(tmp))
+ {
+ // Error
+ *data = NULL;
+ e->Socket = INVALID_SOCKET;
+ return INFINITE;
+ }
+ else
+ {
+ // Success to read a packet
+ *data = MallocFast(ret);
+ Copy(*data, tmp, ret);
+ return ret;
+ }
+
+ return 0;
+}
+#endif // UNIX_LINUX
+
+#ifdef UNIX_SOLARIS
+UINT EthGetPacketSolaris(ETH *e, void **data)
+{
+ UCHAR tmp[UNIX_ETH_TMP_BUFFER_SIZE];
+ struct strbuf buf;
+ int s;
+ int flags = 0;
+ int ret;
+ // Validate arguments
+ if (e == NULL || data == NULL)
+ {
+ return INFINITE;
+ }
+
+ s = e->Socket;
+ if (s == INVALID_SOCKET)
+ {
+ return INFINITE;
+ }
+
+ Zero(&buf, sizeof(buf));
+ buf.buf = tmp;
+ buf.maxlen = sizeof(tmp);
+
+ ret = getmsg(s, NULL, &buf, &flags);
+
+ if (ret < 0 || ret > sizeof(tmp))
+ {
+ if (errno == EAGAIN)
+ {
+ // No packet
+ *data = NULL;
+ return 0;
+ }
+ // Error
+ *data = NULL;
+ return INFINITE;
+ }
+
+ ret = buf.len;
+
+ *data = MallocFast(ret);
+ Copy(*data, tmp, ret);
+ return ret;
+}
+#endif // UNIX_SOLARIS
+
+#ifdef BRIDGE_PCAP
+UINT EthGetPacketPcap(ETH *e, void **data)
+{
+ struct CAPTUREBLOCK *block;
+ UINT size;
+
+ LockQueue(e->Queue);
+ block = GetNext(e->Queue);
+ if(block != NULL){
+ e->QueueSize -= block->Size;
+ }
+ UnlockQueue(e->Queue);
+
+ if(block == NULL){
+ *data = NULL;
+ if(e->Socket == INVALID_SOCKET){
+ return INFINITE;
+ }
+ return 0;
+ }
+
+ *data = block->Buf;
+ size = block->Size;
+ FreeCaptureBlock(block);
+
+ return size;
+}
+#endif // BRIDGE_PCAP
+
+#ifdef BRIDGE_BPF
+#ifdef BRIDGE_BPF_THREAD
+UINT EthGetPacketBpf(ETH *e, void **data)
+{
+ struct CAPTUREBLOCK *block;
+ UINT size;
+
+ LockQueue(e->Queue);
+ block = GetNext(e->Queue);
+ if(block != NULL){
+ e->QueueSize -= block->Size;
+ }
+ UnlockQueue(e->Queue);
+
+ if(block == NULL){
+ *data = NULL;
+ if(e->Socket == INVALID_SOCKET){
+ return INFINITE;
+ }
+ return 0;
+ }
+
+ *data = block->Buf;
+ size = block->Size;
+ FreeCaptureBlock(block);
+
+ return size;
+}
+#else // BRIDGE_BPF_THREAD
+UINT EthGetPacketBpf(ETH *e, void **data)
+{
+ struct bpf_hdr *hdr;
+
+ if(e->Rest<=0){
+ e->Rest = read(e->Socket, e->Buffer, e->BufSize);
+ if(e->Rest < 0){
+ *data = NULL;
+ if(errno != EAGAIN){
+ // Error
+ return INFINITE;
+ }
+ // No packet
+ return 0;
+ }
+ e->Next = e->Buffer;
+ }
+ // Cut out a packet
+ hdr = (struct bpf_hdr*)e->Next;
+ *data = Malloc(hdr->bh_caplen);
+ Copy(*data, e->Next+(hdr->bh_hdrlen), hdr->bh_caplen);
+
+ // Find the head of next packet
+ e->Rest -= BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
+ e->Next += BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
+
+ return hdr->bh_caplen;
+}
+#endif // BRIDGE_BPF_THREAD
+#endif // BRIDGE_BPF
+
+
+// Send multiple packets
+void EthPutPackets(ETH *e, UINT num, void **datas, UINT *sizes)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL || num == 0 || datas == NULL || sizes == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < num;i++)
+ {
+ EthPutPacket(e, datas[i], sizes[i]);
+ }
+}
+
+// Send a packet
+void EthPutPacket(ETH *e, void *data, UINT size)
+{
+ int s, ret;
+ // Validate arguments
+ if (e == NULL || data == NULL)
+ {
+ return;
+ }
+ if (size < 14 || size > MAX_PACKET_SIZE)
+ {
+ Free(data);
+ return;
+ }
+
+ if (e->Tap != NULL)
+ {
+#ifndef NO_VLAN
+ // tap mode
+ VLanPutPacket(e->Tap, data, size);
+#endif // NO_VLAN
+ return;
+ }
+
+ s = e->Socket;
+
+ if (s == INVALID_SOCKET)
+ {
+ Free(data);
+ return;
+ }
+
+ // Send to device
+#ifdef BRIDGE_PCAP
+ ret = pcap_inject(e->Pcap, data, size);
+ if( ret == -1 ){
+#ifdef _DEBUG
+ pcap_perror(e->Pcap, "inject");
+#endif // _DEBUG
+ Debug("EthPutPacket: ret:%d size:%d\n", ret, size);
+ }
+#else // BRIDGE_PCAP
+ ret = write(s, data, size);
+ if (ret<0)
+ {
+ Debug("EthPutPacket: ret:%d errno:%d size:%d\n", ret, errno, size);
+ }
+#endif //BRIDGE_PCAP
+
+ Free(data);
+}
+
+#endif // BRIDGE_C
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/BridgeUnix.h b/src/Cedar/BridgeUnix.h
new file mode 100644
index 00000000..275ce097
--- /dev/null
+++ b/src/Cedar/BridgeUnix.h
@@ -0,0 +1,191 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// BridgeUnix.h
+// Header of BridgeUnix.c
+
+#ifndef BRIDGEUNIX_H
+#define BRIDGEUNIX_H
+
+// Macro
+#ifndef SOL_PACKET
+#define SOL_PACKET 263
+#endif
+#ifndef ifr_newname
+#define ifr_newname ifr_ifru.ifru_slave
+#endif
+
+// Constants
+#define UNIX_ETH_TMP_BUFFER_SIZE (2000)
+#define SOLARIS_MAXDLBUF (32768)
+#define BRIDGE_MAX_QUEUE_SIZE (4096*1500)
+
+// ETH structure
+struct ETH
+{
+ char *Name; // Adapter name
+ char *Title; // Adapter title
+ CANCEL *Cancel; // Cancel object
+ int IfIndex; // Index
+ int Socket; // Socket
+ UINT InitialMtu; // Initial MTU value
+ UINT CurrentMtu; // Current MTU value
+ int SocketBsdIf; // BSD interface operation socket
+ UCHAR MacAddress[6]; // MAC address
+
+#ifdef BRIDGE_PCAP
+ void *Pcap; // Pcap descriptor
+ QUEUE *Queue; // Queue of the relay thread
+ UINT QueueSize; // Number of bytes in Queue
+ THREAD *CaptureThread; // Pcap relay thread
+#endif // BRIDGE_PCAP
+
+#ifdef BRIDGE_BPF
+ UINT BufSize; // Buffer size to read the BPF (error for other)
+#ifdef BRIDGE_BPF_THREAD
+ QUEUE *Queue; // Queue of the relay thread
+ UINT QueueSize; // Number of bytes in Queue
+ THREAD *CaptureThread; // BPF relay thread
+#else // BRIDGE_BPF_THREAD
+ UCHAR *Buffer; // Buffer to read the BPF
+ UCHAR *Next;
+ int Rest;
+#endif // BRIDGE_BPF_THREAD
+#endif // BRIDGE_BPF
+
+ VLAN *Tap; // tap
+};
+
+#if defined( BRIDGE_BPF ) || defined( BRIDGE_PCAP )
+struct CAPTUREBLOCK{
+ UINT Size;
+ UCHAR *Buf;
+};
+#endif // BRIDGE_BPF
+
+
+// Function prototype
+void InitEth();
+void FreeEth();
+bool IsEthSupported();
+bool IsEthSupportedLinux();
+bool IsEthSupportedSolaris();
+bool IsEthSupportedPcap();
+TOKEN_LIST *GetEthList();
+TOKEN_LIST *GetEthListLinux();
+TOKEN_LIST *GetEthListSolaris();
+TOKEN_LIST *GetEthListPcap();
+ETH *OpenEth(char *name, bool local, bool tapmode, char *tapaddr);
+ETH *OpenEthLinux(char *name, bool local, bool tapmode, char *tapaddr);
+ETH *OpenEthSolaris(char *name, bool local, bool tapmode, char *tapaddr);
+ETH *OpenEthPcap(char *name, bool local, bool tapmode, char *tapaddr);
+bool ParseUnixEthDeviceName(char *dst_devname, UINT dst_devname_size, UINT *dst_devid, char *src_name);
+void CloseEth(ETH *e);
+CANCEL *EthGetCancel(ETH *e);
+UINT EthGetPacket(ETH *e, void **data);
+UINT EthGetPacketLinux(ETH *e, void **data);
+UINT EthGetPacketSolaris(ETH *e, void **data);
+UINT EthGetPacketPcap(ETH *e, void **data);
+UINT EthGetPacketBpf(ETH *e, void **data);
+void EthPutPacket(ETH *e, void *data, UINT size);
+void EthPutPackets(ETH *e, UINT num, void **datas, UINT *sizes);
+UINT EthGetMtu(ETH *e);
+bool EthSetMtu(ETH *e, UINT mtu);
+bool EthIsChangeMtuSupported(ETH *e);
+bool EthGetInterfaceDescriptionUnix(char *name, char *str, UINT size);
+bool EthIsInterfaceDescriptionSupportedUnix();
+
+#ifdef UNIX_SOLARIS
+// Function prototype for Solaris
+bool DlipAttatchRequest(int fd, UINT devid);
+bool DlipReceiveAck(int fd);
+bool DlipPromiscuous(int fd, UINT level);
+bool DlipBindRequest(int fd);
+#endif // OS_SOLARIS
+
+int UnixEthOpenRawSocket();
+
+#endif // BRIDGEUNIX_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/BridgeWin32.c b/src/Cedar/BridgeWin32.c
new file mode 100644
index 00000000..985a5111
--- /dev/null
+++ b/src/Cedar/BridgeWin32.c
@@ -0,0 +1,2217 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// BridgeWin32.c
+// Ethernet Bridge Program (Win32)
+
+#include
+
+#ifdef BRIDGE_C
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+static WP *wp = NULL;
+static LIST *eth_list = NULL;
+
+static LOCK *eth_list_lock = NULL;
+static bool is_see_mode = false;
+static bool is_using_selow = false;
+static bool enable_selow = true;
+
+static bool g_bridge_win32_show_all_if = false;
+
+#define LOAD_DLL_ADDR(name) \
+ { \
+ void *addr = GetProcAddress(h, #name); \
+ Copy(&wp->name, &addr, sizeof(void *)); \
+ }
+
+// Set the flag which indicates whether using SeLow
+void Win32SetEnableSeLow(bool b)
+{
+ enable_selow = b;
+}
+
+// Get the flag which indicates whether using SeLow
+bool Win32GetEnableSeLow()
+{
+ return enable_selow;
+}
+
+// Set the flag which indicates whether enumerating all interfaces
+void Win32EthSetShowAllIf(bool b)
+{
+ g_bridge_win32_show_all_if = b;
+}
+
+// Get the flag which indicates whether enumerating all interfaces
+bool Win32EthGetShowAllIf()
+{
+ return g_bridge_win32_show_all_if;
+}
+
+// Compare Ethernet device list
+int CmpRpcEnumEthVLan(void *p1, void *p2)
+{
+ RPC_ENUM_ETH_VLAN_ITEM *v1, *v2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ v1 = *((RPC_ENUM_ETH_VLAN_ITEM **)p1);
+ v2 = *((RPC_ENUM_ETH_VLAN_ITEM **)p2);
+ if (v1 == NULL || v2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(v1->DeviceName, v2->DeviceName);
+}
+
+// Get the value of MTU (Not supported in Windows)
+UINT EthGetMtu(ETH *e)
+{
+ return 0;
+}
+
+// Set the value of MTU (Not supported in Windows)
+bool EthSetMtu(ETH *e, UINT mtu)
+{
+ return false;
+}
+
+// Check whether setting MEU value (Not supported in Windows)
+bool EthIsChangeMtuSupported(ETH *e)
+{
+ return false;
+}
+
+// Set the state of VLAN tag pass-through
+bool SetVLanEnableStatus(char *title, bool enable)
+{
+ RPC_ENUM_ETH_VLAN t;
+ RPC_ENUM_ETH_VLAN_ITEM *e;
+ bool ret = false;
+ char key[MAX_SIZE];
+ char tcpkey[MAX_SIZE];
+ char short_key[MAX_SIZE];
+ // Validate arguments
+ if (title == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+ if (EnumEthVLanWin32(&t) == false)
+ {
+ return false;
+ }
+
+ e = FindEthVLanItem(&t, title);
+
+ if (e != NULL)
+ {
+ if (GetClassRegKeyWin32(key, sizeof(key), short_key, sizeof(short_key), e->Guid))
+ {
+ if (StrCmpi(e->DriverType, "Intel") == 0)
+ {
+ if (enable)
+ {
+ MsRegWriteStr(REG_LOCAL_MACHINE, key, "VlanFiltering", "0");
+ MsRegWriteStr(REG_LOCAL_MACHINE, key, "TaggingMode", "0");
+ MsRegWriteInt(REG_LOCAL_MACHINE, key, "MonitorMode", 1);
+ MsRegWriteInt(REG_LOCAL_MACHINE, key, "MonitorModeEnabled", 1);
+ }
+ else
+ {
+ if (MsRegReadInt(REG_LOCAL_MACHINE, key, "TaggingMode") == 0)
+ {
+ MsRegDeleteValue(REG_LOCAL_MACHINE, key, "TaggingMode");
+ }
+
+ if (MsRegReadInt(REG_LOCAL_MACHINE, key, "MonitorMode") == 1)
+ {
+ MsRegDeleteValue(REG_LOCAL_MACHINE, key, "MonitorMode");
+ }
+
+ if (MsRegReadInt(REG_LOCAL_MACHINE, key, "MonitorModeEnabled") == 1)
+ {
+ MsRegDeleteValue(REG_LOCAL_MACHINE, key, "MonitorModeEnabled");
+ }
+ }
+
+ ret = true;
+ }
+ else if (StrCmpi(e->DriverType, "Broadcom") == 0)
+ {
+ if (enable)
+ {
+ MsRegWriteStr(REG_LOCAL_MACHINE, key, "PreserveVlanInfoInRxPacket", "1");
+ }
+ else
+ {
+ MsRegDeleteValue(REG_LOCAL_MACHINE, key, "PreserveVlanInfoInRxPacket");
+ }
+
+ ret = true;
+ }
+ else if (StrCmpi(e->DriverType, "Marvell") == 0)
+ {
+ if (enable)
+ {
+ MsRegWriteInt(REG_LOCAL_MACHINE, key, "SkDisableVlanStrip", 1);
+ }
+ else
+ {
+ MsRegDeleteValue(REG_LOCAL_MACHINE, key, "SkDisableVlanStrip");
+ }
+
+ ret = true;
+ }
+
+ Format(tcpkey, sizeof(tcpkey),
+ "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%s",
+ e->Guid);
+
+ if (enable)
+ {
+ if (MsRegIsValue(REG_LOCAL_MACHINE, tcpkey, "MTU") == false)
+ {
+ MsRegWriteInt(REG_LOCAL_MACHINE, tcpkey, "MTU", 1500);
+ }
+ }
+ else
+ {
+ UINT mtu = MsRegReadInt(REG_LOCAL_MACHINE, tcpkey, "MTU");
+ if (mtu == 1500)
+ {
+ MsRegDeleteValue(REG_LOCAL_MACHINE, tcpkey, "MTU");
+ }
+ }
+ }
+ }
+
+ FreeRpcEnumEthVLan(&t);
+
+ return ret;
+}
+
+// Find Ethernet device
+RPC_ENUM_ETH_VLAN_ITEM *FindEthVLanItem(RPC_ENUM_ETH_VLAN *t, char *name)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || name == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ if (StrCmpi(t->Items[i].DeviceName, name) == 0)
+ {
+ return &t->Items[i];
+ }
+ }
+
+ return NULL;
+}
+
+// Get the state of VLAN tag pass-through
+void GetVLanEnableStatus(RPC_ENUM_ETH_VLAN_ITEM *e)
+{
+ char key[MAX_SIZE];
+ char short_key[MAX_SIZE];
+ char tcpkey[MAX_SIZE];
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ e->Enabled = false;
+
+ if (e->Support == false)
+ {
+ return;
+ }
+
+ if (GetClassRegKeyWin32(key, sizeof(key), short_key, sizeof(short_key), e->Guid) == false)
+ {
+ return;
+ }
+
+ Format(tcpkey, sizeof(tcpkey),
+ "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%s",
+ e->Guid);
+
+ if (StrCmpi(e->DriverType, "Intel") == 0)
+ {
+ char *VlanFiltering = MsRegReadStr(REG_LOCAL_MACHINE, key, "VlanFiltering");
+ UINT MonitorMode = MsRegReadInt(REG_LOCAL_MACHINE, key, "MonitorMode");
+ UINT MonitorModeEnabled = MsRegReadInt(REG_LOCAL_MACHINE, key, "MonitorModeEnabled");
+ char *TaggingMode = MsRegReadStr(REG_LOCAL_MACHINE, key, "TaggingMode");
+
+ if (StrCmpi(VlanFiltering, "0") == 0 &&
+ MonitorMode == 1 &&
+ MonitorModeEnabled == 1 &&
+ StrCmpi(TaggingMode, "0") == 0)
+ {
+ e->Enabled = true;
+ }
+
+ Free(VlanFiltering);
+ Free(TaggingMode);
+ }
+ else if (StrCmpi(e->DriverType, "Broadcom") == 0)
+ {
+ char *PreserveVlanInfoInRxPacket = MsRegReadStr(REG_LOCAL_MACHINE,
+ key, "PreserveVlanInfoInRxPacket");
+
+ if (StrCmpi(PreserveVlanInfoInRxPacket, "1") == 0)
+ {
+ e->Enabled = true;
+ }
+
+ Free(PreserveVlanInfoInRxPacket);
+ }
+ else if (StrCmpi(e->DriverType, "Marvell") == 0)
+ {
+ DWORD SkDisableVlanStrip = MsRegReadInt(REG_LOCAL_MACHINE,
+ key, "SkDisableVlanStrip");
+
+ if (SkDisableVlanStrip == 1)
+ {
+ e->Enabled = true;
+ }
+ }
+
+ if (MsRegIsValue(REG_LOCAL_MACHINE, tcpkey, "MTU") == false)
+ {
+ e->Enabled = false;
+ }
+}
+
+// Get VLAN tag pass-through availability of the device
+void GetVLanSupportStatus(RPC_ENUM_ETH_VLAN_ITEM *e)
+{
+ BUF *b;
+ char filename[MAX_SIZE];
+ void *wow;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ wow = MsDisableWow64FileSystemRedirection();
+
+ // Read the device driver file
+ CombinePath(filename, sizeof(filename), MsGetSystem32Dir(), "drivers");
+ CombinePath(filename, sizeof(filename), filename, e->DriverName);
+
+ b = ReadDump(filename);
+
+ if (b != NULL)
+ {
+ char intel1[] = "VlanFiltering";
+ char intel2[] = "V\0l\0a\0n\0F\0i\0l\0t\0e\0r\0i\0n\0g";
+ char intel3[] = "MonitorMode";
+ char intel4[] = "M\0o\0n\0i\0t\0o\0r\0M\0o\0d\0e";
+ char intel5[] = "TaggingMode";
+ char intel6[] = "T\0a\0g\0g\0i\0n\0g\0M\0o\0d\0e";
+ char broadcom1[] = "PreserveVlanInfoInRxPacket";
+ char broadcom2[] = "P\0r\0e\0s\0e\0r\0v\0e\0V\0l\0a\0n\0I\0n\0f\0o\0I\0n\0R\0x\0P\0a\0c\0k\0e\0t";
+ char marvell1[] = "SkDisableVlanStrip";
+ char marvell2[] = "S\0k\0D\0i\0s\0a\0b\0l\0e\0V\0l\0a\0n\0S\0t\0r\0i\0p";
+ char *driver_type = "";
+
+ if (SearchBin(b->Buf, 0, b->Size, intel1, sizeof(intel1)) != INFINITE
+ || SearchBin(b->Buf, 0, b->Size, intel2, sizeof(intel2)) != INFINITE
+ || SearchBin(b->Buf, 0, b->Size, intel3, sizeof(intel3)) != INFINITE
+ || SearchBin(b->Buf, 0, b->Size, intel4, sizeof(intel4)) != INFINITE
+ || SearchBin(b->Buf, 0, b->Size, intel5, sizeof(intel5)) != INFINITE
+ || SearchBin(b->Buf, 0, b->Size, intel6, sizeof(intel6)) != INFINITE)
+ {
+ driver_type = "Intel";
+ }
+ else if (SearchBin(b->Buf, 0, b->Size, broadcom1, sizeof(broadcom1)) != INFINITE
+ || SearchBin(b->Buf, 0, b->Size, broadcom2, sizeof(broadcom2)) != INFINITE)
+ {
+ driver_type = "Broadcom";
+ }
+ else if (SearchBin(b->Buf, 0, b->Size, marvell1, sizeof(marvell1)) != INFINITE
+ || SearchBin(b->Buf, 0, b->Size, marvell2, sizeof(marvell2)) != INFINITE)
+ {
+ driver_type = "Marvell";
+ }
+
+ if (IsEmptyStr(driver_type) == false)
+ {
+ StrCpy(e->DriverType, sizeof(e->DriverType), driver_type);
+ e->Support = true;
+ }
+
+ FreeBuf(b);
+ }
+
+ MsRestoreWow64FileSystemRedirection(wow);
+}
+
+// Get the device instance id from short_key
+char *SearchDeviceInstanceIdFromShortKey(char *short_key)
+{
+ char *ret = NULL;
+ TOKEN_LIST *t1;
+ // Validate arguments
+ if (short_key == NULL)
+ {
+ return NULL;
+ }
+
+ t1 = MsRegEnumKey(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Enum");
+
+ if (t1 != NULL)
+ {
+ TOKEN_LIST *t2;
+ char tmp[MAX_SIZE];
+ UINT i;
+
+ for (i = 0;i < t1->NumTokens;i++)
+ {
+ Format(tmp, sizeof(tmp), "SYSTEM\\CurrentControlSet\\Enum\\%s", t1->Token[i]);
+
+ t2 = MsRegEnumKey(REG_LOCAL_MACHINE, tmp);
+
+ if (t2 != NULL)
+ {
+ TOKEN_LIST *t3;
+ UINT i;
+
+ for (i = 0;i < t2->NumTokens;i++)
+ {
+ char tmp2[MAX_SIZE];
+
+ Format(tmp2, sizeof(tmp2), "%s\\%s", tmp, t2->Token[i]);
+
+ t3 = MsRegEnumKey(REG_LOCAL_MACHINE, tmp2);
+
+ if (t3 != NULL)
+ {
+ UINT i;
+
+ for (i = 0;i < t3->NumTokens;i++)
+ {
+ char tmp3[MAX_SIZE];
+ char *s;
+
+ Format(tmp3, sizeof(tmp3), "%s\\%s", tmp2, t3->Token[i]);
+
+ s = MsRegReadStr(REG_LOCAL_MACHINE, tmp3, "Driver");
+
+ if (s != NULL)
+ {
+ if (StrCmpi(s, short_key) == 0)
+ {
+ if (ret != NULL)
+ {
+ Free(ret);
+ }
+
+ ret = CopyStr(tmp3 + StrLen("SYSTEM\\CurrentControlSet\\Enum\\"));
+ }
+
+ Free(s);
+ }
+ }
+
+ FreeToken(t3);
+ }
+ }
+
+ FreeToken(t2);
+ }
+ }
+
+ FreeToken(t1);
+ }
+
+ return ret;
+}
+
+// Get VLAN tag pass-through availability of all devices
+bool EnumEthVLanWin32(RPC_ENUM_ETH_VLAN *t)
+{
+ UINT i;
+ LIST *o;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return false;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_ETH_VLAN));
+
+ if (MsIsWin2000OrGreater() == false)
+ {
+ return false;
+ }
+
+ if (IsEthSupported() == false)
+ {
+ return false;
+ }
+
+ // Get device list
+ Lock(eth_list_lock);
+
+ InitEthAdaptersList();
+
+ o = NewListFast(CmpRpcEnumEthVLan);
+
+ for (i = 0;i < LIST_NUM(eth_list);i++)
+ {
+ WP_ADAPTER *a = LIST_DATA(eth_list, i);
+
+ if (IsEmptyStr(a->Guid) == false)
+ {
+ char class_key[MAX_SIZE];
+ char short_key[MAX_SIZE];
+
+ if (GetClassRegKeyWin32(class_key, sizeof(class_key),
+ short_key, sizeof(short_key), a->Guid))
+ {
+ char *device_instance_id = MsRegReadStr(REG_LOCAL_MACHINE, class_key, "DeviceInstanceID");
+
+ if (IsEmptyStr(device_instance_id))
+ {
+ Free(device_instance_id);
+ device_instance_id = SearchDeviceInstanceIdFromShortKey(short_key);
+ }
+
+ if (IsEmptyStr(device_instance_id) == false)
+ {
+ char device_key[MAX_SIZE];
+ char *service_name;
+
+ Format(device_key, sizeof(device_key), "SYSTEM\\CurrentControlSet\\Enum\\%s",
+ device_instance_id);
+
+ service_name = MsRegReadStr(REG_LOCAL_MACHINE, device_key, "Service");
+ if (IsEmptyStr(service_name) == false)
+ {
+ char service_key[MAX_SIZE];
+ char *sys;
+
+ Format(service_key, sizeof(service_key),
+ "SYSTEM\\CurrentControlSet\\services\\%s",
+ service_name);
+
+ sys = MsRegReadStr(REG_LOCAL_MACHINE, service_key, "ImagePath");
+
+ if (IsEmptyStr(sys) == false)
+ {
+ char sysname[MAX_PATH];
+
+ GetFileNameFromFilePath(sysname, sizeof(sysname), sys);
+
+ Trim(sysname);
+
+ if (EndWith(sysname, ".sys"))
+ {
+ // device found
+ RPC_ENUM_ETH_VLAN_ITEM *e = ZeroMalloc(sizeof(RPC_ENUM_ETH_VLAN_ITEM));
+
+ StrCpy(e->DeviceName, sizeof(e->DeviceName), a->Title);
+ StrCpy(e->Guid, sizeof(e->Guid), a->Guid);
+ StrCpy(e->DeviceInstanceId, sizeof(e->DeviceInstanceId), device_instance_id);
+ StrCpy(e->DriverName, sizeof(e->DriverName), sysname);
+
+ // Get VLAN tag pass-through availability of the device
+ GetVLanSupportStatus(e);
+
+ // Get current pass-through setting of the device
+ GetVLanEnableStatus(e);
+
+ Insert(o, e);
+ }
+ }
+
+ Free(sys);
+ }
+
+ Free(service_name);
+ }
+
+ Free(device_instance_id);
+ }
+ }
+ }
+
+ t->NumItem = LIST_NUM(o);
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_ETH_VLAN_ITEM) * i);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ RPC_ENUM_ETH_VLAN_ITEM *e = LIST_DATA(o, i);
+
+ Copy(&t->Items[i], e, sizeof(RPC_ENUM_ETH_VLAN_ITEM));
+
+ Free(e);
+ }
+
+ ReleaseList(o);
+
+ Unlock(eth_list_lock);
+
+ return true;
+}
+
+// Get registry key of the network class data by GUID
+bool GetClassRegKeyWin32(char *key, UINT key_size, char *short_key, UINT short_key_size, char *guid)
+{
+ TOKEN_LIST *t;
+ bool ret = false;
+ UINT i;
+ // Validate arguments
+ if (key == NULL || short_key == NULL || guid == NULL)
+ {
+ return false;
+ }
+
+ t = MsRegEnumKey(REG_LOCAL_MACHINE,
+ "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}");
+ if (t == NULL)
+ {
+ return false;
+ }
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ char keyname[MAX_SIZE];
+ char *value;
+
+ Format(keyname, sizeof(keyname),
+ "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s",
+ t->Token[i]);
+
+ value = MsRegReadStr(REG_LOCAL_MACHINE, keyname, "NetCfgInstanceId");
+
+ if (StrCmpi(value, guid) == 0)
+ {
+ ret = true;
+
+ StrCpy(key, key_size, keyname);
+
+ Format(short_key, short_key_size, "{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s",
+ t->Token[i]);
+ }
+
+ Free(value);
+ }
+
+ FreeToken(t);
+
+ return ret;
+}
+
+// Send multiple packets
+void EthPutPackets(ETH *e, UINT num, void **datas, UINT *sizes)
+{
+ UINT i, total_size;
+ UCHAR *buf;
+ UINT write_pointer;
+ UINT err = 0;
+ // Validate arguments
+ if (e == NULL || num == 0 || datas == NULL || sizes == NULL)
+ {
+ return;
+ }
+ if (e->HasFatalError)
+ {
+ return;
+ }
+
+ if (e->SuAdapter != NULL)
+ {
+ bool ok = true;
+
+ // Send packets with SeLow
+ for (i = 0;i < num;i++)
+ {
+ UCHAR *data = datas[i];
+ UINT size = sizes[i];
+
+ if (ok)
+ {
+ // Actually, only enqueuing
+ ok = SuPutPacket(e->SuAdapter, data, size);
+ }
+
+ if (ok == false)
+ {
+ // Free memory on write error
+ Free(data);
+ }
+ }
+
+ if (ok)
+ {
+ // Send all data in queue at once
+ ok = SuPutPacket(e->SuAdapter, NULL, 0);
+ }
+
+ if (ok == false)
+ {
+ // Error occurred
+ e->HasFatalError = true;
+ }
+
+ return;
+ }
+
+ if (IsWin32BridgeWithSee() == false)
+ {
+ if (e->LastSetSingleCpu == 0 || (e->LastSetSingleCpu + 10000) <= Tick64())
+ {
+ e->LastSetSingleCpu = Tick64();
+ MsSetThreadSingleCpu();
+ }
+ }
+
+ // Calculate buffer size
+ total_size = 0;
+ for (i = 0;i < num;i++)
+ {
+ void *data = datas[i];
+ UINT size = sizes[i];
+ if (data != NULL && size >= 14 && size <= MAX_PACKET_SIZE)
+ {
+ total_size += size + sizeof(struct dump_bpf_hdr);
+ }
+ }
+
+ buf = MallocFast(total_size * 100 / 75 + 1600);
+
+ write_pointer = 0;
+ // Enqueue
+ for (i = 0;i < num;i++)
+ {
+ void *data = datas[i];
+ UINT size = sizes[i];
+ if (data != NULL && size >= 14 && size <= MAX_PACKET_SIZE)
+ {
+ struct dump_bpf_hdr *h;
+
+ h = (struct dump_bpf_hdr *)(buf + write_pointer);
+ Zero(h, sizeof(struct dump_bpf_hdr));
+ h->caplen = h->len = size;
+ write_pointer += sizeof(struct dump_bpf_hdr);
+ Copy(buf + write_pointer, data, size);
+ write_pointer += size;
+
+ PROBE_DATA2("EthPutPackets", data, size);
+ }
+ // Free original buffer
+ Free(data);
+ }
+
+ // Send
+ if (total_size != 0)
+ {
+ err = wp->PacketSendPackets(e->Adapter, buf, total_size, true);
+ }
+
+ Free(buf);
+
+ if (err == 0x7FFFFFFF)
+ {
+ // Critical error (infinite loop) occurred on sending
+ e->HasFatalError = true;
+ }
+}
+
+// Send a packet
+void EthPutPacket(ETH *e, void *data, UINT size)
+{
+ // Validate arguments
+ if (e == NULL || data == NULL || size == 0)
+ {
+ return;
+ }
+
+ EthPutPackets(e, 1, &data, &size);
+}
+
+// Read next packet
+UINT EthGetPacket(ETH *e, void **data)
+{
+ BLOCK *b;
+ bool flag = false;
+ // Validate arguments
+ if (e == NULL || data == NULL)
+ {
+ return INFINITE;
+ }
+ if (e->HasFatalError)
+ {
+ return INFINITE;
+ }
+
+ if (e->SuAdapter != NULL)
+ {
+ // Read packet with SeLow
+ UINT size;
+ if (SuGetNextPacket(e->SuAdapter, data, &size) == false)
+ {
+ // Error occurred
+ e->HasFatalError = true;
+ return INFINITE;
+ }
+
+ return size;
+ }
+
+RETRY:
+ // Check the presence of the packet in queue
+ b = GetNext(e->PacketQueue);
+ if (b != NULL)
+ {
+ UINT size;
+ size = b->Size;
+ *data = b->Buf;
+ Free(b);
+
+ if (e->PacketQueue->num_item == 0)
+ {
+ e->Empty = true;
+ }
+
+ return size;
+ }
+
+ if (e->Empty)
+ {
+ e->Empty = false;
+ return 0;
+ }
+
+ if (flag == false)
+ {
+ // Try to get next packet
+ PROBE_STR("EthGetPacket: PacketInitPacket");
+ wp->PacketInitPacket(e->Packet, e->Buffer, e->BufferSize);
+ PROBE_STR("EthGetPacket: PacketReceivePacket");
+ if (wp->PacketReceivePacket(e->Adapter, e->Packet, false) == false)
+ {
+ // Failed
+ return INFINITE;
+ }
+ else
+ {
+ UCHAR *buf;
+ UINT total;
+ UINT offset;
+
+ buf = (UCHAR *)e->Packet->Buffer;
+ total = e->Packet->ulBytesReceived;
+ offset = 0;
+
+ while (offset < total)
+ {
+ struct bpf_hdr *header;
+ UINT packet_size;
+ UCHAR *packet_data;
+
+ header = (struct bpf_hdr *)(buf + offset);
+ packet_size = header->bh_caplen;
+ offset += header->bh_hdrlen;
+ packet_data = buf + offset;
+ offset = Packet_WORDALIGN(offset + packet_size);
+
+ if (packet_size >= 14)
+ {
+ UCHAR *tmp;
+ BLOCK *b;
+
+ PROBE_DATA2("EthGetPacket: NewBlock", packet_data, packet_size);
+
+ tmp = MallocFast(packet_size);
+
+ Copy(tmp, packet_data, packet_size);
+ b = NewBlock(tmp, packet_size, 0);
+ InsertQueue(e->PacketQueue, b);
+ }
+ }
+
+ flag = true;
+ goto RETRY;
+ }
+ }
+
+ // No more packet
+ return 0;
+}
+
+// Get cancel object
+CANCEL *EthGetCancel(ETH *e)
+{
+ // Validate arguments
+ if (e == NULL)
+ {
+ return NULL;
+ }
+
+ AddRef(e->Cancel->ref);
+
+ return e->Cancel;
+}
+
+// Close adapter
+void CloseEth(ETH *e)
+{
+ BLOCK *b;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ ReleaseCancel(e->Cancel);
+
+ if (e->SuAdapter != NULL)
+ {
+ // Close SeLow adapter
+ SuCloseAdapter(e->SuAdapter);
+ SuFree(e->Su);
+ }
+ else
+ {
+ // Close SEE adapter
+ wp->PacketCloseAdapter(e->Adapter);
+ wp->PacketFreePacket(e->Packet);
+ wp->PacketFreePacket(e->PutPacket);
+ }
+
+ while (b = GetNext(e->PacketQueue))
+ {
+ FreeBlock(b);
+ }
+ ReleaseQueue(e->PacketQueue);
+
+ Free(e->Name);
+ Free(e->Title);
+ Free(e->Buffer);
+
+ Free(e);
+}
+
+// Search adapter with the name
+struct WP_ADAPTER *Win32EthSearch(char *name)
+{
+ UINT i;
+ UINT id;
+ char simple_name[MAX_SIZE];
+ WP_ADAPTER *ret = NULL;
+
+ id = Win32EthGetNameAndIdFromCombinedName(simple_name, sizeof(simple_name), name);
+
+ if (id != 0)
+ {
+ UINT num_match = 0;
+ // Search with ID when ID is specified
+ for (i = 0;i < LIST_NUM(eth_list);i++)
+ {
+ WP_ADAPTER *a = LIST_DATA(eth_list, i);
+
+ if (a->Id != 0 && a->Id == id)
+ {
+ ret = a;
+ num_match++;
+ }
+ }
+
+ if (num_match >= 2)
+ {
+ // If the ID matches to 2 or more devices, search with the name
+ for (i = 0;i < LIST_NUM(eth_list);i++)
+ {
+ WP_ADAPTER *a = LIST_DATA(eth_list, i);
+
+ if (a->Id != 0 && a->Id == id)
+ {
+ if (StrCmpi(a->Title, name) == 0)
+ {
+ ret = a;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Search with name when ID is not specified
+ for (i = 0;i < LIST_NUM(eth_list);i++)
+ {
+ WP_ADAPTER *a = LIST_DATA(eth_list, i);
+
+ if (StrCmpi(a->Title, name) == 0)
+ {
+ ret = a;
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+// Open adapter
+ETH *OpenEth(char *name, bool local, bool tapmode, char *tapaddr)
+{
+ ETH *ret;
+ void *p;
+
+ p = MsDisableWow64FileSystemRedirection();
+
+ ret = OpenEthInternal(name, local, tapmode, tapaddr);
+
+ MsRestoreWow64FileSystemRedirection(p);
+
+ return ret;
+}
+ETH *OpenEthInternal(char *name, bool local, bool tapmode, char *tapaddr)
+{
+ WP_ADAPTER *t;
+ ETH *e;
+ ADAPTER *a = NULL;
+ HANDLE h;
+ CANCEL *c;
+ MS_ADAPTER *ms;
+ char name_with_id[MAX_SIZE];
+ SU *su = NULL;
+ SU_ADAPTER *su_adapter = NULL;
+ // Validate arguments
+ if (name == NULL || IsEthSupported() == false)
+ {
+ return NULL;
+ }
+
+ if (tapmode)
+ {
+ // Tap is not supported in Windows
+ return NULL;
+ }
+
+ Lock(eth_list_lock);
+
+ InitEthAdaptersList();
+
+ t = Win32EthSearch(name);
+
+ if (t == NULL)
+ {
+ Unlock(eth_list_lock);
+ return NULL;
+ }
+
+ Debug("OpenEthInternal: %s\n", t->Name);
+
+ if (StartWith(t->Name, SL_ADAPTER_ID_PREFIX))
+ {
+ // Open with SU
+ su = SuInit();
+ if (su == NULL)
+ {
+ // Fail to initialize SU
+ Unlock(eth_list_lock);
+ return NULL;
+ }
+
+ su_adapter = SuOpenAdapter(su, t->Name);
+
+ if (su_adapter == NULL)
+ {
+ // Fail to get adapter
+ SuFree(su);
+ Unlock(eth_list_lock);
+ return NULL;
+ }
+
+ is_using_selow = true;
+ }
+ else
+ {
+ // Open with SEE
+ a = wp->PacketOpenAdapter(t->Name);
+ if (a == NULL)
+ {
+ Unlock(eth_list_lock);
+ return NULL;
+ }
+
+ if (IsWin32BridgeWithSee() == false)
+ {
+ MsSetThreadSingleCpu();
+ }
+
+ is_using_selow = false;
+ }
+
+ e = ZeroMalloc(sizeof(ETH));
+ e->Name = CopyStr(t->Name);
+
+ Win32EthMakeCombinedName(name_with_id, sizeof(name_with_id), t->Title, t->Guid);
+ e->Title = CopyStr(name_with_id);
+
+ if (su_adapter != NULL)
+ {
+ // SU
+ e->SuAdapter = su_adapter;
+ e->Su = su;
+
+ // Get event object
+ h = e->SuAdapter->hEvent;
+
+ c = NewCancelSpecial(h);
+ e->Cancel = c;
+ }
+ else
+ {
+ // SEE
+ e->Adapter = a;
+
+ wp->PacketSetBuff(e->Adapter, BRIDGE_WIN32_ETH_BUFFER);
+ wp->PacketSetHwFilter(e->Adapter, local ? 0x0080 : 0x0020);
+ wp->PacketSetMode(e->Adapter, PACKET_MODE_CAPT);
+ wp->PacketSetReadTimeout(e->Adapter, -1);
+ wp->PacketSetNumWrites(e->Adapter, 1);
+
+ if (wp->PacketSetLoopbackBehavior != NULL)
+ {
+ // Filter loopback packet in kernel
+ if (GET_KETA(GetOsType(), 100) >= 3)
+ {
+ if (MsIsWindows8() == false)
+ {
+ // Enable for Windows XP, Server 2003 or later
+ // But disable for Windows 8 or later
+ bool ret = wp->PacketSetLoopbackBehavior(e->Adapter, 1);
+ Debug("*** PacketSetLoopbackBehavior: %u\n", ret);
+
+ e->LoopbackBlock = ret;
+ }
+ }
+ }
+
+ // Get event object
+ h = wp->PacketGetReadEvent(e->Adapter);
+
+ c = NewCancelSpecial(h);
+ e->Cancel = c;
+
+ e->Packet = wp->PacketAllocatePacket();
+
+ e->PutPacket = wp->PacketAllocatePacket();
+ }
+
+ e->Buffer = Malloc(BRIDGE_WIN32_ETH_BUFFER);
+ e->BufferSize = BRIDGE_WIN32_ETH_BUFFER;
+
+ e->PacketQueue = NewQueue();
+
+ // Get MAC address by GUID
+ ms = MsGetAdapterByGuid(t->Guid);
+ if (ms != NULL)
+ {
+ if (ms->AddressSize == 6)
+ {
+ Copy(e->MacAddress, ms->Address, 6);
+ }
+
+ MsFreeAdapter(ms);
+ }
+
+ Unlock(eth_list_lock);
+
+ return e;
+}
+
+// Generate a combined name from NIC name and GUID
+void Win32EthMakeCombinedName(char *dst, UINT dst_size, char *nicname, char *guid)
+{
+ // Validate arguments
+ if (dst == NULL || nicname == NULL || guid == NULL)
+ {
+ return;
+ }
+
+ if (IsEmptyStr(guid) == false)
+ {
+ Format(dst, dst_size, "%s (ID=%010u)", nicname, Win32EthGenIdFromGuid(guid));
+ }
+ else
+ {
+ StrCpy(dst, dst_size, nicname);
+ }
+}
+
+// Decompose combined name
+UINT Win32EthGetNameAndIdFromCombinedName(char *name, UINT name_size, char *str)
+{
+ UINT ret = 0;
+ char id_str[MAX_SIZE];
+ UINT len;
+ // Validate arguments
+ ClearStr(name, name_size);
+ StrCpy(name, name_size, str);
+ if (name == NULL || str == NULL)
+ {
+ return 0;
+ }
+
+ len = StrLen(str);
+
+ if (len >= 16)
+ {
+ StrCpy(id_str, sizeof(id_str), str + len - 16);
+
+ if (StartWith(id_str, " (ID="))
+ {
+ if (EndWith(id_str, ")"))
+ {
+ char num[MAX_SIZE];
+
+ Zero(num, sizeof(num));
+ StrCpy(num, sizeof(num), id_str + 5);
+
+ num[StrLen(num) - 1] = 0;
+
+ ret = ToInt(num);
+
+ if (ret != 0)
+ {
+ name[len - 16] = 0;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+// Generate an ID from GUID
+UINT Win32EthGenIdFromGuid(char *guid)
+{
+ char tmp[MAX_SIZE];
+ UCHAR hash[SHA1_SIZE];
+ UINT i;
+ // Validate arguments
+ if (guid == NULL)
+ {
+ return 0;
+ }
+
+ StrCpy(tmp, sizeof(tmp), guid);
+ Trim(tmp);
+ StrUpper(tmp);
+
+ HashSha1(hash, tmp, StrLen(tmp));
+
+ Copy(&i, hash, sizeof(UINT));
+
+ i = Endian32(i);
+
+ if (i == 0)
+ {
+ i = 1;
+ }
+
+ return i;
+}
+
+// Get Ethernet adapter list
+TOKEN_LIST *GetEthList()
+{
+ UINT v;
+
+ return GetEthListEx(&v);
+}
+TOKEN_LIST *GetEthListEx(UINT *total_num_including_hidden)
+{
+ TOKEN_LIST *ret;
+ UINT i;
+ UINT j;
+ UINT dummy_int;
+ MS_ADAPTER_LIST *adapter_list;
+
+ if (IsEthSupported() == false)
+ {
+ return NULL;
+ }
+
+ if (total_num_including_hidden == NULL)
+ {
+ total_num_including_hidden = &dummy_int;
+ }
+
+ *total_num_including_hidden = 0;
+
+ Lock(eth_list_lock);
+
+ InitEthAdaptersList();
+
+ adapter_list = MsCreateAdapterList();
+
+ ret = ZeroMalloc(sizeof(TOKEN_LIST));
+ ret->NumTokens = LIST_NUM(eth_list);
+ ret->Token = ZeroMalloc(sizeof(char *) * ret->NumTokens);
+ j = 0;
+ for (i = 0;i < ret->NumTokens;i++)
+ {
+ char tmp[MAX_SIZE];
+ WP_ADAPTER *a = LIST_DATA(eth_list, i);
+ MS_ADAPTER *msa = NULL;
+ bool show = true;
+
+ if (Win32EthGetShowAllIf() == false)
+ {
+ msa = MsGetAdapterByGuidFromList(adapter_list, a->Guid);
+
+ if (InStr(a->Title, "vpn client adapter"))
+ {
+ // Hide virtual NIC for VPN client
+ show = false;
+ }
+
+ if (InStr(a->Title, "tunnel adapter"))
+ {
+ // Hide tunnel adapter
+ show = false;
+ }
+
+ if (InStr(a->Title, "teredo tunnel"))
+ {
+ // Hide tunnel adapter
+ show = false;
+ }
+
+ if (InStr(a->Title, "MS Tunnel Interface"))
+ {
+ // Hide tunnel adapter
+ show = false;
+ }
+
+ if (InStr(a->Title, "pseudo-interface"))
+ {
+ // Hide tunnel adapter
+ show = false;
+ }
+ }
+
+ if (msa != NULL)
+ {
+ // Hide except physical Ethernet NIC
+ if (msa->IsNotEthernetLan)
+ {
+ show = false;
+ }
+
+ MsFreeAdapter(msa);
+ }
+
+ Win32EthMakeCombinedName(tmp, sizeof(tmp), a->Title, a->Guid);
+
+ if (show)
+ {
+ ret->Token[j++] = CopyStr(tmp);
+
+ Debug("%s - %s\n", a->Guid, a->Title);
+ }
+ }
+
+ *total_num_including_hidden = ret->NumTokens;
+
+ ret->NumTokens = j;
+
+ Unlock(eth_list_lock);
+
+ MsFreeAdapterList(adapter_list);
+
+ return ret;
+}
+
+// Compare the name of WP_ADAPTER
+int CompareWpAdapter(void *p1, void *p2)
+{
+ int i;
+ WP_ADAPTER *a1, *a2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ a1 = *(WP_ADAPTER **)p1;
+ a2 = *(WP_ADAPTER **)p2;
+ if (a1 == NULL || a2 == NULL)
+ {
+ return 0;
+ }
+ i = StrCmpi(a1->Title, a2->Title);
+ return i;
+}
+
+// Get whether the SeLow is used
+bool Win32IsUsingSeLow()
+{
+ return is_using_selow;
+}
+
+// Get Ethernet adapter list
+LIST *GetEthAdapterList()
+{
+ void *p;
+ LIST *o;
+
+ p = MsDisableWow64FileSystemRedirection();
+
+ o = GetEthAdapterListInternal();
+
+ MsRestoreWow64FileSystemRedirection(p);
+
+ return o;
+}
+LIST *GetEthAdapterListInternal()
+{
+ LIST *o;
+ LIST *ret;
+ UINT size;
+ char *buf;
+ UINT i, j;
+ char *qos_tag = " (Microsoft's Packet Scheduler)";
+ SU *su = NULL;
+ LIST *su_adapter_list = NULL;
+
+ // Try to use SeLow
+ if (enable_selow)
+ {
+ su = SuInit();
+ }
+
+ o = NewListFast(CompareWpAdapter);
+
+ size = 200000;
+ buf = ZeroMalloc(size);
+
+ // Try to enumerate with SeLow
+ if (su != NULL)
+ {
+ su_adapter_list = SuGetAdapterList(su);
+
+ if (su_adapter_list == NULL)
+ {
+ // Fail to enumerate
+ SuFree(su);
+ su = NULL;
+ //WHERE;
+ is_using_selow = false;
+ }
+ else
+ {
+ //WHERE;
+ is_using_selow = true;
+ }
+ }
+ else
+ {
+ is_using_selow = false;
+ }
+
+ if (su_adapter_list != NULL)
+ {
+ // If 1 or more adapters are enumerated by SeLow, create adapter list object
+ UINT i;
+
+ for (i = 0;i < LIST_NUM(su_adapter_list);i++)
+ {
+ SU_ADAPTER_LIST *t = LIST_DATA(su_adapter_list, i);
+ WP_ADAPTER *a = ZeroMalloc(sizeof(WP_ADAPTER));
+
+ StrCpy(a->Name, sizeof(a->Name), t->Name);
+ StrCpy(a->Guid, sizeof(a->Guid), t->Guid);
+ StrCpy(a->Title, sizeof(a->Title), t->Info.FriendlyName);
+
+ TrimCrlf(a->Title);
+ Trim(a->Title);
+ TrimCrlf(a->Title);
+ Trim(a->Title);
+
+ if (EndWith(a->Title, qos_tag))
+ {
+ a->Title[StrLen(a->Title) - StrLen(qos_tag)] = 0;
+ TrimCrlf(a->Title);
+ Trim(a->Title);
+ TrimCrlf(a->Title);
+ Trim(a->Title);
+ }
+
+ Add(o, a);
+ }
+ }
+ else
+ {
+ // When SeLow is not used, create adapter list with SEE or WinPcap
+ if (wp->PacketGetAdapterNames(buf, &size) == false)
+ {
+ Free(buf);
+ return o;
+ }
+
+ i = 0;
+
+ if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType))
+ {
+ // Windows NT
+ if (size >= 2 && buf[0] != 0 && buf[1] != 0)
+ {
+ goto ANSI_STR;
+ }
+
+ while (true)
+ {
+ wchar_t tmp[MAX_SIZE];
+ WP_ADAPTER *a;
+ UniStrCpy(tmp, sizeof(tmp), L"");
+
+ if (*((wchar_t *)(&buf[i])) == 0)
+ {
+ i += sizeof(wchar_t);
+ break;
+ }
+
+ for (;*((wchar_t *)(&buf[i])) != 0;i += sizeof(wchar_t))
+ {
+ wchar_t str[2];
+ str[0] = *((wchar_t *)(&buf[i]));
+ str[1] = 0;
+ UniStrCat(tmp, sizeof(tmp), str);
+ }
+
+ i += sizeof(wchar_t);
+
+ a = ZeroMalloc(sizeof(WP_ADAPTER));
+ UniToStr(a->Name, sizeof(a->Name), tmp);
+
+ Add(o, a);
+ }
+ }
+ else
+ {
+ // Windows 9x
+ANSI_STR:
+ while (true)
+ {
+ char tmp[MAX_SIZE];
+ WP_ADAPTER *a;
+ StrCpy(tmp, sizeof(tmp), "");
+
+ if (*((char *)(&buf[i])) == 0)
+ {
+ i += sizeof(char);
+ break;
+ }
+
+ for (;*((char *)(&buf[i])) != 0;i += sizeof(char))
+ {
+ char str[2];
+ str[0] = *((char *)(&buf[i]));
+ str[1] = 0;
+ StrCat(tmp, sizeof(tmp), str);
+ }
+
+ i += sizeof(char);
+
+ a = ZeroMalloc(sizeof(WP_ADAPTER));
+ StrCpy(a->Name, sizeof(a->Name), tmp);
+
+ Add(o, a);
+ }
+ }
+
+ for (j = 0;j < LIST_NUM(o);j++)
+ {
+ WP_ADAPTER *a = LIST_DATA(o, j);
+
+ StrCpy(a->Title, sizeof(a->Title), &buf[i]);
+ i += StrSize(a->Title);
+
+ // If device description is "Unknown" in Win9x, skip 1 byte
+ if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType))
+ {
+ if (StrCmp(a->Title, "Unknown") == 0)
+ {
+ if (buf[i] == 0)
+ {
+ i+=sizeof(char);
+ }
+ }
+ }
+
+ TrimCrlf(a->Title);
+ Trim(a->Title);
+ TrimCrlf(a->Title);
+ Trim(a->Title);
+
+ if (EndWith(a->Title, qos_tag))
+ {
+ a->Title[StrLen(a->Title) - StrLen(qos_tag)] = 0;
+ TrimCrlf(a->Title);
+ Trim(a->Title);
+ TrimCrlf(a->Title);
+ Trim(a->Title);
+ }
+ }
+ }
+
+ for (j = 0;j < LIST_NUM(o);j++)
+ {
+ // Extract GUID
+ WP_ADAPTER *a = LIST_DATA(o, j);
+
+ if (IsEmptyStr(a->Guid))
+ {
+ StrCpy(a->Guid, sizeof(a->Guid), a->Name);
+ ReplaceStr(a->Guid, sizeof(a->Guid), a->Guid, "\\Device\\SEE_", "");
+ ReplaceStr(a->Guid, sizeof(a->Guid), a->Guid, "\\Device\\NPF_", "");
+ ReplaceStr(a->Guid, sizeof(a->Guid), a->Guid, "\\Device\\PCD_", "");
+ }
+ }
+
+ // Sort
+ if (su_adapter_list != NULL)
+ {
+ // Since adapter list made by SeLow is already sorted, don't sort here
+ Sort(o);
+ }
+
+ ret = NewListFast(CompareWpAdapter);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ WP_ADAPTER *a = LIST_DATA(o, i);
+ ADAPTER *ad;
+ bool is_ethernet = false;
+ bool ok = false;
+
+ if (SearchStrEx(a->Title, "ppp", 0, false) != INFINITE ||
+ SearchStrEx(a->Title, "wan", 0, false) != INFINITE ||
+ SearchStrEx(a->Title, "dialup", 0, false) != INFINITE ||
+ SearchStrEx(a->Title, "pptp", 0, false) != INFINITE ||
+ SearchStrEx(a->Title, "telepho", 0, false) != INFINITE ||
+ SearchStrEx(a->Title, "modem", 0, false) != INFINITE ||
+ SearchStrEx(a->Title, "ras", 0, false) != INFINITE)
+ {
+ Free(a);
+ continue;
+ }
+
+ // Determine whether the adapter type is Ethernet
+ if (su == NULL)
+ {
+ // Determine with See
+ ad = wp->PacketOpenAdapter(a->Name);
+ if (ad != NULL)
+ {
+ NetType type;
+ if (wp->PacketGetNetType(ad, &type))
+ {
+ if (type.LinkType == 0)
+ {
+ is_ethernet = true;
+ }
+ }
+
+ wp->PacketCloseAdapter(ad);
+ }
+ }
+ else
+ {
+ // In using SeLow, all devices should be Ethernet device
+ is_ethernet = true;
+ }
+
+ if (is_ethernet)
+ {
+ // Add only Ethernet device
+ char tmp[MAX_SIZE];
+ UINT k;
+
+ StrCpy(tmp, sizeof(tmp), a->Title);
+
+ for (k = 0;;k++)
+ {
+ if (k == 0)
+ {
+ StrCpy(tmp, sizeof(tmp), a->Title);
+ }
+ else
+ {
+ Format(tmp, sizeof(tmp), "%s (%u)", a->Title, k + 1);
+ }
+
+ ok = true;
+ for (j = 0;j < LIST_NUM(ret);j++)
+ {
+ WP_ADAPTER *aa = LIST_DATA(ret, j);
+ if (StrCmpi(aa->Title, tmp) == 0)
+ {
+ ok = false;
+ }
+ }
+
+ if (ok)
+ {
+ break;
+ }
+ }
+
+ StrCpy(a->Title, sizeof(a->Title), tmp);
+ a->Id = Win32EthGenIdFromGuid(a->Guid);
+ Add(ret, a);
+ }
+
+ if (ok == false)
+ {
+ Free(a);
+ }
+ }
+
+ Free(buf);
+
+ Sort(ret);
+
+ ReleaseList(o);
+
+ if (su != NULL)
+ {
+ SuFreeAdapterList(su_adapter_list);
+
+ SuFree(su);
+ }
+
+ return ret;
+}
+
+// Initialize Ethernet adapter list
+void InitEthAdaptersList()
+{
+ if (eth_list != NULL)
+ {
+ FreeEthAdaptersList();
+ eth_list = NULL;
+ }
+ eth_list = GetEthAdapterList();
+}
+
+// Free Ethernet adapter list
+void FreeEthAdaptersList()
+{
+ UINT i;
+ if (eth_list == NULL)
+ {
+ return;
+ }
+ for (i = 0;i < LIST_NUM(eth_list);i++)
+ {
+ WP_ADAPTER *a = LIST_DATA(eth_list, i);
+ Free(a);
+ }
+ ReleaseList(eth_list);
+ eth_list = NULL;
+}
+
+// Is the SU supported
+bool Win32EthIsSuSupported()
+{
+ bool ret = false;
+ SU *su = SuInit();
+
+ if (su != NULL)
+ {
+ ret = true;
+ }
+
+ SuFree(su);
+
+ return ret;
+}
+
+// Is the Ethernet supported
+bool IsEthSupported()
+{
+ bool ret = IsEthSupportedInner();
+
+ if (ret == false)
+ {
+ ret = Win32EthIsSuSupported();
+ }
+
+ return ret;
+}
+bool IsEthSupportedInner()
+{
+ if (wp == NULL)
+ {
+ return false;
+ }
+
+ return wp->Inited;
+}
+
+// Is the PCD driver supported in current OS
+bool IsPcdSupported()
+{
+ UINT type;
+ OS_INFO *info = GetOsInfo();
+
+ type = info->OsType;
+
+ if (OS_IS_WINDOWS_NT(type) == false)
+ {
+ // Only on Windows NT series
+ return false;
+ }
+
+ if (GET_KETA(type, 100) >= 2)
+ {
+ // Good for Windows 2000 or later
+ return true;
+ }
+
+ // Not good for Windows NT 4.0 or Longhorn
+ return false;
+}
+
+// Save build number of PCD driver
+void SavePcdDriverBuild(UINT build)
+{
+ MsRegWriteInt(REG_LOCAL_MACHINE, BRIDGE_WIN32_PCD_REGKEY, BRIDGE_WIN32_PCD_BUILDVALUE,
+ build);
+}
+
+// Load build number of PCD driver
+UINT LoadPcdDriverBuild()
+{
+ return MsRegReadInt(REG_LOCAL_MACHINE, BRIDGE_WIN32_PCD_REGKEY, BRIDGE_WIN32_PCD_BUILDVALUE);
+}
+
+// Try to install PCD driver
+HINSTANCE InstallPcdDriver()
+{
+ HINSTANCE ret;
+ void *p = MsDisableWow64FileSystemRedirection();
+
+ ret = InstallPcdDriverInternal();
+
+ MsRestoreWow64FileSystemRedirection(p);
+
+ return ret;
+}
+HINSTANCE InstallPcdDriverInternal()
+{
+ char tmp[MAX_PATH];
+ bool install_driver = true;
+ HINSTANCE h;
+ char *dll_filename;
+
+ // Confirm whether the see.sys is installed in system32\drivers folder
+ Format(tmp, sizeof(tmp), "%s\\drivers\\see.sys", MsGetSystem32Dir());
+
+ if (IsFileExists(tmp))
+ {
+ // If driver file is exist, try to get build number from registry
+ if (LoadPcdDriverBuild() >= CEDAR_BUILD)
+ {
+ // Already latest driver is installed
+ install_driver = false;
+ }
+ }
+
+ if (install_driver)
+ {
+ char *src_filename = BRIDGE_WIN32_PCD_SYS;
+ // If need to install the driver, confirm user is administrator
+ if (MsIsAdmin() == false)
+ {
+ // Non administrator can't install driver
+ return NULL;
+ }
+
+ if (MsIsX64())
+ {
+ src_filename = BRIDGE_WIN32_PCD_SYS_X64;
+ }
+
+ if (MsIsIA64())
+ {
+ src_filename = BRIDGE_WIN32_PCD_SYS_IA64;
+ }
+
+ // Copy see.sys
+ if (FileCopy(src_filename, tmp) == false)
+ {
+ return NULL;
+ }
+
+ // Save build number
+ SavePcdDriverBuild(CEDAR_BUILD);
+ }
+
+ dll_filename = BRIDGE_WIN32_PCD_DLL;
+
+ if (Is64())
+ {
+ if (MsIsX64())
+ {
+ dll_filename = BRIDGE_WIN32_PCD_DLL_X64;
+ }
+ else if (MsIsIA64())
+ {
+ dll_filename = BRIDGE_WIN32_PCD_DLL_IA64;
+ }
+ }
+
+ // Try to load see.dll and initialize
+ h = MsLoadLibrary(dll_filename);
+ if (h == NULL)
+ {
+ return NULL;
+ }
+
+ return h;
+}
+
+// Initialize Ethernet
+void InitEth()
+{
+ HINSTANCE h;
+ if (wp != NULL)
+ {
+ // Already initialized
+ return;
+ }
+
+ eth_list_lock = NewLock();
+
+ wp = ZeroMalloc(sizeof(WP));
+
+ is_see_mode = false;
+
+ if (IsPcdSupported())
+ {
+ // PCD is supported in this OS
+ h = InstallPcdDriver();
+ if (h != NULL)
+ {
+ // Try to initialize with PCD
+ if (InitWpWithLoadLibrary(wp, h) == false)
+ {
+ Debug("InitEth: SEE Failed.\n");
+ FreeLibrary(h);
+ }
+ else
+ {
+ Debug("InitEth: SEE Loaded.\n");
+ is_see_mode = true;
+ }
+ }
+ }
+
+ if (wp->Inited == false)
+ {
+ // Try to initialize with Packet.dll of WinPcap
+ h = LoadLibrary(BRIDGE_WIN32_PACKET_DLL);
+ if (h != NULL)
+ {
+ if (InitWpWithLoadLibrary(wp, h) == false)
+ {
+ Debug("InitEth: Packet.dll Failed.\n");
+ FreeLibrary(h);
+ }
+ else
+ {
+ Debug("InitEth: Packet.dll Loaded.\n");
+ }
+ }
+ }
+}
+
+// Get whether local-bridge uses see.sys
+bool IsWin32BridgeWithSee()
+{
+ return is_see_mode;
+}
+
+// Initialize WP structure with DLL
+bool InitWpWithLoadLibrary(WP *wp, HINSTANCE h)
+{
+ TOKEN_LIST *o;
+ UINT total_num = 0;
+ // Validate arguments
+ if (wp == NULL || h == NULL)
+ {
+ return false;
+ }
+ wp->Inited = true;
+ wp->hPacketDll = h;
+
+ LOAD_DLL_ADDR(PacketGetVersion);
+ LOAD_DLL_ADDR(PacketGetDriverVersion);
+ LOAD_DLL_ADDR(PacketSetMinToCopy);
+ LOAD_DLL_ADDR(PacketSetNumWrites);
+ LOAD_DLL_ADDR(PacketSetMode);
+ LOAD_DLL_ADDR(PacketSetReadTimeout);
+ LOAD_DLL_ADDR(PacketSetBpf);
+ LOAD_DLL_ADDR(PacketSetSnapLen);
+ LOAD_DLL_ADDR(PacketGetStats);
+ LOAD_DLL_ADDR(PacketGetStatsEx);
+ LOAD_DLL_ADDR(PacketSetBuff);
+ LOAD_DLL_ADDR(PacketGetNetType);
+ LOAD_DLL_ADDR(PacketOpenAdapter);
+ LOAD_DLL_ADDR(PacketSendPacket);
+ LOAD_DLL_ADDR(PacketSendPackets);
+ LOAD_DLL_ADDR(PacketAllocatePacket);
+ LOAD_DLL_ADDR(PacketInitPacket);
+ LOAD_DLL_ADDR(PacketFreePacket);
+ LOAD_DLL_ADDR(PacketReceivePacket);
+ LOAD_DLL_ADDR(PacketSetHwFilter);
+ LOAD_DLL_ADDR(PacketGetAdapterNames);
+ LOAD_DLL_ADDR(PacketGetNetInfoEx);
+ LOAD_DLL_ADDR(PacketRequest);
+ LOAD_DLL_ADDR(PacketGetReadEvent);
+ LOAD_DLL_ADDR(PacketSetDumpName);
+ LOAD_DLL_ADDR(PacketSetDumpLimits);
+ LOAD_DLL_ADDR(PacketSetDumpLimits);
+ LOAD_DLL_ADDR(PacketIsDumpEnded);
+ LOAD_DLL_ADDR(PacketStopDriver);
+ LOAD_DLL_ADDR(PacketCloseAdapter);
+ LOAD_DLL_ADDR(PacketSetLoopbackBehavior);
+
+ if (wp->PacketSetMinToCopy == NULL ||
+ wp->PacketSetNumWrites == NULL ||
+ wp->PacketSetMode == NULL ||
+ wp->PacketSetReadTimeout == NULL ||
+ wp->PacketSetBuff == NULL ||
+ wp->PacketGetNetType == NULL ||
+ wp->PacketOpenAdapter == NULL ||
+ wp->PacketSendPacket == NULL ||
+ wp->PacketSendPackets == NULL ||
+ wp->PacketAllocatePacket == NULL ||
+ wp->PacketInitPacket == NULL ||
+ wp->PacketFreePacket == NULL ||
+ wp->PacketReceivePacket == NULL ||
+ wp->PacketSetHwFilter == NULL ||
+ wp->PacketGetAdapterNames == NULL ||
+ wp->PacketGetNetInfoEx == NULL ||
+ wp->PacketCloseAdapter == NULL)
+ {
+RELEASE:
+ wp->Inited = false;
+ wp->hPacketDll = NULL;
+
+ return false;
+ }
+
+ o = GetEthListEx(&total_num);
+ if (o == NULL || total_num == 0)
+ {
+ FreeToken(o);
+ goto RELEASE;
+ }
+
+ FreeToken(o);
+
+ return true;
+}
+
+// Free Ethernet
+void FreeEth()
+{
+ if (wp == NULL)
+ {
+ // Not initialized
+ return;
+ }
+
+ // Free adapter list
+ FreeEthAdaptersList();
+
+ if (wp->Inited)
+ {
+ // Free DLL
+ FreeLibrary(wp->hPacketDll);
+ }
+
+ Free(wp);
+ wp = NULL;
+
+ DeleteLock(eth_list_lock);
+ eth_list_lock = NULL;
+}
+
+// Get network connection name from Ethernet device name
+void GetEthNetworkConnectionName(wchar_t *dst, UINT size, char *device_name)
+{
+ WP_ADAPTER *t;
+ char *tmp = NULL, guid[MAX_SIZE];
+ wchar_t *ncname = NULL;
+
+ UniStrCpy(dst, size, L"");
+
+ // Validate arguments
+ if (device_name == NULL || IsEthSupported() == false ||
+ IsNt() == false || MsIsWin2000OrGreater() == false)
+ {
+ return;
+ }
+
+ Lock(eth_list_lock);
+
+ InitEthAdaptersList();
+
+ t = Win32EthSearch(device_name);
+
+ if (t == NULL)
+ {
+ Unlock(eth_list_lock);
+ return;
+ }
+
+ tmp = CopyStr(t->Name);
+ Unlock(eth_list_lock);
+
+ if (IsEmptyStr(t->Guid) == false)
+ {
+ StrCpy(guid, sizeof(guid), t->Guid);
+
+ Free(tmp);
+ }
+ else
+ {
+ ReplaceStr(guid, sizeof(guid), tmp, "\\Device\\SEE_", "");
+ Free(tmp);
+
+ ReplaceStr(guid, sizeof(guid), guid, "\\Device\\NPF_", "");
+ ReplaceStr(guid, sizeof(guid), guid, "\\Device\\PCD_", "");
+ }
+
+ if(guid == NULL)
+ {
+ return;
+ }
+
+ ncname = MsGetNetworkConnectionName(guid);
+ if(ncname != NULL)
+ {
+ UniStrCpy(dst, size, ncname);
+ }
+ Free(ncname);
+}
+
+#endif // BRIDGE_C
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/BridgeWin32.h b/src/Cedar/BridgeWin32.h
new file mode 100644
index 00000000..2cc4615c
--- /dev/null
+++ b/src/Cedar/BridgeWin32.h
@@ -0,0 +1,238 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// BridgeWin32.h
+// Header of BridgeWin32.c
+
+#ifndef BRIDGEWIN32_H
+#define BRIDGEWIN32_H
+
+#define BRIDGE_WIN32_PACKET_DLL "Packet.dll"
+#define BRIDGE_WIN32_PCD_DLL "|see.dll"
+#define BRIDGE_WIN32_PCD_SYS "|see.sys"
+#define BRIDGE_WIN32_PCD_DLL_X64 "|see_x64.dll"
+#define BRIDGE_WIN32_PCD_SYS_X64 "|see_x64.sys"
+#define BRIDGE_WIN32_PCD_DLL_IA64 "|see_ia64.dll"
+#define BRIDGE_WIN32_PCD_SYS_IA64 "|see_ia64.sys"
+#define BRIDGE_WIN32_PCD_REGKEY "SYSTEM\\CurrentControlSet\\services\\SEE"
+#define BRIDGE_WIN32_PCD_BUILDVALUE "CurrentInstalledBuild"
+
+#define BRIDGE_WIN32_ETH_BUFFER (1048576)
+
+
+typedef void *HANDLE;
+
+#ifdef BRIDGE_C
+
+// Header for Internal function (for BridgeWin32.c)
+typedef struct WP
+{
+ bool Inited;
+ HINSTANCE hPacketDll;
+ PCHAR (*PacketGetVersion)();
+ PCHAR (*PacketGetDriverVersion)();
+ BOOLEAN (*PacketSetMinToCopy)(LPADAPTER AdapterObject,int nbytes);
+ BOOLEAN (*PacketSetNumWrites)(LPADAPTER AdapterObject,int nwrites);
+ BOOLEAN (*PacketSetMode)(LPADAPTER AdapterObject,int mode);
+ BOOLEAN (*PacketSetReadTimeout)(LPADAPTER AdapterObject,int timeout);
+ BOOLEAN (*PacketSetBpf)(LPADAPTER AdapterObject,struct bpf_program *fp);
+ INT (*PacketSetSnapLen)(LPADAPTER AdapterObject,int snaplen);
+ BOOLEAN (*PacketGetStats)(LPADAPTER AdapterObject,struct bpf_stat *s);
+ BOOLEAN (*PacketGetStatsEx)(LPADAPTER AdapterObject,struct bpf_stat *s);
+ BOOLEAN (*PacketSetBuff)(LPADAPTER AdapterObject,int dim);
+ BOOLEAN (*PacketGetNetType)(LPADAPTER AdapterObject,NetType *type);
+ LPADAPTER (*PacketOpenAdapter)(PCHAR AdapterName);
+ BOOLEAN (*PacketSendPacket)(LPADAPTER AdapterObject,LPPACKET pPacket,BOOLEAN Sync);
+ INT (*PacketSendPackets)(LPADAPTER AdapterObject,PVOID PacketBuff,ULONG Size, BOOLEAN Sync);
+ LPPACKET (*PacketAllocatePacket)(void);
+ VOID (*PacketInitPacket)(LPPACKET lpPacket,PVOID Buffer,UINT Length);
+ VOID (*PacketFreePacket)(LPPACKET lpPacket);
+ BOOLEAN (*PacketReceivePacket)(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync);
+ BOOLEAN (*PacketSetHwFilter)(LPADAPTER AdapterObject,ULONG Filter);
+ BOOLEAN (*PacketGetAdapterNames)(PTSTR pStr,PULONG BufferSize);
+ BOOLEAN (*PacketGetNetInfoEx)(PCHAR AdapterName, npf_if_addr* buffer, PLONG NEntries);
+ BOOLEAN (*PacketRequest)(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData);
+ HANDLE (*PacketGetReadEvent)(LPADAPTER AdapterObject);
+ BOOLEAN (*PacketSetDumpName)(LPADAPTER AdapterObject, void *name, int len);
+ BOOLEAN (*PacketSetDumpLimits)(LPADAPTER AdapterObject, UINT maxfilesize, UINT maxnpacks);
+ BOOLEAN (*PacketIsDumpEnded)(LPADAPTER AdapterObject, BOOLEAN sync);
+ BOOL (*PacketStopDriver)();
+ VOID (*PacketCloseAdapter)(LPADAPTER lpAdapter);
+ BOOLEAN (*PacketSetLoopbackBehavior)(LPADAPTER AdapterObject, UINT LoopbackBehavior);
+} WP;
+
+// Adapter list
+typedef struct WP_ADAPTER
+{
+ char Name[MAX_SIZE];
+ char Title[MAX_SIZE];
+ char Guid[MAX_SIZE];
+ UINT Id;
+} WP_ADAPTER;
+
+// Internal function prototype
+void InitEthAdaptersList();
+void FreeEthAdaptersList();
+int CompareWpAdapter(void *p1, void *p2);
+LIST *GetEthAdapterList();
+LIST *GetEthAdapterListInternal();
+bool InitWpWithLoadLibrary(WP *wp, HINSTANCE h);
+bool IsPcdSupported();
+HINSTANCE InstallPcdDriver();
+HINSTANCE InstallPcdDriverInternal();
+UINT LoadPcdDriverBuild();
+void SavePcdDriverBuild(UINT build);
+
+#endif // BRIDGE_C
+
+typedef struct _ADAPTER ADAPTER;
+typedef struct _PACKET PACKET;
+
+// ETH structure
+struct ETH
+{
+ char *Name; // Adapter name
+ char *Title; // Adapter title
+ ADAPTER *Adapter; // Adapter
+ CANCEL *Cancel; // Cancel object
+ UCHAR *Buffer; // Buffer
+ UINT BufferSize; // Buffer size
+ PACKET *Packet; // Packet
+ PACKET *PutPacket; // Write packet
+ QUEUE *PacketQueue; // Packet queue
+ UINT64 LastSetSingleCpu; // Date and time set to a single CPU to last
+ bool LoopbackBlock; // Whether to block the loop back packet
+ bool Empty; // It is empty
+ UCHAR MacAddress[6]; // MAC address
+ bool HasFatalError; // A fatal error occurred on the transmission side
+
+ SU *Su; // SeLow handle
+ SU_ADAPTER *SuAdapter; // SeLow adapter handle
+};
+
+// Function prototype
+void InitEth();
+void FreeEth();
+bool IsEthSupported();
+bool IsEthSupportedInner();
+TOKEN_LIST *GetEthList();
+TOKEN_LIST *GetEthListEx(UINT *total_num_including_hidden);
+ETH *OpenEth(char *name, bool local, bool tapmode, char *tapaddr);
+ETH *OpenEthInternal(char *name, bool local, bool tapmode, char *tapaddr);
+void CloseEth(ETH *e);
+CANCEL *EthGetCancel(ETH *e);
+UINT EthGetPacket(ETH *e, void **data);
+void EthPutPacket(ETH *e, void *data, UINT size);
+void EthPutPackets(ETH *e, UINT num, void **datas, UINT *sizes);
+void GetEthNetworkConnectionName(wchar_t *dst, UINT size, char *device_name);
+bool IsWin32BridgeWithSee();
+UINT EthGetMtu(ETH *e);
+bool EthSetMtu(ETH *e, UINT mtu);
+bool EthIsChangeMtuSupported(ETH *e);
+
+bool Win32EthIsSuSupported();
+
+void Win32EthSetShowAllIf(bool b);
+bool Win32EthGetShowAllIf();
+
+bool EnumEthVLanWin32(RPC_ENUM_ETH_VLAN *t);
+bool GetClassRegKeyWin32(char *key, UINT key_size, char *short_key, UINT short_key_size, char *guid);
+int CmpRpcEnumEthVLan(void *p1, void *p2);
+void GetVLanSupportStatus(RPC_ENUM_ETH_VLAN_ITEM *e);
+void GetVLanEnableStatus(RPC_ENUM_ETH_VLAN_ITEM *e);
+bool SetVLanEnableStatus(char *title, bool enable);
+RPC_ENUM_ETH_VLAN_ITEM *FindEthVLanItem(RPC_ENUM_ETH_VLAN *t, char *name);
+char *SearchDeviceInstanceIdFromShortKey(char *short_key);
+void Win32EthMakeCombinedName(char *dst, UINT dst_size, char *nicname, char *guid);
+UINT Win32EthGenIdFromGuid(char *guid);
+UINT Win32EthGetNameAndIdFromCombinedName(char *name, UINT name_size, char *str);
+
+struct WP_ADAPTER *Win32EthSearch(char *name);
+bool Win32IsUsingSeLow();
+void Win32SetEnableSeLow(bool b);
+bool Win32GetEnableSeLow();
+
+#endif // BRIDGEWIN32_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/CM.c b/src/Cedar/CM.c
new file mode 100644
index 00000000..379ee9cd
--- /dev/null
+++ b/src/Cedar/CM.c
@@ -0,0 +1,12394 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// CM.c
+// VPN Client Connection Manager for Win32
+
+#include
+
+#ifdef WIN32
+
+#define CM_C
+#define SM_C
+#define MICROSOFT_C
+
+#define _WIN32_WINNT 0x0502
+#define WINVER 0x0502
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "CMInner.h"
+#include "SMInner.h"
+#include "NMInner.h"
+#include "EMInner.h"
+#include "../PenCore/resource.h"
+
+
+// Get the proxy server settings from the registry string of IE
+bool CmGetProxyServerNameAndPortFromIeProxyRegStr(char *name, UINT name_size, UINT *port, char *str, char *server_type)
+{
+ TOKEN_LIST *t;
+ UINT i;
+ bool ret = false;
+ // Validate arguments
+ if (name == NULL || port == NULL || str == NULL || server_type == NULL)
+ {
+ return false;
+ }
+
+ t = ParseToken(str, ";");
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ char *s = t->Token[i];
+ UINT i;
+
+ Trim(s);
+
+ i = SearchStrEx(s, "=", 0, false);
+ if (i != INFINITE)
+ {
+ char tmp[MAX_PATH];
+
+ StrCpy(name, name_size, s);
+ name[i] = 0;
+
+ if (StrCmpi(name, server_type) == 0)
+ {
+ char *host;
+ StrCpy(tmp, sizeof(tmp), s + i + 1);
+
+ if (ParseHostPort(tmp, &host, port, 0))
+ {
+ StrCpy(name, name_size, host);
+ Free(host);
+
+ if (*port != 0)
+ {
+ ret = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ FreeToken(t);
+
+ return ret;
+}
+
+
+// Reflect the contents of the proxy settings to the connection settings
+void CmProxyDlgSet(HWND hWnd, CLIENT_OPTION *o, CM_INTERNET_SETTING *setting)
+{
+ // Validate arguments
+ if(hWnd == NULL || setting == NULL)
+ {
+ return;
+ }
+
+ // Make check in check-box
+ Check(hWnd, R_DIRECT_TCP, setting->ProxyType == PROXY_DIRECT);
+ Check(hWnd, R_HTTPS, setting->ProxyType == PROXY_HTTP);
+ Check(hWnd, R_SOCKS, setting->ProxyType == PROXY_SOCKS);
+
+ // Proxy Settings
+ if(setting->ProxyType != PROXY_DIRECT)
+ {
+ StrCpy(o->ProxyName, sizeof(setting->ProxyHostName), setting->ProxyHostName);
+ o->ProxyPort = setting->ProxyPort;
+ }
+}
+
+// Get the proxy settings of IE
+void CmGetSystemInternetSetting(CM_INTERNET_SETTING *setting)
+{
+ bool use_proxy;
+ // Validate arguments
+ if (setting == NULL)
+ {
+ return;
+ }
+
+ Zero(setting, sizeof(CM_INTERNET_SETTING));
+
+ use_proxy = MsRegReadInt(REG_CURRENT_USER,
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
+ "ProxyEnable");
+
+ if (use_proxy)
+ {
+ char *str = MsRegReadStr(REG_CURRENT_USER,
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
+ "ProxyServer");
+ if (str != NULL)
+ {
+ char name[MAX_HOST_NAME_LEN + 1];
+ UINT port;
+
+ if (CmGetProxyServerNameAndPortFromIeProxyRegStr(name, sizeof(name),
+ &port, str, "https"))
+ {
+ setting->ProxyType = PROXY_HTTP;
+ StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), name);
+ setting->ProxyPort = port;
+ }
+ else if (CmGetProxyServerNameAndPortFromIeProxyRegStr(name, sizeof(name),
+ &port, str, "http"))
+ {
+ setting->ProxyType = PROXY_HTTP;
+ StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), name);
+ setting->ProxyPort = port;
+ }
+ else if (CmGetProxyServerNameAndPortFromIeProxyRegStr(name, sizeof(name),
+ &port, str, "socks"))
+ {
+ setting->ProxyType = PROXY_SOCKS;
+ StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), name);
+ setting->ProxyPort = port;
+ }
+ else
+ {
+ if (SearchStrEx(str, "=", 0, false) == INFINITE)
+ {
+ char *host;
+ UINT port;
+ if (ParseHostPort(str, &host, &port, 0))
+ {
+ if (port != 0)
+ {
+ setting->ProxyType = PROXY_HTTP;
+ StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), host);
+ setting->ProxyPort = port;
+ }
+ Free(host);
+ }
+ }
+ }
+
+ Free(str);
+ }
+ }
+}
+
+// For the proxy settings to go through, use the IE settings
+void CmProxyDlgUseForIE(HWND hWnd, CLIENT_OPTION *o)
+{
+ CM_INTERNET_SETTING s;
+
+ // Validate arguments
+ if(hWnd == NULL)
+ {
+ return;
+ }
+
+ Zero(&s, sizeof(s));
+ CmGetSystemInternetSetting(&s);
+
+ CmProxyDlgSet(hWnd, o, &s);
+}
+
+// Determine the bitmap ID of the smart card authentication screen
+UINT CmGetSecureBitmapId(char *dest_hostname)
+{
+ // Validate arguments
+ if (dest_hostname == NULL)
+ {
+ return 0;
+ }
+
+ if (EndWith(dest_hostname, ".cc.tsukuba.ac.jp"))
+ {
+ return BMP_TSUKUBA;
+ }
+
+ return 0;
+}
+
+// Activate the window of UAC
+void CmSetUacWindowActive()
+{
+ HWND hWnd;
+
+ if (MsIsVista() == false)
+ {
+ return;
+ }
+
+ hWnd = FindWindowA("$$$Secure UAP Dummy Window Class For Interim Dialog", NULL);
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SwitchToThisWindow(hWnd, true);
+}
+
+// UAC helper thread
+void CmUacHelperThread(THREAD *thread, void *param)
+{
+ CM_UAC_HELPER *c = (CM_UAC_HELPER *)param;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ while (c->Halt == false)
+ {
+ CmSetUacWindowActive();
+
+ Wait(c->HaltEvent, 200);
+ }
+}
+
+// Start the UAC helper
+void *CmStartUacHelper()
+{
+ CM_UAC_HELPER *c = ZeroMalloc(sizeof(CM_UAC_HELPER));
+
+ c->HaltEvent = NewEvent();
+ c->Thread = NewThread(CmUacHelperThread, c);
+
+ return (void *)c;
+}
+
+// Stop the UAC helper
+void CmStopUacHelper(void *p)
+{
+ CM_UAC_HELPER *c = (CM_UAC_HELPER *)p;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->Halt = true;
+ Set(c->HaltEvent);
+ WaitThread(c->Thread, INFINITE);
+ ReleaseEvent(c->HaltEvent);
+ ReleaseThread(c->Thread);
+
+ Free(c);
+}
+
+// Command invocation of the simple connection manager
+void CmEasyDlgOnCommand(HWND hWnd, CM_EASY_DLG *d, WPARAM wParam, LPARAM lParam)
+{
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ switch (wParam)
+ {
+ case B_MODE:
+ Command(hWnd, CMD_CM_SETTING);
+ return;
+
+ case B_STATUS:
+ Command(hWnd, CMD_STATUS);
+ return;
+
+ case IDCANCEL:
+ Close(hWnd);
+ return;
+
+ }
+
+ if (wParam == CMD_CONNECT)
+ {
+ cm->ConnectStartedFlag = false;
+ }
+
+ CmMainWindowOnCommandEx(hWnd, wParam, lParam, true);
+
+ if (wParam == CMD_CONNECT && cm->ConnectStartedFlag)
+ {
+ // Close the window when the connection started successfully
+ Close(hWnd);
+ }
+}
+
+// Keyboard pressing of the simple connection manager
+void CmEasyDlgOnKey(HWND hWnd, CM_EASY_DLG *d, bool ctrl, bool alt, UINT key)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Single key
+ switch (key)
+ {
+ case VK_RETURN:
+ Command(hWnd, IDOK);
+ break;
+ case VK_DELETE:
+ // Delete
+ if (IsFocus(hWnd, L_ACCOUNT))
+ {
+ // Operation on the account list
+ Command(hWnd, CMD_DELETE);
+ }
+ else
+ {
+ // Operation on the virtual LAN card list
+ Command(hWnd, CMD_DELETE_VLAN);
+ }
+ break;
+ case VK_F2:
+ // Change the name
+ Command(hWnd, CMD_RENAME);
+ break;
+ case VK_F5:
+ // Update the status
+ Command(hWnd, CMD_REFRESH);
+ break;
+ }
+
+ if (alt)
+ {
+ switch (key)
+ {
+ case 'Q':
+ // Close
+ Command(hWnd, CMD_QUIT);
+ break;
+ }
+ }
+
+ if (ctrl)
+ {
+ switch (key)
+ {
+ case 'G':
+ // Smart Card Manager
+ Command(hWnd, CMD_SECURE_MANAGER);
+ break;
+ case 'S':
+ // Show the status
+ Command(hWnd, CMD_STATUS);
+ break;
+ case 'I':
+ // Disconnect all connections
+ Command(hWnd, CMD_DISCONNECT_ALL);
+ break;
+ case 'D':
+ // Disconnect
+ Command(hWnd, CMD_DISCONNECT);
+ break;
+ case 'N':
+ // Create a new connection setting
+ Command(hWnd, CMD_NEW);
+ break;
+ case 'C':
+ // Creating a copy
+ Command(hWnd, CMD_CLONE);
+ break;
+ case 'T':
+ // Set to start-up connection
+ Command(hWnd, CMD_STARTUP);
+ break;
+ case 'A':
+ // Select all
+ Command(hWnd, CMD_SELECT_ALL);
+ break;
+ case 'L':
+ // Create a new virtual LAN card
+ Command(hWnd, CMD_NEW_VLAN);
+ break;
+ case 'P':
+ // Set the password
+ Command(hWnd, CMD_PASSWORD);
+ break;
+ case 'O':
+ // Option settings
+ Command(hWnd, CMD_TRAFFIC);
+ break;
+ case 'R':
+ // Certificate management
+ Command(hWnd, CMD_TRUST);
+ break;
+ case 'Q':
+ // Throughput
+ Command(hWnd, CMD_TRAFFIC);
+ break;
+ }
+ }
+}
+
+// Operation on the list view of the simple connection manager
+void CmEasyDlgOnNotify(HWND hWnd, CM_EASY_DLG *d, NMHDR *n)
+{
+ NMLVDISPINFOW *disp_info;
+ NMLVKEYDOWN *key;
+
+ // Validate arguments
+ if (hWnd == NULL || n == NULL)
+ {
+ return;
+ }
+
+ switch (n->idFrom)
+ {
+ case L_ACCOUNT:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ CmEasyDlgUpdate(hWnd, d);
+ break;
+ case NM_DBLCLK:
+ // Double click
+ Command(hWnd, CMD_EASY_DBLCLICK);
+ break;
+ case NM_RCLICK:
+ // Right click
+ CmAccountListRightClick(hWnd);
+ break;
+ case LVN_ENDLABELEDITW:
+ // Change the name
+ disp_info = (NMLVDISPINFOW *)n;
+ if (disp_info->item.pszText != NULL)
+ {
+ wchar_t *new_name = disp_info->item.pszText;
+ wchar_t *old_name = LvGetStr(hWnd, L_ACCOUNT, disp_info->item.iItem, 0);
+
+ if (old_name != NULL)
+ {
+ if (UniStrCmp(new_name, old_name) != 0 && UniIsEmptyStr(new_name) == false)
+ {
+ RPC_RENAME_ACCOUNT a;
+ Zero(&a, sizeof(a));
+ UniStrCpy(a.OldName, sizeof(a.OldName), old_name);
+ UniStrCpy(a.NewName, sizeof(a.NewName), new_name);
+ if (CALL(hWnd, CcRenameAccount(cm->Client, &a)))
+ {
+ LvSetItem(hWnd, L_ACCOUNT, disp_info->item.iItem, 0, new_name);
+ }
+ }
+
+ Free(old_name);
+ }
+ }
+ break;
+ case LVN_KEYDOWN:
+ // Key-press
+ key = (NMLVKEYDOWN *)n;
+ if (key != NULL)
+ {
+ bool ctrl, alt;
+ UINT code = key->wVKey;
+ ctrl = (GetKeyState(VK_CONTROL) & 0x8000) == 0 ? false : true;
+ alt = (GetKeyState(VK_MENU) & 0x8000) == 0 ? false : true;
+ CmEasyDlgOnKey(hWnd, d, ctrl, alt, code);
+ }
+ break;
+ }
+ break;
+ }
+}
+
+// Send an update notification to the Simple Connection Manager
+void CmRefreshEasy()
+{
+ if (cm->hEasyWnd == NULL)
+ {
+ return;
+ }
+
+ SendMessage(cm->hEasyWnd, WM_CM_EASY_REFRESH, 0, 0);
+}
+
+// Initialze the Simple Connect Manager
+void CmEasyDlgInit(HWND hWnd, CM_EASY_DLG *d)
+{
+ HFONT hFontForList;
+ HFONT hFontButton;
+ HFONT hFontTitle;
+ HFONT hFontInfo;
+ HFONT hFontOther;
+ UINT i, num, num2, j;
+ bool b = false;
+ char *font_name = NULL;
+ bool font_bold = true;
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_VPN);
+
+ // Window handle registration
+ cm->hEasyWnd = hWnd;
+
+ // Show in the center
+ Center(hWnd);
+
+ // Update the account list
+ CmInitAccountListEx(hWnd, true);
+
+ // Font settings of the list
+ if (cm->VistaStyle)
+ {
+ if (_GETLANG() == 0)
+ {
+ font_name = "Meiryo";
+ font_bold = false;
+ }
+ else if (_GETLANG() == 2)
+ {
+ font_name = "Microsoft YaHei";
+ font_bold = false;
+ }
+ }
+
+ hFontForList = GetFont(font_name, 14, font_bold, false, false, false);
+ hFontButton = GetFont(font_name, 13, font_bold, false, false, false);
+ hFontTitle = GetFont(font_name, 14, font_bold, false, false, false);
+ hFontInfo = GetFont(font_name, 11, font_bold, false, false, false);
+ hFontOther = GetDialogDefaultFont();
+
+ if (cm->VistaStyle)
+ {
+ hFontOther = GetMeiryoFont();
+ }
+
+ SetFont(hWnd, L_ACCOUNT, hFontForList);
+ SetFont(hWnd, IDOK, hFontButton);
+ SetFont(hWnd, S_TITLE, hFontTitle);
+ SetFont(hWnd, S_INFO, hFontInfo);
+ SetFont(hWnd, B_MODE, hFontOther);
+ SetFont(hWnd, IDCANCEL, hFontOther);
+ SetFont(hWnd, B_VGC, hFontOther);
+
+ SetShow(hWnd, B_VGC, cm->Client->IsVgcSupported);
+
+ CmEasyDlgRefresh(hWnd, d);
+
+ num = LvNum(hWnd, L_ACCOUNT);
+ num2 = 0;
+ j = 0;
+ for (i = 0;i < num;i++)
+ {
+ wchar_t *str = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+
+ if (str != NULL)
+ {
+ if (UniStrCmpi(str, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(str, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+ {
+ num2++;
+ j = i;
+ }
+ Free(str);
+ }
+ }
+
+ if (num2 == 1)
+ {
+ LvSelect(hWnd, L_ACCOUNT, j);
+ b = true;
+ }
+
+ if (b == false)
+ {
+ if (UniIsEmptyStr(cm->EasyLastSelectedAccountName) == false)
+ {
+ i = LvSearchStr(hWnd, L_ACCOUNT, 0, cm->EasyLastSelectedAccountName);
+ if (i != INFINITE)
+ {
+ LvSelect(hWnd, L_ACCOUNT, i);
+ b = true;
+ }
+ }
+ }
+
+ if (b == false)
+ {
+ if (LvNum(hWnd, L_ACCOUNT) != 0)
+ {
+ LvSelect(hWnd, L_ACCOUNT, 0);
+ }
+ }
+
+ Focus(hWnd, L_ACCOUNT);
+
+ CmEasyDlgUpdate(hWnd, d);
+}
+
+// Update the Simple Connection Manager control
+void CmEasyDlgUpdate(HWND hWnd, CM_EASY_DLG *d)
+{
+ bool ok = true;
+ bool show_status = false;
+ wchar_t *button_str = _UU("CM_EASY_CONNECT_BUTTON_1");
+ wchar_t *info_str = _UU("CM_EASY_INFO_1");
+ wchar_t *title_str = _UU("CM_EASY_TITLE");
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ if (LvIsSingleSelected(hWnd, L_ACCOUNT) == false)
+ {
+ ok = false;
+ }
+
+ if (ok)
+ {
+ UINT i = LvGetSelected(hWnd, L_ACCOUNT);
+ wchar_t *str = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+
+ info_str = _UU("CM_EASY_INFO_2");
+
+ if (str != NULL)
+ {
+ if (UniStrCmpi(str, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(str, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+ {
+ button_str = _UU("CM_EASY_CONNECT_BUTTON_2");
+ show_status = true;
+ info_str = _UU("CM_EASY_INFO_3");
+
+ if (UniStrCmpi(str, _UU("CM_ACCOUNT_ONLINE")) == 0)
+ {
+ title_str = _UU("CM_EASY_CONNECTED");
+ }
+ else
+ {
+ title_str = _UU("CM_EASY_CONNECTING");
+ }
+ }
+ Free(str);
+ }
+ }
+
+ SetShow(hWnd, B_STATUS, show_status);
+
+ SetText(hWnd, IDOK, button_str);
+ SetText(hWnd, S_INFO, info_str);
+ SetText(hWnd, S_TITLE, title_str);
+
+ SetShow(hWnd, IDOK, ok);
+}
+
+// Update the Simple Connect Manager content
+void CmEasyDlgRefresh(HWND hWnd, CM_EASY_DLG *d)
+{
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ // Update the account list
+ CmRefreshAccountListEx(hWnd, true);
+
+ CmEasyDlgUpdate(hWnd, d);
+}
+
+// Dialog procedure of the simple connection manager
+UINT CmEasyDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ CM_EASY_DLG *d = (CM_EASY_DLG *)param;
+ NMHDR *n;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmEasyDlgInit(hWnd, d);
+ SetTimer(hWnd, 1, 10, NULL);
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+ SetForegroundWindow(hWnd);
+ SetActiveWindow(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CM_EASY_REFRESH:
+ CmEasyDlgRefresh(hWnd, d);
+ break;
+
+ case WM_COMMAND:
+ CmEasyDlgOnCommand(hWnd, d, wParam, lParam);
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ CmEasyDlgOnNotify(hWnd, d, n);
+ break;
+
+ case WM_CLOSE:
+ i = LvGetSelected(hWnd, L_ACCOUNT);
+ if (i != INFINITE)
+ {
+ wchar_t *s = LvGetStr(hWnd, L_ACCOUNT, i, 0);
+ if (s != NULL)
+ {
+ UniStrCpy(cm->EasyLastSelectedAccountName, sizeof(cm->EasyLastSelectedAccountName),
+ s);
+ Free(s);
+ }
+ }
+ else
+ {
+ Zero(cm->EasyLastSelectedAccountName, sizeof(cm->EasyLastSelectedAccountName));
+ }
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Show the window of the simple connection manager (This is called by a delaying timer)
+void CmMainWindowOnShowEasy(HWND hWnd)
+{
+ CM_EASY_DLG d;
+
+ Zero(&d, sizeof(d));
+
+ if (cm->CmSetting.EasyMode == false)
+ {
+ // Not in simple mode
+ return;
+ }
+
+ if (cm->hEasyWnd != NULL)
+ {
+ // It is shown already
+ SetForegroundWindow(cm->hEasyWnd);
+ SetActiveWindow(cm->hEasyWnd);
+ return;
+ }
+
+ Dialog(NULL, D_CM_EASY, CmEasyDlg, &d);
+
+ cm->hEasyWnd = NULL;
+}
+
+// Show the window of the simple connection manager
+void CmShowEasy()
+{
+ SetTimer(cm->hMainWnd, 4, 2, NULL);
+}
+
+// Close the window of the simple connection manager
+void CmCloseEasy()
+{
+ if (cm->hEasyWnd == NULL)
+ {
+ return;
+ }
+
+ SendMessage(cm->hEasyWnd, WM_CLOSE, 0, 0);
+}
+
+// Message processing for such as clicking on the tray icon
+void CmMainWindowOnTrayClicked(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+ bool easymode = cm->CmSetting.EasyMode;
+
+ switch (wParam)
+ {
+ case 1:
+ switch (lParam)
+ {
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ // Click
+ if (easymode == false)
+ {
+ if (IsEnable(hWnd, 0))
+ {
+ CmShowTrayMenu(hWnd);
+ }
+ else
+ {
+ CmShowOrHideWindow(hWnd);
+ }
+ }
+ else
+ {
+ if (cm->hEasyWnd == NULL || IsEnable(cm->hEasyWnd, 0))
+ {
+ CmShowTrayMenu(hWnd);
+ }
+ else
+ {
+ //CmShowOrHideWindow(hWnd);
+ }
+ }
+ break;
+ case WM_LBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ // Double click
+ if (easymode == false)
+ {
+ if (IsEnable(hWnd, 0))
+ {
+ CmShowOrHideWindow(hWnd);
+ }
+ }
+ else
+ {
+ if (cm->hEasyWnd == NULL)
+ {
+ CmShowEasy();
+ }
+ else
+ {
+ SetForegroundWindow(cm->hEasyWnd);
+ SetActiveWindow(cm->hEasyWnd);
+ }
+ }
+ break;
+ }
+ break;
+ }
+}
+
+// Apply the setting of the operation mode
+void CmApplyCmSetting()
+{
+ CM_SETTING a;
+ bool changed = false;
+
+ if (cm->CmSettingSupported == false)
+ {
+ return;
+ }
+
+ // Get the configuration of the current vpnclient
+ Zero(&a, sizeof(a));
+ CcGetCmSetting(cm->Client, &a);
+
+ // Check whether there is change point as compared to the previous CM_SETTING
+ if (cm->CmSetting.EasyMode != a.EasyMode)
+ {
+ changed = true;
+ }
+ if (cm->CmSetting.LockMode != a.LockMode)
+ {
+ changed = true;
+ }
+
+ Copy(&cm->CmSetting, &a, sizeof(CM_SETTING));
+
+ if (changed == false)
+ {
+ return;
+ }
+
+ if (cm->StartupFinished)
+ {
+ if (IsShow(cm->hMainWnd, 0) && cm->CmSetting.EasyMode)
+ {
+ // Close the main window if it is shown
+ Hide(cm->hMainWnd, 0);
+ }
+ else
+ {
+ WINDOWPLACEMENT current_pos;
+ if (cm->CmSetting.EasyMode == false && IsShow(cm->hMainWnd, 0) == false)
+ {
+ // When restored to normal mode, restore the main window
+ if (IsZero(&cm->FakeWindowPlacement, sizeof(cm->FakeWindowPlacement)) == false)
+ {
+ cm->FakeWindowPlacement.flags = cm->FakeWindowPlacement.flags & ~SW_MINIMIZE;
+ SetWindowPlacement(cm->hMainWnd, &cm->FakeWindowPlacement);
+ Zero(&cm->FakeWindowPlacement, sizeof(cm->FakeWindowPlacement));
+ Hide(cm->hMainWnd, 0);
+ }
+ CmShowOrHideWindow(cm->hMainWnd);
+ }
+
+ if (cm->CmSetting.EasyMode == false)
+ {
+ if (GetWindowPlacement(cm->hMainWnd, ¤t_pos))
+ {
+ if (current_pos.rcNormalPosition.right < 0 ||
+ current_pos.rcNormalPosition.bottom < 0)
+ {
+ // If the window is off the screen for some reason,
+ // return it in a visible place
+ SetWindowPos(cm->hMainWnd, NULL, 0, 0, CM_DEFAULT_WIDTH, CM_DEFAULT_HEIGHT, SWP_NOREDRAW | SWP_SHOWWINDOW);
+ Center(cm->hMainWnd);
+ }
+ }
+ }
+ }
+
+ Command(cm->hMainWnd, CMD_REFRESH);
+ }
+
+ if (cm->CmSetting.EasyMode)
+ {
+ if (cm->StartupFinished == false && cm->StartupMode)
+ {
+ // Don't show in the case of /startup
+ }
+ else
+ {
+ CmShowEasy();
+ }
+ }
+ else
+ {
+ CmCloseEasy();
+ }
+}
+
+// Initialize the operation mode changing dialog
+void CmSettingDlgInit(HWND hWnd, CM_SETTING_DLG *d)
+{
+ CM_SETTING a;
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ // Get the configuration of the current vpnclient
+ Zero(&a, sizeof(a));
+ CcGetCmSetting(cm->Client, &a);
+
+ Check(hWnd, R_EASY, a.EasyMode);
+ Check(hWnd, R_NORMAL, a.EasyMode == false);
+
+ if (a.EasyMode == false)
+ {
+ Focus(hWnd, R_NORMAL);
+ }
+ else
+ {
+ Focus(hWnd, R_EASY);
+ }
+
+ Check(hWnd, R_LOCK, a.LockMode);
+
+ SetEnable(hWnd, R_EASY, cm->CmEasyModeSupported);
+
+ if (a.LockMode)
+ {
+ if (IsZero(a.HashedPassword, sizeof(a.HashedPassword)) == false)
+ {
+ // Password is set
+ SetText(hWnd, S_PASSWORD1, _UU("CM_SETTING_PASSWORD"));
+ Hide(hWnd, S_PASSWORD3);
+ Hide(hWnd, E_PASSWORD2);
+
+ d->CheckPassword = true;
+ Copy(d->HashedPassword, a.HashedPassword, sizeof(d->HashedPassword));
+ }
+ }
+
+ SetShow(hWnd, S_VGS1, cm->Client->IsVgcSupported);
+ SetShow(hWnd, S_VGS2, cm->Client->IsVgcSupported);
+ SetShow(hWnd, S_VGS3, cm->Client->IsVgcSupported);
+ SetShow(hWnd, B_VGS, cm->Client->IsVgcSupported);
+
+ CmSettingDlgUpdate(hWnd, d);
+}
+
+// Update the operation mode changing dialog
+void CmSettingDlgUpdate(HWND hWnd, CM_SETTING_DLG *d)
+{
+ bool ok = true;
+ char tmp1[MAX_SIZE], tmp2[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ GetTxtA(hWnd, E_PASSWORD1, tmp1, sizeof(tmp1));
+ GetTxtA(hWnd, E_PASSWORD2, tmp2, sizeof(tmp2));
+
+ if (d->CheckPassword == false)
+ {
+ if (IsChecked(hWnd, R_LOCK))
+ {
+ if (StrCmp(tmp1, tmp2) != 0)
+ {
+ ok = false;
+ }
+ }
+ }
+ else
+ {
+ bool password_ok = false;
+ UCHAR hash[SHA1_SIZE];
+
+ Hash(hash, tmp1, StrLen(tmp1), true);
+ if (Cmp(hash, d->HashedPassword, sizeof(hash)) == 0)
+ {
+ password_ok = true;
+ }
+
+ if (password_ok == false)
+ {
+ Check(hWnd, R_LOCK, true);
+ Disable(hWnd, R_LOCK);
+ }
+ else
+ {
+ Enable(hWnd, R_LOCK);
+ }
+ }
+
+ SetEnable(hWnd, S_PASSWORD1, IsChecked(hWnd, R_LOCK));
+ SetEnable(hWnd, S_PASSWORD2, IsChecked(hWnd, R_LOCK));
+ SetEnable(hWnd, S_PASSWORD3, IsChecked(hWnd, R_LOCK));
+ SetEnable(hWnd, E_PASSWORD1, IsChecked(hWnd, R_LOCK));
+ SetEnable(hWnd, E_PASSWORD2, IsChecked(hWnd, R_LOCK));
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Operation mode changing dialog OK
+void CmSettingDlgOnOk(HWND hWnd, CM_SETTING_DLG *d)
+{
+ CM_SETTING a;
+ char tmp1[MAX_SIZE], tmp2[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ GetTxtA(hWnd, E_PASSWORD1, tmp1, sizeof(tmp1));
+ GetTxtA(hWnd, E_PASSWORD2, tmp2, sizeof(tmp2));
+
+ Zero(&a, sizeof(a));
+
+ a.EasyMode = IsChecked(hWnd, R_EASY);
+ a.LockMode = IsChecked(hWnd, R_LOCK);
+
+ if (a.LockMode)
+ {
+ if (d->CheckPassword && IsEnable(hWnd, R_LOCK) == false)
+ {
+ Copy(a.HashedPassword, d->HashedPassword, sizeof(a.HashedPassword));
+ }
+ else
+ {
+ if (StrLen(tmp1) >= 1)
+ {
+ Hash(a.HashedPassword, tmp1, StrLen(tmp1), true);
+ }
+ }
+ }
+
+ CcSetCmSetting(cm->Client, &a);
+
+ EndDialog(hWnd, true);
+}
+
+// Operation mode changing dialog
+UINT CmSettingDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ CM_SETTING_DLG *d = (CM_SETTING_DLG *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmSettingDlgInit(hWnd, d);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case R_EASY:
+ case R_NORMAL:
+ case R_LOCK:
+ case E_PASSWORD1:
+ case E_PASSWORD2:
+ case IDOK:
+ case IDCANCEL:
+ CmSettingDlgUpdate(hWnd, d);
+ break;
+ }
+ switch (wParam)
+ {
+ case IDOK:
+ CmSettingDlgOnOk(hWnd, d);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case R_LOCK:
+ if (IsChecked(hWnd, R_LOCK))
+ {
+ if (IsEmpty(hWnd, E_PASSWORD1))
+ {
+ Focus(hWnd, E_PASSWORD1);
+ }
+ }
+ break;
+
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+
+// Change operation mode
+bool CmSetting(HWND hWnd)
+{
+ CM_SETTING_DLG d;
+
+ Zero(&d, sizeof(d));
+
+ return Dialog(hWnd, D_CM_SETTING, CmSettingDlg, &d);
+}
+
+
+// Attempting thread for starting the UI Helper
+void CmTryToExecUiHelperThread(THREAD *thread, void *param)
+{
+ bool first_flag = true;
+
+ while (cm->TryExecUiHelperHalt == false && cm->WindowsShutdowning == false)
+ {
+ if (first_flag == false)
+ {
+ // Wait a little for other than the first time
+ Wait(cm->TryExecUiHelperHaltEvent, CM_TRY_EXEC_UI_HELPER_INTERVAL * 2);
+
+ if (cm->TryExecUiHelperHalt || cm->WindowsShutdowning)
+ {
+ break;
+ }
+ }
+ first_flag = false;
+
+ if (cm->TryExecUiHelperHalt == false && cm->WindowsShutdowning == false)
+ {
+ if (cm->TryExecUiHelperProcessHandle == NULL)
+ {
+ CmTryToExecUiHelper();
+ }
+ }
+
+ if (cm->TryExecUiHelperHalt || cm->WindowsShutdowning)
+ {
+ break;
+ }
+
+ if (cm->TryExecUiHelperProcessHandle == NULL)
+ {
+ Wait(cm->TryExecUiHelperHaltEvent, CM_TRY_EXEC_UI_HELPER_INTERVAL);
+ }
+ else
+ {
+ HANDLE handles[2];
+ handles[0] = cm->TryExecUiHelperProcessHandle;
+ handles[1] = (HANDLE)cm->TryExecUiHelperHaltEvent->pData;
+ WaitForMultipleObjects(2, handles, false, CM_TRY_EXEC_UI_HELPER_INTERVAL);
+
+ if (WaitForSingleObject(cm->TryExecUiHelperProcessHandle, 0) != WAIT_TIMEOUT)
+ {
+ CloseHandle(cm->TryExecUiHelperProcessHandle);
+ cm->TryExecUiHelperProcessHandle = NULL;
+ if (cm->TryExecUiHelperHalt || cm->WindowsShutdowning)
+ {
+ break;
+ }
+ Wait(cm->TryExecUiHelperHaltEvent, CM_TRY_EXEC_UI_HELPER_INTERVAL * 2);
+ }
+ }
+ }
+}
+
+// Stop the UI Helper
+void CmFreeTryToExecUiHelper()
+{
+ cm->TryExecUiHelperHalt = true;
+ Set(cm->TryExecUiHelperHaltEvent);
+
+ WaitThread(cm->TryExecUiHelperThread, INFINITE);
+
+ ReleaseThread(cm->TryExecUiHelperThread);
+ cm->TryExecUiHelperThread = NULL;
+
+ ReleaseEvent(cm->TryExecUiHelperHaltEvent);
+ cm->TryExecUiHelperHaltEvent = NULL;
+
+ cm->TryExecUiHelperHalt = false;
+ cm->TryExecUiHelperProcessHandle = NULL;
+}
+
+// Initialize the UI Helper starting
+void CmInitTryToExecUiHelper()
+{
+ cm->TryExecUiHelperProcessHandle = NULL;
+ cm->TryExecUiHelperHalt = false;
+ cm->TryExecUiHelperHaltEvent = NewEvent();
+ cm->TryExecUiHelperThread = NewThread(CmTryToExecUiHelperThread, NULL);
+}
+
+// Start the UI Helper
+void *CmExecUiHelperMain()
+{
+ HANDLE h;
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), L"%s\\%S", MsGetExeDirNameW(), CiGetVpnClientExeFileName());
+
+ // Start
+ h = Win32RunExW(tmp, SVC_ARG_UIHELP_W, false);
+
+ return (void *)h;
+}
+
+// Attempt to start the UI Helper
+void CmTryToExecUiHelper()
+{
+ HANDLE h;
+ // Check that it isn't already running
+ if (CnCheckAlreadyExists(false))
+ {
+ // It have already started
+ return;
+ }
+
+ h = (HANDLE)CmExecUiHelperMain();
+
+ if (h != NULL)
+ {
+ cm->TryExecUiHelperProcessHandle = h;
+ }
+}
+
+// Initialize the dialog
+void CmTrafficResultDlgInit(HWND hWnd, TT_RESULT *res)
+{
+ LVB *ct;
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ char str[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || res == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_SWITCH);
+
+ SetFont(hWnd, L_STATUS, GetFont(_SS("DEFAULT_FONT_2"), 10, false, false, false, false));
+
+ LvInit(hWnd, L_STATUS);
+ LvSetStyle(hWnd, L_STATUS, LVS_EX_GRIDLINES);
+ LvInsertColumn(hWnd, L_STATUS, 0, _UU("TTC_RES_COLUMN_1"), 100);
+ LvInsertColumn(hWnd, L_STATUS, 1, _UU("TTC_RES_COLUMN_2"), 100);
+ LvInsertColumn(hWnd, L_STATUS, 2, _UU("TTC_RES_COLUMN_3"), 100);
+
+ ct = LvInsertStart();
+
+ // Time that was used to measure
+ GetSpanStrMilli(str, sizeof(str), res->Span);
+ StrToUni(tmp, sizeof(tmp), str);
+ LvInsertAdd(ct, ICO_DATETIME, NULL, 3, _UU("TTC_RES_SPAN"), tmp, L"");
+
+ // Correct the data for Ethernet frame
+ LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_ETHER"), res->Raw ? _UU("SEC_NO") : _UU("SEC_YES"), L"");
+
+ // Amount of communication data of download direction
+ ToStr3(str, sizeof(str), res->NumBytesDownload);
+ UniFormat(tmp1, sizeof(tmp1), L"%S Bytes", str);
+ ToStrByte1000(str, sizeof(str), res->NumBytesDownload);
+ StrToUni(tmp2, sizeof(tmp2), str);
+ LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_BYTES_DOWNLOAD"), tmp1, tmp2);
+
+ // Amount of communication data of upload direction
+ ToStr3(str, sizeof(str), res->NumBytesUpload);
+ UniFormat(tmp1, sizeof(tmp1), L"%S Bytes", str);
+ ToStrByte1000(str, sizeof(str), res->NumBytesUpload);
+ StrToUni(tmp2, sizeof(tmp2), str);
+ LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_BYTES_UPLOAD"), tmp1, tmp2);
+
+ // Total amount of communication data
+ ToStr3(str, sizeof(str), res->NumBytesTotal);
+ UniFormat(tmp1, sizeof(tmp1), L"%S Bytes", str);
+ ToStrByte1000(str, sizeof(str), res->NumBytesTotal);
+ StrToUni(tmp2, sizeof(tmp2), str);
+ LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_BYTES_TOTAL"), tmp1, tmp2);
+
+ // Calculate the total throughput of input and output of the relay equipment
+ LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_DOUBLE"), (res->Double == false) ? _UU("SEC_NO") : _UU("SEC_YES"), L"");
+
+ // Average throughput of download direction
+ ToStr3(str, sizeof(str), res->BpsDownload);
+ UniFormat(tmp1, sizeof(tmp1), L"%S bps", str);
+ ToStrByte1000(str, sizeof(str), res->BpsDownload);
+ ReplaceStr(str, sizeof(str), str, "Bytes", "bps");
+ StrToUni(tmp2, sizeof(tmp2), str);
+ LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_BPS_DOWNLOAD"), tmp1, tmp2);
+
+ // Average throughput of upload direction
+ ToStr3(str, sizeof(str), res->BpsUpload);
+ UniFormat(tmp1, sizeof(tmp1), L"%S bps", str);
+ ToStrByte1000(str, sizeof(str), res->BpsUpload);
+ ReplaceStr(str, sizeof(str), str, "Bytes", "bps");
+ StrToUni(tmp2, sizeof(tmp2), str);
+ LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_BPS_UPLOAD"), tmp1, tmp2);
+
+ // Total average throughput
+ ToStr3(str, sizeof(str), res->BpsTotal);
+ UniFormat(tmp1, sizeof(tmp1), L"%S bps", str);
+ ToStrByte1000(str, sizeof(str), res->BpsTotal);
+ ReplaceStr(str, sizeof(str), str, "Bytes", "bps");
+ StrToUni(tmp2, sizeof(tmp2), str);
+ LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_BPS_TOTAL"), tmp1, tmp2);
+
+ LvInsertEnd(ct, hWnd, L_STATUS);
+
+ LvAutoSize(hWnd, L_STATUS);
+}
+
+// Dialog procedure to display results of traffic measurements
+UINT CmTrafficResultDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ TT_RESULT *r = (TT_RESULT *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmTrafficResultDlgInit(hWnd, r);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Display results of traffic measurement
+void CmTrafficResult(HWND hWnd, TT_RESULT *r)
+{
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_CM_TRAFFIC_RESULT, CmTrafficResultDlg, r);
+}
+
+// Thread to wait for the termination of the client
+void CmTrafficRunDlgClientWaitThread(THREAD *t, void *param)
+{
+ CM_TRAFFIC_DLG *d = (CM_TRAFFIC_DLG *)param;
+ TT_RESULT result;
+ UINT ret;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ Zero(&result, sizeof(result));
+ ret = FreeTtc(d->Ttc, &result);
+ d->Ttc = NULL;
+
+ d->RetCode = ret;
+ Copy(&d->Result, &result, sizeof(TT_RESULT));
+
+ PostMessage(d->hWnd, WM_APP + 66, 0, 0);
+}
+
+// Append the string
+void CmTrafficRunDlgAddStr(HWND hWnd, wchar_t *str)
+{
+ wchar_t *tmp;
+ UINT tmp_size;
+
+ tmp_size = UniStrSize(str) + 32;
+ tmp = Malloc(tmp_size);
+ UniStrCpy(tmp, tmp_size, str);
+ if (UniEndWith(str, L"\n") == false)
+ {
+ UniStrCat(tmp, tmp_size, L"\n");
+ }
+
+ UniReplaceStrEx(tmp, tmp_size, tmp, L"\r\n", L"\n", false);
+ UniReplaceStrEx(tmp, tmp_size, tmp, L"\n", L"\r\n", false);
+
+ if (MsIsNt())
+ {
+ SendMsg(hWnd, E_EDIT, EM_SETSEL, 0x7fffffff, 0x7fffffff);
+ SendMsg(hWnd, E_EDIT, EM_REPLACESEL, false, (LPARAM)tmp);
+ }
+ else
+ {
+ char *s = CopyUniToStr(tmp);
+ UINT len;
+
+ len = GetWindowTextLength(DlgItem(hWnd, E_EDIT));
+ SendMsg(hWnd, E_EDIT, EM_SETSEL, 0x7fffffff, 0x7fffffff);
+ SendMsg(hWnd, E_EDIT, EM_SETSEL, len, len);
+ SendMsg(hWnd, E_EDIT, EM_REPLACESEL, false, (LPARAM)s);
+ Free(s);
+ }
+
+ Free(tmp);
+}
+
+// Show the string
+void CmTrafficRunDlgPrintProc(void *param, wchar_t *str)
+{
+ CM_TRAFFIC_DLG *d = (CM_TRAFFIC_DLG *)param;
+ HWND hWnd;
+ // Validate arguments
+ if (param == NULL || str == NULL)
+ {
+ return;
+ }
+
+ hWnd = d->hWnd;
+
+ PostMessage(hWnd, WM_APP + 64, 0, (LPARAM)UniCopyStr(str));
+}
+
+// Thread for stop the measurement program
+void CmTrafficRunDlgHaltThread(THREAD *t, void *param)
+{
+ CM_TRAFFIC_DLG *d = (CM_TRAFFIC_DLG *)param;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ if (d->Setting->ServerMode)
+ {
+ // Stop the server
+ d->RetCode = FreeTts(d->Tts);
+
+ PostMessage(d->hWnd, WM_APP + 65, 0, 0);
+ }
+}
+
+// Stop the measurement program
+void CmTrafficRunDlgHalt(HWND hWnd, CM_TRAFFIC_DLG *d)
+{
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ if (d->Started == false)
+ {
+ return;
+ }
+
+ if (d->Setting->ServerMode)
+ {
+ if (d->HaltThread == NULL)
+ {
+ Disable(hWnd, IDCANCEL);
+ d->HaltThread = NewThread(CmTrafficRunDlgHaltThread, d);
+ }
+ }
+ else
+ {
+ if (d->ClientEndWaitThread != NULL)
+ {
+ StopTtc(d->Ttc);
+ }
+ else
+ {
+ EndDialog(hWnd, 0);
+ }
+ }
+}
+
+// Start the operation of traffic measurement
+void CmTrafficRunDlgStart(HWND hWnd, CM_TRAFFIC_DLG *d)
+{
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ if (d->Setting->ServerMode)
+ {
+ // Start the measurement server
+ d->Tts = NewTts(d->Setting->Port, d, CmTrafficRunDlgPrintProc);
+ }
+ else
+ {
+ // Start the measurement client
+ d->Ttc = NewTtc(d->Setting->Host, d->Setting->Port,
+ d->Setting->NumTcp, d->Setting->Type, d->Setting->Span * 1000ULL,
+ d->Setting->Double, d->Setting->Raw, CmTrafficRunDlgPrintProc, d);
+
+ d->ClientEndWaitThread = NewThread(CmTrafficRunDlgClientWaitThread, d);
+ }
+
+ d->Started = true;
+}
+
+// Traffic measurement operation dialog initialization
+void CmTrafficRunDlgInit(HWND hWnd, CM_TRAFFIC_DLG *d)
+{
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ d->hWnd = hWnd;
+
+ SetIcon(hWnd, 0, ICO_SWITCH);
+ DlgFont(hWnd, S_INFO, 11, false);
+ SetFont(hWnd, E_EDIT, GetFont(_SS("DEFAULT_FONT_2"), 0, false, false,
+ false, false));
+
+ Focus(hWnd, IDCANCEL);
+}
+
+// Traffic measurement operation dialog procedure
+UINT CmTrafficRunDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ CM_TRAFFIC_DLG *d = (CM_TRAFFIC_DLG *)param;
+ wchar_t *s;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmTrafficRunDlgInit(hWnd, d);
+
+ SetTimer(hWnd, 1, 10, NULL);
+ break;
+
+ case WM_APP + 64:
+ // Add a string
+ s = (wchar_t *)lParam;
+ if (s != NULL)
+ {
+ CmTrafficRunDlgAddStr(hWnd, s);
+ Free(s);
+ }
+ break;
+
+ case WM_APP + 65:
+ // Stopping complete
+ if (d->HaltThread != NULL)
+ {
+ WaitThread(d->HaltThread, INFINITE);
+ ReleaseThread(d->HaltThread);
+ d->HaltThread = NULL;
+ EndDialog(hWnd, 0);
+ }
+ break;
+
+ case WM_APP + 66:
+ // Show results
+ if (d->RetCode == ERR_NO_ERROR)
+ {
+ CmTrafficResult(hWnd, &d->Result);
+ }
+
+ if (d->ClientEndWaitThread != NULL)
+ {
+ WaitThread(d->ClientEndWaitThread, INFINITE);
+ ReleaseThread(d->ClientEndWaitThread);
+ d->ClientEndWaitThread = NULL;
+ }
+
+ if (d->CloseDialogAfter)
+ {
+ EndDialog(hWnd, 0);
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+
+ CmTrafficRunDlgStart(hWnd, d);
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ d->CloseDialogAfter = true;
+ CmTrafficRunDlgHalt(hWnd, d);
+ return 1;
+ }
+
+ return 0;
+}
+
+// Execute a traffic measurement
+void CmExecTraffic(HWND hWnd, CM_TRAFFIC *t)
+{
+ CM_TRAFFIC_DLG d;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Zero(&d, sizeof(d));
+ d.Setting = t;
+ d.ResultShowEvent = NewEvent();
+
+ MsSetThreadPriorityHigh();
+ Dialog(hWnd, D_CM_TRAFFIC_RUN, CmTrafficRunDlg, &d);
+ MsRestoreThreadPriority();
+
+ ReleaseEvent(d.ResultShowEvent);
+}
+
+// Write the settings to the registry
+void CmTrafficSaveToReg(CM_TRAFFIC *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "ServerMode", t->ServerMode ? 1 : 0);
+ MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Double", t->Double ? 1 : 0);
+ MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Raw", t->Raw ? 1 : 0);
+ MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Port", t->Port);
+ MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "NumTcp", t->NumTcp);
+ MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Type", t->Type);
+ MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Span", t->Span);
+ MsRegWriteStr(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Host", t->Host);
+}
+
+// Read the settings from the registry
+bool CmTrafficLoadFromReg(CM_TRAFFIC *t)
+{
+ char *s;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return false;
+ }
+
+ Zero(t, sizeof(CM_TRAFFIC));
+
+ if (MsRegIsKey(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY) == false)
+ {
+ return false;
+ }
+
+ t->Double = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Double") == 0 ? false : true;
+ t->Raw = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Raw") == 0 ? false : true;
+ t->Port = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Port");
+ if (t->Port == 0)
+ {
+ t->Port = TRAFFIC_DEFAULT_PORT;
+ }
+
+ s = MsRegReadStr(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Host");
+
+ if (IsEmptyStr(s) == false)
+ {
+ Trim(s);
+ StrCpy(t->Host, sizeof(t->Host), s);
+ }
+
+ Free(s);
+
+ t->NumTcp = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "NumTcp");
+ t->NumTcp = MAKESURE(t->NumTcp, 1, TRAFFIC_NUMTCP_MAX);
+ t->Type = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Type");
+
+ if (t->Type != TRAFFIC_TYPE_DOWNLOAD && t->Type != TRAFFIC_TYPE_UPLOAD &&
+ t->Type != TRAFFIC_TYPE_FULL)
+ {
+ t->Type = TRAFFIC_TYPE_FULL;
+ }
+
+ t->Span = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Span");
+ if (t->Span == 0)
+ {
+ t->Span = TRAFFIC_SPAN_DEFAULT;
+ }
+
+ t->ServerMode = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "ServerMode") == 0 ? false : true;
+
+ return true;
+}
+
+// Get the default settings
+void CmTrafficGetDefaultSetting(CM_TRAFFIC *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(CM_TRAFFIC));
+
+ t->Double = false;
+ t->Raw = false;
+ t->Port = TRAFFIC_DEFAULT_PORT;
+ t->NumTcp = TRAFFIC_NUMTCP_DEFAULT;
+ t->Type = TRAFFIC_TYPE_FULL;
+ t->Span = TRAFFIC_SPAN_DEFAULT;
+ t->ServerMode = false;
+}
+
+// Communication throughput measurement tool dialog initialization
+void CmTrafficDlgInit(HWND hWnd)
+{
+ CM_TRAFFIC t;
+ LIST *c1, *c2;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ DlgFont(hWnd, S_8, 9, true);
+ DlgFont(hWnd, S_3, 9, true);
+
+ Zero(&t, sizeof(t));
+ if (CmTrafficLoadFromReg(&t) == false)
+ {
+ CmTrafficGetDefaultSetting(&t);
+ }
+
+ // Write the settings to the dialog
+ Check(hWnd, R_SERVER, t.ServerMode);
+ Check(hWnd, R_CLIENT, t.ServerMode == false);
+
+ c1 = ReadCandidateFromReg(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "HostCandidate");
+ if (c1 != NULL)
+ {
+ UINT i;
+
+ CbReset(hWnd, C_HOST);
+
+ for (i = 0;i < LIST_NUM(c1);i++)
+ {
+ CANDIDATE *c = LIST_DATA(c1, i);
+
+ CbAddStr(hWnd, C_HOST, c->Str, 0);
+ }
+
+ FreeCandidateList(c1);
+ }
+
+ if (CbNum(hWnd, C_HOST) == 0)
+ {
+ CbAddStr(hWnd, C_HOST, L"speed.softether.com", 0);
+ }
+
+ if (IsEmptyStr(t.Host) == false)
+ {
+ SetTextA(hWnd, C_HOST, t.Host);
+ }
+
+ c2 = ReadCandidateFromReg(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "PortCandidate");
+ if (c2 != NULL)
+ {
+ UINT i;
+
+ if (t.Port != 0)
+ {
+ wchar_t tmp[32];
+
+ UniToStru(tmp, t.Port);
+
+ AddCandidate(c2, tmp, 0);
+ }
+
+ CbReset(hWnd, C_PORT);
+
+ for (i = 0;i < LIST_NUM(c2);i++)
+ {
+ CANDIDATE *c = LIST_DATA(c2, i);
+
+ CbAddStr(hWnd, C_PORT, c->Str, 0);
+ }
+
+ FreeCandidateList(c2);
+ }
+
+ CbReset(hWnd, C_NUM);
+
+ for (i = 1;i <= TRAFFIC_NUMTCP_MAX;i++)
+ {
+ wchar_t tmp[32];
+
+ UniToStru(tmp, i);
+
+ CbAddStr(hWnd, C_NUM, tmp, i);
+ }
+
+ CbSelect(hWnd, C_NUM, t.NumTcp);
+
+ Check(hWnd, R_DOWNLOAD, t.Type == TRAFFIC_TYPE_DOWNLOAD);
+ Check(hWnd, R_UPLOAD, t.Type == TRAFFIC_TYPE_UPLOAD);
+ Check(hWnd, R_FULL, t.Type == TRAFFIC_TYPE_FULL);
+
+ Check(hWnd, R_ETHERNET, t.Raw ? false : true);
+ Check(hWnd, R_DOUBLE, t.Double);
+
+ SetIntEx(hWnd, E_SPAN, t.Span);
+
+ CmTrafficDlgUpdate(hWnd);
+}
+
+// Put the contents of the dialog to structure
+void CmTrafficDlgToStruct(HWND hWnd, CM_TRAFFIC *t)
+{
+ // Validate arguments
+ if (hWnd == NULL || t == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(CM_TRAFFIC));
+ t->ServerMode = IsChecked(hWnd, R_SERVER);
+ GetTxtA(hWnd, C_HOST, t->Host, sizeof(t->Host));
+ Trim(t->Host);
+
+ t->Port = GetInt(hWnd, C_PORT);
+ t->NumTcp = CbGetSelect(hWnd, C_NUM);
+ t->Span = GetInt(hWnd, E_SPAN);
+ t->Raw = IsChecked(hWnd, R_ETHERNET) ? false : true;
+ t->Double = IsChecked(hWnd, R_DOUBLE);
+
+ if (IsChecked(hWnd, R_DOWNLOAD))
+ {
+ t->Type = TRAFFIC_TYPE_DOWNLOAD;
+ }
+ else if (IsChecked(hWnd, R_UPLOAD))
+ {
+ t->Type = TRAFFIC_TYPE_UPLOAD;
+ }
+ else
+ {
+ t->Type = TRAFFIC_TYPE_FULL;
+ }
+}
+
+// Communication throughput measurement tool dialog update
+bool CmTrafficDlgUpdate(HWND hWnd)
+{
+ CM_TRAFFIC t;
+ bool ok = true;
+ bool client_only;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return false;
+ }
+
+ CmTrafficDlgToStruct(hWnd, &t);
+
+ client_only = t.ServerMode ? false : true;
+
+ SetEnable(hWnd, C_HOST, client_only);
+ SetEnable(hWnd, S_5, client_only);
+ SetEnable(hWnd, S_8, client_only);
+ SetEnable(hWnd, S_9, client_only);
+ SetEnable(hWnd, R_DOWNLOAD, client_only);
+ SetEnable(hWnd, R_UPLOAD, client_only);
+ SetEnable(hWnd, R_FULL, client_only);
+ SetEnable(hWnd, S_10, client_only);
+ SetEnable(hWnd, S_11, client_only);
+ SetEnable(hWnd, C_NUM, client_only);
+ SetEnable(hWnd, S_14, client_only);
+ SetEnable(hWnd, S_12, client_only);
+ SetEnable(hWnd, E_SPAN, client_only);
+ SetEnable(hWnd, S_13, client_only);
+ SetEnable(hWnd, R_ETHERNET, client_only);
+ SetEnable(hWnd, R_DOUBLE, client_only);
+
+ if (t.Port == 0 || t.Port >= 65536)
+ {
+ ok = false;
+ }
+
+ if (t.ServerMode == false)
+ {
+ if (IsEmptyStr(t.Host))
+ {
+ ok = false;
+ }
+
+ if (t.NumTcp == 0 || t.NumTcp >= 33)
+ {
+ ok = false;
+ }
+
+ if (t.Span == 0)
+ {
+ ok = false;
+ }
+
+ if (t.Type == TRAFFIC_TYPE_FULL && ((t.NumTcp % 2) != 0))
+ {
+ ok = false;
+ }
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+
+ return ok;
+}
+
+// Communication throughput measurement tool dialog OK button
+void CmTrafficDlgOnOk(HWND hWnd)
+{
+ CM_TRAFFIC t;
+ LIST *c;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Get the basic data
+ CmTrafficDlgToStruct(hWnd, &t);
+
+ // Save to registry
+ CmTrafficSaveToReg(&t);
+
+ // Retrieve and save the server name candidate
+ if (IsEmptyStr(t.Host) == false)
+ {
+ c = ReadCandidateFromReg(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "HostCandidate");
+ if (c != NULL)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ StrToUni(tmp, sizeof(tmp), t.Host);
+ AddCandidate(c, tmp, 0);
+
+ WriteCandidateToReg(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, c, "HostCandidate");
+
+ FreeCandidateList(c);
+ }
+ }
+
+ if (t.Port != 0 && t.Port <= 65536)
+ {
+ // Retrieve and store the port number candidate
+ c = ReadCandidateFromReg(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "PortCandidate");
+ if (c != NULL)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniToStru(tmp, t.Port);
+ AddCandidate(c, tmp, 0);
+
+ WriteCandidateToReg(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, c, "PortCandidate");
+
+ FreeCandidateList(c);
+ }
+ }
+
+ // Execute
+ CmExecTraffic(hWnd, &t);
+
+ // Update the dialog
+ CmTrafficDlgInit(hWnd);
+}
+
+// Communication throughput measurement tool dialog procedure
+UINT CmTrafficDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetIcon(hWnd, 0, ICO_SWITCH);
+ CmTrafficDlgInit(hWnd);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case R_SERVER:
+ case R_CLIENT:
+ case C_HOST:
+ case C_PORT:
+ case R_DOWNLOAD:
+ case R_UPLOAD:
+ case R_FULL:
+ case C_NUM:
+ case E_SPAN:
+ case R_ETHERNET:
+ case R_DOUBLE:
+ CmTrafficDlgUpdate(hWnd);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ CmTrafficDlgOnOk(hWnd);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Communication throughput measurement tool
+void CmTraffic(HWND hWnd)
+{
+ Dialog(hWnd, D_CM_TRAFFIC, CmTrafficDlgProc, NULL);
+}
+
+// Delete old startup file
+void CmDeleteOldStartupTrayFile()
+{
+ char tmp[MAX_SIZE];
+ char *tag = _SS("CM_JAPANESE_ONLY_OLD_STARTUP");
+ if (IsEmptyStr(tag))
+ {
+ return;
+ }
+
+ Format(tmp, sizeof(tmp), tag, MsGetCommonStartupDir());
+
+ FileDelete(tmp);
+}
+
+// PKCS license confirmation dialog
+UINT CmPkcsEulaDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ UINT id;
+ SECURE_DEVICE *dev;
+ char *name;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ id = (UINT)param;
+ dev = GetSecureDevice(id);
+ if (dev == NULL)
+ {
+ EndDialog(hWnd, 0);
+ return 0;
+ }
+
+ name = dev->ModuleName;
+
+ FormatText(hWnd, S_INFO_1, name);
+ FormatText(hWnd, S_INFO_2, name, name);
+ FormatText(hWnd, S_INFO_3, name);
+
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ EndDialog(hWnd, 1);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Confirmation screen of whether the user accepts the EULA of the PKCS DLL
+bool CmCheckPkcsEula(HWND hWnd, UINT id)
+{
+ return (Dialog(hWnd, D_CM_PKCSEULA, CmPkcsEulaDlg, (void *)id) == 0) ? false : true;
+}
+
+// Update controls
+void CmSecurePinDlgUpdate(HWND hWnd)
+{
+ char *tmp1, *tmp2, *tmp3;
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ tmp1 = GetTextA(hWnd, E_PIN1);
+ tmp2 = GetTextA(hWnd, E_PIN2);
+ tmp3 = GetTextA(hWnd, E_PIN3);
+ if (IsEmptyStr(tmp1))
+ {
+ ok = false;
+ }
+ if (IsEmptyStr(tmp2))
+ {
+ ok = false;
+ }
+ if (IsEmptyStr(tmp3))
+ {
+ ok = false;
+ }
+ if (StrCmp(tmp2, tmp3) != 0)
+ {
+ ok = false;
+ }
+ Free(tmp1);
+ Free(tmp2);
+ Free(tmp3);
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// PIN code changing dialog
+UINT CmSecurePinDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ UINT id = (UINT)param;
+ char *src, *dst;
+ SECURE *s;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmSecurePinDlgUpdate(hWnd);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_PIN1:
+ case E_PIN2:
+ case E_PIN3:
+ CmSecurePinDlgUpdate(hWnd);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ src = GetTextA(hWnd, E_PIN1);
+ dst = GetTextA(hWnd, E_PIN3);
+
+ Disable(hWnd, IDOK);
+ Disable(hWnd, IDCANCEL);
+
+ s = OpenSec(id);
+ if (s == NULL)
+ {
+ if (GetSecureDevice(id) != NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SEC_PIN_DEVICE_OPEN_ERR"),
+ GetSecureDevice(id)->DeviceName);
+ }
+ else
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SEC_PIN_DEVICE_OPEN_ERR"),
+ "Unknown");
+ }
+ }
+ else
+ {
+ if (OpenSecSession(s, 0) == false)
+ {
+ if (GetSecureDevice(id) != NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SEC_PIN_DEVICE_OPEN_ERR"),
+ GetSecureDevice(id)->DeviceName);
+ }
+ else
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SEC_PIN_DEVICE_OPEN_ERR"),
+ "Unknown");
+ }
+ }
+ else
+ {
+ if (LoginSec(s, src) == false)
+ {
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SEC_PIN_CURRENT_BAD"));
+ FocusEx(hWnd, E_PIN1);
+ }
+ else
+ {
+ if (ChangePin(s, src, dst) == false)
+ {
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SEC_PIN_CHANGE_FAILED"));
+ FocusEx(hWnd, E_PIN1);
+ }
+ else
+ {
+ // Clear the cache for PIN code
+ cached_pin_code_expires = 0;
+ cached_pin_code[0] = 0;
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SEC_PIN_OK"));
+ EndDialog(hWnd, true);
+ }
+
+ LogoutSec(s);
+ }
+
+ CloseSecSession(s);
+ }
+ CloseSec(s);
+ }
+
+ Enable(hWnd, IDOK);
+ Enable(hWnd, IDCANCEL);
+
+ Free(src);
+ Free(dst);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Change the PIN code
+void CmSecurePin(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL || id == 0 || CheckSecureDeviceId(id) == false)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_CM_SECURE_PIN, CmSecurePinDlg, (void *)id);
+}
+
+// Object type selection dialog
+UINT CmSecureTypeDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ UINT type;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ type = MsRegReadInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "DefaultImportType");
+ Check(hWnd, R_DATA, type == SEC_DATA);
+ Check(hWnd, R_CERT, type == SEC_X);
+ Check(hWnd, R_KEY, type == SEC_K);
+ goto UPDATE_CONTROL;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ type = SEC_DATA;
+ if (IsChecked(hWnd, R_CERT))
+ {
+ type = SEC_X;
+ }
+ else if (IsChecked(hWnd, R_KEY))
+ {
+ type = SEC_K;
+ }
+
+ MsRegWriteInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "DefaultImportType", type);
+
+ EndDialog(hWnd, type);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ case R_CERT:
+ case R_KEY:
+ case R_DATA:
+UPDATE_CONTROL:
+ SetEnable(hWnd, IDOK, IsChecked(hWnd, R_CERT) ||
+ IsChecked(hWnd, R_KEY) ||
+ IsChecked(hWnd, R_DATA));
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, INFINITE);
+ break;
+ }
+
+ return 0;
+}
+
+// Object type selection
+UINT CmSecureType(HWND hWnd)
+{
+ return Dialog(hWnd, D_CM_SECURE_TYPE, CmSecureTypeDlg, NULL);
+}
+
+// Initialize the dialog
+void CmSecureManagerDlgInit(HWND hWnd, UINT id)
+{
+ SECURE_DEVICE *dev;
+ // Validate arguments
+ if (hWnd == NULL || id == 0)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_SECURE);
+
+ dev = GetSecureDevice(id);
+ if (dev != NULL)
+ {
+ FormatText(hWnd, S_INFO, dev->DeviceName);
+ }
+
+ SetFont(hWnd, B_BOLD, Font(0, true));
+
+ LvInit(hWnd, L_LIST);
+ LvInsertColumn(hWnd, L_LIST, 0, _UU("SEC_MGR_COLUMN1"), 200);
+ LvInsertColumn(hWnd, L_LIST, 1, _UU("SEC_MGR_COLUMN2"), 110);
+
+ CmSecureManagerDlgUpdate(hWnd, id);
+}
+
+// Update controls
+void CmSecureManagerDlgUpdate(HWND hWnd, UINT id)
+{
+ bool b = true;
+ bool read_only = IsJPKI(id);
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (LvIsSingleSelected(hWnd, L_LIST) == false)
+ {
+ b = false;
+ }
+
+ SetEnable(hWnd, B_EXPORT, b && ((UINT)LvGetParam(hWnd, L_LIST, LvGetSelected(hWnd, L_LIST)) != SEC_K));
+ SetEnable(hWnd, B_DELETE, b && (read_only == false));
+ SetEnable(hWnd, B_PIN, (read_only == false));
+ SetEnable(hWnd, B_IMPORT, (read_only == false));
+ SetEnable(hWnd, B_NEW_CERT, (read_only == false));
+}
+
+// Content update
+void CmSecureManagerDlgRefresh(HWND hWnd, UINT id)
+{
+ bool ret;
+ LIST *o;
+ WINUI_SECURE_BATCH batch[] =
+ {
+ {WINUI_SECURE_ENUM_OBJECTS, NULL, false, NULL, NULL, NULL, NULL, NULL, NULL},
+ };
+ // Validate arguments
+ if (hWnd == NULL || id == 0)
+ {
+ return;
+ }
+
+ ret = SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0);
+
+ if (ret == false)
+ {
+ return;
+ }
+
+ o = batch[0].EnumList;
+ if (o != NULL)
+ {
+ CmSecureManagerDlgPrintList(hWnd, o);
+
+ FreeEnumSecObject(o);
+ }
+
+ // update controls
+ CmSecureManagerDlgUpdate(hWnd, id);
+}
+
+// Show the list of secure objects
+void CmSecureManagerDlgPrintList(HWND hWnd, LIST *o)
+{
+ CmSecureManagerDlgPrintListEx(hWnd, L_LIST, o, INFINITE);
+}
+void CmSecureManagerDlgPrintListEx(HWND hWnd, UINT id, LIST *o, UINT type)
+{
+ UINT i;
+ LVB *v;
+ // Validate arguments
+ if (hWnd == NULL || o == NULL)
+ {
+ return;
+ }
+
+ LvReset(hWnd, id);
+
+ v = LvInsertStart();
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ UINT icon = ICO_LOG2;
+ wchar_t tmp1[MAX_SIZE], *tmp2, *tmp3;
+ SEC_OBJ *obj = LIST_DATA(o, i);
+
+ if (type == INFINITE || obj->Type == type)
+ {
+ StrToUni(tmp1, sizeof(tmp1), obj->Name);
+ tmp2 = CmSecureObjTypeToStr(obj->Type);
+ tmp3 = obj->Private ? _UU("SEC_YES") : _UU("SEC_NO");
+
+ if (obj->Type == SEC_X)
+ {
+ icon = ICO_CERT;
+ }
+ else if (obj->Type == SEC_K || obj->Type == SEC_P)
+ {
+ icon = ICO_KEY;
+ }
+
+ LvInsertAdd(v, icon, (void *)obj->Type, 2, tmp1, tmp2);
+ }
+ }
+
+ LvInsertEnd(v, hWnd, id);
+}
+
+// Convert the type of secure object to a string
+wchar_t *CmSecureObjTypeToStr(UINT type)
+{
+ wchar_t *ret = _UU("SEC_TYPE_DATA");
+
+ if (type == SEC_X)
+ {
+ ret = _UU("SEC_TYPE_CERT");
+ }
+ else if (type == SEC_K)
+ {
+ ret = _UU("SEC_TYPE_KEY");
+ }
+ else if (type == SEC_P)
+ {
+ ret = _UU("SEC_TYPE_PUB");
+ }
+
+ return ret;
+}
+
+// Write by creating a new certificate
+void CmSecureManagerDlgNewCert(HWND hWnd, UINT id)
+{
+ X *x;
+ K *k;
+ char default_name[MAX_SIZE];
+ char *object_name;
+ bool ok = false;
+ WINUI_SECURE_BATCH batch[] =
+ {
+ {WINUI_SECURE_WRITE_CERT, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL},
+ {WINUI_SECURE_WRITE_KEY, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL},
+ {WINUI_SECURE_ENUM_OBJECTS, NULL, false, NULL, NULL, NULL, NULL, NULL, NULL},
+ };
+ // Validate arguments
+ if (hWnd == NULL || id == 0)
+ {
+ return;
+ }
+
+ // Dialog for creating certificate
+ if (SmCreateCert(hWnd, &x, &k, true, NULL, false) == false)
+ {
+ return;
+ }
+ // Generate the default name
+ GetPrintNameFromXA(default_name, sizeof(default_name), x);
+ ConvertSafeFileName(default_name, sizeof(default_name), default_name);
+
+ object_name = StringDlgA(hWnd, _UU("SEC_OBJECT_NAME_TITLE"),
+ _UU("SEC_OBJECT_NAME_INFO"), default_name, ICO_CERT, false, false);
+
+ if (object_name != NULL)
+ {
+ // Enumerate and write
+ batch[0].InputX = x;
+ batch[0].Name = object_name;
+ batch[1].InputK = k;
+ batch[1].Name = object_name;
+
+ if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0) == false)
+ {
+ // Failure
+ }
+ else
+ {
+ ok = true;
+ }
+
+ Free(object_name);
+ }
+
+ if (ok)
+ {
+ LIST *o = batch[2].EnumList;
+
+ CmSecureManagerDlgPrintList(hWnd, o);
+
+ FreeEnumSecObject(o);
+
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SEC_NEW_CERT_IMPORT_OK"));
+ }
+
+ FreeX(x);
+ FreeK(k);
+}
+
+// Import
+void CmSecureManagerDlgImport(HWND hWnd, UINT id)
+{
+ UINT type;
+ char name[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t *tmp;
+ wchar_t *filename;
+ BUF *b;
+ K *k;
+ bool ok = false;
+ X *x;
+ WINUI_SECURE_BATCH batch[] =
+ {
+ {WINUI_SECURE_WRITE_DATA, name, true, NULL, NULL, NULL, NULL, NULL, NULL},
+ {WINUI_SECURE_ENUM_OBJECTS, NULL, false, NULL, NULL, NULL, NULL, NULL, NULL},
+ };
+ // Validate arguments
+ if (hWnd == NULL || id == 0)
+ {
+ return;
+ }
+
+ // Select the type of secure object
+ type = CmSecureType(hWnd);
+
+ switch (type)
+ {
+ case SEC_DATA:
+ // Data
+ tmp = OpenDlg(hWnd, _UU("DLG_ALL_FILES"), _UU("SEC_IMPORT_DATA"));
+ if (tmp == NULL)
+ {
+ return;
+ }
+
+ filename = CopyUniStr(tmp);
+ Free(tmp);
+
+ // Read the file
+ b = ReadDumpW(filename);
+ if (b == NULL)
+ {
+ // Read failure
+ MsgBox(hWnd, MB_ICONSTOP, _UU("SEC_READ_FAILED"));
+ }
+ else
+ {
+ if (b->Size > MAX_SEC_DATA_SIZE)
+ {
+ // File size is too large
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SEC_DATA_TOO_BIG"), MAX_SEC_DATA_SIZE);
+ }
+ else
+ {
+ // Generate the default name
+ char default_name[MAX_SIZE];
+ wchar_t default_name_w[MAX_SIZE];
+ char *object_name;
+ GetFileNameFromFilePathW(default_name_w, sizeof(default_name_w), filename);
+ UniToStr(default_name, sizeof(default_name), default_name_w);
+ ConvertSafeFileName(default_name, sizeof(default_name), default_name);
+
+ object_name = StringDlgA(hWnd, _UU("SEC_OBJECT_NAME_TITLE"),
+ _UU("SEC_OBJECT_NAME_INFO"), default_name, ICO_LOG2, false, false);
+
+ if (object_name != NULL)
+ {
+ // Enumerate and write
+ batch[0].InputData = b;
+ batch[0].Name = object_name;
+
+ if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0) == false)
+ {
+ // Failure
+ }
+ else
+ {
+ ok = true;
+ }
+
+ Free(object_name);
+ }
+ }
+
+ FreeBuf(b);
+ }
+
+ Free(filename);
+ break;
+
+ case SEC_X:
+ // Read a certificate
+ if (CmLoadXExW(hWnd, &x, tmp2, sizeof(tmp2)))
+ {
+ // Generate the default name
+ char default_name[MAX_SIZE];
+ wchar_t default_name_w[MAX_PATH];
+ char *object_name;
+ GetFileNameFromFilePathW(default_name_w, sizeof(default_name_w), tmp2);
+ UniToStr(default_name, sizeof(default_name), default_name_w);
+ ConvertSafeFileName(default_name, sizeof(default_name), default_name);
+
+ object_name = StringDlgA(hWnd, _UU("SEC_OBJECT_NAME_TITLE"),
+ _UU("SEC_OBJECT_NAME_INFO"), default_name, ICO_CERT, false, false);
+
+ if (object_name != NULL)
+ {
+ // Enumerate and write
+ batch[0].Type = WINUI_SECURE_WRITE_CERT;
+ batch[0].InputX = x;
+ batch[0].Name = object_name;
+
+ if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0) == false)
+ {
+ // Failure
+ }
+ else
+ {
+ ok = true;
+ }
+
+ Free(object_name);
+ }
+
+ FreeX(x);
+ }
+
+ break;
+
+ case SEC_K:
+ // Secret key
+ if (CmLoadKExW(hWnd, &k, tmp2, sizeof(tmp2)))
+ {
+ // Generate the default name
+ char default_name[MAX_SIZE];
+ wchar_t default_name_w[MAX_PATH];
+ char *object_name;
+ GetFileNameFromFilePathW(default_name_w, sizeof(default_name_w), tmp2);
+ UniToStr(default_name, sizeof(default_name), default_name_w);
+ ConvertSafeFileName(default_name, sizeof(default_name), default_name);
+
+ object_name = StringDlgA(hWnd, _UU("SEC_OBJECT_NAME_TITLE"),
+ _UU("SEC_OBJECT_NAME_INFO"), default_name, ICO_KEY, false, false);
+
+ if (object_name != NULL)
+ {
+ // Enumerate and write
+ batch[0].Type = WINUI_SECURE_WRITE_KEY;
+ batch[0].InputK = k;
+ batch[0].Name = object_name;
+
+ if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0) == false)
+ {
+ // Failure
+ }
+ else
+ {
+ ok = true;
+ }
+
+ Free(object_name);
+ }
+
+ FreeK(k);
+ }
+ break;
+
+ default:
+ // Invalid
+ return;
+ }
+
+ if (ok)
+ {
+ LIST *o = batch[1].EnumList;
+
+ CmSecureManagerDlgPrintList(hWnd, o);
+
+ FreeEnumSecObject(o);
+
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SEC_OBJECT_IMPORT_OK"));
+ }
+}
+
+// Export the object
+void CmSecureManagerDlgExport(HWND hWnd, UINT id)
+{
+ char name[MAX_SIZE];
+ UINT method = WINUI_SECURE_READ_DATA;
+ char *tmp;
+ UINT type;
+ wchar_t filename[MAX_PATH];
+ wchar_t *uni_tmp;
+ X *x;
+ BUF *b;
+ wchar_t default_name[128];
+ WINUI_SECURE_BATCH batch[] =
+ {
+ {WINUI_SECURE_READ_DATA, name, true, NULL, NULL, NULL, NULL, NULL, NULL},
+ };
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || id == 0)
+ {
+ return;
+ }
+
+ i = LvGetSelected(hWnd, L_LIST);
+ if (i == INFINITE)
+ {
+ return;
+ }
+
+ tmp = LvGetStrA(hWnd, L_LIST, i, 0);
+ StrCpy(name, sizeof(name), tmp);
+ Free(tmp);
+
+ type = (UINT)LvGetParam(hWnd, L_LIST, i);
+
+ switch (type)
+ {
+ case SEC_X:
+ method = WINUI_SECURE_READ_CERT;
+ break;
+
+ default:
+ method = WINUI_SECURE_READ_DATA;
+ break;
+ }
+
+ batch[0].Type = method;
+
+ // Operate the smart card
+ if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0) == false)
+ {
+ return;
+ }
+
+ switch (type)
+ {
+ case SEC_X:
+ // Certificate
+ x = batch[0].OutputX;
+
+ CertDlg(hWnd, x, NULL, true);
+
+ FreeX(x);
+ break;
+
+ default:
+ // File
+ b = batch[0].OutputData;
+ StrToUni(default_name, sizeof(default_name), name);
+ uni_tmp = SaveDlg(hWnd, _UU("DLG_ALL_FILES"), _UU("DLG_SAVE_FILE"), default_name, NULL);
+
+ if (uni_tmp != NULL)
+ {
+ UniStrCpy(filename, sizeof(filename), uni_tmp);
+
+ DumpBufW(b, filename);
+
+ Free(uni_tmp);
+
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SEC_OBJECT_EXPORT_OK"));
+ }
+
+
+ FreeBuf(b);
+ break;
+ }
+}
+
+// Delete the object
+void CmSecureManagerDlgDelete(HWND hWnd, UINT id)
+{
+ char name[MAX_SIZE];
+ UINT method = WINUI_SECURE_DELETE_DATA;
+ char *tmp;
+ UINT type;
+ LIST *o;
+ WINUI_SECURE_BATCH batch[] =
+ {
+ {WINUI_SECURE_DELETE_OBJECT, name, false, NULL, NULL, NULL, NULL, NULL, NULL},
+ {WINUI_SECURE_ENUM_OBJECTS, NULL, false, NULL, NULL, NULL, NULL, NULL, NULL},
+ };
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || id == 0)
+ {
+ return;
+ }
+
+ i = LvGetSelected(hWnd, L_LIST);
+ if (i == INFINITE)
+ {
+ return;
+ }
+
+ tmp = LvGetStrA(hWnd, L_LIST, i, 0);
+ StrCpy(name, sizeof(name), tmp);
+ Free(tmp);
+
+ type = (UINT)LvGetParam(hWnd, L_LIST, i);
+
+ switch (type)
+ {
+ case SEC_X:
+ method = WINUI_SECURE_DELETE_CERT;
+ break;
+
+ case SEC_K:
+ method = WINUI_SECURE_DELETE_KEY;
+ break;
+
+ default:
+ method = WINUI_SECURE_DELETE_DATA;
+ break;
+ }
+
+ batch[0].Type = method;
+
+ if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0) == false)
+ {
+ return;
+ }
+
+ o = batch[1].EnumList;
+
+ CmSecureManagerDlgPrintList(hWnd, o);
+
+ FreeEnumSecObject(o);
+}
+
+static bool cm_secure_manager_no_new_cert = false;
+
+// Smart Card Manager dialog
+UINT CmSecureManagerDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ NMHDR *n;
+ UINT id = (UINT)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmSecureManagerDlgInit(hWnd, id);
+
+ if (cm_secure_manager_no_new_cert)
+ {
+ Hide(hWnd, B_NEW_CERT);
+ }
+
+ SetTimer(hWnd, 1, 1, NULL);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_REFRESH:
+ CmSecureManagerDlgRefresh(hWnd, id);
+ break;
+
+ case B_IMPORT:
+ CmSecureManagerDlgImport(hWnd, id);
+ break;
+
+ case B_EXPORT:
+ CmSecureManagerDlgExport(hWnd, id);
+ break;
+
+ case B_DELETE:
+ if (MsgBox(hWnd, MB_YESNO | MB_ICONEXCLAMATION | MB_DEFBUTTON2,
+ _UU("SEC_DELETE_MSG")) == IDYES)
+ {
+ CmSecureManagerDlgDelete(hWnd, id);
+ }
+ break;
+
+ case B_NEW_CERT:
+ CmSecureManagerDlgNewCert(hWnd, id);
+ break;
+
+ case B_PIN:
+ CmSecurePin(hWnd, id);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+
+ CmSecureManagerDlgRefresh(hWnd, id);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ CmSecureManagerDlgUpdate(hWnd, id);
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Smart Card Manager
+void CmSecureManager(HWND hWnd, UINT id)
+{
+ CmSecureManagerEx(hWnd, id, false);
+}
+void CmSecureManagerEx(HWND hWnd, UINT id, bool no_new_cert)
+{
+ // Validate arguments
+ if (hWnd == NULL || id == 0)
+ {
+ return;
+ }
+
+ // ID check
+ if (CheckSecureDeviceId(id) == false)
+ {
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SEC_INVALID_ID"));
+ return;
+ }
+
+ if (no_new_cert)
+ {
+ cm_secure_manager_no_new_cert = true;
+ }
+ else
+ {
+ cm_secure_manager_no_new_cert = false;
+ }
+
+ Dialog(hWnd, D_CM_SECURE_MANAGER, CmSecureManagerDlg, (void *)id);
+}
+
+// Smart Card Manager for Client
+void CmClientSecureManager(HWND hWnd)
+{
+ RPC_USE_SECURE t;
+ UINT id;
+
+ Zero(&t, sizeof(t));
+ CcGetUseSecure(cm->Client, &t);
+
+ id = t.DeviceId;
+
+ if (id == 0 || CheckSecureDeviceId(id) == false)
+ {
+ id = CmClientSelectSecure(hWnd);
+ }
+
+ if (id == 0)
+ {
+ return;
+ }
+
+ CmSecureManager(hWnd, id);
+}
+
+// Initialize the dialog
+void CmSelectSecureDlgInit(HWND hWnd, UINT default_id)
+{
+ UINT i;
+ LIST *o;
+ LVB *v;
+
+ SetIcon(hWnd, 0, ICO_SECURE);
+
+ o = GetSecureDeviceList();
+
+ LvInit(hWnd, L_LIST);
+ LvInsertColumn(hWnd, L_LIST, 0, _UU("SEC_COLUMN1"), 150);
+ LvInsertColumn(hWnd, L_LIST, 1, _UU("SEC_COLUMN2"), 100);
+ LvInsertColumn(hWnd, L_LIST, 2, _UU("SEC_COLUMN3"), 130);
+ LvInsertColumn(hWnd, L_LIST, 3, _UU("SEC_COLUMN4"), 100);
+
+ v = LvInsertStart();
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t *tmp2;
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ SECURE_DEVICE *dev = LIST_DATA(o, i);
+
+ StrToUni(tmp1, sizeof(tmp1), dev->DeviceName);
+ tmp2 = (dev->Type == SECURE_IC_CARD) ? _UU("SEC_SMART_CARD") : _UU("SEC_USB_TOKEN");
+ StrToUni(tmp3, sizeof(tmp3), dev->Manufacturer);
+ StrToUni(tmp4, sizeof(tmp4), dev->ModuleName);
+
+ LvInsertAdd(v, ICO_SECURE, (void *)dev->Id, 4, tmp1, tmp2, tmp3, tmp4);
+ }
+
+ LvInsertEnd(v, hWnd, L_LIST);
+
+ if (default_id != 0)
+ {
+ LvSelect(hWnd, L_LIST, LvSearchParam(hWnd, L_LIST, (void *)default_id));
+ }
+
+ ReleaseList(o);
+
+ // Control update
+ CmSelectSecureDlgUpdate(hWnd);
+}
+
+// Update controls of the dialog
+void CmSelectSecureDlgUpdate(HWND hWnd)
+{
+ SetEnable(hWnd, IDOK, LvIsSingleSelected(hWnd, L_LIST));
+}
+
+// Smart card selection dialog
+UINT CmSelectSecureDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ UINT default_id = (UINT)param;
+ NMHDR *n = NULL;
+ static UINT old_id;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ old_id = default_id;
+ CmSelectSecureDlgInit(hWnd, default_id);
+
+ if (LvNum(hWnd, L_LIST) == 0)
+ {
+ // There is no smart card
+ SetTimer(hWnd, 1, 100, NULL);
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+
+ Disable(hWnd, L_LIST);
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SEC_NO_SECURE_DEVICE"));
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ if (IsEnable(hWnd, IDOK))
+ {
+ UINT i = LvGetSelected(hWnd, L_LIST);
+ if (i != INFINITE)
+ {
+ UINT id = (UINT)LvGetParam(hWnd, L_LIST, i);
+
+ if (old_id != id)
+ {
+ if (CmCheckPkcsEula(hWnd, id) == false)
+ {
+ break;
+ }
+ }
+ EndDialog(hWnd, id);
+ }
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ CmSelectSecureDlgUpdate(hWnd);
+ break;
+ case NM_DBLCLK:
+ Command(hWnd, IDOK);
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Select the smart card device to be used
+UINT CmSelectSecure(HWND hWnd, UINT current_id)
+{
+ return Dialog(hWnd, D_CM_SELECT_SECURE, CmSelectSecureDlg, (void *)current_id);
+}
+
+// Select the smart card device to be used (client)
+UINT CmClientSelectSecure(HWND hWnd)
+{
+ UINT id;
+ RPC_USE_SECURE t;
+
+ if (cm->server_name != NULL)
+ {
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("CM_SECURE_MUST_LOCAL"));
+ return 0;
+ }
+
+ Zero(&t, sizeof(t));
+ CcGetUseSecure(cm->Client, &t);
+
+ id = t.DeviceId;
+
+ id = CmSelectSecure(hWnd, id);
+ if (id != 0)
+ {
+ Zero(&t, sizeof(t));
+ t.DeviceId = id;
+
+ CALL(hWnd, CcUseSecure(cm->Client, &t));
+
+ SmWriteSelectSecureIdReg(id);
+ }
+
+ return id;
+}
+
+// Shortcut connection
+void CmConnectShortcut(UCHAR *key)
+{
+ UINT ret;
+ // Validate arguments
+ if (key == NULL)
+ {
+ return;
+ }
+
+ // Attempt to connect
+ ret = CcShortcut(key);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ if (ret == ERR_ACCOUNT_ACTIVE)
+ {
+ // Because it is currently connected, to query whether or not to disconnect
+ if (MsgBox(NULL, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_SHORTCUT_DISCONNECT")) == IDYES)
+ {
+ // Try to disconnect
+ ret = CcShortcutDisconnect(key);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error
+ MsgBox(NULL, MB_ICONEXCLAMATION, GetUniErrorStr(ret));
+ }
+ }
+ }
+ else
+ {
+ // Other errors
+ MsgBox(NULL, MB_ICONEXCLAMATION, GetUniErrorStr(ret));
+ }
+ }
+}
+
+// Play the audio guide
+void CmVoice(char *name)
+{
+ UINT i;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return;
+ }
+
+ // Voice guidance features disappeared!!
+ return;
+
+ if (cm->DisableVoice)
+ {
+ return;
+ }
+
+ for (i = 0;i < sizeof(cm_voice) / sizeof(CM_VOICE);i++)
+ {
+ if (cm_voice[i].voice_id == cm->VoiceId)
+ {
+ char tmp[MAX_SIZE];
+ Format(tmp, sizeof(tmp), "%s_%s.wav", cm_voice[i].perfix, name);
+ MsPlaySound(tmp);
+ return;
+ }
+ }
+}
+
+// Update the password changing dialog
+void CmChangePasswordUpdate(HWND hWnd, CM_CHANGE_PASSWORD *p)
+{
+ bool ok = true;
+ char *s1, *s2;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (IsEmpty(hWnd, E_USERNAME))
+ {
+ ok = false;
+ }
+
+ s1 = GetTextA(hWnd, E_NEW_PASSWORD1);
+ s2 = GetTextA(hWnd, E_NEW_PASSWORD2);
+
+ if (StrCmp(s1, s2) != 0)
+ {
+ ok = false;
+ }
+
+ Free(s1);
+ Free(s2);
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Password changing dialog procedure
+UINT CmChangePasswordProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ CM_CHANGE_PASSWORD *p = (CM_CHANGE_PASSWORD *)param;
+ char username[MAX_USERNAME_LEN + 1];
+ char old_pass[MAX_PASSWORD_LEN + 1];
+ char new_pass[MAX_PASSWORD_LEN + 1];
+ UINT ret;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetTextA(hWnd, E_HUBNAME, p->HubName);
+ SetTextA(hWnd, E_USERNAME, p->Username);
+ FormatText(hWnd, S_TITLE, p->ClientOption->Hostname);
+
+ if (IsEmpty(hWnd, E_USERNAME))
+ {
+ FocusEx(hWnd, E_USERNAME);
+ }
+ else
+ {
+ FocusEx(hWnd, E_OLD_PASSWORD);
+ }
+
+ CmChangePasswordUpdate(hWnd, p);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_USERNAME:
+ case E_OLD_PASSWORD:
+ case E_NEW_PASSWORD1:
+ case E_NEW_PASSWORD2:
+ CmChangePasswordUpdate(hWnd, p);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ GetTxtA(hWnd, E_USERNAME, username, sizeof(username));
+ GetTxtA(hWnd, E_OLD_PASSWORD, old_pass, sizeof(old_pass));
+ GetTxtA(hWnd, E_NEW_PASSWORD1, new_pass, sizeof(new_pass));
+
+ Disable(hWnd, E_USERNAME);
+ Disable(hWnd, E_OLD_PASSWORD);
+ Disable(hWnd, E_NEW_PASSWORD1);
+ Disable(hWnd, E_NEW_PASSWORD2);
+ Disable(hWnd, IDOK);
+ Disable(hWnd, IDCANCEL);
+
+ ret = ChangePassword(cm->Cedar, p->ClientOption, p->HubName, username, old_pass, new_pass);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_PASSWORD_CHANGED"));
+ EndDialog(hWnd, true);
+ }
+ else
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _E(ret));
+ Enable(hWnd, E_USERNAME);
+ Enable(hWnd, E_OLD_PASSWORD);
+ Enable(hWnd, E_NEW_PASSWORD1);
+ Enable(hWnd, E_NEW_PASSWORD2);
+ Enable(hWnd, IDOK);
+ Enable(hWnd, IDCANCEL);
+
+ SetTextA(hWnd, E_OLD_PASSWORD, "");
+ SetTextA(hWnd, E_NEW_PASSWORD1, "");
+ SetTextA(hWnd, E_NEW_PASSWORD2, "");
+
+ Focus(hWnd, E_OLD_PASSWORD);
+ }
+
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ }
+
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Show the password changing dialog
+void CmChangePassword(HWND hWnd, CLIENT_OPTION *o, char *hubname, char *username)
+{
+ CM_CHANGE_PASSWORD p;
+ // Validate arguments
+ if (hWnd == NULL || o == NULL || hubname == NULL || username == NULL)
+ {
+ return;
+ }
+
+ Zero(&p, sizeof(p));
+ StrCpy(p.Username, sizeof(p.Username), username);
+ StrCpy(p.HubName, sizeof(p.HubName), hubname);
+ p.ClientOption = o;
+
+ CmVoice("password");
+
+ Dialog(hWnd, D_CM_CHANGE_PASSWORD, CmChangePasswordProc, &p);
+}
+
+// Prohibit the installation of the virtual LAN card
+bool CmStopInstallVLan(HWND hWnd)
+{
+ if (cm->Client->Unix)
+ {
+ // There is no need to be prohibited if the client is an UNIX
+ return true;
+ }
+ if (cm->Client->Win9x)
+ {
+ // There is no need to prohibit if the client is a Win9x
+ return true;
+ }
+
+ return true;
+
+ if (MsIsTerminalServiceInstalled() || MsIsUserSwitchingInstalled())
+ {
+ if (MsGetCurrentTerminalSessionId() == 0)
+ {
+ // There is no need to prohibit
+ return true;
+ }
+ else
+ {
+ // Prohibit to install the device drivers since
+ // the user logged in other than the console session
+ wchar_t *user = MsGetSessionUserName(0);
+
+ if (user == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("CM_STOP_INST_VLAN_2"),
+ MsIsTerminalServiceInstalled() ? _UU("CM_DESKTOP_MSG_LOCAL_TS") : _UU("CM_DESKTOP_MSG_LOCAL_SW"),
+ MsGetCurrentTerminalSessionId());
+ }
+ else
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("CM_STOP_INST_VLAN_1"),
+ MsIsTerminalServiceInstalled() ? _UU("CM_DESKTOP_MSG_LOCAL_TS") : _UU("CM_DESKTOP_MSG_LOCAL_SW"),
+ MsGetCurrentTerminalSessionId(), 0, user);
+ }
+
+ if (user != NULL)
+ {
+ Free(user);
+ }
+ return false;
+ }
+ }
+ else
+ {
+ // There is no need to prohibit
+ return true;
+ }
+}
+
+// Desktop difference warning message dialog initialization
+void CmDesktopDlgInit(HWND hWnd, wchar_t *account_name)
+{
+ wchar_t tmp[2048];
+ bool remote = false;
+ bool user_switching = false;
+ bool console_active = false;
+ wchar_t *console_user = NULL;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ FormatText(hWnd, 0, account_name);
+ FormatText(hWnd, S_TITLE, account_name);
+ DlgFont(hWnd, S_TITLE, 11, true);
+ DlgFont(hWnd, S_INFO, 11, true);
+ if (cm->server_name == NULL)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_DESKTOP_LOCAL_PC"));
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_REMOTE_PC"), cm->server_name);
+ }
+ FormatText(hWnd, S_WARNING, tmp);
+
+ if (cm->server_name != NULL)
+ {
+ remote = true;
+ }
+ else
+ {
+ if (MsIsTerminalServiceInstalled())
+ {
+ user_switching = false;
+ }
+ else
+ {
+ user_switching = true;
+ }
+
+ console_user = MsGetSessionUserName(0);
+
+ if (console_user == NULL)
+ {
+ console_active = false;
+ }
+ else
+ {
+ console_active = true;
+ }
+ }
+
+ // MSG1
+ if (remote == false)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_LOCAL_1"),
+ user_switching ? _UU("CM_DESKTOP_MSG_LOCAL_SW") : _UU("CM_DESKTOP_MSG_LOCAL_TS"));
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_REMOTE_1"),
+ cm->server_name);
+ }
+ SetText(hWnd, S_MSG_1, tmp);
+
+ // MSG2
+ if (remote == false)
+ {
+ if (console_active)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_LOCAL_21"),
+ console_user, MsGetCurrentTerminalSessionId());
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_LOCAL_22"),
+ MsGetCurrentTerminalSessionId());
+ }
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_REMOTE_2"), cm->server_name);
+ }
+ SetText(hWnd, S_MSG_2, tmp);
+
+ // MSG3
+ if (remote == false)
+ {
+ if (console_active)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_LOCAL_31"),
+ console_user, account_name);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_LOCAL_32"),
+ account_name);
+ }
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_REMOTE_3"), cm->server_name,
+ account_name);
+ }
+ SetText(hWnd, S_MSG_3, tmp);
+
+ if (console_user != NULL)
+ {
+ Free(console_user);
+ }
+}
+
+// Desktop difference warning message dialog
+UINT CmDesktopDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ wchar_t *account_name = (wchar_t *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmDesktopDlgInit(hWnd, account_name);
+ break;
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ EndDialog(hWnd, true);
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Show a warning message that the desktop is different, if necessary
+bool CmWarningDesktop(HWND hWnd, wchar_t *account_name)
+{
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return false;
+ }
+
+ if (cm->Client->Unix)
+ {
+ //There is no need for warning if the client is an UNIX
+ return true;
+ }
+
+ if (/*MsIsTerminalServiceInstalled() || MsIsUserSwitchingInstalled() ||*/ (cm->server_name != NULL))
+ {
+ if (cm->server_name == NULL)
+ {
+ //if (MsGetCurrentTerminalSessionId() == 0)
+ {
+ // No need for warning
+ return true;
+ }
+ }
+ // There is a need for warning
+ return Dialog(hWnd, D_CM_DESKTOP, CmDesktopDlgProc, account_name);
+ }
+ else
+ {
+ // No need for warning
+ return true;
+ }
+}
+
+// Update the password setting dialog
+void CmPasswordRefresh(HWND hWnd)
+{
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SetEnable(hWnd, E_PASSWORD, IsChecked(hWnd, R_USE_PASSWORD));
+ SetEnable(hWnd, E_PASSWORD2, IsChecked(hWnd, R_USE_PASSWORD));
+ SetEnable(hWnd, IDC_STATIC1, IsChecked(hWnd, R_USE_PASSWORD));
+ SetEnable(hWnd, IDC_STATIC2, IsChecked(hWnd, R_USE_PASSWORD));
+ SetEnable(hWnd, R_REMOTE_ONLY, IsChecked(hWnd, R_USE_PASSWORD));
+
+ if (IsChecked(hWnd, R_USE_PASSWORD))
+ {
+ char tmp1[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ if (IsEmpty(hWnd, E_PASSWORD))
+ {
+ ok = false;
+ }
+ GetTxtA(hWnd, E_PASSWORD, tmp1, sizeof(tmp1));
+ GetTxtA(hWnd, E_PASSWORD2, tmp2, sizeof(tmp2));
+ if (StrCmp(tmp1, tmp2) != 0)
+ {
+ ok = false;
+ }
+ if (StrCmp(tmp1, HIDDEN_PASSWORD) == 0)
+ {
+ ok = false;
+ }
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Password setting procedure
+UINT CmPasswordProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ RPC_CLIENT_PASSWORD_SETTING c;
+ RPC_CLIENT_PASSWORD p;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Get the password setting
+ if (CALL(hWnd, CcGetPasswordSetting(cm->Client, &c)))
+ {
+ Check(hWnd, R_USE_PASSWORD, c.IsPasswordPresented);
+ if (c.IsPasswordPresented)
+ {
+ SetTextA(hWnd, E_PASSWORD, HIDDEN_PASSWORD);
+ SetTextA(hWnd, E_PASSWORD2, HIDDEN_PASSWORD);
+ FocusEx(hWnd, E_PASSWORD);
+ Check(hWnd, R_REMOTE_ONLY, c.PasswordRemoteOnly);
+ }
+ else
+ {
+ Focus(hWnd, R_USE_PASSWORD);
+ }
+ }
+ CmPasswordRefresh(hWnd);
+ break;
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case R_USE_PASSWORD:
+ if (IsChecked(hWnd, R_USE_PASSWORD))
+ {
+ FocusEx(hWnd, E_PASSWORD);
+ }
+ break;
+ case IDOK:
+ GetTxtA(hWnd, E_PASSWORD, tmp, sizeof(tmp));
+ Zero(&p, sizeof(p));
+ if (IsChecked(hWnd, R_USE_PASSWORD))
+ {
+ StrCpy(p.Password, sizeof(p.Password), tmp);
+ p.PasswordRemoteOnly = IsChecked(hWnd, R_REMOTE_ONLY);
+ }
+
+ if (CALL(hWnd, CcSetPassword(cm->Client, &p)))
+ {
+ if (StrLen(p.Password) > 0)
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_PASSWORD_SET"));
+ }
+ else
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_PASSWORD_REMOVE"));
+ }
+ EndDialog(hWnd, true);
+ }
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ switch (LOWORD(wParam))
+ {
+ case R_USE_PASSWORD:
+ case R_REMOTE_ONLY:
+ case E_PASSWORD:
+ case E_PASSWORD2:
+ CmPasswordRefresh(hWnd);
+ break;
+ }
+ switch (wParam)
+ {
+ case R_REMOTE_ONLY:
+ case R_USE_PASSWORD:
+ if (IsChecked(hWnd, R_USE_PASSWORD))
+ {
+ FocusEx(hWnd, E_PASSWORD);
+ }
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Set the password
+void CmPassword(HWND hWnd)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_CM_PASSWORD, CmPasswordProc, NULL);
+}
+
+// CA dialog update
+void CmTrustDlgUpdate(HWND hWnd)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SetEnable(hWnd, B_EXPORT, LvIsSelected(hWnd, L_CERT));
+ SetEnable(hWnd, B_DELETE, LvIsSelected(hWnd, L_CERT) && cm->CmSetting.LockMode == false);
+ SetEnable(hWnd, IDOK, LvIsSelected(hWnd, L_CERT));
+ SetEnable(hWnd, B_IMPORT, cm->CmSetting.LockMode == false);
+}
+
+// Update the list of certificates
+void CmTrustDlgRefresh(HWND hWnd)
+{
+ RPC_CLIENT_ENUM_CA c;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (CALL(hWnd, CcEnumCa(cm->Client, &c)))
+ {
+ UINT i;
+ LVB *b = LvInsertStart();
+ for (i = 0;i < c.NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_CA_ITEM *cert = c.Items[i];
+ wchar_t tmp[MAX_SIZE];
+
+ GetDateStrEx64(tmp, sizeof(tmp), SystemToLocal64(cert->Expires), NULL);
+ LvInsertAdd(b, ICO_CERT, (void *)cert->Key, 3,
+ cert->SubjectName, cert->IssuerName, tmp);
+ }
+ LvInsertEnd(b, hWnd, L_CERT);
+ CiFreeClientEnumCa(&c);
+ }
+
+ CmTrustDlgUpdate(hWnd);
+}
+
+// Import
+void CmTrustImport(HWND hWnd)
+{
+ X *x;
+ RPC_CERT c;
+ if (CmLoadXFromFileOrSecureCard(hWnd, &x) == false)
+ {
+ return;
+ }
+
+ Zero(&c, sizeof(c));
+ c.x = x;
+
+ CALL(hWnd, CcAddCa(cm->Client, &c));
+ CmVoice("new_cert");
+
+ FreeX(c.x);
+ CmTrustDlgRefresh(hWnd);
+}
+
+// Export
+void CmTrustExport(HWND hWnd)
+{
+ UINT key;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ key = (UINT)LvGetParam(hWnd, L_CERT, LvGetSelected(hWnd, L_CERT));
+ if (key != INFINITE)
+ {
+ RPC_GET_CA a;
+ Zero(&a, sizeof(a));
+ a.Key = key;
+
+ if (CALL(hWnd, CcGetCa(cm->Client, &a)))
+ {
+ wchar_t *name;
+ X *x = CloneX(a.x);
+ CiFreeGetCa(&a);
+
+ // Save
+ name = SaveDlg(hWnd, _UU("DLG_CERT_FILES"), _UU("DLG_SAVE_CERT"), NULL, L".cer");
+ if (name != NULL)
+ {
+ wchar_t str[MAX_SIZE];
+ UniStrCpy(str, sizeof(str), name);
+ if (XToFileW(x, str, true))
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("DLG_CERT_SAVE_OK"));
+ }
+ else
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("DLG_CERT_SAVE_ERROR"));
+ }
+ Free(name);
+ }
+ FreeX(x);
+ }
+ }
+}
+
+// Display
+void CmTrustView(HWND hWnd)
+{
+ UINT key;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ key = (UINT)LvGetParam(hWnd, L_CERT, LvGetSelected(hWnd, L_CERT));
+ if (key != INFINITE)
+ {
+ RPC_GET_CA a;
+ Zero(&a, sizeof(a));
+ a.Key = key;
+
+ if (CALL(hWnd, CcGetCa(cm->Client, &a)))
+ {
+ X *x = CloneX(a.x);
+ X *x_issuer;
+ CiFreeGetCa(&a);
+
+ x_issuer = CmGetIssuer(x);
+ CertDlg(hWnd, x, x_issuer, true);
+ FreeX(x);
+ FreeX(x_issuer);
+ }
+ }
+}
+
+// CA dialog procedure
+UINT CmTrustDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ NMHDR *n;
+ UINT index;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ LvInit(hWnd, L_CERT);
+ LvInsertColumn(hWnd, L_CERT, 0, _UU("CM_CERT_COLUMN_1"), 190);
+ LvInsertColumn(hWnd, L_CERT, 1, _UU("CM_CERT_COLUMN_2"), 190);
+ LvInsertColumn(hWnd, L_CERT, 2, _UU("CM_CERT_COLUMN_3"), 160);
+ CmTrustDlgRefresh(hWnd);
+ break;
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_IMPORT:
+ CmTrustImport(hWnd);
+ break;
+ case B_EXPORT:
+ CmTrustExport(hWnd);
+ break;
+ case B_DELETE:
+ index = LvGetSelected(hWnd, L_CERT);
+ if (index != INFINITE)
+ {
+ UINT key = (UINT)LvGetParam(hWnd, L_CERT, index);
+ if (key != INFINITE)
+ {
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_CERT_DELETE_MSG")) == IDYES)
+ {
+ RPC_CLIENT_DELETE_CA c;
+ Zero(&c, sizeof(c));
+ c.Key = key;
+ if (CALL(hWnd, CcDeleteCa(cm->Client, &c)))
+ {
+ CmTrustDlgRefresh(hWnd);
+ }
+ }
+ }
+ }
+ break;
+ case IDOK:
+ if (IsEnable(hWnd, IDOK))
+ {
+ CmTrustView(hWnd);
+ }
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_CERT:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ CmTrustDlgUpdate(hWnd);
+ break;
+ case NM_DBLCLK:
+ Command(hWnd, IDOK);
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ LvSortHander(hWnd, msg, wParam, lParam, L_CERT);
+
+ return 0;
+}
+
+// Show the CA dialog
+void CmTrustDlg(HWND hWnd)
+{
+ Dialog(hWnd, D_CM_TRUST, CmTrustDlgProc, NULL);
+}
+
+// Main window procedure
+UINT CmMainWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ NMHDR *n;
+ static UINT taskbar_msg = 0;
+ COPYDATASTRUCT *cpy;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ if (taskbar_msg != 0 && msg == taskbar_msg)
+ {
+ // The task-bar is regenerated
+ if (cm->TrayInited)
+ {
+ MsRestoreIconOnTray();
+ }
+ }
+
+ // CmSetForegroundProcessToCnService();
+
+ switch (msg)
+ {
+ case WM_CM_SETTING_CHANGED_MESSAGE:
+ // CM_SETTING has changed
+ CmApplyCmSetting();
+ break;
+ case WM_INITDIALOG:
+ CmMainWindowOnInit(hWnd);
+ taskbar_msg = RegisterWindowMessage("TaskbarCreated");
+ CmEndStartupMutex();
+ break;
+ case WM_CM_SHOW:
+ // Received a display request from another process
+ if (cm->CmSetting.EasyMode == false)
+ {
+ ShowWindow(hWnd, SW_SHOWNORMAL);
+ }
+ else
+ {
+ if (cm->hEasyWnd == NULL)
+ {
+ CmShowEasy();
+ }
+ else
+ {
+ SetForegroundWindow(cm->hEasyWnd);
+ SetActiveWindow(cm->hEasyWnd);
+ }
+ }
+ break;
+ case WM_COMMAND:
+ CmMainWindowOnCommand(hWnd, wParam, lParam);
+ break;
+ case WM_SIZE:
+ CmMainWindowOnSize(hWnd);
+ break;
+ case WM_CLOSE:
+ if (cm->CmSetting.EasyMode == false)
+ {
+ CmShowOrHideWindow(hWnd);
+ }
+ else
+ {
+ if (cm->hEasyWnd == NULL)
+ {
+ CmShowEasy();
+ }
+ else
+ {
+ SetForegroundWindow(cm->hEasyWnd);
+ SetActiveWindow(cm->hEasyWnd);
+ }
+ }
+ return 1;
+ case WM_INITMENUPOPUP:
+ if (HIWORD(lParam) == false)
+ {
+ CmMainWindowOnPopupMenu(hWnd, (HMENU)wParam, LOWORD(lParam));
+ }
+ break;
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ if (n->idFrom == L_ACCOUNT && (n->code == LVN_BEGINLABELEDITW || n->code == LVN_BEGINLABELEDITA))
+ {
+ wchar_t *tmp = LvGetSelectedStr(hWnd, L_ACCOUNT, 0);
+ if (tmp != NULL)
+ {
+ if (UniStrCmpi(tmp, _UU("CM_NEW_ICON")) == 0 || UniStrCmpi(tmp, _UU("CM_VGC_ICON")) == 0 || UniStrCmpi(tmp, _UU("CM_VGC_LINK")) == 0
+ )
+ {
+ SendMsg(hWnd, L_ACCOUNT, LVM_CANCELEDITLABEL, 0, 0);
+ Free(tmp);
+ return true;
+ }
+ Free(tmp);
+ }
+ }
+ CmMainWindowOnNotify(hWnd, (NMHDR *)lParam);
+ break;
+ case WM_CM_NOTIFY:
+ CmRefreshVLanList(hWnd);
+ CmRefreshAccountList(hWnd);
+ CmRefreshStatusBar(hWnd);
+ break;
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ CmSetForegroundProcessToCnService();
+ break;
+ case 2:
+ CmPollingTray(hWnd);
+ break;
+ case 3:
+ KillTimer(hWnd, 3);
+ Hide(hWnd, 0);
+ break;
+ case 4:
+ KillTimer(hWnd, 4);
+ CmMainWindowOnShowEasy(hWnd);
+ break;
+ case 6:
+ if (cm->Update == NULL)
+ {
+ if (cm->server_name == NULL)
+ {
+ if (CmGetNumConnected(hWnd) == 0)
+ {
+ cm->Update = InitUpdateUi(_UU("PRODUCT_NAME_VPN_CMGR"), NAME_OF_VPN_CLIENT_MANAGER, NULL,
+ GetCurrentBuildDate(), CEDAR_BUILD, CEDAR_VER, ((cm->Client == NULL) ? NULL : cm->Client->ClientId));
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case WM_CM_TRAY_MESSAGE:
+ // Message from the icon in the task tray
+ CmMainWindowOnTrayClicked(hWnd, wParam, lParam);
+ break;
+ case WM_COPYDATA:
+ cpy = (COPYDATASTRUCT *)lParam;
+ if (cpy != NULL)
+ {
+ if (cpy->dwData == CM_IMPORT_FILENAME_MSG || cpy->dwData == CM_IMPORT_FILENAME_MSG_OVERWRITE)
+ {
+ char *filename = (char *)cpy->lpData;
+
+ if (cm->CmSetting.LockMode == false || cpy->dwData == CM_IMPORT_FILENAME_MSG_OVERWRITE)
+ {
+ wchar_t fullpath[MAX_PATH];
+
+ if (StrLen(filename) >= 2 && IsFileExists(filename))
+ {
+ StrToUni(fullpath, sizeof(fullpath), filename);
+ }
+ else
+ {
+ UniStrCpy(fullpath, sizeof(fullpath), (wchar_t *)filename);
+ }
+
+ CmImportAccountMainEx(cm->hEasyWnd ? cm->hEasyWnd : hWnd, fullpath, cpy->dwData == CM_IMPORT_FILENAME_MSG_OVERWRITE);
+ }
+ else
+ {
+ MsgBox(cm->hEasyWnd ? cm->hEasyWnd : hWnd, MB_ICONEXCLAMATION | MB_SETFOREGROUND | MB_TOPMOST, _UU("CM_VPN_FILE_IMPORT_NG"));
+ }
+ }
+ }
+ break;
+ case WM_QUERYENDSESSION:
+ // Windows is about to terminate
+ cm->WindowsShutdowning = true;
+ CmSaveMainWindowPos(hWnd);
+ SleepThread(256);
+ break;
+ case WM_ENDSESSION:
+ // Windows has terminated
+ _exit(0);
+ break;
+ }
+
+ LvSortHander(hWnd, msg, wParam, lParam, L_ACCOUNT);
+ LvSortHander(hWnd, msg, wParam, lParam, L_VLAN);
+
+ return 0;
+}
+
+// Specify the notification service to the foreground process
+void CmSetForegroundProcessToCnService()
+{
+ if (cm->MenuPopuping)
+ {
+ return;
+ }
+ if (cm->server_name == NULL)
+ {
+ if (CnCheckAlreadyExists(false))
+ {
+ AllowFGWindow(MsRegReadInt(REG_CURRENT_USER,
+ CM_REG_KEY, "NotifyServerProcessId"));
+ }
+ }
+}
+
+// Show the [recent destination] sub-menu
+HMENU CmCreateRecentSubMenu(HWND hWnd, UINT start_id)
+{
+ HMENU h = NULL;
+ UINT i;
+ RPC_CLIENT_ENUM_ACCOUNT a;
+ LIST *o;
+ bool easy;
+
+ easy = cm->CmSetting.EasyMode;
+
+ Zero(&a, sizeof(a));
+
+ if (CcEnumAccount(cm->Client, &a) == ERR_NO_ERROR)
+ {
+ o = NewListFast(CiCompareClientAccountEnumItemByLastConnectDateTime);
+
+ for (i = 0;i < a.NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = a.Items[i];
+
+ item->tmp1 = i;
+
+ if (item->LastConnectDateTime != 0)
+ {
+ Add(o, item);
+ }
+ }
+
+ Sort(o);
+
+ for (i = 0;i < MIN(LIST_NUM(o), CM_NUM_RECENT);i++)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = (RPC_CLIENT_ENUM_ACCOUNT_ITEM *)LIST_DATA(o, i);
+ wchar_t tmp[MAX_PATH];
+ wchar_t *account_name;
+ char *server_name;
+ char *hub_name;
+ UINT pos;
+
+ if (h == NULL)
+ {
+ h = CreatePopupMenu();
+ }
+
+ account_name = item->AccountName;
+ server_name = item->ServerName;
+ hub_name = item->HubName;
+
+ UniStrCpy(tmp, sizeof(tmp), account_name);
+
+ pos = LvSearchStr(hWnd, L_ACCOUNT, 0, account_name);
+ if (pos != INFINITE)
+ {
+ MsAppendMenu(h, MF_STRING, start_id + pos, tmp);
+ }
+ }
+
+ ReleaseList(o);
+
+ CiFreeClientEnumAccount(&a);
+ }
+
+ return h;
+}
+
+// Show the sub-menu of the right-click menu in the task tray
+HMENU CmCreateTraySubMenu(HWND hWnd, bool flag, UINT start_id)
+{
+ HMENU h = NULL;
+ UINT i, num;
+ bool easy;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return NULL;
+ }
+
+ easy = cm->CmSetting.EasyMode;
+
+ num = LvNum(hWnd, L_ACCOUNT);
+
+ for (i = 0;i < num;i++)
+ {
+ wchar_t *status_str = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+
+ if (status_str != NULL)
+ {
+ bool b = false;
+ bool is_account = false;
+
+ if (UniStrCmpi(status_str, _UU("CM_ACCOUNT_OFFLINE")) == 0)
+ {
+ if (flag == false)
+ {
+ b = true;
+ }
+
+ is_account = true;
+ }
+
+ if (UniStrCmpi(status_str, _UU("CM_ACCOUNT_ONLINE")) == 0 ||
+ UniStrCmpi(status_str, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+ {
+ if (flag == true)
+ {
+ b = true;
+ }
+
+ is_account = true;
+ }
+
+ if (b)
+ {
+ wchar_t tmp[MAX_PATH];
+ wchar_t *account_name, *server_name;
+ wchar_t *hub_name;
+ if (h == NULL)
+ {
+ h = CreatePopupMenu();
+ }
+
+ account_name = LvGetStr(hWnd, L_ACCOUNT, i, 0);
+ server_name = LvGetStr(hWnd, L_ACCOUNT, i, 2);
+ hub_name = LvGetStr(hWnd, L_ACCOUNT, i, 3);
+
+ if (easy == false)
+ {
+ UniFormat(tmp, sizeof(tmp), L"%s\t- %s [%s]", account_name, server_name, hub_name);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), account_name);
+ }
+
+ MsAppendMenu(h, MF_STRING, start_id + i, tmp);
+
+ Free(account_name);
+ Free(server_name);
+ Free(hub_name);
+ }
+
+ Free(status_str);
+ }
+ }
+
+ return h;
+}
+
+// Display the right-click menu of the task tray
+void CmShowTrayMenu(HWND hWnd)
+{
+ HMENU h;
+ POINT p;
+ HMENU sub1, sub2, sub3, sub4;
+ bool locked;
+ bool easy;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ cm->MenuPopuping = true;
+
+ locked = cm->CmSetting.LockMode;
+ easy = cm->CmSetting.EasyMode;
+
+ // Create a menu
+ h = CreatePopupMenu();
+
+ // Cancel
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, 100007, _UU("CM_TRAY_MENU_CANCEL"));
+
+ // Separator
+ MsAppendMenu(h, MF_SEPARATOR, 10006, NULL);
+
+ if (locked == false && easy == false)
+ {
+ // Creating a new connection settings
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_NEW, _UU("CM_TRAY_MENU_NEW"));
+
+ // Separator
+ MsAppendMenu(h, MF_SEPARATOR, 10005, NULL);
+ }
+
+ // Connection menu
+ sub1 = CmCreateTraySubMenu(hWnd, false, CM_TRAY_MENU_CONNECT_ID_START);
+ if (sub1 != NULL)
+ {
+ MsAppendMenu(h, MF_BYPOSITION | MF_ENABLED | MF_POPUP | MF_STRING,
+ (UINT_PTR)sub1, _UU("CM_TRAY_MENU_CONNECT"));
+ }
+
+ // Disconnection menu
+ sub2 = CmCreateTraySubMenu(hWnd, true, CM_TRAY_MENU_DISCONNECT_ID_START);
+ if (sub2 != NULL)
+ {
+ MsAppendMenu(h, MF_BYPOSITION | MF_ENABLED | MF_POPUP | MF_STRING,
+ (UINT_PTR)sub2, _UU("CM_TRAY_MENU_DISCONNECT"));
+ }
+
+ // Status Display menu
+ sub3 = CmCreateTraySubMenu(hWnd, true, CM_TRAY_MENU_STATUS_ID_START);
+ if (sub3 != NULL)
+ {
+ MsAppendMenu(h, MF_BYPOSITION | MF_ENABLED | MF_POPUP | MF_STRING,
+ (UINT_PTR)sub3, _UU("CM_TRAY_MENU_STATUS"));
+ }
+
+ if (sub3 != NULL)
+ {
+ // Disconnect all connections
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_DISCONNECT_ALL, _UU("CM_TRAY_MENU_DISCONNECT_ALL"));
+ }
+
+ if (sub1 != NULL || sub2 != NULL || sub3 != NULL)
+ {
+ // Separator
+ MsAppendMenu(h, MF_SEPARATOR, 10003, NULL);
+ }
+
+ // Connect to the recently connected VPN server
+ sub4 = CmCreateRecentSubMenu(hWnd, CM_TRAY_MENU_RECENT_ID_START);
+ if (sub4 != NULL)
+ {
+ MsAppendMenu(h, MF_BYPOSITION | MF_ENABLED | MF_POPUP | MF_STRING,
+ (UINT_PTR)sub4, _UU("CM_TRAY_MENU_RECENT"));
+ MsAppendMenu(h, MF_SEPARATOR, 10008, NULL);
+ }
+
+ if (locked == false && easy == false)
+ {
+ // Communication throughput measurement
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_TRAFFIC, _UU("CM_TRAY_MENU_TRAFFIC"));
+ }
+
+ if (easy == false)
+ {
+ // Network device status
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_NETIF, _UU("CM_TRAY_MENU_NETIF"));
+ }
+
+ // Version information
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_ABOUT, _UU("CM_TRAY_MENU_ABOUT"));
+
+ // Separator
+ MsAppendMenu(h, MF_SEPARATOR, 10001, NULL);
+
+ // Change the operating mode
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_CM_SETTING, _UU("CM_TRAY_MENU_SETTING"));
+
+ // Separator
+ MsAppendMenu(h, MF_SEPARATOR, 10001, NULL);
+
+ // Hide the icon
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_TRAYICON, _UU("CM_MENU@CMD_TRAYICON"));
+
+ // Separator
+ MsAppendMenu(h, MF_SEPARATOR, 10001, NULL);
+
+ // Show or hide
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_EXIT,
+ IsHide(hWnd, 0) ? _UU("CM_TRAY_MENU_1_SHOW") : _UU("CM_TRAY_MENU_1_HIDE"));
+
+ // Quit
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_QUIT, _UU("CM_TRAY_MENU_2_QUIT"));
+
+ // Show the menu
+ GetCursorPos(&p);
+
+ SetForegroundWindow(hWnd);
+ TrackPopupMenu(h, TPM_LEFTALIGN, p.x, p.y, 0, hWnd, NULL);
+ PostMessage(hWnd, WM_NULL, 0, 0);
+
+ if (sub1 != NULL)
+ {
+ DestroyMenu(sub1);
+ }
+
+ if (sub2 != NULL)
+ {
+ DestroyMenu(sub2);
+ }
+
+ if (sub3 != NULL)
+ {
+ DestroyMenu(sub3);
+ }
+
+ DestroyMenu(h);
+
+ cm->MenuPopuping = false;
+}
+
+// Hide or show the main window
+void CmShowOrHideWindow(HWND hWnd)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (IsHide(hWnd, 0))
+ {
+ Show(hWnd, 0);
+ if (IsIconic(hWnd))
+ {
+ ShowWindow(hWnd, SW_SHOWNORMAL);
+ }
+ SetForegroundWindow(hWnd);
+ SetActiveWindow(hWnd);
+ }
+ else
+ {
+ CmSaveMainWindowPos(hWnd);
+ Hide(hWnd, 0);
+
+ if (cm->TrayInited == false)
+ {
+ Command(hWnd, CMD_QUIT);
+ return;
+ }
+ }
+}
+
+// Right-clicked on the account list
+void CmAccountListRightClick(HWND hWnd)
+{
+ HMENU h;
+ HMENU parent;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Load the menu
+ h = LoadSubMenu(M_MAIN, 0, &parent);
+ if (h == NULL)
+ {
+ return;
+ }
+
+ InitMenuInternational(h, "CM_MENU");
+
+ // Remove the shortcut key
+ RemoveShortcutKeyStrFromMenu(h);
+
+ // Delete the exit menu
+ i = GetMenuItemPos(h, CMD_QUIT);
+ if (i != INFINITE)
+ {
+ DeleteMenuItem(h, i);
+ DeleteMenuItem(h, i - 1);
+ DeleteMenuItem(h, i - 2);
+ DeleteMenuItem(h, i - 3);
+ }
+
+ // Set enable / disable
+ CmMainWindowOnPopupMenu(hWnd, h, INFINITE);
+
+ if (h != NULL)
+ {
+ // Determine whether the selected account is under connecting
+ UINT i = LvGetSelected(hWnd, L_ACCOUNT);
+ wchar_t *str;
+ bool is_connected = false;
+ if (i != INFINITE)
+ {
+ str = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+ if (str != NULL)
+ {
+ if (UniStrCmpi(str, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(str, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+ {
+ // Connecting
+ is_connected = true;
+ }
+ Free(str);
+ }
+ }
+
+ if (i == INFINITE)
+ {
+ // Bold the New menu
+ SetMenuItemBold(h, GetMenuItemPos(h, CMD_NEW), true);
+ }
+ else
+ {
+ if (is_connected == false)
+ {
+ // Bold the connection menu
+ SetMenuItemBold(h, GetMenuItemPos(h, CMD_CONNECT), true);
+ }
+ else
+ {
+ // Bold the status menu
+ SetMenuItemBold(h, GetMenuItemPos(h, CMD_STATUS), true);
+ }
+ }
+ }
+
+ // Show the menu
+ PrintMenu(hWnd, h);
+
+ DestroyMenu(parent);
+}
+
+// Right-clicked on the virtual LAN card list
+void CmVLanListRightClick(HWND hWnd)
+{
+ HMENU h;
+ HMENU parent;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Load the menu
+ h = LoadSubMenu(M_MAIN, 3, &parent);
+ if (h == NULL)
+ {
+ return;
+ }
+
+ InitMenuInternational(h, "CM_MENU");
+
+ // Remove the shortcut key
+ RemoveShortcutKeyStrFromMenu(h);
+
+ // Set enable / disable
+ CmMainWindowOnPopupMenu(hWnd, h, INFINITE);
+
+ if (h != NULL)
+ {
+ // Examine whether the selected device is enabled
+ UINT i = LvGetSelected(hWnd, L_VLAN);
+ wchar_t *str;
+ bool is_active = false;
+ if (i != INFINITE)
+ {
+ str = LvGetStr(hWnd, L_VLAN, i, 1);
+ if (str != NULL)
+ {
+ if (UniStrCmpi(str, _UU("CM_VLAN_ENABLED")) == 0)
+ {
+ // Enabled
+ is_active = true;
+ }
+ Free(str);
+ }
+ }
+
+ if (i == INFINITE)
+ {
+ // Bold the New menu
+ SetMenuItemBold(h, GetMenuItemPos(h, CMD_NEW_VLAN), true);
+ }
+ else
+ {
+ if (is_active == false)
+ {
+ // Bold the enable menu
+ SetMenuItemBold(h, GetMenuItemPos(h, CMD_ENABLE_VLAN), true);
+ }
+ else
+ {
+ // Bold the Windows Network Setup menu
+ SetMenuItemBold(h, GetMenuItemPos(h, CMD_WINNET), true);
+ }
+ }
+ }
+
+ // Show the menu
+ PrintMenu(hWnd, h);
+
+ DestroyMenu(parent);
+}
+
+// Notify to the main window
+void CmMainWindowOnNotify(HWND hWnd, NMHDR *n)
+{
+ bool item_vlan;
+ NMLVDISPINFOW *disp_info;
+ NMLVKEYDOWN *key;
+
+ // Validate arguments
+ if (hWnd == NULL || n == NULL)
+ {
+ return;
+ }
+
+ switch (n->idFrom)
+ {
+ case L_ACCOUNT:
+ case L_VLAN:
+ if (n->idFrom == L_ACCOUNT)
+ {
+ item_vlan = false;
+ }
+ else
+ {
+ item_vlan = true;
+ }
+
+ switch (n->code)
+ {
+ case NM_DBLCLK:
+ // Double click
+ CmOnKey(hWnd, false, false, VK_RETURN);
+ break;
+ case NM_RCLICK:
+ // Right click
+ if (item_vlan == false)
+ {
+ CmAccountListRightClick(hWnd);
+ }
+ else
+ {
+ CmVLanListRightClick(hWnd);
+ }
+ break;
+ case LVN_ENDLABELEDITW:
+ // Change the name
+ disp_info = (NMLVDISPINFOW *)n;
+ if (disp_info->item.pszText != NULL)
+ {
+ wchar_t *new_name = disp_info->item.pszText;
+ wchar_t *old_name = LvGetStr(hWnd, L_ACCOUNT, disp_info->item.iItem, 0);
+
+ if (old_name != NULL)
+ {
+ if (UniStrCmp(new_name, old_name) != 0 && UniIsEmptyStr(new_name) == false)
+ {
+ RPC_RENAME_ACCOUNT a;
+ Zero(&a, sizeof(a));
+ UniStrCpy(a.OldName, sizeof(a.OldName), old_name);
+ UniStrCpy(a.NewName, sizeof(a.NewName), new_name);
+ if (CALL(hWnd, CcRenameAccount(cm->Client, &a)))
+ {
+ LvSetItem(hWnd, L_ACCOUNT, disp_info->item.iItem, 0, new_name);
+ }
+ }
+
+ Free(old_name);
+ }
+ }
+ break;
+ case LVN_KEYDOWN:
+ // Key pressed
+ key = (NMLVKEYDOWN *)n;
+ if (key != NULL)
+ {
+ bool ctrl, alt;
+ UINT code = key->wVKey;
+ ctrl = (GetKeyState(VK_CONTROL) & 0x8000) == 0 ? false : true;
+ alt = (GetKeyState(VK_MENU) & 0x8000) == 0 ? false : true;
+ CmOnKey(hWnd, ctrl, alt, code);
+ }
+ break;
+ }
+ break;
+ }
+}
+
+// Keyboard pressed
+void CmOnKey(HWND hWnd, bool ctrl, bool alt, UINT key)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Single key
+ switch (key)
+ {
+ case VK_RETURN:
+ Command(hWnd, IDOK);
+ break;
+ case VK_DELETE:
+ // Delete
+ if (IsFocus(hWnd, L_ACCOUNT))
+ {
+ // Operation on the account list
+ Command(hWnd, CMD_DELETE);
+ }
+ else
+ {
+ // Operation on the virtual LAN card list
+ Command(hWnd, CMD_DELETE_VLAN);
+ }
+ break;
+ case VK_F2:
+ // Change the name
+ Command(hWnd, CMD_RENAME);
+ break;
+ case VK_F5:
+ // Update the status
+ Command(hWnd, CMD_REFRESH);
+ break;
+ }
+
+ if (alt)
+ {
+ switch (key)
+ {
+ case 'Q':
+ // Close
+ Command(hWnd, CMD_QUIT);
+ break;
+ }
+ }
+
+ if (ctrl)
+ {
+ switch (key)
+ {
+ case 'G':
+ // Smart Card Manager
+ Command(hWnd, CMD_SECURE_MANAGER);
+ break;
+ case 'S':
+ // Show the state
+ Command(hWnd, CMD_STATUS);
+ break;
+ case 'I':
+ // Disconnect all connections
+ Command(hWnd, CMD_DISCONNECT_ALL);
+ break;
+ case 'D':
+ // Disconnect
+ Command(hWnd, CMD_DISCONNECT);
+ break;
+ case 'N':
+ // Create a new connection settings
+ Command(hWnd, CMD_NEW);
+ break;
+ case 'C':
+ // Creating a copy
+ Command(hWnd, CMD_CLONE);
+ break;
+ case 'T':
+ // Set to start-up connection
+ Command(hWnd, CMD_STARTUP);
+ break;
+ case 'A':
+ // Select all
+ Command(hWnd, CMD_SELECT_ALL);
+ break;
+ case 'L':
+ // Create a new virtual LAN card
+ Command(hWnd, CMD_NEW_VLAN);
+ break;
+ case 'E':
+ // Enable the virtual LAN card
+ Command(hWnd, CMD_ENABLE_VLAN);
+ break;
+ case 'B':
+ // Disable the virtual LAN card
+ Command(hWnd, CMD_DISABLE_VLAN);
+ break;
+ case 'U':
+ // Reinstall the driver
+ Command(hWnd, CMD_REINSTALL);
+ break;
+ case 'W':
+ // Configure Windows network connection
+ Command(hWnd, CMD_WINNET);
+ break;
+ case 'P':
+ // Set the password
+ Command(hWnd, CMD_PASSWORD);
+ break;
+ case 'O':
+ // Option settings
+ Command(hWnd, CMD_TRAFFIC);
+ break;
+ case 'R':
+ // Certificate management
+ Command(hWnd, CMD_TRUST);
+ break;
+ case 'Q':
+ // Throughput
+ Command(hWnd, CMD_TRAFFIC);
+ break;
+ }
+ }
+}
+
+// Command of the main window
+void CmMainWindowOnCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+ CmMainWindowOnCommandEx(hWnd, wParam, lParam, false);
+}
+void CmMainWindowOnCommandEx(HWND hWnd, WPARAM wParam, LPARAM lParam, bool easy)
+{
+ wchar_t *tmp;
+ char *name;
+ UINT index;
+ UINT id;
+ bool ctrl, alt;
+ UINT flag = 0;
+ // Validate arguments
+ wchar_t *selected_name = NULL;
+ UINT starter_id = 0;
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ ctrl = (GetKeyState(VK_CONTROL) & 0x8000) == 0 ? false : true;
+ alt = (GetKeyState(VK_MENU) & 0x8000) == 0 ? false : true;
+
+ if (wParam == IDOK)
+ {
+ tmp = LvGetSelectedStr(hWnd, L_ACCOUNT, 0);
+ if (tmp != NULL)
+ {
+ if (UniStrCmpi(tmp, _UU("CM_NEW_ICON")) == 0)
+ {
+ Free(tmp);
+ Command(hWnd, CMD_NEW);
+ return;
+ }
+ if (UniStrCmpi(tmp, _UU("CM_VGC_ICON")) == 0 || UniStrCmpi(tmp, _UU("CM_VGC_LINK")) == 0)
+ {
+ Free(tmp);
+ Command(hWnd, CMD_VGC_CONNECT);
+ return;
+ }
+ Free(tmp);
+ }
+ }
+
+ if (CmIsEnabled(hWnd, (UINT)wParam) == false)
+ {
+ return;
+ }
+
+ if (CM_TRAY_IS_CONNECT_ID(wParam))
+ {
+ // Connection request
+ starter_id = CM_TRAY_MENU_CONNECT_ID_START;
+ flag = 1;
+ }
+
+ if (CM_TRAY_IS_STATUS_ID(wParam))
+ {
+ // Information display request
+ starter_id = CM_TRAY_MENU_STATUS_ID_START;
+ flag = 2;
+ }
+
+ if (CM_TRAY_IS_DISCONNECT_ID(wParam))
+ {
+ // Disconnect request
+ starter_id = CM_TRAY_MENU_DISCONNECT_ID_START;
+ flag = 3;
+ }
+
+ if (CM_TRAY_IS_RECENT_ID(wParam))
+ {
+ // Recent destinations
+ starter_id = CM_TRAY_MENU_RECENT_ID_START;
+ flag = 1;
+ }
+
+ if (starter_id != 0)
+ {
+ UINT num;
+
+ id = (UINT)wParam - starter_id;
+
+ num = LvNum(hWnd, L_ACCOUNT);
+
+ if (id < num)
+ {
+ selected_name = LvGetStr(hWnd, L_ACCOUNT, id, 0);
+
+ if (selected_name != NULL)
+ {
+ if (UniStrCmpi(selected_name, _UU("CM_NEW_ICON")) != 0 &&
+ UniStrCmpi(selected_name, _UU("CM_VGC_ICON")) != 0 &&
+ UniStrCmpi(selected_name, _UU("CM_VGC_LINK")) != 0)
+ {
+ switch (flag)
+ {
+ case 1:
+ CmConnect(hWnd, selected_name);
+ break;
+
+ case 2:
+ CmStatus(hWnd, selected_name);
+ break;
+
+ case 3:
+ CmDisconnect(hWnd, selected_name);
+ break;
+ }
+ }
+ }
+
+ Free(selected_name);
+ }
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ case CMD_EASY_DBLCLICK:
+ // Property or connection
+ if (IsFocus(hWnd, L_ACCOUNT) || (hWnd == cm->hEasyWnd))
+ {
+ // Operation about the account list
+ if (alt == false)
+ {
+ UINT index = LvGetSelected(hWnd, L_ACCOUNT);
+ bool b = false;
+ if (index != INFINITE)
+ {
+ wchar_t *s = LvGetStr(hWnd, L_ACCOUNT, index, 1);
+ if (s != NULL)
+ {
+ if (UniStrCmpi(s, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(s, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+ {
+ b = true;
+ }
+ Free(s);
+ }
+ }
+
+ if (b == false)
+ {
+ // Connection
+ Command(hWnd, CMD_CONNECT);
+ }
+ else
+ {
+ if (hWnd != cm->hEasyWnd || wParam == CMD_EASY_DBLCLICK)
+ {
+ // Display status
+ Command(hWnd, CMD_STATUS);
+ }
+ else
+ {
+ // Disconnect
+ Command(hWnd, CMD_DISCONNECT);
+ }
+ }
+ }
+ else
+ {
+ // Property
+ Command(hWnd, CMD_PROPERTY);
+ }
+ }
+ else
+ {
+ // Configure Windows network connection
+ Command(hWnd, CMD_WINNET);
+ }
+ break;
+ case CMD_CONNECT:
+ // Connection
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ CmConnect(hWnd, tmp);
+ Free(tmp);
+ }
+ break;
+ case CMD_STATUS:
+ // Show the status
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ CmStatus(hWnd, tmp);
+ Free(tmp);
+ }
+ break;
+ case CMD_DISCONNECT_ALL:
+ // Disconnect all connections
+ CmDisconnectAll(hWnd);
+ break;
+ case CMD_DISCONNECT:
+ // Disconnect
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ CmDisconnect(hWnd, tmp);
+ Free(tmp);
+ }
+ break;
+ case CMD_NEW:
+ // Create new
+ CmNewAccount(hWnd);
+ break;
+
+
+ case CMD_CLONE:
+ // Copy
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ CmCopyAccount(hWnd, tmp);
+ Free(tmp);
+ }
+ break;
+ case CMD_SHORTCUT:
+ // Create a shortcut
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ CmSortcut(hWnd, tmp);
+ Free(tmp);
+ }
+ break;
+ case CMD_EXPORT_ACCOUNT:
+ // Export settings
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ CmExportAccount(hWnd, tmp);
+ Free(tmp);
+ }
+ break;
+ case CMD_IMPORT_ACCOUNT:
+ // Import settings
+ CmImportAccount(hWnd);
+ break;
+ case CMD_STARTUP:
+ // Set to start-up connection
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ RPC_CLIENT_DELETE_ACCOUNT c;
+ Zero(&c, sizeof(c));
+ UniStrCpy(c.AccountName, sizeof(c.AccountName), tmp);
+ CALL(hWnd, CcSetStartupAccount(cm->Client, &c));
+ CmVoice("set_startup");
+ MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("CM_SET_STARTUP"), tmp);
+ Free(tmp);
+ }
+ break;
+ case CMD_NOSTARTUP:
+ // Unset the start-up connection
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
+ _UU("CM_REMOVE_STARTUP"), tmp) == IDYES)
+ {
+ RPC_CLIENT_DELETE_ACCOUNT c;
+ Zero(&c, sizeof(c));
+ UniStrCpy(c.AccountName, sizeof(c.AccountName), tmp);
+ CALL(hWnd, CcRemoveStartupAccount(cm->Client, &c));
+ CmVoice("remove_startup");
+ }
+ Free(tmp);
+ }
+ break;
+ case CMD_DELETE:
+ // Delete
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ CmDeleteAccount(hWnd, tmp);
+ Free(tmp);
+ }
+ break;
+ case CMD_RENAME:
+ // Change the name
+ Focus(hWnd, L_ACCOUNT);
+ LvRename(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT));
+ break;
+ case CMD_PROPERTY:
+ // Property
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ CmEditAccount(hWnd, tmp);
+ Free(tmp);
+ }
+ break;
+ case IDCANCEL:
+ case CMD_EXIT:
+ // Close
+ Close(hWnd);
+ break;
+ case CMD_QUIT:
+ // Exit
+ CmMainWindowOnQuit(hWnd);
+ break;
+ case CMD_SELECT_ALL:
+ // Select all
+ LvSelectAll(hWnd, L_ACCOUNT);
+ LvSelectAll(hWnd, L_VLAN);
+ break;
+ case CMD_SWITCH_SELECT:
+ // Invert selection
+ LvSwitchSelect(hWnd, L_ACCOUNT);
+ LvSwitchSelect(hWnd, L_VLAN);
+ break;
+ case CMD_GRID:
+ // Show grid
+ cm->ShowGrid = !cm->ShowGrid;
+ CmRefreshVLanListEx(hWnd, true);
+ CmRefreshAccountListEx2(hWnd, false, true);
+ break;
+ case CMD_STATUSBAR:
+ // Show the status bar
+ if (cm->HideStatusBar == false)
+ {
+ cm->HideStatusBar = true;
+ Hide(hWnd, S_STATUSBAR);
+ CmMainWindowOnSize(hWnd);
+ }
+ else
+ {
+ cm->HideStatusBar = false;
+ Show(hWnd, S_STATUSBAR);
+ CmMainWindowOnSize(hWnd);
+ }
+ CmSaveMainWindowPos(hWnd);
+ break;
+ case CMD_VISTASTYLE:
+ cm->VistaStyle = !cm->VistaStyle;
+ CmRefreshEx(hWnd, true);
+ CmSaveMainWindowPos(hWnd);
+ break;
+ case CMD_TRAYICON:
+ // Tray icon display
+ if (cm->HideTrayIcon == false)
+ {
+ cm->HideTrayIcon = true;
+ CmFreeTray(hWnd);
+
+ if (IsHide(hWnd, 0))
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_TRAY_ICON_RESTORE"));
+ }
+ }
+ else
+ {
+ cm->HideTrayIcon = false;
+ if (cm->server_name == NULL)
+ {
+ CmInitTray(hWnd);
+ }
+ }
+ break;
+ case CMD_SHOWPORT:
+ // Show the port number
+ cm->ShowPort = !cm->ShowPort;
+ CmRefresh(hWnd);
+ break;
+ case CMD_ICON:
+ // Show the icon
+ if (cm->IconView == false)
+ {
+ cm->IconView = true;
+ CmRefresh(hWnd);
+ }
+ break;
+ case CMD_DETAIL:
+ // Show details
+ if (cm->IconView)
+ {
+ cm->IconView = false;
+ CmRefresh(hWnd);
+ }
+ break;
+ case CMD_REFRESH:
+ if (easy == false)
+ {
+ // Display update
+ LvReset(hWnd, L_ACCOUNT);
+ LvReset(hWnd, L_VLAN);
+ CmRefresh(hWnd);
+ }
+ break;
+ case CMD_NEW_VLAN:
+ // Create a Virtual LAN card
+ if (CmStopInstallVLan(hWnd) == false)
+ {
+ // Installation is prohibited
+ break;
+ }
+ name = CmNewVLanDlg(hWnd);
+ if (name != NULL)
+ {
+ wchar_t tmp[MAX_SIZE];
+ void *helper = NULL;
+ RPC_CLIENT_CREATE_VLAN c;
+ Zero(&c, sizeof(c));
+ StrCpy(c.DeviceName, sizeof(c.DeviceName), name);
+ if (MsIsNt() == false)
+ {
+ // Change the title of the window
+ GetTxt(hWnd, 0, tmp, sizeof(tmp));
+ SetText(hWnd, 0, _UU("CM_VLAN_INSTALLING"));
+ }
+ // Minimize
+ if (MsIsVista() == false)
+ {
+ ShowWindow(hWnd, SW_SHOWMINIMIZED);
+ }
+
+ if (MsIsVista())
+ {
+ helper = CmStartUacHelper();
+ }
+
+ if (CALL(hWnd, CcCreateVLan(cm->Client, &c)))
+ {
+ CmVoice("new_vlan");
+ }
+
+ CmStopUacHelper(helper);
+
+ if (MsIsNt() == false)
+ {
+ // Restore the title of the window
+ SetText(hWnd, 0, tmp);
+ }
+ // Restore
+ if (MsIsVista() == false)
+ {
+ ShowWindow(hWnd, SW_SHOWNORMAL);
+ }
+ Free(name);
+ }
+ break;
+ case CMD_DELETE_VLAN:
+ // Delete the Virtual LAN card
+ index = LvGetSelected(hWnd, L_VLAN);
+ if (index != INFINITE)
+ {
+ if (cm->Client->Win9x == false)
+ {
+ // Windows 2000 or later
+ wchar_t *s = LvGetStr(hWnd, L_VLAN, index, 0);
+ if (s != NULL)
+ {
+ RPC_CLIENT_CREATE_VLAN c;
+ char str[MAX_SIZE];
+ CmVoice("delete_vlan_1");
+ if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_DELETE_VLAN"), s) == IDYES)
+ {
+ Zero(&c, sizeof(c));
+ UniToStr(str, sizeof(str), s);
+ if (CmPrintNameToVLanName(c.DeviceName, sizeof(c.DeviceName), str))
+ {
+ if (CALL(hWnd, CcDeleteVLan(cm->Client, &c)))
+ {
+ CmVoice("delete_vlan_2");
+ }
+ }
+ }
+ Free(s);
+ }
+ }
+ else
+ {
+ // Windows 9x
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("CM_9X_VLAN_UNINSTALL")) == IDYES)
+ {
+ Run("rundll32.exe", "shell32.dll,Control_RunDLL NETCPL.CPL",
+ false, false);
+ }
+ }
+ }
+ break;
+ case CMD_ENABLE_VLAN:
+ // Enable the virtual LAN card
+ index = LvGetSelected(hWnd, L_VLAN);
+ if (index != INFINITE)
+ {
+ wchar_t *s = LvGetStr(hWnd, L_VLAN, index, 0);
+ if (s != NULL)
+ {
+ RPC_CLIENT_CREATE_VLAN c;
+ char str[MAX_SIZE];
+ Zero(&c, sizeof(c));
+ UniToStr(str, sizeof(str), s);
+ if (CmPrintNameToVLanName(c.DeviceName, sizeof(c.DeviceName), str))
+ {
+ CALL(hWnd, CcEnableVLan(cm->Client, &c));
+ }
+ Free(s);
+ }
+ }
+ break;
+ case CMD_DISABLE_VLAN:
+ // Disable the virtual LAN card
+ index = LvGetSelected(hWnd, L_VLAN);
+ if (index != INFINITE)
+ {
+ wchar_t *s = LvGetStr(hWnd, L_VLAN, index, 0);
+ if (s != NULL)
+ {
+ RPC_CLIENT_CREATE_VLAN c;
+ char str[MAX_SIZE];
+ Zero(&c, sizeof(c));
+ UniToStr(str, sizeof(str), s);
+ if (CmPrintNameToVLanName(c.DeviceName, sizeof(c.DeviceName), str))
+ {
+ CALL(hWnd, CcDisableVLan(cm->Client, &c));
+ }
+ Free(s);
+ }
+ }
+ break;
+ case CMD_REINSTALL:
+ // Reinstall the virtual LAN card
+ if (CmStopInstallVLan(hWnd) == false)
+ {
+ // Installation is prohibited
+ break;
+ }
+ index = LvGetSelected(hWnd, L_VLAN);
+ if (index != INFINITE)
+ {
+ wchar_t *s = LvGetStr(hWnd, L_VLAN, index, 0);
+ if (s != NULL)
+ {
+ RPC_CLIENT_CREATE_VLAN c;
+ char str[MAX_SIZE];
+ Zero(&c, sizeof(c));
+ UniToStr(str, sizeof(str), s);
+ if (CmPrintNameToVLanName(c.DeviceName, sizeof(c.DeviceName), str))
+ {
+ void *helper = NULL;
+
+ if (MsIsVista() == false)
+ {
+ ShowWindow(hWnd, SW_SHOWMINIMIZED);
+ }
+
+ if (MsIsVista())
+ {
+ helper = CmStartUacHelper();
+ }
+
+ CALL(hWnd, CcUpgradeVLan(cm->Client, &c));
+
+ CmStopUacHelper(helper);
+
+ if (MsIsVista() == false)
+ {
+ ShowWindow(hWnd, SW_SHOWNORMAL);
+ }
+ }
+ Free(s);
+ }
+ }
+ break;
+ case CMD_PASSWORD:
+ // Password setting
+ CmPassword(hWnd);
+ break;
+ case CMD_OPTION:
+ // Option
+ CmConfigDlg(hWnd);
+ break;
+ case CMD_LANGUAGE:
+ // Language settings
+ if (true)
+ {
+ wchar_t path[MAX_SIZE];
+
+ CombinePathW(path, sizeof(path), MsGetExeDirNameW(), L"vpnsetup.exe");
+
+ if (MsExecuteW(path, L"/language:yes") == false)
+ {
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SW_CHILD_PROCESS_ERROR"));
+ }
+ }
+ break;
+ case CMD_TRUST:
+ // Certificate management
+ CmTrustDlg(hWnd);
+ break;
+ case CMD_ABOUT:
+ // Version information
+ if (IsEnable(hWnd, 0))
+ {
+ AboutEx(hWnd, cm->Cedar, _UU("PRODUCT_NAME_VPN_CMGR"), cm->Update);
+ }
+ break;
+ case CMD_VOIDE_NONE:
+ cm->DisableVoice = true;
+ break;
+ case CMD_VOICE_NORMAL:
+ cm->DisableVoice = false;
+ cm->VoiceId = VOICE_SSK;
+ break;
+ case CMD_VOICE_ODD:
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("CM_EXT_VOICE_MSG")) == IDYES)
+ {
+ cm->DisableVoice = false;
+ cm->VoiceId = VOICE_AHO;
+ }
+ break;
+ case CMD_SECURE_MANAGER:
+ // Smart Card Manager
+ CmClientSecureManager(hWnd);
+ break;
+ case CMD_SECURE_SELECT:
+ // Select a smart card
+ CmClientSelectSecure(hWnd);
+ break;
+ case CMD_NETIF:
+ // State of the network device
+ if (IsEnable(hWnd, 0))
+ {
+ UtSpeedMeterEx(hWnd);
+ }
+ break;
+ case CMD_MMCSS:
+ // Optimization utility for Windows Vista
+ if (MsIsVista() == false)
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("VISTA_MMCSS_MSG_4"));
+ }
+ else
+ {
+ if (MsIsAdmin() == false)
+ {
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("VISTA_MMCSS_MSG_4"));
+ }
+ else
+ {
+ if (MsIsMMCSSNetworkThrottlingEnabled())
+ {
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("VISTA_MMCSS_MSG")) == IDYES)
+ {
+ MsSetMMCSSNetworkThrottlingEnable(false);
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("VISTA_MMCSS_MSG_5"));
+ }
+ }
+ else
+ {
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("VISTA_MMCSS_MSG_2")) == IDYES)
+ {
+ MsSetMMCSSNetworkThrottlingEnable(true);
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("VISTA_MMCSS_MSG_6"));
+ }
+ }
+ }
+ }
+ break;
+ case CMD_TRAFFIC:
+ // Communication traffic measurement
+ if (IsEnable(hWnd, 0))
+ {
+ CmTraffic(hWnd);
+ }
+ break;
+ case CMD_CM_SETTING:
+ // Operation mode setting
+ if (IsEnable(hWnd, 0))
+ {
+ if (CmSetting(hWnd))
+ {
+ CmApplyCmSetting();
+ }
+ }
+ break;
+ case CMD_WINNET:
+ // Windows network settings
+ ShowWindowsNetworkConnectionDialog();
+ break;
+ }
+}
+
+// Option dialog
+void CmConfigDlg(HWND hWnd)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_CM_CONFIG, CmConfigDlgProc, NULL);
+}
+
+// Initialize the option dialog
+void CmConfigDlgInit(HWND hWnd)
+{
+ bool use_alpha;
+ UINT alpha_value;
+ UINT os;
+ CLIENT_CONFIG c;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ DlgFont(hWnd, S_WARNING, 10, true);
+ DlgFont(hWnd, S_INFO, 10, false);
+
+ Zero(&c, sizeof(c));
+ if (CALL(hWnd, CcGetClientConfig(cm->Client, &c)) == false)
+ {
+ EndDialog(hWnd, 0);
+ return;
+ }
+
+ Check(hWnd, R_ALLOW_REMOTE_CONFIG, c.AllowRemoteConfig);
+
+ Check(hWnd, R_USE_KEEP_CONNECT, c.UseKeepConnect);
+ SetTextA(hWnd, E_HOSTNAME, c.KeepConnectHost);
+ SetIntEx(hWnd, E_PORT, c.KeepConnectPort);
+ SetIntEx(hWnd, E_INTERVAL, c.KeepConnectInterval);
+
+ Check(hWnd, R_TCP, c.KeepConnectProtocol == CONNECTION_TCP);
+ Check(hWnd, R_UDP, c.KeepConnectProtocol == CONNECTION_UDP);
+
+ use_alpha = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "UseAlpha") == 0 ? false : true;
+ alpha_value = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "AlphaValue");
+ alpha_value = MAKESURE(alpha_value, 0, 100);
+
+ SetInt(hWnd, E_ALPHA_VALUE, alpha_value == 0 ? 50 : alpha_value);
+ Check(hWnd, R_ALPHA, use_alpha);
+
+ os = GetOsInfo()->OsType;
+ if (OS_IS_WINDOWS_NT(os) && GET_KETA(os, 100) >= 2)
+ {
+ Enable(hWnd, R_ALPHA);
+ }
+ else
+ {
+ Disable(hWnd, R_ALPHA);
+ }
+
+ CmConfigDlgRefresh(hWnd);
+}
+
+// Update the option dialog
+void CmConfigDlgRefresh(HWND hWnd)
+{
+ bool ok = true;
+ bool use_keep_connect;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ use_keep_connect = IsChecked(hWnd, R_USE_KEEP_CONNECT);
+ SetEnable(hWnd, S_HOSTNAME, use_keep_connect);
+ SetEnable(hWnd, S_PORT, use_keep_connect);
+ SetEnable(hWnd, S_INTERVAL, use_keep_connect);
+ SetEnable(hWnd, S_INTERVAL2, use_keep_connect);
+ SetEnable(hWnd, S_PROTOCOL, use_keep_connect);
+ SetEnable(hWnd, S_INFO, use_keep_connect);
+ SetEnable(hWnd, S_INFO2, use_keep_connect);
+ SetEnable(hWnd, E_HOSTNAME, use_keep_connect);
+ SetEnable(hWnd, E_PORT, use_keep_connect);
+ SetEnable(hWnd, E_INTERVAL, use_keep_connect);
+ SetEnable(hWnd, R_TCP, use_keep_connect);
+ SetEnable(hWnd, R_UDP, use_keep_connect);
+
+ SetEnable(hWnd, S_WARNING, IsChecked(hWnd, R_ALLOW_REMOTE_CONFIG));
+
+ if (IsChecked(hWnd, R_USE_KEEP_CONNECT))
+ {
+ if (IsEmpty(hWnd, E_HOSTNAME))
+ {
+ ok = false;
+ }
+ if (IsChecked(hWnd, R_TCP) == false && IsChecked(hWnd, R_UDP) == false)
+ {
+ ok = false;
+ }
+ if (GetInt(hWnd, E_PORT) == 0 || GetInt(hWnd, E_PORT) >= 65536)
+ {
+ ok = false;
+ }
+ if (GetInt(hWnd, E_INTERVAL) == 0)
+ {
+ ok = false;
+ }
+ }
+
+ if (IsChecked(hWnd, R_ALPHA))
+ {
+ UINT i = GetInt(hWnd, E_ALPHA_VALUE);
+ if (i < 20 || i >= 100)
+ {
+ ok = false;
+ }
+ Enable(hWnd, E_ALPHA_VALUE);
+ }
+ else
+ {
+ Disable(hWnd, E_ALPHA_VALUE);
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Save the setting of the option dialog
+void CmConfigDlgOnOk(HWND hWnd)
+{
+ CLIENT_CONFIG c;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ Zero(&c, sizeof(c));
+ c.AllowRemoteConfig = IsChecked(hWnd, R_ALLOW_REMOTE_CONFIG);
+ c.UseKeepConnect = IsChecked(hWnd, R_USE_KEEP_CONNECT);
+ GetTxtA(hWnd, E_HOSTNAME, c.KeepConnectHost, sizeof(c.KeepConnectHost));
+ c.KeepConnectPort = GetInt(hWnd, E_PORT);
+ c.KeepConnectInterval = GetInt(hWnd, E_INTERVAL);
+ if (IsChecked(hWnd, R_TCP))
+ {
+ c.KeepConnectProtocol = CONNECTION_TCP;
+ }
+ else if (IsChecked(hWnd, R_UDP))
+ {
+ c.KeepConnectProtocol = CONNECTION_UDP;
+ }
+ else
+ {
+ return;
+ }
+
+ if (c.UseKeepConnect)
+ {
+ if (c.KeepConnectInterval < KEEP_INTERVAL_MIN || c.KeepConnectInterval > KEEP_INTERVAL_MAX)
+ {
+ MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("CM_KEEP_INTERVAL_MSG"),
+ KEEP_INTERVAL_MIN, KEEP_INTERVAL_MAX);
+ FocusEx(hWnd, E_INTERVAL);
+ return;
+ }
+ }
+
+ if (CALL(hWnd, CcSetClientConfig(cm->Client, &c)) == false)
+ {
+ return;
+ }
+
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "AlphaValue", GetInt(hWnd, E_ALPHA_VALUE));
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "UseAlpha", IsChecked(hWnd, R_ALPHA));
+
+ EndDialog(hWnd, true);
+}
+
+// Option setting dialog procedure
+UINT CmConfigDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmConfigDlgInit(hWnd);
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case R_ALLOW_REMOTE_CONFIG:
+ case R_USE_KEEP_CONNECT:
+ case E_HOSTNAME:
+ case E_PORT:
+ case E_INTERVAL:
+ case R_ALPHA:
+ case E_ALPHA_VALUE:
+ CmConfigDlgRefresh(hWnd);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ CmConfigDlgRefresh(hWnd);
+ CmConfigDlgOnOk(hWnd);
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ case R_ALLOW_REMOTE_CONFIG:
+ if (IsChecked(hWnd, R_ALLOW_REMOTE_CONFIG) == false)
+ {
+ if (cm->server_name != NULL)
+ {
+ // If the current user is remotely connected, show a warning
+ // when the user choose to disable the remote management
+ if (MsgBoxEx(hWnd, MB_ICONEXCLAMATION | MB_DEFBUTTON2 | MB_YESNO, _UU("CM_REMOTE_WARNING"),
+ cm->server_name, cm->server_name) == IDNO)
+ {
+ Check(hWnd, R_ALLOW_REMOTE_CONFIG, true);
+ }
+ }
+ }
+ break;
+ case R_USE_KEEP_CONNECT:
+ if (IsChecked(hWnd, R_USE_KEEP_CONNECT))
+ {
+ FocusEx(hWnd, E_HOSTNAME);
+ }
+ break;
+ case R_ALPHA:
+ if (IsChecked(hWnd, R_ALPHA))
+ {
+ FocusEx(hWnd, E_ALPHA_VALUE);
+ }
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Create a shortcut
+void CmSortcut(HWND hWnd, wchar_t *account_name)
+{
+ wchar_t tmp[MAX_SIZE];
+ CM_ACCOUNT *a;
+ wchar_t *filename;
+ UCHAR key[SHA1_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return;
+ }
+
+ // Get the account information
+ a = CmGetExistAccountObject(hWnd, account_name);
+ if (a == NULL)
+ {
+ return;
+ }
+
+ Copy(key, a->ShortcutKey, SHA1_SIZE);
+
+ if (IsZero(key, SHA1_SIZE))
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_SHORTCUT_UNSUPPORTED"));
+ }
+ else
+ {
+ // Determine the file name
+ UniFormat(tmp, sizeof(tmp), L"%s.lnk", account_name);
+ UniSafeFileName(tmp);
+
+ filename = SaveDlg(hWnd, _UU("CM_SHORTCUT_FILE"),
+ _UU("CM_SHORTCUT_SAVE_TITLE"), tmp, L".vpn");
+
+ if (filename != NULL)
+ {
+ char key_str[64];
+ wchar_t target[MAX_PATH];
+ wchar_t workdir[MAX_PATH];
+ wchar_t args[MAX_PATH];
+ wchar_t comment[MAX_SIZE];
+ wchar_t icon[MAX_PATH];
+
+ BinToStr(key_str, sizeof(key_str), key, SHA1_SIZE);
+
+ // Create a shortcut
+ UniStrCpy(target, sizeof(target), MsGetExeFileNameW());
+ UniStrCpy(workdir, sizeof(workdir), MsGetExeDirNameW());
+ StrToUni(args, sizeof(args), key_str);
+ UniFormat(comment, sizeof(comment), _UU("CM_SHORTCUT_COMMENT"), account_name);
+ UniStrCpy(icon, sizeof(icon), MsGetExeFileNameW());
+
+ if (CreateLink(filename, target, workdir, args, comment, icon, 1) == false)
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("CM_SHORTCUT_ERROR"));
+ }
+
+ Free(filename);
+ }
+ }
+
+ CmFreeAccountObject(hWnd, a);
+}
+
+// Export the account
+void CmExportAccount(HWND hWnd, wchar_t *account_name)
+{
+ wchar_t tmp[MAX_SIZE];
+ CM_ACCOUNT *a;
+ wchar_t *filename;
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return;
+ }
+
+ // Get the account information
+ a = CmGetExistAccountObject(hWnd, account_name);
+ if (a == NULL)
+ {
+ return;
+ }
+
+ // Determine the file name
+ UniFormat(tmp, sizeof(tmp), L"%s.vpn", account_name);
+ UniSafeFileName(tmp);
+
+ filename = SaveDlg(hWnd, _UU("CM_ACCOUNT_SETTING_FILE"),
+ _UU("CM_ACCOUNT_SAVE_TITLE"), tmp, L".vpn");
+
+ if (filename != NULL)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT t;
+ BUF *b;
+ BUF *b2;
+ wchar_t tmp[MAX_SIZE];
+ UCHAR *buf;
+ UINT buf_size;
+ UCHAR bom[] = {0xef, 0xbb, 0xbf, };
+
+ Zero(&t, sizeof(t));
+ t.ClientOption = a->ClientOption;
+ t.ClientAuth = a->ClientAuth;
+ t.StartupAccount = a->Startup;
+ t.CheckServerCert = a->CheckServerCert;
+ t.ServerCert = a->ServerCert;
+ t.ClientOption->FromAdminPack = false;
+
+ b = CiAccountToCfg(&t);
+
+ SeekBuf(b, 0, 0);
+
+ // Check whether the password is contained
+ if (CiHasAccountSensitiveInformation(b))
+ {
+ SeekBuf(b, 0, 0);
+
+ // Confirm that the user want to clear the password
+ if (MsgBox(hWnd, MB_YESNO | MB_ICONQUESTION, _UU("CM_ACCOUNT_MSG_SENSITIVE")) == IDYES)
+ {
+ // Erase
+ CiEraseSensitiveInAccount(b);
+ }
+ }
+
+ UniStrCpy(tmp, sizeof(tmp), filename);
+ b2 = NewBuf();
+
+ WriteBuf(b2, bom, sizeof(bom));
+
+ // Add a header part
+ buf_size = CalcUniToUtf8(_UU("CM_ACCOUNT_FILE_BANNER"));
+ buf = ZeroMalloc(buf_size + 32);
+ UniToUtf8(buf, buf_size, _UU("CM_ACCOUNT_FILE_BANNER"));
+
+ WriteBuf(b2, buf, StrLen((char *)buf));
+ WriteBuf(b2, b->Buf, b->Size);
+ SeekBuf(b2, 0, 0);
+
+ FreeBuf(b);
+
+ if (DumpBufW(b2, tmp) == false)
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("CM_FAILED_TO_SAVE_FILE"));
+ }
+
+ Free(filename);
+ FreeBuf(b2);
+ Free(buf);
+ }
+
+ CmFreeAccountObject(hWnd, a);
+}
+
+// Main process of importing account
+void CmImportAccountMain(HWND hWnd, wchar_t *filename)
+{
+ CmImportAccountMainEx(hWnd, filename, false);
+}
+void CmImportAccountMainEx(HWND hWnd, wchar_t *filename, bool overwrite)
+{
+ wchar_t name[MAX_SIZE];
+ wchar_t tmp[MAX_SIZE];
+ BUF *b;
+ RPC_CLIENT_CREATE_ACCOUNT *t;
+ // Validate arguments
+ if (hWnd == NULL || filename == NULL)
+ {
+ return;
+ }
+
+ UniStrCpy(tmp, sizeof(tmp), filename);
+
+ b = ReadDumpW(tmp);
+ if (b == NULL)
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("CM_FAILED_TO_OPEN_FILE"));
+ return;
+ }
+
+ t = CiCfgToAccount(b);
+ if (t == NULL)
+ {
+ FreeBuf(b);
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("CM_ACCOUNT_PARSE_FAILED"));
+ return;
+ }
+
+ if (overwrite)
+ {
+ // If the same name already exists, remove it
+ if (LvSearchStr(hWnd, L_ACCOUNT, 0, t->ClientOption->AccountName) != INFINITE)
+ {
+ RPC_CLIENT_DELETE_ACCOUNT d;
+ RPC_CLIENT_GET_ACCOUNT get;
+ HWND h = cm->hEasyWnd == NULL ? hWnd : cm->hEasyWnd;
+
+ Zero(&d, sizeof(d));
+ UniStrCpy(d.AccountName, sizeof(d.AccountName), t->ClientOption->AccountName);
+
+ Zero(&get, sizeof(get));
+ UniStrCpy(get.AccountName, sizeof(get.AccountName), t->ClientOption->AccountName);
+ if (CcGetAccount(cm->Client, &get) == ERR_NO_ERROR)
+ {
+ // Inherit the information of some of the client option by getting
+ // the account information of the same name that already exists
+ if (get.ClientOption != NULL && get.ClientAuth != NULL)
+ {
+ CLIENT_OPTION *old_option = get.ClientOption;
+ CLIENT_AUTH *old_auth = get.ClientAuth;
+
+ // Inherit the connection parameters
+ t->ClientOption->ProxyType = old_option->ProxyType;
+ StrCpy(t->ClientOption->ProxyName, sizeof(t->ClientOption->ProxyName),
+ old_option->ProxyName);
+ t->ClientOption->ProxyPort = old_option->ProxyPort;
+ StrCpy(t->ClientOption->ProxyUsername, sizeof(t->ClientOption->ProxyUsername),
+ old_option->ProxyUsername);
+ StrCpy(t->ClientOption->ProxyPassword, sizeof(t->ClientOption->ProxyPassword),
+ old_option->ProxyPassword);
+ t->ClientOption->NumRetry = old_option->NumRetry;
+ t->ClientOption->RetryInterval = old_option->RetryInterval;
+ t->ClientOption->MaxConnection = old_option->MaxConnection;
+ t->ClientOption->UseEncrypt = old_option->UseEncrypt;
+ t->ClientOption->UseCompress = old_option->UseCompress;
+ t->ClientOption->HalfConnection = old_option->HalfConnection;
+ t->ClientOption->NoRoutingTracking = old_option->NoRoutingTracking;
+ StrCpy(t->ClientOption->DeviceName, sizeof(t->ClientOption->DeviceName),
+ old_option->DeviceName);
+ t->ClientOption->AdditionalConnectionInterval = old_option->AdditionalConnectionInterval;
+ t->ClientOption->ConnectionDisconnectSpan = old_option->ConnectionDisconnectSpan;
+ t->ClientOption->HideStatusWindow = old_option->HideStatusWindow;
+ t->ClientOption->RequireMonitorMode = old_option->RequireMonitorMode;
+ t->ClientOption->RequireBridgeRoutingMode = old_option->RequireBridgeRoutingMode;
+ t->ClientOption->DisableQoS = old_option->DisableQoS;
+ t->ClientOption->NoTls1 = old_option->NoTls1;
+
+ // Inherit the authentication data
+ CiFreeClientAuth(t->ClientAuth);
+ t->ClientAuth = CopyClientAuth(old_auth);
+
+ // Other Settings
+ t->StartupAccount = get.StartupAccount;
+ t->CheckServerCert = get.CheckServerCert;
+ if (t->ServerCert != NULL)
+ {
+ FreeX(t->ServerCert);
+ }
+ t->ServerCert = NULL;
+ if (get.ServerCert != NULL)
+ {
+ t->ServerCert = CloneX(get.ServerCert);
+ }
+ Copy(t->ShortcutKey, get.ShortcutKey, sizeof(t->ShortcutKey));
+ }
+
+ CiFreeClientGetAccount(&get);
+ }
+
+ if (CALL(h, CcDeleteAccount(cm->Client, &d)) == false)
+ {
+ CiFreeClientCreateAccount(t);
+ Free(t);
+ return;
+ }
+
+ CmRefreshAccountList(hWnd);
+ }
+ }
+
+ CmGenerateImportName(hWnd, name, sizeof(name), t->ClientOption->AccountName);
+ UniStrCpy(t->ClientOption->AccountName, sizeof(t->ClientOption->AccountName), name);
+
+ if (overwrite)
+ {
+ t->ClientOption->FromAdminPack = true;
+ }
+
+ CALL(hWnd, CcCreateAccount(cm->Client, t));
+
+ CiFreeClientCreateAccount(t);
+ Free(t);
+
+ FreeBuf(b);
+
+ if (overwrite)
+ {
+ // Start to connect the VPN
+ CmConnect(hWnd, name);
+ }
+
+ //MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("CM_IMPORT_MESSAGE"), filename, name);
+}
+
+// Import an account
+void CmImportAccount(HWND hWnd)
+{
+ wchar_t *filename;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Open the file
+ filename = OpenDlg(hWnd, _UU("CM_ACCOUNT_SETTING_FILE"), _UU("CM_ACCOUNT_OPEN_TITLE"));
+ if (filename == NULL)
+ {
+ return;
+ }
+
+ UniStrCpy(tmp, sizeof(tmp), filename);
+ Free(filename);
+
+ CmImportAccountMain(hWnd, tmp);
+}
+
+// Create a copy of the account
+void CmCopyAccount(HWND hWnd, wchar_t *account_name)
+{
+ wchar_t tmp[MAX_SIZE];
+ CM_ACCOUNT *a;
+ RPC_CLIENT_CREATE_ACCOUNT c;
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return;
+ }
+
+ CmGenerateCopyName(hWnd, tmp, sizeof(tmp), account_name);
+
+ // Get an account information
+ a = CmGetExistAccountObject(hWnd, account_name);
+ if (a == NULL)
+ {
+ return;
+ }
+
+ // Change the account name
+ UniStrCpy(a->ClientOption->AccountName, sizeof(a->ClientOption->AccountName), tmp);
+
+ // Write
+ Zero(&c, sizeof(c));
+ c.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(c.ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));
+ c.ClientAuth = CopyClientAuth(a->ClientAuth);
+ if (a->ServerCert)
+ {
+ c.ServerCert = CloneX(a->ServerCert);
+ }
+ c.CheckServerCert = a->CheckServerCert;
+ c.StartupAccount = false; // Don't copy the startup attribute
+
+ CALL(hWnd, CcCreateAccount(cm->Client, &c));
+ CiFreeClientCreateAccount(&c);
+
+ CmFreeAccountObject(hWnd, a);
+}
+
+// Update the Virtual LAN Card Name dialog
+void CmNewVLanDlgUpdate(HWND hWnd)
+{
+ bool ok = true;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ GetTxtA(hWnd, E_NAME, tmp, sizeof(tmp));
+ if (IsSafeStr(tmp) == false)
+ {
+ ok = false;
+ }
+ if (SearchStrEx(tmp, " ", 0, false) != INFINITE)
+ {
+ ok = false;
+ }
+
+ Trim(tmp);
+ if (StrLen(tmp) == 0)
+ {
+ ok = false;
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Virtual LAN card name decision dialog procedure
+UINT CmNewVLanDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ char *tmp = (char *)param;
+ char default_name[MAX_SIZE];
+ RPC_CLIENT_VERSION ver;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ LimitText(hWnd, E_NAME, cm->Client->Win9x ? MAX_DEVICE_NAME_LEN_9X : MAX_DEVICE_NAME_LEN);
+ FormatText(hWnd, S_INFO, cm->Client->Win9x ? MAX_DEVICE_NAME_LEN_9X : MAX_DEVICE_NAME_LEN);
+
+ Zero(&ver, sizeof(ver));
+
+ if (CcGetClientVersion(cm->Client, &ver) == ERR_NO_ERROR)
+ {
+ if (ver.IsVLanNameRegulated)
+ {
+ Show(hWnd, S_WIN8);
+ }
+ }
+
+ if (CiGetNextRecommendedVLanName(cm->Client, default_name, sizeof(default_name)))
+ {
+ // Show a default virtual LAN card name candidate
+ SetTextA(hWnd, E_NAME, default_name);
+ }
+
+ CmNewVLanDlgUpdate(hWnd);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ if (cm->Client->Win9x)
+ {
+ // For Windows 9x, show a confirmation message
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_OKCANCEL, _UU("CM_9X_VLAN_INSTALL")) == IDCANCEL)
+ {
+ break;
+ }
+ }
+ GetTxtA(hWnd, E_NAME, tmp, (cm->Client->Win9x ? MAX_DEVICE_NAME_LEN_9X : MAX_DEVICE_NAME_LEN) + 1);
+ Trim(tmp);
+
+ if (CcGetClientVersion(cm->Client, &ver) == ERR_NO_ERROR)
+ {
+ if (ver.IsVLanNameRegulated)
+ {
+ if (CiIsValidVLanRegulatedName(tmp) == false)
+ {
+ // Virtual LAN card name isn't meeting the format
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("D_CM_NEW_VLAN@S_WIN8"));
+
+ FocusEx(hWnd, E_NAME);
+ break;
+ }
+ }
+ }
+
+ EndDialog(hWnd, true);
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ switch (LOWORD(wParam))
+ {
+ case E_NAME:
+ CmNewVLanDlgUpdate(hWnd);
+ break;
+
+ case R_USE_DISCONNECT:
+ if (IsChecked(hWnd, R_USE_DISCONNECT))
+ {
+ FocusEx(hWnd, E_DISCONNECT_SPAN);
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Dialog to determine the new virtual LAN card name
+char *CmNewVLanDlg(HWND hWnd)
+{
+ char tmp[MAX_DEVICE_NAME_LEN + 1];
+
+ if (Dialog(hWnd, D_CM_NEW_VLAN, CmNewVLanDlgProc, tmp) == false)
+ {
+ return NULL;
+ }
+
+ return CopyStr(tmp);
+}
+
+// Update the advanced settings dialog
+void CmDetailDlgUpdate(HWND hWnd, CM_ACCOUNT *a)
+{
+ bool ok = true;
+ bool locked;
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+ locked = a->LockMode;
+
+ if (a->LinkMode || a->NatMode)
+ {
+ Disable(hWnd, R_NO_ROUTING);
+ }
+ else
+ {
+ if (cm->Client->Unix)
+ {
+ Disable(hWnd, R_NO_ROUTING);
+ }
+ }
+
+ SetEnable(hWnd, E_DISCONNECT_SPAN, IsChecked(hWnd, R_USE_DISCONNECT));
+
+ SetEnable(hWnd, IDOK, ok);
+
+ if (locked)
+ {
+ Disable(hWnd, C_NUM_TCP);
+ Disable(hWnd, S_STATIC5);
+ Disable(hWnd, S_STATIC8);
+ Disable(hWnd, E_INTERVAL);
+ Disable(hWnd, S_STATIC9);
+ Disable(hWnd, E_DISCONNECT_SPAN);
+ Disable(hWnd, S_STATIC10);
+ Disable(hWnd, S_STATIC11);
+ Disable(hWnd, R_USE_DISCONNECT);
+ Disable(hWnd, R_USE_HALF_CONNECTION);
+ Disable(hWnd, R_DISABLE_QOS);
+ Disable(hWnd, R_USE_ENCRYPT);
+ Disable(hWnd, R_USE_COMPRESS);
+ Disable(hWnd, R_BRIDGE);
+ Disable(hWnd, R_MONITOR);
+ Disable(hWnd, R_NO_ROUTING);
+ }
+}
+
+// Advanced Settings dialog procedure
+UINT CmDetailDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ CM_ACCOUNT *a = (CM_ACCOUNT *)param;
+ UINT i;
+ UINT num;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Number of TCP connections
+ for (i = 1;i <= MAX_TCP_CONNECTION;i++)
+ {
+ UniFormat(tmp, sizeof(tmp), L"%u", i);
+ CbAddStr(hWnd, C_NUM_TCP, tmp, i);
+ }
+ CbSelect(hWnd, C_NUM_TCP, a->ClientOption->MaxConnection);
+
+ // Connection establishment interval
+ SetInt(hWnd, E_INTERVAL, a->ClientOption->AdditionalConnectionInterval);
+
+ // Lifetime
+ SetIntEx(hWnd, E_DISCONNECT_SPAN, a->ClientOption->ConnectionDisconnectSpan);
+ Check(hWnd, R_USE_DISCONNECT, a->ClientOption->ConnectionDisconnectSpan != 0);
+ Check(hWnd, R_USE_HALF_CONNECTION, a->ClientOption->HalfConnection);
+ Check(hWnd, R_USE_ENCRYPT, a->ClientOption->UseEncrypt);
+ Check(hWnd, R_USE_COMPRESS, a->ClientOption->UseCompress);
+ Check(hWnd, R_NO_ROUTING, a->ClientOption->NoRoutingTracking);
+ Check(hWnd, R_DISABLE_QOS, a->ClientOption->DisableQoS);
+ Check(hWnd, R_DISABLE_UDP, a->ClientOption->NoUdpAcceleration);
+
+ // Select the Connection Mode
+ if (a->LinkMode == false)
+ {
+ Check(hWnd, R_BRIDGE, a->ClientOption->RequireBridgeRoutingMode);
+ Check(hWnd, R_MONITOR, a->ClientOption->RequireMonitorMode);
+ }
+ else
+ {
+ Check(hWnd, R_BRIDGE, true);
+ Check(hWnd, R_MONITOR, false);
+
+ SetText(hWnd, S_MODE, _UU("CM_DETAIL_MODE_LINK_STR"));
+ Disable(hWnd, R_BRIDGE);
+ Disable(hWnd, R_MONITOR);
+ }
+
+ CmDetailDlgUpdate(hWnd, a);
+ Focus(hWnd, IDOK);
+ break;
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ if (IsChecked(hWnd, R_USE_DISCONNECT) && GetInt(hWnd, E_DISCONNECT_SPAN) == 0)
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_NO_DISCONNECT_SPAN"));
+ FocusEx(hWnd, E_DISCONNECT_SPAN);
+ break;
+ }
+ num = GetInt(hWnd, C_NUM_TCP);
+ if (num == 0)
+ {
+ break;
+ }
+ if (num == 1 && IsChecked(hWnd, R_USE_HALF_CONNECTION))
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_HALF_MSG"));
+ Focus(hWnd, C_NUM_TCP);
+ break;
+ }
+ if (GetInt(hWnd, E_INTERVAL) < 1)
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_TOO_SMALL_INTERVAL"));
+ Focus(hWnd, E_INTERVAL);
+ break;
+ }
+
+ a->ClientOption->MaxConnection = num;
+ a->ClientOption->AdditionalConnectionInterval = GetInt(hWnd, E_INTERVAL);
+ if (IsChecked(hWnd, R_USE_DISCONNECT) == false)
+ {
+ a->ClientOption->ConnectionDisconnectSpan = 0;
+ }
+ else
+ {
+ a->ClientOption->ConnectionDisconnectSpan = GetInt(hWnd, E_DISCONNECT_SPAN);
+ }
+ a->ClientOption->HalfConnection = IsChecked(hWnd, R_USE_HALF_CONNECTION);
+ a->ClientOption->UseEncrypt = IsChecked(hWnd, R_USE_ENCRYPT);
+ a->ClientOption->UseCompress = IsChecked(hWnd, R_USE_COMPRESS);
+ a->ClientOption->NoRoutingTracking = IsChecked(hWnd, R_NO_ROUTING);
+ a->ClientOption->DisableQoS = IsChecked(hWnd, R_DISABLE_QOS);
+ a->ClientOption->NoUdpAcceleration = IsChecked(hWnd, R_DISABLE_UDP);
+
+ if (a->LinkMode)
+ {
+ a->ClientOption->RequireBridgeRoutingMode = true;
+ a->ClientOption->RequireMonitorMode = false;
+ }
+ else
+ {
+ a->ClientOption->RequireBridgeRoutingMode = IsChecked(hWnd, R_BRIDGE);
+ a->ClientOption->RequireMonitorMode = IsChecked(hWnd, R_MONITOR);
+ }
+
+ EndDialog(hWnd, true);
+
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ switch (LOWORD(wParam))
+ {
+ case C_NUM_TCP:
+ case E_INTERVAL:
+ case E_DISCONNECT_SPAN:
+ case R_USE_DISCONNECT:
+ case R_USE_HALF_CONNECTION:
+ CmDetailDlgUpdate(hWnd, a);
+ break;
+ }
+ switch (wParam)
+ {
+ case R_USE_DISCONNECT:
+ if (IsChecked(hWnd, R_USE_DISCONNECT))
+ {
+ FocusEx(hWnd, E_DISCONNECT_SPAN);
+ }
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Advanced Settings dialog
+bool CmDetailDlg(HWND hWnd, CM_ACCOUNT *a)
+{
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return false;
+ }
+
+ return Dialog(hWnd, D_CM_DETAIL, CmDetailDlgProc, a);
+}
+
+// Update the account editing dialog procedure
+void CmEditAccountDlgUpdate(HWND hWnd, CM_ACCOUNT *a)
+{
+ bool ok = true;
+ char str[MAX_SIZE];
+ bool locked;
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+ locked = a->LockMode;
+
+ if (a->Inited == false)
+ {
+ return;
+ }
+
+ if (a->EditMode)
+ {
+ Disable(hWnd, E_ACCOUNT_NAME);
+ }
+
+ // The name of connection settings
+ GetTxt(hWnd, E_ACCOUNT_NAME, a->ClientOption->AccountName, sizeof(a->ClientOption->AccountName));
+ UniTrim(a->ClientOption->AccountName);
+
+ // Host name
+ GetTxtA(hWnd, E_HOSTNAME, a->ClientOption->Hostname, sizeof(a->ClientOption->Hostname));
+ Trim(a->ClientOption->Hostname);
+
+ // Port number
+ a->ClientOption->Port = GetInt(hWnd, C_PORT);
+
+ // HUB name
+ GetTxtA(hWnd,C_HUBNAME, a->ClientOption->HubName, sizeof(a->ClientOption->HubName));
+
+ // Type of proxy
+ a->ClientOption->ProxyType = PROXY_DIRECT;
+ if (IsChecked(hWnd, R_HTTPS))
+ {
+ a->ClientOption->ProxyType = PROXY_HTTP;
+ }
+ if (IsChecked(hWnd, R_SOCKS))
+ {
+ a->ClientOption->ProxyType = PROXY_SOCKS;
+ }
+
+ // To validate the server certificate
+ a->CheckServerCert = IsChecked(hWnd, R_CHECK_CERT);
+
+ if (a->NatMode)
+ {
+ Disable(hWnd, R_CHECK_CERT);
+ Disable(hWnd, B_TRUST);
+ }
+
+ if (a->HideTrustCert)
+ {
+ Disable(hWnd, B_TRUST);
+ }
+
+ // Device name
+ StrCpy(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName), "");
+ if (LvIsSelected(hWnd, L_VLAN))
+ {
+ wchar_t *s = LvGetStr(hWnd, L_VLAN, LvGetSelected(hWnd, L_VLAN), 0);
+ if (s != NULL)
+ {
+ char str[MAX_SIZE];
+ UniToStr(str, sizeof(str), s);
+ CmPrintNameToVLanName(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName), str);
+ Free(s);
+ }
+ }
+
+ // User authentication
+ a->ClientAuth->AuthType = CbGetSelect(hWnd, C_TYPE);
+ GetTxtA(hWnd, E_USERNAME, a->ClientAuth->Username, sizeof(a->ClientAuth->Username));
+ Trim(a->ClientAuth->Username);
+ switch (a->ClientAuth->AuthType)
+ {
+ case CLIENT_AUTHTYPE_PASSWORD:
+ // Password authentication
+ GetTxtA(hWnd, E_PASSWORD, str, sizeof(str));
+ if (StrCmp(str, HIDDEN_PASSWORD) != 0)
+ {
+ HashPassword(a->ClientAuth->HashedPassword, a->ClientAuth->Username, str);
+ }
+ break;
+ case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+ // Plaintext password authentication
+ GetTxtA(hWnd, E_PASSWORD, str, sizeof(str));
+ if (StrCmp(str, HIDDEN_PASSWORD) != 0)
+ {
+ StrCpy(a->ClientAuth->PlainPassword, sizeof(a->ClientAuth->PlainPassword), str);
+ }
+ break;
+ }
+
+ // Reconnection option
+ if ((a->LinkMode || a->NatMode) || a->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE)
+ {
+ Disable(hWnd, R_RETRY);
+ }
+ else
+ {
+ Enable(hWnd, R_RETRY);
+ }
+
+ if (IsChecked(hWnd, R_RETRY) == false)
+ {
+ a->ClientOption->NumRetry = 0;
+ }
+ else
+ {
+ if (IsChecked(hWnd, R_INFINITE))
+ {
+ a->ClientOption->NumRetry = INFINITE;
+ }
+ else
+ {
+ a->ClientOption->NumRetry = GetInt(hWnd, E_RETRY_NUM);
+ }
+ }
+ a->ClientOption->RetryInterval = GetInt(hWnd, E_RETRY_SPAN);
+
+ a->ClientOption->NoTls1 = IsChecked(hWnd, R_NOTLS1);
+
+ // Information determining
+ if (UniStrLen(a->ClientOption->AccountName) == 0 && a->NatMode == false)
+ {
+ ok = false;
+ }
+ if (StrLen(a->ClientOption->Hostname) == 0)
+ {
+ ok = false;
+ }
+ if (a->ClientOption->Port == 0 || a->ClientOption->Port >= 65536)
+ {
+ ok = false;
+ }
+ if (StrLen(a->ClientOption->HubName) == 0)
+ {
+ ok = false;
+ }
+ if (StrLen(a->ClientAuth->Username) == 0)
+ {
+ ok = false;
+ }
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)
+ {
+ if (a->ClientAuth->ClientK == NULL || a->ClientAuth->ClientX == NULL)
+ {
+ ok = false;
+ }
+ }
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE)
+ {
+ if (IsEmptyStr(a->ClientAuth->SecurePrivateKeyName) || IsEmptyStr(a->ClientAuth->SecurePublicCertName))
+ {
+ ok = false;
+ }
+ }
+
+ // Display update
+ if (IsChecked(hWnd, R_RETRY) && IsEnable(hWnd, R_RETRY))
+ {
+ if (a->LinkMode == false && a->NatMode == false)
+ {
+ Enable(hWnd, R_INFINITE);
+ Enable(hWnd, E_RETRY_SPAN);
+ Enable(hWnd, S_RETRY_SPAN_1);
+ Enable(hWnd, S_RETRY_SPAN_2);
+ }
+ else
+ {
+ Disable(hWnd, R_INFINITE);
+ Disable(hWnd, E_RETRY_SPAN);
+ Disable(hWnd, S_RETRY_SPAN_1);
+ Disable(hWnd, S_RETRY_SPAN_2);
+ }
+ if (IsChecked(hWnd, R_INFINITE) == false)
+ {
+ Enable(hWnd, E_RETRY_NUM);
+ Enable(hWnd, S_RETRY_NUM_1);
+ Enable(hWnd, S_RETRY_NUM_2);
+ if (GetInt(hWnd, E_RETRY_NUM) == 0)
+ {
+ ok = false;
+ }
+ }
+ else
+ {
+ Disable(hWnd, E_RETRY_NUM);
+ Disable(hWnd, S_RETRY_NUM_1);
+ Disable(hWnd, S_RETRY_NUM_2);
+ }
+ }
+ else
+ {
+ Disable(hWnd, E_RETRY_NUM);
+ Disable(hWnd, E_RETRY_SPAN);
+ Disable(hWnd, R_INFINITE);
+ Disable(hWnd, S_RETRY_NUM_1);
+ Disable(hWnd, S_RETRY_NUM_2);
+ Disable(hWnd, S_RETRY_SPAN_1);
+ Disable(hWnd, S_RETRY_SPAN_2);
+ }
+
+ if (a->NatMode == false)
+ {
+ if (a->ServerCert == NULL)
+ {
+ SetText(hWnd, B_SERVER_CERT, _UU("CM_SERVER_CERT_1"));
+ Disable(hWnd, B_VIEW_SERVER_CERT);
+ }
+ else
+ {
+ SetText(hWnd, B_SERVER_CERT, _UU("CM_SERVER_CERT_2"));
+ Enable(hWnd, B_VIEW_SERVER_CERT);
+ }
+ }
+ else
+ {
+ Disable(hWnd, B_VIEW_SERVER_CERT);
+ Disable(hWnd, B_SERVER_CERT);
+ }
+
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT || a->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE)
+ {
+ wchar_t tmp[MAX_SIZE * 2];
+ wchar_t issuer[MAX_SIZE];
+ wchar_t subject[MAX_SIZE];
+ wchar_t expires[MAX_SIZE];
+
+ SetIcon(hWnd, S_CERT, (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT) ? ICO_CERT : ICO_SECURE);
+
+ Hide(hWnd, S_PASSWORD);
+ Hide(hWnd, E_PASSWORD);
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)
+ {
+ if (a->ClientAuth->ClientX != NULL)
+ {
+ Enable(hWnd, B_VIEW_CLIENT_CERT);
+ SetText(hWnd, B_REGIST_CLIENT_CERT, _UU("CM_CLIENT_CERT_2"));
+ GetPrintNameFromName(issuer, sizeof(issuer), a->ClientAuth->ClientX->issuer_name);
+ GetPrintNameFromName(subject, sizeof(subject), a->ClientAuth->ClientX->subject_name);
+ GetDateStrEx64(expires, sizeof(expires), SystemToLocal64(a->ClientAuth->ClientX->notAfter), NULL);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_CERT_INFO"), subject, issuer, expires);
+ }
+ else
+ {
+ Disable(hWnd, B_VIEW_CLIENT_CERT);
+ SetText(hWnd, B_REGIST_CLIENT_CERT, _UU("CM_CLIENT_CERT_1"));
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_NO_CERT"));
+ }
+ SetText(hWnd, B_VIEW_CLIENT_CERT, _UU("CM_VIEW_CLIENT_CERT"));
+
+ Enable(hWnd, B_REGIST_CLIENT_CERT);
+ }
+ else
+ {
+ if (IsEmptyStr(a->ClientAuth->SecurePrivateKeyName) || IsEmptyStr(a->ClientAuth->SecurePublicCertName))
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_NO_SECURE"));
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_CERT_SECURE_INFO"),
+ a->ClientAuth->SecurePublicCertName, a->ClientAuth->SecurePrivateKeyName);
+ }
+
+ SetText(hWnd, B_VIEW_CLIENT_CERT, _UU("CM_SELECT_SECURE_DEVICE"));
+ SetText(hWnd, B_REGIST_CLIENT_CERT, _UU("CM_SELECT_CERT_INCARD"));
+ Enable(hWnd, B_VIEW_CLIENT_CERT);
+
+ if (SmGetCurrentSecureIdFromReg() == 0)
+ {
+ Disable(hWnd, B_REGIST_CLIENT_CERT);
+ }
+ else
+ {
+ Enable(hWnd, B_REGIST_CLIENT_CERT);
+ }
+ }
+ SetText(hWnd, S_CERT_INFO, tmp);
+ Show(hWnd, S_CERT);
+ Show(hWnd, S_CERT_INFO);
+ Show(hWnd, B_VIEW_CLIENT_CERT);
+ Show(hWnd, B_REGIST_CLIENT_CERT);
+ }
+ else
+ {
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_ANONYMOUS)
+ {
+ Hide(hWnd, S_PASSWORD);
+ Hide(hWnd, E_PASSWORD);
+ }
+ else
+ {
+ Show(hWnd, S_PASSWORD);
+ Show(hWnd, E_PASSWORD);
+ }
+ Hide(hWnd, S_CERT);
+ Hide(hWnd, S_CERT_INFO);
+ Hide(hWnd, B_VIEW_CLIENT_CERT);
+ Hide(hWnd, B_REGIST_CLIENT_CERT);
+ }
+
+ if (a->ClientOption->ProxyType != PROXY_DIRECT)
+ {
+ Enable(hWnd, B_PROXY_CONFIG);
+ if (StrLen(a->ClientOption->ProxyName) == 0)
+ {
+ ok = false;
+ }
+ if (a->ClientOption->ProxyPort == 0)
+ {
+ ok = false;
+ }
+ }
+ else
+ {
+ Disable(hWnd, B_PROXY_CONFIG);
+ }
+
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_PASSWORD)
+ {
+ bool b = true;
+
+ if (ok == false)
+ {
+ b = false;
+ }
+
+ if (a->LinkMode == false && a->NatMode == false)
+ {
+ SetEnable(hWnd, B_CHANGE_PASSWORD, b);
+ SetEnable(hWnd, S_CHANGE_PASSWORD, b);
+ Show(hWnd, B_CHANGE_PASSWORD);
+ Show(hWnd, S_CHANGE_PASSWORD);
+ }
+ else
+ {
+ Hide(hWnd, B_CHANGE_PASSWORD);
+ Hide(hWnd, S_CHANGE_PASSWORD);
+ }
+ }
+ else
+ {
+ Hide(hWnd, B_CHANGE_PASSWORD);
+ Hide(hWnd, S_CHANGE_PASSWORD);
+ }
+
+ if ((StrLen(a->ClientOption->DeviceName) == 0) && (a->LinkMode == false && a->NatMode == false))
+ {
+ ok = false;
+ }
+
+ if (a->LinkMode || a->NatMode)
+ {
+ Disable(hWnd, L_VLAN);
+ }
+
+ if (a->EditMode == false)
+ {
+ char tmp[MAX_SIZE];
+ GetTxtA(hWnd, E_HOSTNAME, tmp, sizeof(tmp));
+ Trim(tmp);
+
+ if (StartWith(tmp, "127.") || (StrCmpi(tmp, "localhost") == 0))
+ {
+ if (a->Flag1 == false)
+ {
+ a->Flag1 = true;
+ a->ClientOption->UseEncrypt = a->ClientOption->UseCompress = false;
+ a->ClientOption->MaxConnection = 1;
+ }
+ }
+ }
+
+ a->ClientOption->HideStatusWindow = IsChecked(hWnd, R_HIDE);
+ a->ClientOption->HideNicInfoWindow = IsChecked(hWnd, R_HIDE2);
+
+ if (locked)
+ {
+ SetEnable(hWnd, E_HOSTNAME, false);
+ SetEnable(hWnd, C_PORT, false);
+ SetEnable(hWnd, C_HUBNAME, false);
+ SetEnable(hWnd, S_STATIC2, false);
+ SetEnable(hWnd, S_STATIC3, false);
+ SetEnable(hWnd, S_STATIC4, false);
+ SetEnable(hWnd, S_STATIC5, false);
+ SetEnable(hWnd, S_STATIC66, false);
+ SetEnable(hWnd, S_STATIC7, false);
+ SetEnable(hWnd, S_STATIC11, false);
+ SetEnable(hWnd, R_CHECK_CERT, false);
+ SetEnable(hWnd, B_TRUST, false);
+ SetEnable(hWnd, B_SERVER_CERT, false);
+ SetEnable(hWnd, B_VIEW_SERVER_CERT, false);
+ SetEnable(hWnd, R_RETRY, false);
+ SetEnable(hWnd, S_RETRY_NUM_1, false);
+ SetEnable(hWnd, E_RETRY_NUM, false);
+ SetEnable(hWnd, S_RETRY_NUM_2, false);
+ SetEnable(hWnd, S_RETRY_SPAN_1, false);
+ SetEnable(hWnd, E_RETRY_SPAN, false);
+ SetEnable(hWnd, S_RETRY_SPAN_2, false);
+ SetEnable(hWnd, R_INFINITE, false);
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Initialize the account editing dialog
+void CmEditAccountDlgInit(HWND hWnd, CM_ACCOUNT *a)
+{
+ RPC_CLIENT_ENUM_VLAN v;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+ if (a->LockMode)
+ {
+ SetText(hWnd, S_STATIC1, _UU("CM_EASY_ACCOUNT_WARNING"));
+ }
+
+ // Connection settings name
+ if (a->EditMode || a->NatMode)
+ {
+ Disable(hWnd, E_ACCOUNT_NAME);
+ }
+
+ if (a->NatMode || a->LinkMode)
+ {
+ Hide(hWnd, R_HIDE);
+ Hide(hWnd, R_HIDE2);
+ }
+
+ Check(hWnd, R_HIDE, a->ClientOption->HideStatusWindow);
+ Check(hWnd, R_HIDE2, a->ClientOption->HideNicInfoWindow);
+
+ if (a->NatMode)
+ {
+ Hide(hWnd, E_ACCOUNT_NAME);
+ Hide(hWnd, S_ACCOUNT_NAME);
+ }
+
+ if ((cm != NULL && cm->server_name != NULL) || a->LinkMode)
+ {
+ Hide(hWnd, B_IE);
+ }
+
+ SetText(hWnd, E_ACCOUNT_NAME, a->ClientOption->AccountName);
+
+ // Host name
+ SetTextA(hWnd, E_HOSTNAME, a->ClientOption->Hostname);
+ StrCpy(a->old_server_name, sizeof(a->old_server_name), a->ClientOption->Hostname);
+
+ // Port number
+ CbSetHeight(hWnd, C_PORT, 18);
+ CbAddStr(hWnd, C_PORT, _UU("CM_PORT_1"), 0);
+ CbAddStr(hWnd, C_PORT, _UU("CM_PORT_2"), 0);
+ CbAddStr(hWnd, C_PORT, _UU("CM_PORT_3"), 0);
+ CbAddStr(hWnd, C_PORT, _UU("CM_PORT_4"), 0);
+ SetInt(hWnd, C_PORT, a->ClientOption->Port);
+
+ // Virtual HUB name
+ CbSetHeight(hWnd, C_HUBNAME, 18);
+ SetTextA(hWnd, C_HUBNAME, a->ClientOption->HubName);
+
+ // Type of proxy
+ Check(hWnd, R_DIRECT_TCP, a->ClientOption->ProxyType == PROXY_DIRECT);
+ Check(hWnd, R_HTTPS, a->ClientOption->ProxyType == PROXY_HTTP);
+ Check(hWnd, R_SOCKS, a->ClientOption->ProxyType == PROXY_SOCKS);
+
+ // Verify the server certificate
+ Check(hWnd, R_CHECK_CERT, a->CheckServerCert);
+
+ // LAN card list
+ if (a->NatMode == false && a->LinkMode == false)
+ {
+ Zero(&v, sizeof(v));
+ CcEnumVLan(cm->Client, &v);
+ LvInit(hWnd, L_VLAN);
+ LvInsertColumn(hWnd, L_VLAN, 0, L"DeviceName", 345);
+ for (i = 0;i < v.NumItem;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+ CmVLanNameToPrintName(str, sizeof(str), v.Items[i]->DeviceName);
+ StrToUni(tmp, sizeof(tmp), str);
+ LvInsert(hWnd, L_VLAN, ICO_NIC_ONLINE, NULL, 1, tmp);
+ }
+// LvAutoSize(hWnd, L_VLAN);
+
+ if (v.NumItem == 1)
+ {
+ // If only one virtual LAN card exists, initially select it
+ LvSelect(hWnd, L_VLAN, 0);
+ }
+
+ CiFreeClientEnumVLan(&v);
+ }
+
+ // Select the LAN card
+ if (StrLen(a->ClientOption->DeviceName) != 0)
+ {
+ char str[MAX_SIZE];
+ wchar_t tmp[MAX_SIZE];
+ UINT index;
+ CmVLanNameToPrintName(str, sizeof(str), a->ClientOption->DeviceName);
+ StrToUni(tmp, sizeof(tmp), str);
+ index = LvSearchStr(hWnd, L_VLAN, 0, tmp);
+ if (index != INFINITE)
+ {
+ LvSelect(hWnd, L_VLAN, index);
+ }
+ }
+
+ // Authentication type
+ CbSetHeight(hWnd, C_TYPE, 18);
+ CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_0"), CLIENT_AUTHTYPE_ANONYMOUS);
+ CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_1"), CLIENT_AUTHTYPE_PASSWORD);
+ CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_2"), CLIENT_AUTHTYPE_PLAIN_PASSWORD);
+
+ if (a->HideClientCertAuth == false)
+ {
+ // Certificate authentication is not available when HideClientCertAuth is true
+ CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_3"), CLIENT_AUTHTYPE_CERT);
+ }
+
+ if (a->HideSecureAuth == false)
+ {
+ // Authentication using a smart card
+ CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_4"), CLIENT_AUTHTYPE_SECURE);
+ }
+
+ // Select an authentication
+ CbSelect(hWnd, C_TYPE, a->ClientAuth->AuthType);
+
+ // User name
+ SetTextA(hWnd, E_USERNAME, a->ClientAuth->Username);
+
+ // Password
+ if (a->EditMode)
+ {
+ SetTextA(hWnd, E_PASSWORD, HIDDEN_PASSWORD);
+ }
+
+ // Reconnection times
+ if (a->ClientOption->NumRetry == 0)
+ {
+ Check(hWnd, R_RETRY, false);
+ }
+ else
+ {
+ Check(hWnd, R_RETRY, true);
+ if (a->ClientOption->NumRetry == INFINITE)
+ {
+ Check(hWnd, R_INFINITE, true);
+ }
+ else
+ {
+ Check(hWnd, R_INFINITE, false);
+ SetInt(hWnd, E_RETRY_NUM, a->ClientOption->NumRetry);
+ }
+ }
+ SetIntEx(hWnd, E_RETRY_SPAN, a->ClientOption->RetryInterval);
+
+ Check(hWnd, R_NOTLS1, a->ClientOption->NoTls1);
+
+ // Title
+ if (a->NatMode == false)
+ {
+ if (a->EditMode == false)
+ {
+ SetText(hWnd, 0, _UU("CM_ACCOUNT_TITLE_1"));
+ FocusEx(hWnd, E_ACCOUNT_NAME);
+ }
+ else
+ {
+ SetText(hWnd, 0, _UU("CM_ACCOUNT_TITLE_2"));
+ FormatText(hWnd, 0, a->ClientOption->AccountName);
+ FocusEx(hWnd, E_HOSTNAME);
+ }
+ }
+ else
+ {
+ SetText(hWnd, 0, _UU("NM_ACCOUNT_TITLE"));
+ FocusEx(hWnd, E_HOSTNAME);
+ }
+
+ if (a->LinkMode || a->NatMode)
+ {
+ Hide(hWnd, L_VLAN);
+
+ if (a->NatMode == false)
+ {
+ SetText(hWnd, S_VLAN_GROUP, _UU("SM_LINK_POLICY_GROUP"));
+ Show(hWnd, S_POLICY_1);
+ Show(hWnd, S_POLICY_2);
+ Show(hWnd, B_POLICY);
+ }
+ else
+ {
+ Hide(hWnd, S_VLAN_GROUP);
+ Show(hWnd, S_ROUTER_LOGO);
+ }
+ }
+
+ // Display update
+ a->Inited = true;
+ CmEditAccountDlgUpdate(hWnd, a);
+}
+
+// Account editing dialog procedure
+UINT CmEditAccountDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ CM_ACCOUNT *a = (CM_ACCOUNT *)param;
+ NMHDR *n;
+ X *x;
+ K *k;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmEditAccountDlgInit(hWnd, a);
+ if (a->EditMode == false && a->LinkMode == false && a->NatMode == false)
+ {
+ SetTimer(hWnd, 1, 100, NULL);
+ }
+ break;
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ {
+ CM_INTERNET_SETTING s;
+
+ KillTimer(hWnd, 1);
+
+ Zero(&s, sizeof(s));
+ CmGetSystemInternetSetting(&s);
+
+ if (s.ProxyType != PROXY_DIRECT)
+ {
+ if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO,
+ _UU("CM_WOULDYOULOAD_IE_PROXY"),
+ s.ProxyHostName) == IDYES)
+ {
+ Command(hWnd, B_IE);
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_ACCOUNT_NAME:
+ case E_HOSTNAME:
+ case C_PORT:
+ case C_HUBNAME:
+ case R_DIRECT_TCP:
+ case R_HTTPS:
+ case R_SOCKS:
+ case R_CHECK_CERT:
+ case C_TYPE:
+ case E_USERNAME:
+ case E_PASSWORD:
+ case R_RETRY:
+ case E_RETRY_NUM:
+ case E_RETRY_SPAN:
+ case R_INFINITE:
+ CmEditAccountDlgUpdate(hWnd, a);
+ break;
+ }
+ switch (HIWORD(wParam))
+ {
+ case EN_KILLFOCUS:
+ switch (LOWORD(wParam))
+ {
+ case E_HOSTNAME:
+ CmEditAccountDlgStartEnumHub(hWnd, a);
+ break;
+ }
+ break;
+ case BN_KILLFOCUS:
+ switch (LOWORD(wParam))
+ {
+ case R_DIRECT_TCP:
+ case R_HTTPS:
+ case R_SOCKS:
+ CmEditAccountDlgStartEnumHub(hWnd, a);
+ break;
+ }
+ break;
+ case CBN_KILLFOCUS:
+ switch (LOWORD(wParam))
+ {
+ case C_PORT:
+ CmEditAccountDlgStartEnumHub(hWnd, a);
+ break;
+ }
+ break;
+ }
+ if (HIWORD(wParam) == 0)
+ {
+ CmEditAccountDlgUpdate(hWnd, a);
+ }
+ switch (wParam)
+ {
+ case B_POLICY:
+ // Policy
+ if (a->LinkMode || a->NatMode)
+ {
+ a->Policy.Access = true;
+ a->Policy.MonitorPort = false;
+ SmPolicyDlgEx2(hWnd, &a->Policy, _UU("SM_LINK_POLICY_CAPTION"), true, a->PolicyVer);
+ a->Policy.Access = true;
+ a->Policy.MonitorPort = false;
+ }
+ break;
+ case IDOK:
+ CmEditAccountDlgUpdate(hWnd, a);
+ CmEditAccountDlgOnOk(hWnd, a);
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ case B_PROXY_CONFIG:
+ // Proxy Settings
+ if (CmProxyDlg(hWnd, a->ClientOption))
+ {
+ UINT n = GetInt(hWnd, C_PORT);
+ if (a->ClientOption->ProxyType == PROXY_HTTP &&
+ n != 443)
+ {
+ // Show a warning message if the destination port is
+ // other than 443 and HTTP proxy is used
+ if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("CM_HTTP_PROXY_WARNING"), n) == IDYES)
+ {
+ // Change the port number to 443
+ SetText(hWnd, C_PORT, _UU("CM_PORT_2"));
+ }
+ }
+ CmEditAccountDlgStartEnumHub(hWnd, a);
+ CmEditAccountDlgUpdate(hWnd, a);
+ }
+ break;
+ case B_IE:
+ // Use the IE settings
+ if(cm->server_name == NULL)
+ {
+ CmProxyDlgUseForIE(hWnd, a->ClientOption);
+ CmEditAccountDlgUpdate(hWnd, a);
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_PROXY_FROM_IE"));
+ }
+ break;
+ case B_TRUST:
+ // CA
+ if (a->LinkMode == false)
+ {
+ CmTrustDlg(hWnd);
+ }
+ else
+ {
+ SmCaDlg(hWnd, a->Hub);
+ }
+ break;
+ case B_SERVER_CERT:
+ // Server certificate registration / delete
+ if (a->ServerCert == NULL)
+ {
+ if (CmLoadXFromFileOrSecureCard(hWnd, &x))
+ {
+ a->ServerCert = x;
+ CmEditAccountDlgUpdate(hWnd, a);
+ }
+ }
+ else
+ {
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_DELETE_SERVER_CERT")) == IDYES)
+ {
+ FreeX(a->ServerCert);
+ a->ServerCert = NULL;
+ CmEditAccountDlgUpdate(hWnd, a);
+ }
+ }
+ break;
+ case B_VIEW_SERVER_CERT:
+ // Show the server certificate
+ if (a->ServerCert != NULL)
+ {
+ X *issuer = CmGetIssuer(a->ServerCert);
+ CertDlg(hWnd, a->ServerCert, issuer, true);
+ FreeX(issuer);
+ }
+ break;
+ case B_VIEW_CLIENT_CERT:
+ if (a->ClientAuth->AuthType != CLIENT_AUTHTYPE_SECURE)
+ {
+ // Show the client certificate
+ if (a->ClientAuth->ClientX != NULL)
+ {
+ X *issuer = CmGetIssuer(a->ClientAuth->ClientX);
+ CertDlg(hWnd, a->ClientAuth->ClientX, issuer, true);
+ FreeX(issuer);
+ }
+ }
+ else
+ {
+ UINT id;
+ // Select the type of smart card
+ SmSelectSecureId(hWnd);
+ id = SmGetCurrentSecureIdFromReg();
+ if (id != 0)
+ {
+ if (cm->server_name == NULL)
+ {
+ RPC_USE_SECURE t;
+
+ Zero(&t, sizeof(t));
+ t.DeviceId = id;
+ CcUseSecure(cm->Client, &t);
+ }
+ }
+ CmEditAccountDlgUpdate(hWnd, a);
+ }
+ break;
+ case B_REGIST_CLIENT_CERT:
+ if (a->ClientAuth->AuthType != CLIENT_AUTHTYPE_SECURE)
+ {
+ // Client certificate registration / deletion
+ if (a->ClientAuth->ClientX == NULL)
+ {
+ if (CmLoadXAndK(hWnd, &x, &k))
+ {
+ a->ClientAuth->ClientX = x;
+ a->ClientAuth->ClientK = k;
+ CmEditAccountDlgUpdate(hWnd, a);
+ }
+ }
+ else
+ {
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_DELETE_CLIENT_CERT")) == IDYES)
+ {
+ FreeX(a->ClientAuth->ClientX);
+ FreeK(a->ClientAuth->ClientK);
+ a->ClientAuth->ClientX = NULL;
+ a->ClientAuth->ClientK = NULL;
+ CmEditAccountDlgUpdate(hWnd, a);
+ }
+ }
+ }
+ else
+ {
+ char cert[MAX_SECURE_DEVICE_FILE_LEN + 1], priv[MAX_SECURE_DEVICE_FILE_LEN + 1];
+
+ // Select a certificate in the smart card
+ if (SmSelectKeyPairEx(hWnd, cert, sizeof(cert), priv, sizeof(priv), CmGetSecureBitmapId(a->ClientOption->Hostname)))
+ {
+ StrCpy(a->ClientAuth->SecurePublicCertName, sizeof(a->ClientAuth->SecurePublicCertName), cert);
+ StrCpy(a->ClientAuth->SecurePrivateKeyName, sizeof(a->ClientAuth->SecurePrivateKeyName), priv);
+ CmEditAccountDlgUpdate(hWnd, a);
+ }
+ }
+ break;
+ case B_DETAIL:
+ // Advanced communication settings
+ if (CmDetailDlg(hWnd, a))
+ {
+ CmEditAccountDlgUpdate(hWnd, a);
+ }
+ break;
+ case B_CHANGE_PASSWORD:
+ // Change the password
+ CmChangePassword(hWnd, a->ClientOption, a->ClientOption->HubName,
+ a->ClientAuth->Username);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_VLAN:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ CmEditAccountDlgUpdate(hWnd, a);
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Update the proxy server settings
+void CmProxyDlgUpdate(HWND hWnd, CLIENT_OPTION *a)
+{
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+ if (IsEmpty(hWnd, E_HOSTNAME))
+ {
+ ok = false;
+ }
+ if (GetInt(hWnd, C_PORT) == 0)
+ {
+ ok = false;
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Proxy server settings dialog c
+UINT CmProxyDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ CLIENT_OPTION *a = (CLIENT_OPTION *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetTextA(hWnd, E_HOSTNAME, a->ProxyName);
+ CbSetHeight(hWnd, C_PORT, 18);
+ CbAddStr(hWnd, C_PORT, L"8080", 0);
+ CbAddStr(hWnd, C_PORT, L"1080", 0);
+ CbAddStr(hWnd, C_PORT, L"80", 0);
+ CbAddStr(hWnd, C_PORT, L"3128", 0);
+ CbAddStr(hWnd, C_PORT, L"443", 0);
+ CbAddStr(hWnd, C_PORT, L"9821", 0);
+ CbAddStr(hWnd, C_PORT, L"9801", 0);
+ SetIntEx(hWnd, C_PORT, a->ProxyPort);
+ SetTextA(hWnd, E_USERNAME, a->ProxyUsername);
+ SetTextA(hWnd, E_PASSWORD, a->ProxyPassword);
+ if (a->ProxyPort == 0)
+ {
+ if (a->ProxyType == PROXY_HTTP)
+ {
+ SetInt(hWnd, C_PORT, 8080);
+ }
+ else
+ {
+ SetInt(hWnd, C_PORT, 1080);
+ }
+ }
+ CmProxyDlgUpdate(hWnd, a);
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_HOSTNAME:
+ case C_PORT:
+ case E_USERNAME:
+ case E_PASSWORD:
+ CmProxyDlgUpdate(hWnd, a);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ GetTxtA(hWnd, E_HOSTNAME, a->ProxyName, sizeof(a->ProxyName));
+ GetTxtA(hWnd, E_USERNAME, a->ProxyUsername, sizeof(a->ProxyUsername));
+ GetTxtA(hWnd, E_PASSWORD, a->ProxyPassword, sizeof(a->ProxyPassword));
+ a->ProxyPort = GetInt(hWnd, C_PORT);
+ EndDialog(hWnd, true);
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Proxy server settings
+bool CmProxyDlg(HWND hWnd, CLIENT_OPTION *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return false;
+ }
+
+ return Dialog(hWnd, D_CM_PROXY, CmProxyDlgProc, a);
+}
+
+// Get issuer of the specified certificate if it is known
+X *CmGetIssuer(X *x)
+{
+ RPC_GET_ISSUER a;
+ X *ret;
+ // Validate arguments
+ if (x == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&a, sizeof(a));
+ a.x = CloneX(x);
+ if (CALLEX(cm->hMainWnd, CcGetIssuer(cm->Client, &a)) == 0)
+ {
+ ret = CloneX(a.issuer_x);
+ }
+ else
+ {
+ ret = NULL;
+ }
+
+ CiFreeGetIssuer(&a);
+
+ return ret;
+}
+
+// Initialize the dialog
+void CmLoadXFromFileOrSecureCardDlgInit(HWND hWnd, CM_LOADX *p)
+{
+ UINT current;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ current = MsRegReadInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "CertLoadSource");
+
+ Check(hWnd, R_FROM_FILE, current == 0);
+ Check(hWnd, R_FROM_SECURE, current != 0);
+
+ SetFont(hWnd, S_INFO, Font(0, true));
+
+ CmLoadXFromFileOrSecureCardDlgUpdate(hWnd, p);
+}
+
+// Update the dialog control
+void CmLoadXFromFileOrSecureCardDlgUpdate(HWND hWnd, CM_LOADX *p)
+{
+ SECURE_DEVICE *dev;
+ wchar_t tmp[MAX_SIZE];
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ dev = GetSecureDevice(SmGetCurrentSecureIdFromReg());
+ if (dev == NULL)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SEC_CURRENT_NO_DEVICE"));
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SEC_CURRENT_DEVICE"), dev->DeviceName);
+ }
+
+ SetText(hWnd, S_INFO, tmp);
+
+ if (IsChecked(hWnd, R_FROM_SECURE))
+ {
+ if (dev == NULL)
+ {
+ ok = false;
+ }
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+ SetEnable(hWnd, B_SELECT, IsChecked(hWnd, R_FROM_SECURE));
+ SetEnable(hWnd, S_CERT, IsChecked(hWnd, R_FROM_SECURE));
+ SetEnable(hWnd, S_FILE, IsChecked(hWnd, R_FROM_FILE));
+}
+
+// Certificate reading selection dialog procedure
+UINT CmLoadXFromFileOrSecureCardDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ CM_LOADX *p = (CM_LOADX *)param;
+ X *x;
+ UINT current;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmLoadXFromFileOrSecureCardDlgInit(hWnd, p);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ current = (IsChecked(hWnd, R_FROM_FILE)) ? 0 : 1;
+ MsRegWriteInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "CertLoadSource", current);
+
+ if (current == 0)
+ {
+ // From file
+ if (CmLoadX(hWnd, &x))
+ {
+ p->x = x;
+ EndDialog(hWnd, true);
+ }
+ }
+ else
+ {
+ // From the smart card
+ char name[MAX_SIZE];
+
+ // Select the certificate name in the card
+ if (SmSelectKeyPair(hWnd, name, sizeof(name), NULL, 0))
+ {
+ // Read
+ WINUI_SECURE_BATCH batch[] =
+ {
+ {WINUI_SECURE_READ_CERT, name, true, NULL, NULL, NULL, NULL, NULL, NULL},
+ };
+
+ // Do reading
+ if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), SmGetCurrentSecureIdFromReg(), 0))
+ {
+ // Success
+ p->x = batch[0].OutputX;
+ EndDialog(hWnd, true);
+ }
+ }
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case R_FROM_FILE:
+ CmLoadXFromFileOrSecureCardDlgUpdate(hWnd, p);
+ break;
+
+ case R_FROM_SECURE:
+ CmLoadXFromFileOrSecureCardDlgUpdate(hWnd, p);
+ break;
+
+ case B_SELECT:
+ SmSelectSecureId(hWnd);
+ CmLoadXFromFileOrSecureCardDlgUpdate(hWnd, p);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Read certificate from a file or a smart card
+bool CmLoadXFromFileOrSecureCard(HWND hWnd, X **x)
+{
+ CM_LOADX p;
+ // Validate arguments
+ if (x == NULL)
+ {
+ return false;
+ }
+
+ Zero(&p, sizeof(p));
+ if (Dialog(hWnd, D_CM_LOAD_X, CmLoadXFromFileOrSecureCardDlgProc, &p) == false)
+ {
+ return false;
+ }
+
+ *x = p.x;
+
+ return true;
+}
+
+// Read the certificate
+bool CmLoadX(HWND hWnd, X **x)
+{
+ return CmLoadXEx(hWnd, x, NULL, 0);
+}
+bool CmLoadXEx(HWND hWnd, X **x, char *filename, UINT size)
+{
+ wchar_t *filename_w = CopyStrToUni(filename);
+ bool ret;
+
+ ret = CmLoadXExW(hWnd, x, filename_w, size);
+
+ Free(filename_w);
+
+ return ret;
+}
+bool CmLoadXExW(HWND hWnd, X **x, wchar_t *filename, UINT size)
+{
+ wchar_t *s;
+ bool is_p12;
+ wchar_t tmp[MAX_SIZE];
+ K *k;
+ // Validate arguments
+ if (x == NULL)
+ {
+ return false;
+ }
+
+ // Read the certificate
+ s = OpenDlg(hWnd, _UU("DLG_CERT_OR_P12_FILTER"), _UU("DLG_OPEN_CERT"));
+ if (s == NULL)
+ {
+ return false;
+ }
+ UniStrCpy(tmp, sizeof(tmp), s);
+ if (filename != NULL)
+ {
+ UniStrCpy(filename, size, tmp);
+ }
+ Free(s);
+ if (UniEndWith(tmp, L".p12") || UniEndWith(tmp, L".pfx"))
+ {
+ is_p12 = true;
+ }
+ else
+ {
+ is_p12 = false;
+ }
+
+ if (is_p12)
+ {
+ // Processing of PKCS#12
+ BUF *b = ReadDumpW(tmp);
+ P12 *p12;
+ if (b == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+ return false;
+ }
+ p12 = BufToP12(b);
+ if (p12 == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+ FreeBuf(b);
+ return false;
+ }
+ if (IsEncryptedP12(p12) == false)
+ {
+ if (ParseP12(p12, x, &k, NULL) == false)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+ FreeP12(p12);
+ FreeBuf(b);
+ return false;
+ }
+ }
+ else
+ {
+ char password[MAX_SIZE];
+ if (PassphraseDlg(hWnd, password, sizeof(password), b, true) == false)
+ {
+ FreeP12(p12);
+ FreeBuf(b);
+ return false;
+ }
+ else
+ {
+ if (ParseP12(p12, x, &k, password) == false)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+ FreeP12(p12);
+ FreeBuf(b);
+ return false;
+ }
+ }
+ }
+ FreeP12(p12);
+ FreeBuf(b);
+ FreeK(k);
+ return true;
+ }
+ else
+ {
+ // Processing of X509
+ BUF *b = ReadDumpW(tmp);
+ X *x509;
+ if (b == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+ return false;
+ }
+
+ x509 = BufToX(b, IsBase64(b));
+ FreeBuf(b);
+ if (x509 == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_X509_W"), tmp);
+ return false;
+ }
+
+ *x = x509;
+ return true;
+ }
+}
+
+// Read the secret key
+bool CmLoadK(HWND hWnd, K **k)
+{
+ return CmLoadKEx(hWnd, k, NULL, 0);
+}
+bool CmLoadKEx(HWND hWnd, K **k, char *filename, UINT size)
+{
+ wchar_t *filename_w = CopyStrToUni(filename);
+ bool ret;
+
+ ret = CmLoadKExW(hWnd, k, filename_w, size);
+
+ Free(filename_w);
+
+ return ret;
+}
+bool CmLoadKExW(HWND hWnd, K **k, wchar_t *filename, UINT size)
+{
+ wchar_t *s;
+ bool is_p12;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (k == NULL)
+ {
+ return false;
+ }
+
+ // Read the certificate
+ s = OpenDlg(hWnd, _UU("DLG_KEY_OR_P12_FILTER"), _UU("DLG_OPEN_KEY"));
+ if (s == NULL)
+ {
+ return false;
+ }
+ UniStrCpy(tmp, sizeof(tmp), s);
+ Free(s);
+ if (filename != NULL)
+ {
+ UniStrCpy(filename, size, tmp);
+ }
+ if (UniEndWith(tmp, L".p12") || UniEndWith(tmp, L".pfx"))
+ {
+ is_p12 = true;
+ }
+ else
+ {
+ is_p12 = false;
+ }
+
+ if (is_p12)
+ {
+ // Processing of PKCS#12
+ BUF *b = ReadDumpW(tmp);
+ P12 *p12;
+ if (b == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+ return false;
+ }
+ p12 = BufToP12(b);
+ if (p12 == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+ FreeBuf(b);
+ return false;
+ }
+ if (IsEncryptedP12(p12) == false)
+ {
+ X *x;
+ if (ParseP12(p12, &x, k, NULL) == false)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+ FreeP12(p12);
+ FreeBuf(b);
+ return false;
+ }
+
+ FreeX(x);
+ }
+ else
+ {
+ char password[MAX_SIZE];
+ if (PassphraseDlg(hWnd, password, sizeof(password), b, true) == false)
+ {
+ FreeP12(p12);
+ FreeBuf(b);
+ return false;
+ }
+ else
+ {
+ X *x;
+ if (ParseP12(p12, &x, k, password) == false)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+ FreeP12(p12);
+ FreeBuf(b);
+ return false;
+ }
+
+ FreeX(x);
+ }
+ }
+ FreeP12(p12);
+ FreeBuf(b);
+ return true;
+ }
+ else
+ {
+ // Processing of private key
+ BUF *b = ReadDumpW(tmp);
+ K *key;
+ if (b == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+ return false;
+ }
+
+ if (IsEncryptedK(b, true) == false)
+ {
+ key = BufToK(b, true, IsBase64(b), NULL);
+ }
+ else
+ {
+ char pass[MAX_SIZE];
+ if (PassphraseDlg(hWnd, pass, sizeof(pass), b, false) == false)
+ {
+ FreeBuf(b);
+ return false;
+ }
+ key = BufToK(b, true, IsBase64(b), pass);
+ }
+
+ if (key == NULL)
+ {
+ FreeBuf(b);
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_KEY_W"), tmp);
+ return false;
+ }
+
+ FreeBuf(b);
+ *k = key;
+ return true;
+ }
+}
+
+// Read a set of certificate and private key
+bool CmLoadXAndK(HWND hWnd, X **x, K **k)
+{
+ wchar_t *s;
+ bool is_p12;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (x == NULL || k == NULL)
+ {
+ return false;
+ }
+START_FIRST:
+
+ // Read the certificate
+ s = OpenDlg(hWnd, _UU("DLG_CERT_OR_P12_FILTER"), _UU("DLG_OPEN_CERT"));
+ if (s == NULL)
+ {
+ return false;
+ }
+ UniStrCpy(tmp, sizeof(tmp), s);
+ Free(s);
+ if (UniEndWith(tmp, L".p12") || UniEndWith(tmp, L".pfx"))
+ {
+ is_p12 = true;
+ }
+ else
+ {
+ is_p12 = false;
+ }
+
+ if (is_p12)
+ {
+ // Processing of PKCS#12
+ BUF *b = ReadDumpW(tmp);
+ P12 *p12;
+ if (b == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+ return false;
+ }
+ p12 = BufToP12(b);
+ if (p12 == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+ FreeBuf(b);
+ return false;
+ }
+ if (IsEncryptedP12(p12) == false)
+ {
+ if (ParseP12(p12, x, k, NULL) == false)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+ FreeP12(p12);
+ FreeBuf(b);
+ return false;
+ }
+ }
+ else
+ {
+ char password[MAX_SIZE];
+ if (PassphraseDlg(hWnd, password, sizeof(password), b, true) == false)
+ {
+ FreeP12(p12);
+ FreeBuf(b);
+ return false;
+ }
+ else
+ {
+ if (ParseP12(p12, x, k, password) == false)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+ FreeP12(p12);
+ FreeBuf(b);
+ return false;
+ }
+ }
+ }
+ if (CheckXandK(*x, *k) == false)
+ {
+ FreeX(*x);
+ FreeK(*k);
+ FreeP12(p12);
+ FreeBuf(b);
+ if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_RETRYCANCEL, _UU("DLG_BAD_SIGNATURE")) == IDRETRY)
+ {
+ goto START_FIRST;
+ }
+ return false;
+ }
+ FreeP12(p12);
+ FreeBuf(b);
+ return true;
+ }
+ else
+ {
+ // Processing of X509
+ BUF *b = ReadDumpW(tmp);
+ X *x509;
+ K *key;
+ if (b == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+ return false;
+ }
+
+ x509 = BufToX(b, IsBase64(b));
+ FreeBuf(b);
+ if (x509 == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_X509_W"), tmp);
+ return false;
+ }
+
+ // Read the secret key
+ s = OpenDlg(hWnd, _UU("DLG_KEY_FILTER"), _UU("DLG_OPEN_KEY_WITH_CERT"));
+ if (s == NULL)
+ {
+ FreeX(x509);
+ return false;
+ }
+ UniStrCpy(tmp, sizeof(tmp), s);
+ Free(s);
+
+ b = ReadDumpW(tmp);
+ if (b == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+ FreeX(x509);
+ return false;
+ }
+
+ if (IsEncryptedK(b, true) == false)
+ {
+ key = BufToK(b, true, IsBase64(b), NULL);
+ }
+ else
+ {
+ char pass[MAX_SIZE];
+ if (PassphraseDlg(hWnd, pass, sizeof(pass), b, false) == false)
+ {
+ FreeBuf(b);
+ FreeX(x509);
+ return false;
+ }
+ key = BufToK(b, true, IsBase64(b), pass);
+ }
+
+ if (key == NULL)
+ {
+ FreeBuf(b);
+ FreeX(x509);
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_KEY_W"), tmp);
+ return false;
+ }
+
+ if (CheckXandK(x509, key) == false)
+ {
+ FreeBuf(b);
+ FreeX(x509);
+ FreeK(key);
+ if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_RETRYCANCEL, _UU("DLG_BAD_SIGNATURE")) == IDRETRY)
+ {
+ goto START_FIRST;
+ }
+ return false;
+ }
+
+ FreeBuf(b);
+ *x = x509;
+ *k = key;
+ return true;
+ }
+}
+
+// Virtual HUB enumeration start
+void CmEditAccountDlgStartEnumHub(HWND hWnd, CM_ACCOUNT *a)
+{
+ char server_name[MAX_HOST_NAME_LEN + 1];
+ UINT old_proxy_type;
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+
+ if (StrLen(a->ClientOption->Hostname) == 0)
+ {
+ return;
+ }
+ if (a->ClientOption->Port == 0)
+ {
+ return;
+ }
+ if (a->ClientOption->ProxyType != PROXY_DIRECT &&
+ (StrLen(a->ClientOption->ProxyName) == 0 ||
+ a->ClientOption->ProxyPort == 0))
+ {
+ return;
+ }
+
+ GetTxtA(hWnd, E_HOSTNAME, server_name, sizeof(server_name));
+
+ if (StrCmpi(server_name, a->old_server_name) == 0)
+ {
+ if (CbNum(hWnd, C_HUBNAME) != 0)
+ {
+ return;
+ }
+ }
+ else
+ {
+ StrCpy(a->old_server_name, sizeof(a->old_server_name), server_name);
+ CbReset(hWnd, C_HUBNAME);
+ }
+
+ old_proxy_type = a->ClientOption->ProxyType;
+
+ if (IsChecked(hWnd, R_DIRECT_TCP))
+ {
+ a->ClientOption->ProxyType = PROXY_DIRECT;
+ }
+ if (IsChecked(hWnd, R_HTTPS))
+ {
+ a->ClientOption->ProxyType = PROXY_HTTP;
+ }
+ if (IsChecked(hWnd, R_SOCKS))
+ {
+ a->ClientOption->ProxyType = PROXY_SOCKS;
+ }
+
+ CmEnumHubStart(hWnd, a->ClientOption);
+
+ a->ClientOption->ProxyType = old_proxy_type;
+}
+
+// [OK] button
+void CmEditAccountDlgOnOk(HWND hWnd, CM_ACCOUNT *a)
+{
+ RPC_CLIENT_CREATE_ACCOUNT c;
+ bool b;
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+ if (a->ClientOption->NumRetry != 0 && a->ClientOption->RetryInterval < 5)
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_RETRY_INTERVAL_ERROR"));
+ FocusEx(hWnd, E_RETRY_SPAN);
+ return;
+ }
+
+ CmEditAccountDlgUpdate(hWnd, a);
+
+ if (a->LinkMode == false && a->NatMode == false)
+ {
+ // Save the account
+ Zero(&c, sizeof(c));
+ c.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(c.ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));
+ c.ClientAuth = CopyClientAuth(a->ClientAuth);
+ c.CheckServerCert = a->CheckServerCert;
+ if (a->ServerCert != NULL)
+ {
+ c.ServerCert = CloneX(a->ServerCert);
+ }
+ c.StartupAccount = a->Startup;
+
+ if (a->EditMode == false)
+ {
+ b = CALL(hWnd, CcCreateAccount(cm->Client, &c));
+ }
+ else
+ {
+ b = CALL(hWnd, CcSetAccount(cm->Client, &c));
+ }
+
+ CiFreeClientCreateAccount(&c);
+
+ // Check whether this account is currently running
+ if (b)
+ {
+ RPC_CLIENT_GET_CONNECTION_STATUS st;
+ Zero(&st, sizeof(st));
+ UniStrCpy(st.AccountName, sizeof(st.AccountName), a->ClientOption->AccountName);
+ if (CALL(hWnd, CcGetAccountStatus(cm->Client, &st)))
+ {
+ if (st.Active)
+ {
+ MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("CM_CURRENT_ACTIVE"),
+ st.AccountName);
+ }
+ }
+ }
+
+ if (b)
+ {
+ EndDialog(hWnd, true);
+ }
+ }
+ else
+ {
+ if (a->LinkMode)
+ {
+ // Link mode
+ RPC_CREATE_LINK t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), a->Hub->HubName);
+ t.Online = a->OnlineFlag;
+ Copy(&t.Policy, &a->Policy, sizeof(POLICY));
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(t.ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));
+ t.ClientAuth = CopyClientAuth(a->ClientAuth);
+ t.CheckServerCert = a->CheckServerCert;
+ t.ServerCert = CloneX(a->ServerCert);
+
+ // Save the settings for cascade connection
+ if (a->EditMode)
+ {
+ if (CALL(hWnd, ScSetLink(a->Hub->Rpc, &t)))
+ {
+ if (a->OnlineFlag)
+ {
+ MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("SM_LINK_SAVE_ONLINE"), a->ClientOption->AccountName);
+ }
+ EndDialog(hWnd, true);
+ }
+ }
+ else
+ {
+ if (CALL(hWnd, ScCreateLink(a->Hub->Rpc, &t)))
+ {
+ if (a->Link_ConnectNow)
+ {
+ RPC_LINK tt;
+
+ Zero(&tt, sizeof(tt));
+ UniStrCpy(tt.AccountName, sizeof(tt.AccountName), a->ClientOption->AccountName);
+ StrCpy(tt.HubName, sizeof(tt.HubName), a->Hub->HubName);
+
+ CALL(hWnd, ScSetLinkOnline(a->Hub->Rpc, &tt));
+ }
+ EndDialog(hWnd, true);
+ }
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+ else
+ {
+ // NAT mode
+ RPC_CREATE_LINK t;
+ Zero(&t, sizeof(t));
+
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(t.ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));
+ t.ClientAuth = CopyClientAuth(a->ClientAuth);
+
+ if (CALL(hWnd, NcSetClientConfig(a->Rpc, &t)))
+ {
+ EndDialog(hWnd, true);
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+ }
+}
+
+// Show the account editing dialog
+bool CmEditAccountDlg(HWND hWnd, CM_ACCOUNT *a)
+{
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return false;
+ }
+
+ return Dialog(hWnd, D_CM_ACCOUNT, CmEditAccountDlgProc, a);
+}
+
+// Edit the account
+void CmEditAccount(HWND hWnd, wchar_t *account_name)
+{
+ CM_ACCOUNT *a;
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return;
+ }
+
+ a = CmGetExistAccountObject(hWnd, account_name);
+ if (a == NULL)
+ {
+ return;
+ }
+
+ CmVoice("input_config");
+ if (CmEditAccountDlg(hWnd, a))
+ {
+ CmVoice("set_config");
+ }
+
+ CmFreeAccountObject(hWnd, a);
+}
+
+// Create an account
+void CmNewAccount(HWND hWnd)
+{
+ CM_ACCOUNT *a;
+ RPC_CLIENT_ENUM_VLAN t;
+ UINT num_vlan = 0;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (IsEnable(hWnd, 0) == false)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ if (CcEnumVLan(cm->Client, &t) == ERR_NO_ERROR)
+ {
+ num_vlan = t.NumItem;
+
+ CiFreeClientEnumVLan(&t);
+ }
+
+ if (num_vlan == 0)
+ {
+ if (MsgBox(hWnd, MB_ICONINFORMATION | MB_YESNO, _UU("CM_NO_VLAN")) == IDNO)
+ {
+ return;
+ }
+ else
+ {
+ if (cm->server_name == NULL)
+ {
+ Command(hWnd, CMD_NEW_VLAN);
+ return;
+ }
+ else
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_VLAN_REMOTE_ERROR"));
+ }
+ return;
+ }
+ }
+
+ a = CmCreateNewAccountObject(hWnd);
+ if (a == NULL)
+ {
+ return;
+ }
+
+ CmVoice("input_config");
+ if (CmEditAccountDlg(hWnd, a))
+ {
+ CmVoice("new_config");
+ }
+
+ CmFreeAccountObject(hWnd, a);
+}
+
+// Release the account object
+void CmFreeAccountObject(HWND hWnd, CM_ACCOUNT *a)
+{
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+ Free(a->ClientOption);
+ CiFreeClientAuth(a->ClientAuth);
+ if (a->ServerCert != NULL)
+ {
+ FreeX(a->ServerCert);
+ }
+ Free(a);
+}
+
+// Get an existing account object
+CM_ACCOUNT *CmGetExistAccountObject(HWND hWnd, wchar_t *account_name)
+{
+ RPC_CLIENT_GET_ACCOUNT c;
+ CM_ACCOUNT *a;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&c, sizeof(c));
+ UniStrCpy(c.AccountName, sizeof(c.AccountName), account_name);
+ if (CALL(hWnd, CcGetAccount(cm->Client, &c)) == false)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(CM_ACCOUNT));
+ a->EditMode = true;
+ a->CheckServerCert = c.CheckServerCert;
+ a->Startup = c.StartupAccount;
+ if (c.ServerCert != NULL)
+ {
+ a->ServerCert = CloneX(c.ServerCert);
+ }
+ a->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(a->ClientOption, c.ClientOption, sizeof(CLIENT_OPTION));
+ a->ClientAuth = CopyClientAuth(c.ClientAuth);
+ Copy(a->ShortcutKey, c.ShortcutKey, SHA1_SIZE);
+ CiFreeClientGetAccount(&c);
+
+ a->LockMode = cm->CmSetting.LockMode;
+
+ return a;
+}
+
+// Create a new account object
+CM_ACCOUNT *CmCreateNewAccountObject(HWND hWnd)
+{
+ CM_ACCOUNT *a;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(CM_ACCOUNT));
+ a->EditMode = false;
+ a->CheckServerCert = false;
+ a->Startup = false;
+ a->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+
+ // Initialize the client options
+ CmGenerateNewAccountName(hWnd, a->ClientOption->AccountName, sizeof(a->ClientOption->AccountName));
+ a->ClientOption->Port = 443; // Default port number
+ a->ClientOption->NumRetry = INFINITE;
+ a->ClientOption->RetryInterval = 15;
+ a->ClientOption->MaxConnection = 1;
+ a->ClientOption->HalfConnection = false;
+ a->ClientOption->UseEncrypt = true;
+ a->ClientOption->AdditionalConnectionInterval = 1;
+
+ if (cm->Client->Unix)
+ {
+ a->ClientOption->NoRoutingTracking = true;
+ }
+
+ a->ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+
+ // Password authentication
+ a->ClientAuth->AuthType = CLIENT_AUTHTYPE_PASSWORD;
+
+ return a;
+}
+
+// Create an imported account name
+void CmGenerateImportName(HWND hWnd, wchar_t *name, UINT size, wchar_t *old_name)
+{
+ UINT i;
+ // Validate arguments
+ if (name == NULL || hWnd == NULL)
+ {
+ return;
+ }
+
+ for (i = 1;;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ if (i == 1)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_IMPORT_NAME_1"), old_name);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_IMPORT_NAME_2"), old_name, i);
+ }
+
+ if (LvSearchStr(hWnd, L_ACCOUNT, 0, tmp) == INFINITE)
+ {
+ UniStrCpy(name, size, tmp);
+ return;
+ }
+ }
+}
+
+// Create a copy name
+void CmGenerateCopyName(HWND hWnd, wchar_t *name, UINT size, wchar_t *old_name)
+{
+ UINT i;
+ // Validate arguments
+ if (name == NULL || hWnd == NULL)
+ {
+ return;
+ }
+
+ for (i = 1;;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ if (i == 1)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_COPY_NAME_1"), old_name);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_COPY_NAME_2"), i, old_name);
+ }
+
+ if (LvSearchStr(hWnd, L_ACCOUNT, 0, tmp) == INFINITE)
+ {
+ UniStrCpy(name, size, tmp);
+ return;
+ }
+ }
+}
+
+// Create a new account name
+void CmGenerateNewAccountName(HWND hWnd, wchar_t *name, UINT size)
+{
+ UINT i;
+ // Validate arguments
+ if (name == NULL || hWnd == NULL)
+ {
+ return;
+ }
+
+ for (i = 1;;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ if (i == 1)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_NEW_ACCOUNT_NAME_1"));
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_NEW_ACCOUNT_NAME_2"), i);
+ }
+
+ if (LvSearchStr(hWnd, L_ACCOUNT, 0, tmp) == INFINITE)
+ {
+ UniStrCpy(name, size, tmp);
+ return;
+ }
+ }
+}
+
+// Show the policy list
+void CmPolicyDlgPrint(HWND hWnd, CM_POLICY *p)
+{
+ CmPolicyDlgPrintEx(hWnd, p, false);
+}
+void CmPolicyDlgPrintEx(HWND hWnd, CM_POLICY *p, bool cascade_mode)
+{
+ CmPolicyDlgPrintEx2(hWnd, p, cascade_mode, POLICY_CURRENT_VERSION);
+}
+void CmPolicyDlgPrintEx2(HWND hWnd, CM_POLICY *p, bool cascade_mode, UINT ver)
+{
+ POLICY *pol;
+ UINT i;
+ LVB *b;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ pol = p->Policy;
+
+ b = LvInsertStart();
+
+ for (i = 0;i < NUM_POLICY_ITEM;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ if (cascade_mode)
+ {
+ if (PolicyIsSupportedForCascade(i) == false)
+ {
+ continue;
+ }
+ }
+
+ if (IS_POLICY_FOR_CURRENT_VER(i, ver))
+ {
+ if (policy_item[i].TypeInt == false)
+ {
+ // bool type
+ UniStrCpy(tmp, sizeof(tmp), POLICY_BOOL(pol, i) ? _UU("POL_BOOL_ENABLE") : (p->Extension ? _UU("POL_BOOL_DISABLE_EX") : _UU("POL_BOOL_DISABLE")));
+ }
+ else
+ {
+ // int type
+ if (policy_item[i].AllowZero && POLICY_INT(pol, i) == 0)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("POL_INT_ZERO"));
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU(policy_item[i].FormatStr), POLICY_INT(pol, i));
+ }
+ }
+
+ LvInsertAdd(b, ICO_MACHINE, (void *)i, 2, GetPolicyTitle(i), tmp);
+ }
+ }
+
+ LvInsertEnd(b, hWnd, L_POLICY);
+}
+
+// Policy list dialog box
+UINT CmPolicyDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ CM_POLICY *p = (CM_POLICY *)param;
+ NMHDR *n;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ FormatText(hWnd, 0, p->AccountName);
+ FormatText(hWnd, S_TITLE, p->AccountName);
+ p->hWnd = hWnd;
+ if (p->CmStatus != NULL)
+ {
+ p->CmStatus->hWndPolicy = hWnd;
+ }
+
+ // Initialize the column
+ LvInit(hWnd, L_POLICY);
+ LvInsertColumn(hWnd, L_POLICY, 0, _UU("POL_TITLE_STR"), 375);
+ LvInsertColumn(hWnd, L_POLICY, 1, _UU("POL_VALUE_STR"), 100);
+
+ // Display
+ CmPolicyDlgPrint(hWnd, p);
+
+ // Select the first
+ LvSelect(hWnd, L_POLICY, 0);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_POLICY:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ // Change selection
+ if (LvIsSelected(hWnd, L_POLICY) == false)
+ {
+ SetText(hWnd, S_DESCRIPTION, L"");
+ }
+ else
+ {
+ UINT index = LvGetSelected(hWnd, L_POLICY);
+ UINT id = (UINT)LvGetParam(hWnd, L_POLICY, index);
+ if (id < NUM_POLICY_ITEM)
+ {
+ SetText(hWnd, S_DESCRIPTION, GetPolicyDescription(id));
+ }
+ }
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ LvSortHander(hWnd, msg, wParam, lParam, L_POLICY);
+
+ return 0;
+}
+
+// Show the policy list dialog
+void CmPolicyDlg(HWND hWnd, CM_STATUS *st)
+{
+ RPC_CLIENT_GET_CONNECTION_STATUS s;
+ POLICY *policy;
+ CM_POLICY cp;
+ // Validate arguments
+ if (hWnd == NULL || st == NULL)
+ {
+ return;
+ }
+
+ // Get the policy
+ Zero(&s, sizeof(s));
+ UniStrCpy(s.AccountName, sizeof(s.AccountName), st->AccountName);
+ if (CALL(hWnd, CcGetAccountStatus(cm->Client, &s)) == false)
+ {
+ return;
+ }
+ if (s.Active == false)
+ {
+ return;
+ }
+
+ policy = &s.Policy;
+
+ Zero(&cp, sizeof(cp));
+ UniStrCpy(cp.AccountName, sizeof(cp.AccountName), st->AccountName);
+ cp.Policy = policy;
+ cp.CmStatus = st;
+
+ Dialog(hWnd, D_CM_POLICY, CmPolicyDlgProc, &cp);
+
+ st->hWndPolicy = NULL;
+
+ CiFreeClientGetConnectionStatus(&s);
+}
+
+// Show the certificate
+void CmStatusDlgPrintCert(HWND hWnd, CM_STATUS *st, bool server)
+{
+ RPC_CLIENT_GET_CONNECTION_STATUS s;
+ X *x, *issuer;
+ // Validate arguments
+ if (hWnd == NULL || st == NULL)
+ {
+ return;
+ }
+
+ // Get the latest information
+ Zero(&s, sizeof(s));
+ UniStrCpy(s.AccountName, sizeof(s.AccountName), st->AccountName);
+ if (CALL(hWnd, CcGetAccountStatus(cm->Client, &s)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ if (s.Active == false)
+ {
+ // Disconnect
+ Close(hWnd);
+ return;
+ }
+
+ if (server == false)
+ {
+ // Show the client certificate
+ x = s.ClientX;
+ }
+ else
+ {
+ // Show the server certificate
+ x = s.ServerX;
+ }
+
+ cm->WindowCount++;
+ issuer = CmGetIssuer(x);
+ CertDlg(hWnd, x, issuer, true);
+ FreeX(issuer);
+ cm->WindowCount--;
+
+ CiFreeClientGetConnectionStatus(&s);
+}
+
+// Show the information of the status dialog
+void CmStatusDlgPrint(HWND hWnd, CM_STATUS *cmst)
+{
+ RPC_CLIENT_GET_CONNECTION_STATUS s;
+ LVB *b;
+ // Validate arguments
+ if (hWnd == NULL || cmst == NULL)
+ {
+ return;
+ }
+
+ // Get the latest information
+ Zero(&s, sizeof(s));
+ UniStrCpy(s.AccountName, sizeof(s.AccountName), cmst->AccountName);
+ if (CALL(hWnd, CcGetAccountStatus(cm->Client, &s)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ if (s.Active == false)
+ {
+ // Disconnect
+ Close(hWnd);
+ return;
+ }
+
+ // Show the status in the list box in the status dialog
+ b = LvInsertStart();
+ CmPrintStatusToListView(b, &s);
+ LvInsertEnd(b, hWnd, L_STATUS);
+
+ LvAutoSize(hWnd, L_STATUS);
+
+ SetEnable(hWnd, B_POLICY, s.Connected);
+
+ SetEnable(hWnd, B_SERVER_CERT, s.ServerX != NULL);
+ SetEnable(hWnd, B_CLIENT_CERT, s.ClientX != NULL);
+
+ CiFreeClientGetConnectionStatus(&s);
+}
+
+// Show the status in the list box in the status dialog
+void CmPrintStatusToListView(LVB *b, RPC_CLIENT_GET_CONNECTION_STATUS *s)
+{
+ CmPrintStatusToListViewEx(b, s, false);
+}
+void CmPrintStatusToListViewEx(LVB *b, RPC_CLIENT_GET_CONNECTION_STATUS *s, bool server_mode)
+{
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+ char vv[128];
+ // Validate arguments
+ if (b == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (server_mode == false)
+ {
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_ACCOUNT_NAME"), s->AccountName);
+
+ if (s->Connected == false)
+ {
+ wchar_t *st = _UU("CM_ST_CONNECTED_FALSE");
+ switch (s->SessionStatus)
+ {
+ case CLIENT_STATUS_CONNECTING:
+ st = _UU("CM_ST_CONNECTING");
+ break;
+ case CLIENT_STATUS_NEGOTIATION:
+ st = _UU("CM_ST_NEGOTIATION");
+ break;
+ case CLIENT_STATUS_AUTH:
+ st = _UU("CM_ST_AUTH");
+ break;
+ case CLIENT_STATUS_ESTABLISHED:
+ st = _UU("CM_ST_ESTABLISHED");
+ break;
+ case CLIENT_STATUS_RETRY:
+ st = _UU("CM_ST_RETRY");
+ break;
+ case CLIENT_STATUS_IDLE:
+ st = _UU("CM_ST_IDLE");
+ break;
+ }
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_CONNECTED"), st);
+ }
+ else
+ {
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_CONNECTED"), _UU("CM_ST_CONNECTED_TRUE"));
+ }
+ }
+
+ if (s->Connected)
+ {
+ if (s->VLanId == 0)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_ST_NO_VLAN"));
+ }
+ else
+ {
+ UniToStru(tmp, s->VLanId);
+ }
+
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_VLAN_ID"), tmp);
+
+ if (server_mode == false)
+ {
+ StrToUni(tmp, sizeof(tmp), s->ServerName);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SERVER_NAME"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_PORT_TCP"), s->ServerPort);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SERVER_PORT"), tmp);
+ }
+
+ StrToUni(tmp, sizeof(tmp), s->ServerProductName);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SERVER_P_NAME"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), L"%u.%02u", s->ServerProductVer / 100, s->ServerProductVer % 100);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SERVER_P_VER"), tmp);
+ UniFormat(tmp, sizeof(tmp), L"Build %u", s->ServerProductBuild);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SERVER_P_BUILD"), tmp);
+ }
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->StartTime), NULL);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_START_TIME"), tmp);
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->FirstConnectionEstablisiedTime), NULL);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_FIRST_ESTAB_TIME"), s->FirstConnectionEstablisiedTime == 0 ? _UU("CM_ST_NONE") : tmp);
+
+ if (s->Connected)
+ {
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->CurrentConnectionEstablishTime), NULL);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_CURR_ESTAB_TIME"), tmp);
+ }
+
+ if (server_mode == false)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_STR"), s->NumConnectionsEatablished);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_NUM_ESTABLISHED"), tmp);
+ }
+
+ if (s->Connected)
+ {
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_HALF_CONNECTION"), s->HalfConnection ? _UU("CM_ST_HALF_TRUE") : _UU("CM_ST_HALF_FALSE"));
+
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_QOS"), s->QoS ? _UU("CM_ST_QOS_TRUE") : _UU("CM_ST_QOS_FALSE"));
+
+ UniFormat(tmp, sizeof(tmp), L"%u", s->NumTcpConnections);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_NUM_TCP"), tmp);
+
+ if (s->HalfConnection)
+ {
+ UniFormat(tmp, sizeof(tmp), L"%u", s->NumTcpConnectionsUpload);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_NUM_TCP_UPLOAD"), tmp);
+ UniFormat(tmp, sizeof(tmp), L"%u", s->NumTcpConnectionsDownload);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_NUM_TCP_DOWNLOAD"), tmp);
+ }
+
+ UniFormat(tmp, sizeof(tmp), L"%u", s->MaxTcpConnections);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_MAX_TCP"), tmp);
+
+ if (s->UseEncrypt == false)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_ST_USE_ENCRYPT_FALSE"));
+ }
+ else
+ {
+ if (StrLen(s->CipherName) != 0)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_USE_ENCRYPT_TRUE"), s->CipherName);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_USE_ENCRYPT_TRUE2"));
+ }
+ }
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_USE_ENCRYPT"), tmp);
+
+ if (s->UseCompress)
+ {
+ UINT percent = 0;
+ if ((s->TotalRecvSize + s->TotalSendSize) > 0)
+ {
+ percent = (UINT)((UINT64)100 - (UINT64)(s->TotalRecvSizeReal + s->TotalSendSizeReal) * (UINT64)100 /
+ (s->TotalRecvSize + s->TotalSendSize));
+ percent = MAKESURE(percent, 0, 100);
+ }
+
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_COMPRESS_TRUE"), percent);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_ST_COMPRESS_FALSE"));
+ }
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_USE_COMPRESS"), tmp);
+
+ if (IsEmptyStr(s->UnderlayProtocol) == false)
+ {
+ StrToUni(tmp, sizeof(tmp), s->UnderlayProtocol);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_UNDERLAY_PROTOCOL"), tmp);
+ }
+
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_UDP_ACCEL_ENABLED"), (s->IsUdpAccelerationEnabled ? _UU("CM_ST_YES") : _UU("CM_ST_NO")));
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_UDP_ACCEL_USING"), (s->IsUsingUdpAcceleration ? _UU("CM_ST_YES") : _UU("CM_ST_NO")));
+
+ StrToUni(tmp, sizeof(tmp), s->SessionName);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SESSION_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), s->ConnectionName);
+ if (UniStrCmpi(tmp, L"INITING") != 0)
+ {
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_CONNECTION_NAME"), tmp);
+ }
+
+ BinToStr(str, sizeof(str), s->SessionKey, sizeof(s->SessionKey));
+ StrToUni(tmp, sizeof(tmp), str);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SESSION_KEY"), tmp);
+
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_BRIDGE_MODE"), s->IsBridgeMode ? _UU("CM_ST_YES") : _UU("CM_ST_NO"));
+
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_MONITOR_MODE"), s->IsMonitorMode ? _UU("CM_ST_YES") : _UU("CM_ST_NO"));
+
+ ToStr3(vv, sizeof(vv), s->TotalSendSize);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SEND_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->TotalRecvSize);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_RECV_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Send.UnicastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SEND_UCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Send.UnicastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SEND_UCAST_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Send.BroadcastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SEND_BCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Send.BroadcastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SEND_BCAST_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Recv.UnicastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_RECV_UCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Recv.UnicastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_RECV_UCAST_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Recv.BroadcastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_RECV_BCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Recv.BroadcastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_RECV_BCAST_SIZE"), tmp);
+ }
+}
+
+// Status dialog procedure
+UINT CmStatusDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ wchar_t tmp[MAX_SIZE];
+ CM_STATUS *s = (CM_STATUS *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetIcon(hWnd, 0, ICO_TOWER);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_TITLE"), s->AccountName);
+ SetText(hWnd, 0, tmp);
+ FormatText(hWnd, S_TITLE, s->AccountName);
+ DlgFont(hWnd, S_TITLE, 0, 1);
+
+ Add(cm->StatusWindowList, hWnd);
+
+ SetTimer(hWnd, 1, 500, NULL);
+
+ LvInitEx(hWnd, L_STATUS, true);
+ ListView_SetImageList(DlgItem(hWnd, L_STATUS), NULL, LVSIL_NORMAL);
+ ListView_SetImageList(DlgItem(hWnd, L_STATUS), NULL, LVSIL_SMALL);
+ LvInsertColumn(hWnd, L_STATUS, 0, _UU("CM_ST_COLUMN_1"), 160);
+ LvInsertColumn(hWnd, L_STATUS, 1, _UU("CM_ST_COLUMN_2"), 270);
+
+ CmStatusDlgPrint(hWnd, s);
+
+ break;
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+ CmStatusDlgPrint(hWnd, s);
+ SetTimer(hWnd, 1, 500, NULL);
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ case IDCANCEL:
+ // Close
+ Close(hWnd);
+ break;
+ case B_POLICY:
+ // Show the policy
+ CmPolicyDlg(hWnd, s);
+ break;
+ case B_SERVER_CERT:
+ CmStatusDlgPrintCert(hWnd, s, true);
+ break;
+ case B_CLIENT_CERT:
+ CmStatusDlgPrintCert(hWnd, s, false);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ Delete(cm->StatusWindowList, hWnd);
+ if (s->hWndPolicy != NULL)
+ {
+ EndDialog(s->hWndPolicy, false);
+ s->hWndPolicy = NULL;
+ }
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Show the status dialog
+void CmStatusDlg(HWND hWnd, wchar_t *account_name)
+{
+ CM_STATUS *s;
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return;
+ }
+
+ s = ZeroMalloc(sizeof(CM_STATUS));
+ UniStrCpy(s->AccountName, sizeof(s->AccountName), account_name);
+
+ Dialog(hWnd, D_CONNECTION_STATUS, CmStatusDlgProc, s);
+
+ Free(s);
+}
+
+// Show the status
+void CmStatus(HWND hWnd, wchar_t *account_name)
+{
+ UINT i;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return;
+ }
+
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_TITLE"), account_name);
+
+ for (i = 0;i < LIST_NUM(cm->StatusWindowList);i++)
+ {
+ HWND h = LIST_DATA(cm->StatusWindowList, i);
+ if (h != NULL)
+ {
+ wchar_t tmp2[MAX_SIZE];
+ if (GetTxt(h, 0, tmp2, sizeof(tmp2)))
+ {
+ if (UniStrCmpi(tmp2, tmp) == 0)
+ {
+ SetActiveWindow(h);
+ return;
+ }
+ }
+ }
+ }
+
+ CmStatusDlg(hWnd, account_name);
+}
+
+// Delete
+void CmDeleteAccount(HWND hWnd, wchar_t *account_name)
+{
+ RPC_CLIENT_DELETE_ACCOUNT c;
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return;
+ }
+ Zero(&c, sizeof(c));
+ UniStrCpy(c.AccountName, sizeof(c.AccountName), account_name);
+
+ CmVoice("delete_config_1");
+ if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_DELETE_ACCOUNT_MSG"), account_name)
+ == IDNO)
+ {
+ return;
+ }
+
+ CALL(hWnd, CcDeleteAccount(cm->Client, &c));
+ CmVoice("delete_config_2");
+}
+
+// Disconnect
+void CmDisconnect(HWND hWnd, wchar_t *account_name)
+{
+ RPC_CLIENT_CONNECT c;
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return;
+ }
+
+ Zero(&c, sizeof(c));
+ UniStrCpy(c.AccountName, sizeof(c.AccountName), account_name);
+
+ cm->PositiveDisconnectFlag = true;
+
+ CALL(hWnd, CcDisconnect(cm->Client, &c));
+}
+
+// Show the promotional window
+void SmShowPublicVpnServerHtml(HWND hWnd)
+{
+ char *langstr = _SS("LANGSTR");
+
+ if(StrCmpi(langstr, "Japanese") == 0)
+ {
+ ShowHtml(hWnd, PUBLIC_SERVER_HTML, PUBLIC_SERVER_TAG);
+ }
+ else
+ {
+ ShowHtml(hWnd, PUBLIC_SERVER_HTML_EN, PUBLIC_SERVER_TAG);
+ }
+}
+
+// Connection
+void CmConnect(HWND hWnd, wchar_t *account_name)
+{
+ RPC_CLIENT_CONNECT c;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return;
+ }
+
+ if (IsEnable(hWnd, 0) == false)
+ {
+ return;
+ }
+
+ if (hWnd == cm->hMainWnd)
+ {
+ if (LvNum(hWnd, L_VLAN) == 0 && cm->Client->Win9x)
+ {
+ if (MsgBox(hWnd, MB_ICONINFORMATION | MB_YESNO, _UU("CM_NO_VLAN_2")) == IDNO)
+ {
+ return;
+ }
+ else
+ {
+ if (cm->server_name == NULL || cm->Client->Unix)
+ {
+ Command(hWnd, CMD_NEW_VLAN);
+ return;
+ }
+ else
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_VLAN_REMOTE_ERROR"));
+ }
+ return;
+ }
+ }
+ }
+
+ // (If necessary) display a warning
+ if (CmWarningDesktop(hWnd, account_name) == false)
+ {
+ return;
+ }
+
+ if (cm->server_name == NULL)
+ {
+ if (cm->BadProcessChecked == false)
+ {
+ cm->BadProcessChecked = true;
+
+ CheckBadProcesses(hWnd);
+ }
+ }
+
+ if (cm->server_name == NULL)
+ {
+ // Check the Windows version
+ RPC_WINVER winver;
+ wchar_t winver_msg_client[3800];
+
+ GetWinVer(&winver);
+ Zero(winver_msg_client, sizeof(winver_msg_client));
+
+ if (IsSupportedWinVer(&winver) == false)
+ {
+ SYSTEMTIME st;
+
+ LocalTime(&st);
+
+ UniFormat(winver_msg_client, sizeof(winver_msg_client), _UU("WINVER_ERROR_FORMAT"),
+ _UU("WINVER_ERROR_PC_LOCAL"),
+ winver.Title,
+ _UU("WINVER_ERROR_VPNCLIENT"),
+ SUPPORTED_WINDOWS_LIST,
+ _UU("WINVER_ERROR_PC_LOCAL"),
+ _UU("WINVER_ERROR_VPNCLIENT"),
+ _UU("WINVER_ERROR_VPNCLIENT"),
+ _UU("WINVER_ERROR_VPNCLIENT"),
+ st.wYear, st.wMonth);
+ }
+
+ if (UniIsEmptyStr(winver_msg_client) == false)
+ {
+ OnceMsgEx(hWnd, _UU("WINVER_TITLE"), winver_msg_client,
+ true, ICO_WARNING, NULL);
+ }
+ }
+
+ i = LvSearchStr(hWnd, L_ACCOUNT, 0, account_name);
+ if (i != INFINITE)
+ {
+ wchar_t *tmp = LvGetStr(hWnd, L_ACCOUNT, i, 2);
+ if (tmp != NULL)
+ {
+ wchar_t tag[MAX_SIZE];
+ StrToUni(tag, sizeof(tag), PUBLIC_SERVER_NAME);
+
+ if (UniSearchStrEx(tmp, tag, 0, false) != INFINITE)
+ {
+ SmShowPublicVpnServerHtml(hWnd);
+ }
+
+ Free(tmp);
+ }
+ }
+
+ if (cm->CheckedAndShowedAdminPackMessage == false)
+ {
+ cm->CheckedAndShowedAdminPackMessage = true;
+ //CmCheckAndShowAdminPackTrialVersionNoticeMessage(NULL);
+ }
+
+ Zero(&c, sizeof(c));
+ UniStrCpy(c.AccountName, sizeof(c.AccountName), account_name);
+
+ CmSetForegroundProcessToCnService();
+
+ if (CALL(hWnd, CcConnect(cm->Client, &c)))
+ {
+ cm->ConnectStartedFlag = true;
+ }
+}
+
+// Determine whether to bold the specified menu item
+bool CmIsBold(UINT id)
+{
+ return false;
+}
+
+// Determine whether to enable the specified menu item
+bool CmIsEnabled(HWND hWnd, UINT id)
+{
+ UINT index;
+ wchar_t *name;
+ bool locked = false;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return false;
+ }
+
+ locked = cm->CmSetting.LockMode;
+
+ if (locked)
+ {
+ switch (id)
+ {
+ case CMD_NEW:
+ case CMD_CLONE:
+ case CMD_IMPORT_ACCOUNT:
+ case CMD_DELETE:
+ case CMD_OPTION:
+ case CMD_VOIDE_NONE:
+ case CMD_VOICE_NORMAL:
+ case CMD_VOICE_ODD:
+ case CMD_STARTUP:
+ case CMD_NOSTARTUP:
+ case CMD_TRAFFIC:
+ case CMD_MMCSS:
+ return false;
+ case CMD_NEW_VLAN:
+ case CMD_ENABLE_VLAN:
+ case CMD_DISABLE_VLAN:
+ case CMD_DELETE_VLAN:
+ case CMD_REINSTALL:
+ case CMD_WINNET:
+ if (cm->CmEasyModeSupported)
+ {
+ return false;
+ }
+ }
+ }
+
+ switch (id)
+ {
+ case CMD_LANGUAGE:
+ return MsIsNt();
+ case CMD_SHOWPORT:
+ case CMD_GRID:
+ if (cm->IconView)
+ {
+ return false;
+ }
+ return true;
+ case CMD_MMCSS:
+ if (MsIsVista() == false || IsEmptyStr(cm->server_name) == false)
+ {
+ return false;
+ }
+ if (OS_IS_SERVER(GetOsType()))
+ {
+ return false;
+ }
+ return true;
+ case CMD_TRAYICON:
+ case CMD_TRAFFIC:
+ return (cm->server_name == NULL);
+ case CMD_NETIF:
+ if (MsIsNt() == false)
+ {
+ return false;
+ }
+ return (cm->server_name == NULL);
+ case CMD_CM_SETTING:
+ return cm->CmSettingSupported;
+ case CMD_CONNECT:
+ case CMD_DISCONNECT:
+ case CMD_STATUS:
+ case CMD_RENAME:
+ case CMD_DELETE:
+ if (LvIsMultiMasked(hWnd, L_ACCOUNT))
+ {
+ return false;
+ }
+ if (LvIsSelected(hWnd, L_ACCOUNT) == false)
+ {
+ return false;
+ }
+ else
+ {
+ // Determine whether the selected account is under connecting
+ UINT i = LvGetSelected(hWnd, L_ACCOUNT);
+ wchar_t *str = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+ wchar_t *name = LvGetStr(hWnd, L_ACCOUNT, i, 0);
+ bool is_connected = false;
+ if (str != NULL)
+ {
+ if (UniStrCmpi(str, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(str, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+ {
+ is_connected = true;
+ }
+ Free(str);
+ }
+ if (name != NULL)
+ {
+ if (UniStrCmpi(name, _UU("CM_NEW_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_LINK")) == 0)
+ {
+ Free(name);
+ return false;
+ }
+ Free(name);
+ }
+ if (id == CMD_CONNECT || id == CMD_RENAME || id == CMD_DELETE)
+ {
+ return !is_connected;
+ }
+ else
+ {
+ return is_connected;
+ }
+ }
+ break;
+ case CMD_DISCONNECT_ALL:
+ if (CmGetNumConnected(hWnd) == 0)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ case CMD_SHORTCUT:
+ // Create a shortcut
+ if (cm->Client->Rpc->Sock->RemoteIP.addr[0] != 127)
+ {
+ return false;
+ }
+ case CMD_EXPORT_ACCOUNT:
+ if (LvIsMultiMasked(hWnd, L_ACCOUNT))
+ {
+ return false;
+ }
+ name = LvGetSelectedStr(hWnd, L_ACCOUNT, 0);
+ if (name != NULL)
+ {
+ if (UniStrCmpi(name, _UU("CM_NEW_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_LINK")) == 0
+ )
+ {
+ Free(name);
+ return false;
+ }
+ Free(name);
+ }
+ return LvIsSelected(hWnd, L_ACCOUNT);
+ case CMD_CLONE:
+ if (LvIsMultiMasked(hWnd, L_ACCOUNT))
+ {
+ return false;
+ }
+ name = LvGetSelectedStr(hWnd, L_ACCOUNT, 0);
+ if (name != NULL)
+ {
+ if (UniStrCmpi(name, _UU("CM_NEW_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_LINK")) == 0
+ )
+ {
+ Free(name);
+ return false;
+ }
+ Free(name);
+ }
+ return LvIsSelected(hWnd, L_ACCOUNT);
+ case CMD_STARTUP:
+ case CMD_NOSTARTUP:
+ name = LvGetSelectedStr(hWnd, L_ACCOUNT, 0);
+ if (name != NULL)
+ {
+ if (UniStrCmpi(name, _UU("CM_NEW_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_LINK")) == 0
+ )
+ {
+ Free(name);
+ return false;
+ }
+ Free(name);
+ }
+ if (LvIsMultiMasked(hWnd, L_ACCOUNT))
+ {
+ return false;
+ }
+ if (LvIsSelected(hWnd, L_ACCOUNT) == false)
+ {
+ return false;
+ }
+ else
+ {
+ // Determine whether the selected account is a startup account
+ UINT i = LvGetSelected(hWnd, L_ACCOUNT);
+ bool is_startup = (bool)LvGetParam(hWnd, L_ACCOUNT, i);
+ if (id == CMD_STARTUP)
+ {
+ return !is_startup;
+ }
+ else
+ {
+ return is_startup;
+ }
+ }
+ break;
+ case CMD_NEW_VLAN:
+ if (cm->Client->Unix == false && cm->Client->Win9x == false)
+ {
+ if (cm->server_name != NULL)
+ {
+ return false;
+ }
+ }
+ if (cm->Client->Win9x)
+ {
+ if (LvNum(hWnd, L_VLAN) >= 1)
+ {
+ // You can not install two or more virtual LAN cards in Win9x
+ return false;
+ }
+ }
+ break;
+ case CMD_PROPERTY:
+ name = LvGetSelectedStr(hWnd, L_ACCOUNT, 0);
+ if (name != NULL)
+ {
+ if (UniStrCmpi(name, _UU("CM_NEW_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_LINK")) == 0)
+ {
+ Free(name);
+ return false;
+ }
+ Free(name);
+ }
+ if (LvIsMultiMasked(hWnd, L_ACCOUNT))
+ {
+ return false;
+ }
+ return LvIsSelected(hWnd, L_ACCOUNT);
+ case CMD_DELETE_VLAN:
+ if (LvIsMultiMasked(hWnd, L_VLAN))
+ {
+ return false;
+ }
+ return LvIsSelected(hWnd, L_VLAN);
+ case CMD_ENABLE_VLAN:
+ if (cm->Client->Win9x)
+ {
+ return false;
+ }
+ if (LvIsMultiMasked(hWnd, L_VLAN))
+ {
+ return false;
+ }
+ index = LvGetSelected(hWnd, L_VLAN);
+ if (index == INFINITE)
+ {
+ return false;
+ }
+ else
+ {
+ wchar_t *s = LvGetStr(hWnd, L_VLAN, index, 1);
+ if (s != NULL)
+ {
+ if (UniStrCmpi(s, _UU("CM_VLAN_DISABLED")) == 0)
+ {
+ Free(s);
+ return true;
+ }
+ Free(s);
+ }
+ return false;
+ }
+ break;
+ case CMD_DISABLE_VLAN:
+ if (cm->Client->Win9x)
+ {
+ return false;
+ }
+ if (LvIsMultiMasked(hWnd, L_VLAN))
+ {
+ return false;
+ }
+ index = LvGetSelected(hWnd, L_VLAN);
+ if (index == INFINITE)
+ {
+ return false;
+ }
+ else
+ {
+ wchar_t *s = LvGetStr(hWnd, L_VLAN, index, 1);
+ if (s != NULL)
+ {
+ if (UniStrCmpi(s, _UU("CM_VLAN_ENABLED")) == 0)
+ {
+ Free(s);
+ return true;
+ }
+ Free(s);
+ }
+ return false;
+ }
+ break;
+ case CMD_REINSTALL:
+ if (cm->server_name != NULL)
+ {
+ return false;
+ }
+ if (cm->Client->Win9x || cm->Client->Unix)
+ {
+ // Upgrading the virtual LAN card on a UNIX system or Win9x is unavailable
+ return false;
+ }
+ if (LvIsMultiMasked(hWnd, L_VLAN))
+ {
+ return false;
+ }
+ return LvIsSelected(hWnd, L_VLAN);
+ case CMD_WINNET:
+ {
+ UINT os_type = GetOsInfo()->OsType;
+
+ if (OS_IS_WINDOWS_NT(os_type) && GET_KETA(os_type, 100) >= 2)
+ {
+ if (cm->server_name != NULL)
+ {
+ return false;
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ break;
+ case CMD_EXIT:
+ return cm->TrayInited;
+ }
+ return true;
+}
+
+// Convert a VLAN device name to the display name
+void CmVLanNameToPrintName(char *str, UINT size, char *name)
+{
+ // Validate arguments
+ if (str == NULL || name == NULL)
+ {
+ return;
+ }
+
+ Format(str, size, VLAN_ADAPTER_NAME_TAG, name);
+}
+
+// Convert a display name to a VLAN device name
+bool CmPrintNameToVLanName(char *name, UINT size, char *str)
+{
+ // Validate arguments
+ if (name == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ if (StartWith(str, VLAN_ADAPTER_NAME))
+ {
+ if (StrLen(str) < (StrLen(VLAN_ADAPTER_NAME) + 3))
+ {
+ return false;
+ }
+
+ StrCpy(name, size, str + StrLen(VLAN_ADAPTER_NAME) + 3);
+
+ return true;
+ }
+
+ if (StartWith(str, VLAN_ADAPTER_NAME_OLD))
+ {
+ if (StrLen(str) < (StrLen(VLAN_ADAPTER_NAME_OLD) + 3))
+ {
+ return false;
+ }
+
+ StrCpy(name, size, str + StrLen(VLAN_ADAPTER_NAME_OLD) + 3);
+
+ return true;
+ }
+
+ return false;
+}
+
+// Initialize the account list
+void CmInitAccountList(HWND hWnd)
+{
+ CmInitAccountListEx(hWnd, false);
+}
+void CmInitAccountListEx(HWND hWnd, bool easy)
+{
+ UINT width[5];
+ BUF *b;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Read the setting
+ b = MsRegReadBin(REG_CURRENT_USER, CM_REG_KEY, "AccountListColumnWidth");
+ if ((b != NULL) && (b->Size == sizeof(width)))
+ {
+ Copy(width, b->Buf, sizeof(width));
+ }
+ else if ((b != NULL) && (b->Size == (sizeof(width) - sizeof(UINT))))
+ {
+ // Migrating from previous versions
+ Zero(width, sizeof(width));
+ Copy(width, b->Buf, sizeof(width) - sizeof(UINT));
+ width[4] = width[3];
+ width[3] = 0;
+ }
+ else
+ {
+ Zero(width, sizeof(width));
+ }
+ FreeBuf(b);
+
+ LvInitEx2(hWnd, L_ACCOUNT, false, easy);
+
+// LvSetStyle(hWnd, L_ACCOUNT, LVS_EX_TRACKSELECT);
+
+ // Initialize the column
+ if (easy == false)
+ {
+ LvInsertColumn(hWnd, L_ACCOUNT, 0, _UU("CM_ACCOUNT_COLUMN_1"), width[0] == 0 ? 215 : width[0]);
+ LvInsertColumn(hWnd, L_ACCOUNT, 1, _UU("CM_ACCOUNT_COLUMN_2"), width[1] == 0 ? 80 : width[1]);
+ LvInsertColumn(hWnd, L_ACCOUNT, 2, _UU("CM_ACCOUNT_COLUMN_3"), width[2] == 0 ? 220 : width[2]);
+ LvInsertColumn(hWnd, L_ACCOUNT, 3, _UU("CM_ACCOUNT_COLUMN_3_2"), width[3] == 0 ? 90 : width[3]);
+ LvInsertColumn(hWnd, L_ACCOUNT, 4, _UU("CM_ACCOUNT_COLUMN_4"), (width[4] == 0 || width[4] == 250) ? 120 : width[4]);
+ }
+ else
+ {
+ LvInsertColumn(hWnd, L_ACCOUNT, 0, _UU("CM_ACCOUNT_COLUMN_1"), 345);
+ LvInsertColumn(hWnd, L_ACCOUNT, 1, _UU("CM_ACCOUNT_COLUMN_2"), 140);
+ LvInsertColumn(hWnd, L_ACCOUNT, 2, _UU("CM_ACCOUNT_COLUMN_3"), 0);
+ LvInsertColumn(hWnd, L_ACCOUNT, 3, _UU("CM_ACCOUNT_COLUMN_3_2"), 0);
+ LvInsertColumn(hWnd, L_ACCOUNT, 4, _UU("CM_ACCOUNT_COLUMN_4"), 0);
+ }
+}
+
+// Release the account list
+void CmSaveAccountListPos(HWND hWnd)
+{
+ UINT width[5];
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < 5;i++)
+ {
+ width[i] = LvGetColumnWidth(hWnd, L_ACCOUNT, i);
+ }
+
+ MsRegWriteBin(REG_CURRENT_USER, CM_REG_KEY, "AccountListColumnWidth", width, sizeof(width));
+}
+
+// Initialize the VLAN list
+void CmInitVLanList(HWND hWnd)
+{
+ UINT width[4];
+ BUF *b;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Read the setting
+ b = MsRegReadBin(REG_CURRENT_USER, CM_REG_KEY, "VLanListColumnWidth");
+ if ((b != NULL) && (b->Size == sizeof(width)))
+ {
+ Copy(width, b->Buf, sizeof(width));
+ }
+ else
+ {
+ Zero(width, sizeof(width));
+ }
+ FreeBuf(b);
+
+ LvInit(hWnd, L_VLAN);
+
+// LvSetStyle(hWnd, L_ACCOUNT, LVS_EX_TRACKSELECT);
+
+ // Initialize the column
+ LvInsertColumn(hWnd, L_VLAN, 0, _UU("CM_VLAN_COLUMN_1"), width[0] == 0 ? 310 : width[0]);
+ LvInsertColumn(hWnd, L_VLAN, 1, _UU("CM_VLAN_COLUMN_2"), width[1] == 0 ? 120 : width[1]);
+ LvInsertColumn(hWnd, L_VLAN, 2, _UU("CM_VLAN_COLUMN_3"), width[2] == 0 ? 175 : width[2]);
+ LvInsertColumn(hWnd, L_VLAN, 3, _UU("CM_VLAN_COLUMN_4"), width[3] == 0 ? 120 : width[3]);
+}
+
+// Release the VLAN list
+void CmSaveVLanListPos(HWND hWnd)
+{
+ UINT width[4];
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < 4;i++)
+ {
+ width[i] = LvGetColumnWidth(hWnd, L_VLAN, i);
+ }
+
+ MsRegWriteBin(REG_CURRENT_USER, CM_REG_KEY, "VLanListColumnWidth", width, sizeof(width));
+}
+
+// Update the account list
+void CmRefreshAccountList(HWND hWnd)
+{
+ CmRefreshAccountListEx(hWnd, false);
+ CmRefreshEasy();
+}
+void CmRefreshAccountListEx(HWND hWnd, bool easy)
+{
+ CmRefreshAccountListEx2(hWnd, easy, false);
+}
+void CmRefreshAccountListEx2(HWND hWnd, bool easy, bool style_changed)
+{
+ UINT num = 0;
+ RPC_CLIENT_ENUM_ACCOUNT a;
+ UINT num_connecting = 0, num_connected = 0;
+ wchar_t tmp[MAX_SIZE];
+ wchar_t new_inserted_item[MAX_ACCOUNT_NAME_LEN + 1];
+ bool select_new_insteted_item = true;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Switching of icon / detail view
+ LvSetView(hWnd, L_ACCOUNT, cm->IconView == false || easy);
+
+ // Show grid
+ if (cm->ShowGrid || easy)
+ {
+ LvSetStyle(hWnd, L_ACCOUNT, LVS_EX_GRIDLINES);
+ }
+ else
+ {
+ LvRemoveStyle(hWnd, L_ACCOUNT, LVS_EX_GRIDLINES);
+ }
+
+ if (style_changed)
+ {
+ // Change the font
+ if (easy == false)
+ {
+ if (cm->VistaStyle)
+ {
+ SetFontMeiryo(hWnd, L_ACCOUNT, 9);
+ }
+ else
+ {
+ SetFontDefault(hWnd, L_ACCOUNT);
+ }
+
+ if (cm->VistaStyle && (cm->IconView == false))
+ {
+ LvSetStyle(hWnd, L_ACCOUNT, LVS_EX_FULLROWSELECT);
+ }
+ else
+ {
+ LvRemoveStyle(hWnd, L_ACCOUNT, LVS_EX_FULLROWSELECT);
+ }
+ }
+ }
+
+ Zero(new_inserted_item, sizeof(new_inserted_item));
+
+ if (LvNum(hWnd, L_ACCOUNT) == 0)
+ {
+ select_new_insteted_item = false;
+ }
+
+ // Enumerate the account list
+ if (CALL(hWnd, CcEnumAccount(cm->Client, &a)))
+ {
+ UINT i;
+ LVB *b = LvInsertStart();
+
+ if (cm->CmSetting.LockMode == false && (easy == false))
+ {
+ // Creating a new connection
+ LvInsertAdd(b, ICO_NEW, NULL, 4, _UU("CM_NEW_ICON"), L"", L"", L"");
+
+ if (cm->Client->IsVgcSupported)
+ {
+ // VPN Gate
+ LvInsertAdd(b, ICO_RESEARCH, NULL, 4, _UU("CM_VGC_ICON"), L"", L"", L"");
+ }
+ else if (cm->Client->ShowVgcLink)
+ {
+ // VPN Gate Link
+ LvInsertAdd(b, ICO_INTERNET, NULL, 4, _UU("CM_VGC_LINK"), L"", L"", L"");
+ }
+ }
+
+ for (i = 0;i < a.NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *t = a.Items[i];
+ UINT icon;
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ char tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ IP ip;
+ char ip_str[MAX_SIZE];
+
+ // Special treatment in the case of IPv6 address
+ if (StrToIP6(&ip, t->ServerName) && StartWith(t->ServerName, "[") == false)
+ {
+ Format(ip_str, sizeof(ip_str),
+ "[%s]", t->ServerName);
+ }
+ else
+ {
+ StrCpy(ip_str, sizeof(ip_str), t->ServerName);
+ }
+
+ // Determine the icon
+ if (t->Active == false)
+ {
+ if (t->StartupAccount == false)
+ {
+ icon = ICO_SERVER_OFFLINE;
+ }
+ else
+ {
+ icon = ICO_SERVER_OFFLINE_EX;
+ }
+ }
+ else
+ {
+ num++;
+ if (t->StartupAccount == false)
+ {
+ icon = ICO_SERVER_ONLINE;
+ }
+ else
+ {
+ icon = ICO_SERVER_ONLINE_EX;
+ }
+ }
+
+ // Adding
+ if (easy == false)
+ {
+ //CmVLanNameToPrintName(tmp3, sizeof(tmp3), t->DeviceName);
+ StrCpy(tmp3, sizeof(tmp3), t->DeviceName);
+ StrToUni(tmp, sizeof(tmp), tmp3);
+ }
+ else
+ {
+ StrToUni(tmp, sizeof(tmp), t->DeviceName);
+ }
+
+ if (t->Port == 0 || cm->ShowPort == false)
+ {
+ // Port number is unknown
+ UniFormat(tmp2, sizeof(tmp2), L"%S (%s)", ip_str, CmGetProtocolName(t->ProxyType));
+ }
+ else
+ {
+ // Port number are also shown
+ UniFormat(tmp2, sizeof(tmp2), L"%S:%u (%s)", ip_str, t->Port, CmGetProtocolName(t->ProxyType));
+ }
+
+ if (LvSearchStr(hWnd, L_ACCOUNT, 0, t->AccountName) == INFINITE)
+ {
+ UniStrCpy(new_inserted_item, sizeof(new_inserted_item), t->AccountName);
+ }
+
+ // Virtual HUB name
+ StrToUni(tmp4, sizeof(tmp4), t->HubName);
+
+ if (easy == false)
+ {
+ LvInsertAdd(b, icon, (void *)t->StartupAccount, 5, t->AccountName,
+ t->Active == false ? _UU("CM_ACCOUNT_OFFLINE") :
+ (t->Connected ? _UU("CM_ACCOUNT_ONLINE") : _UU("CM_ACCOUNT_CONNECTING")),
+ tmp2, tmp4,
+ tmp);
+ }
+ else
+ {
+ LvInsertAdd(b, icon, (void *)t->StartupAccount, 5, t->AccountName,
+ t->Active == false ? _UU("CM_ACCOUNT_OFFLINE") :
+ (t->Connected ? _UU("CM_ACCOUNT_ONLINE") : _UU("CM_ACCOUNT_CONNECTING")),
+ tmp2, tmp4,
+ tmp);
+ }
+
+ if (t->Active)
+ {
+ if (t->Connected)
+ {
+ num_connected++;
+ }
+ else
+ {
+ num_connecting++;
+ }
+ }
+ }
+
+ LvInsertEnd(b, hWnd, L_ACCOUNT);
+
+ CiFreeClientEnumAccount(&a);
+
+ if (select_new_insteted_item)
+ {
+ if (UniStrLen(new_inserted_item) >= 1)
+ {
+ LvSelect(hWnd, L_ACCOUNT, INFINITE);
+ LvSelect(hWnd, L_ACCOUNT, LvSearchStr(hWnd, L_ACCOUNT, 0, new_inserted_item));
+ }
+ }
+ }
+
+ if (easy == false)
+ {
+ // For voice guidance, detect new connection and connection lost
+ if (cm->UpdateConnectedNumFlag == false)
+ {
+ cm->UpdateConnectedNumFlag = true;
+ cm->OldConnectedNum = num;
+ }
+ else
+ {
+ if (cm->OldConnectedNum != num)
+ {
+ if (cm->OldConnectedNum < num)
+ {
+ CmVoice("connect");
+ }
+ else
+ {
+ CmVoice("disconnect");
+
+ if (cm->CmSetting.EasyMode && cm->PositiveDisconnectFlag == false)
+ {
+ CmShowEasy();
+ }
+
+ cm->PositiveDisconnectFlag = false;
+ }
+ cm->OldConnectedNum = num;
+ }
+ }
+
+ if (num_connecting == 0 && num_connected == 0)
+ {
+ // There is no connecting or connected account
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_TRAY_NOT_CONNECTED"));
+ }
+ else if (num_connected == 0)
+ {
+ // There is only connecting account
+ UniFormat(tmp, sizeof(tmp), _UU("CM_TRAY_CONNECTED_1"), num_connecting);
+ }
+ else if (num_connecting == 0)
+ {
+ // There is only connected account
+ UniFormat(tmp, sizeof(tmp), _UU("CM_TRAY_CONNECTED_2"), num_connected);
+ }
+ else
+ {
+ // There are both
+ UniFormat(tmp, sizeof(tmp), _UU("CM_TRAY_CONNECTED_0"), num_connected, num_connecting);
+ }
+
+ if (num_connecting == 0 && num_connected == 0)
+ {
+ cm->TrayAnimation = false;
+ cm->TraySpeedAnimation = false;
+ }
+ else
+ {
+ cm->TrayAnimation = true;
+
+ if (num_connecting == 0)
+ {
+ cm->TraySpeedAnimation = false;
+ }
+ else
+ {
+ cm->TraySpeedAnimation = true;
+ }
+ }
+
+ CmChangeTrayString(hWnd, tmp);
+ }
+
+ Refresh(hWnd);
+
+ //Updated the Jump List
+ CmUpdateJumpList(0);
+}
+
+// Updating the VLAN list
+void CmRefreshVLanList(HWND hWnd)
+{
+ CmRefreshVLanListEx(hWnd, false);
+}
+void CmRefreshVLanListEx(HWND hWnd, bool style_changed)
+{
+ RPC_CLIENT_ENUM_VLAN e;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ LvSetView(hWnd, L_VLAN, cm->IconView == false);
+
+ // Show grid
+ if (cm->ShowGrid)
+ {
+ LvSetStyle(hWnd, L_VLAN, LVS_EX_GRIDLINES);
+ }
+ else
+ {
+ LvRemoveStyle(hWnd, L_VLAN, LVS_EX_GRIDLINES);
+ }
+
+ if (style_changed)
+ {
+ // Change the font
+ if (cm->VistaStyle)
+ {
+ SetFontMeiryo(hWnd, L_VLAN, 9);
+ }
+ else
+ {
+ SetFontDefault(hWnd, L_VLAN);
+ }
+
+ if (cm->VistaStyle && (cm->IconView == false))
+ {
+ LvSetStyle(hWnd, L_VLAN, LVS_EX_FULLROWSELECT);
+ }
+ else
+ {
+ LvRemoveStyle(hWnd, L_VLAN, LVS_EX_FULLROWSELECT);
+ }
+ }
+
+ // Enumeration
+ Zero(&e, sizeof(e));
+ if (CALL(hWnd, CcEnumVLan(cm->Client, &e)))
+ {
+ LVB *b = LvInsertStart();
+ UINT i;
+ for (i = 0;i < e.NumItem;i++)
+ {
+ wchar_t name[MAX_SIZE];
+ wchar_t mac[MAX_SIZE];
+ wchar_t ver[MAX_SIZE];
+ char str[MAX_SIZE];
+ wchar_t *status;
+ RPC_CLIENT_ENUM_VLAN_ITEM *v = e.Items[i];
+
+ // Device name
+ CmVLanNameToPrintName(str, sizeof(str), v->DeviceName);
+ StrToUni(name, sizeof(name), str);
+
+ // Status
+ status = v->Enabled ? _UU("CM_VLAN_ENABLED") : _UU("CM_VLAN_DISABLED");
+
+ // MAC address
+ StrToUni(mac, sizeof(mac), v->MacAddress);
+
+ // Version
+ StrToUni(ver, sizeof(ver), v->Version);
+
+ LvInsertAdd(b, v->Enabled ? ICO_NIC_ONLINE : ICO_NIC_OFFLINE, NULL, 4,
+ name, status, mac, ver);
+ }
+ LvInsertEnd(b, hWnd, L_VLAN);
+
+ CiFreeClientEnumVLan(&e);
+ }
+}
+
+// Get a protocol name string
+wchar_t *CmGetProtocolName(UINT n)
+{
+ return GetProtocolName(n);
+}
+
+// Display update
+void CmRefresh(HWND hWnd)
+{
+ CmRefreshEx(hWnd, false);
+}
+void CmRefreshEx(HWND hWnd, bool style_changed)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Update size
+ CmMainWindowOnSize(hWnd);
+
+ // Updating the VLAN list
+ CmRefreshVLanListEx(hWnd, style_changed);
+
+ // Update the account list
+ CmRefreshAccountListEx2(hWnd, false, style_changed);
+
+ // Update the status bar
+ CmRefreshStatusBar(hWnd);
+}
+
+// Determine whether to check the specified menu item
+bool CmIsChecked(UINT id)
+{
+ switch (id)
+ {
+ case CMD_TRAYICON:
+ return cm->HideTrayIcon == false;
+ case CMD_STATUSBAR:
+ return cm->HideStatusBar == false;
+ case CMD_VISTASTYLE:
+ return cm->VistaStyle;
+ case CMD_ICON:
+ return cm->IconView;
+ case CMD_DETAIL:
+ return cm->IconView == false;
+ case CMD_GRID:
+ return cm->ShowGrid;
+ case CMD_VOIDE_NONE:
+ return cm->DisableVoice;
+ case CMD_SHOWPORT:
+ return cm->ShowPort;
+ case CMD_VOICE_NORMAL:
+ if (cm->DisableVoice)
+ {
+ return false;
+ }
+ else
+ {
+ return cm->VoiceId == VOICE_SSK;
+ }
+ case CMD_VOICE_ODD:
+ if (cm->DisableVoice)
+ {
+ return false;
+ }
+ else
+ {
+ return cm->VoiceId == VOICE_AHO;
+ }
+ }
+ return false;
+}
+
+// The menu popped-up
+void CmMainWindowOnPopupMenu(HWND hWnd, HMENU hMenu, UINT pos)
+{
+ UINT num_menu, i, id;
+ // Validate arguments
+ if (hWnd == NULL || hMenu == NULL)
+ {
+ return;
+ }
+
+ num_menu = GetMenuItemCount(hMenu);
+ for (i = 0;i < num_menu;i++)
+ {
+ id = GetMenuItemID(hMenu, i);
+
+ if (id != INFINITE)
+ {
+ bool enable_flag = CmIsEnabled(hWnd, id);
+ bool checked_flag = CmIsChecked(id);
+ bool bold_flag = CmIsBold(id);
+ MENUITEMINFO info;
+
+ Zero(&info, sizeof(info));
+ info.cbSize = sizeof(info);
+ info.fMask = MIIM_STATE;
+ info.fState = (enable_flag ? MFS_ENABLED : MFS_DISABLED) |
+ (checked_flag ? MFS_CHECKED : MFS_UNCHECKED) |
+ (bold_flag ? MFS_DEFAULT : 0);
+
+ if (id == CMD_ICON || id == CMD_DETAIL || id == CMD_VOIDE_NONE ||
+ id == CMD_VOICE_NORMAL || id == CMD_VOICE_ODD)
+ {
+ info.fMask |= MIIM_FTYPE;
+ info.fType = MFT_RADIOCHECK;
+ }
+
+ SetMenuItemInfo(hMenu, id, false, &info);
+ }
+
+ if (id == CMD_RECENT)
+ {
+ HMENU sub = CmCreateRecentSubMenu(hWnd, CM_TRAY_MENU_RECENT_ID_START);
+
+ if (sub != NULL)
+ {
+ DeleteMenu(hMenu, i, MF_BYPOSITION);
+ MsInsertMenu(hMenu, i, MF_BYPOSITION | MF_ENABLED | MF_POPUP | MF_STRING,
+ (UINT_PTR)sub, _UU("CM_TRAY_MENU_RECENT"));
+ }
+ else
+ {
+ MENUITEMINFO info;
+
+ Zero(&info, sizeof(info));
+ info.cbSize = sizeof(info);
+ info.fMask = MIIM_STATE;
+ info.fState = MFS_DISABLED;
+
+ SetMenuItemInfo(hMenu, id, false, &info);
+ }
+ }
+ }
+}
+
+// Set the main window title
+wchar_t *CmGenerateMainWindowTitle()
+{
+ wchar_t tmp[MAX_SIZE];
+ if (cm->server_name == NULL)
+ {
+ UniFormat(tmp, sizeof(tmp), L"%s", _UU("CM_TITLE"));
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), L"%s - %S", _UU("CM_TITLE"), cm->server_name);
+ }
+
+ return CopyUniStr(tmp);
+}
+
+// Initialize the task tray
+void CmInitTray(HWND hWnd)
+{
+ bool ret;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (cm->server_name != NULL)
+ {
+ return;
+ }
+
+ if (cm->TrayInited)
+ {
+ return;
+ }
+
+ ret = MsShowIconOnTray(hWnd, LoadSmallIcon(CmGetTrayIconId(false, 0)), _UU("CM_TRAY_INITING"), WM_CM_TRAY_MESSAGE);
+
+ cm->TrayInited = true;
+ cm->TrayAnimation = false;
+ cm->TraySucceed = ret;
+
+ SetTimer(hWnd, 2, CM_TRAY_ANIMATION_INTERVAL / 4, NULL);
+}
+
+// Change the string in the task tray
+void CmChangeTrayString(HWND hWnd, wchar_t *str)
+{
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return;
+ }
+ if (cm->TrayInited == false)
+ {
+ return;
+ }
+
+ MsChangeIconOnTray(NULL, str);
+}
+
+// Release the task tray
+void CmFreeTray(HWND hWnd)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (cm->TrayInited == false)
+ {
+ return;
+ }
+
+ MsHideIconOnTray();
+
+ cm->TrayInited = false;
+}
+void CmFreeTrayExternal(void *hWnd)
+{
+ CmFreeTray((HWND)hWnd);
+}
+
+// Periodical processing to the task tray
+void CmPollingTray(HWND hWnd)
+{
+ UINT interval;
+ bool ret;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (cm->TrayInited == false)
+ {
+ return;
+ }
+
+ ret = MsChangeIconOnTrayEx(LoadSmallIcon(CmGetTrayIconId(cm->TrayAnimation, cm->TrayAnimationCounter)),
+ NULL, NULL, NULL, NIIF_NONE, !cm->TraySucceed);
+
+ if (cm->TraySucceed == false)
+ {
+ cm->TraySucceed = ret;
+ }
+
+ cm->TrayAnimationCounter++;
+
+ KillTimer(hWnd, 2);
+ interval = CM_TRAY_ANIMATION_INTERVAL / 4;
+ if (cm->TraySpeedAnimation)
+ {
+ interval /= 4;
+ }
+ SetTimer(hWnd, 2, interval, NULL);
+}
+
+// Get the icon ID of the task tray for animation
+UINT CmGetTrayIconId(bool animation, UINT animation_counter)
+{
+ if (animation == false)
+ {
+ return ICO_TRAY0;
+ }
+ else
+ {
+ switch (animation_counter % 4)
+ {
+ case 0:
+ return ICO_TRAY1;
+
+ case 1:
+ return ICO_TRAY2;
+
+ case 2:
+ return ICO_TRAY3;
+
+ default:
+ return ICO_TRAY4;
+ }
+ }
+}
+
+// Initialize the main window
+void CmMainWindowOnInit(HWND hWnd)
+{
+ wchar_t *s;
+ BUF *b;
+ bool startup_mode = cm->StartupMode;
+ CM_SETTING a;
+ bool fake = false;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Font settings of list
+ SetFontMeiryo(hWnd, L_ACCOUNT, 9);
+ SetFontMeiryo(hWnd, L_VLAN, 9);
+
+ // Get the configuration of the current vpnclient
+ Zero(&a, sizeof(a));
+ CcGetCmSetting(cm->Client, &a);
+
+ if (a.EasyMode)
+ {
+ fake = true;
+ }
+
+ InitMenuInternational(GetMenu(hWnd), "CM_MENU");
+
+ cm->HideStatusBar = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "HideStatusBar");
+ cm->HideTrayIcon = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "HideTrayIcon");
+ cm->IconView = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "IconView");
+ cm->ShowGrid = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "ShowGrid");
+
+ if (MsRegIsValue(REG_CURRENT_USER, CM_REG_KEY, "VistaStyle"))
+ {
+ cm->VistaStyle = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "VistaStyle");
+ }
+ else
+ {
+ cm->VistaStyle = MsIsVista();
+ }
+
+ if (MsRegIsValue(REG_CURRENT_USER, CM_REG_KEY, "ShowPort"))
+ {
+ cm->ShowPort = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "ShowPort");
+ }
+ else
+ {
+ cm->ShowPort = false;
+ }
+
+ if (MsRegIsValue(REG_CURRENT_USER, CM_REG_KEY, "DisableVoice"))
+ {
+ cm->DisableVoice = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "DisableVoice");
+ }
+ else
+ {
+ cm->DisableVoice = true;
+ }
+ cm->VoiceId = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "VoiceId");
+
+ cm->StatusWindowList = NewList(NULL);
+
+ SetIcon(hWnd, 0, ICO_VPN);
+
+ s = CmGenerateMainWindowTitle();
+ SetText(hWnd, 0, s);
+ Free(s);
+
+ // Initialize the window position
+ b = MsRegReadBin(REG_CURRENT_USER, CM_REG_KEY, "WindowPlacement");
+ if (b != NULL && b->Size == sizeof(WINDOWPLACEMENT))
+ {
+ // Restore the window position
+ WINDOWPLACEMENT *p;
+ p = ZeroMalloc(b->Size);
+ Copy(p, b->Buf, b->Size);
+
+ if (startup_mode)
+ {
+ p->showCmd = SW_SHOWMINIMIZED;
+ }
+
+ if (fake)
+ {
+ Copy(&cm->FakeWindowPlacement, p, sizeof(WINDOWPLACEMENT));
+ }
+ else
+ {
+ SetWindowPlacement(hWnd, p);
+ }
+ Free(p);
+ }
+ else
+ {
+ // Initialize the window position
+ SetWindowPos(hWnd, NULL, 0, 0, CM_DEFAULT_WIDTH, CM_DEFAULT_HEIGHT, SWP_NOREDRAW);
+ Center(hWnd);
+ if (startup_mode)
+ {
+ ShowWindow(hWnd, SW_SHOWMINIMIZED);
+ }
+
+ if (fake)
+ {
+ WINDOWPLACEMENT p;
+
+ Zero(&p, sizeof(p));
+ p.length = sizeof(p);
+ GetWindowPlacement(hWnd, &p);
+ Copy(&cm->FakeWindowPlacement, &p, sizeof(WINDOWPLACEMENT));
+ }
+ }
+ FreeBuf(b);
+
+ if (fake)
+ {
+ SetWindowPos(hWnd, NULL, -200, -200, 100, 100,
+ SWP_NOREDRAW | SWP_SHOWWINDOW);
+ }
+
+ // Initialize the status bar related items
+ cm->hMainWnd = hWnd;
+ cm->hStatusBar = CreateStatusWindowW(WS_CHILD |
+ (cm->HideStatusBar == false ? WS_VISIBLE : 0),
+ _UU("CM_TITLE"),
+ hWnd, S_STATUSBAR);
+
+ UniStrCpy(cm->StatudBar1, sizeof(cm->StatudBar1), _UU("CM_TITLE"));
+ UniStrCpy(cm->StatudBar2, sizeof(cm->StatudBar2), _UU("CM_CONN_NO"));
+ UniFormat(cm->StatudBar3, sizeof(cm->StatudBar3), _UU("CM_PRODUCT_NAME"), CEDAR_BUILD);
+
+ cm->Icon2 = LoadSmallIcon(ICO_SERVER_OFFLINE);
+ cm->Icon3 = LoadSmallIcon(ICO_VPN);
+
+ // Initialize the account list
+ CmInitAccountList(hWnd);
+
+ // Initialize the VLAN list
+ CmInitVLanList(hWnd);
+
+ // Display update
+ CmRefreshEx(hWnd, true);
+
+ // Start a thread of notification client
+ CmInitNotifyClientThread();
+
+ // Timer setting
+ SetTimer(hWnd, 1, 128, NULL);
+ SetTimer(hWnd, 6, 5000, NULL);
+
+ // Initialize the task tray
+ if (cm->server_name == NULL)
+ {
+ if (cm->HideTrayIcon == false)
+ {
+ CmInitTray(hWnd);
+ }
+ }
+
+ CmVoice("start");
+
+ if (startup_mode || a.EasyMode)
+ {
+ SetTimer(hWnd, 3, 1, NULL);
+ }
+
+ if (cm->import_file_name != NULL)
+ {
+ // Import a file specified as an argument
+ CmSendImportMessage(hWnd, cm->import_file_name, cm->CmSettingInitialFlag == CM_SETTING_INIT_NONE ? CM_IMPORT_FILENAME_MSG : CM_IMPORT_FILENAME_MSG_OVERWRITE);
+ /*if (a.LockMode == false)
+ {
+ CmImportAccountMainEx(hWnd, cm->import_file_name, cm->CmSettingInitialFlag != CM_SETTING_INIT_NONE);
+ }
+ else
+ {
+ MsgBox(cm->hEasyWnd ? cm->hEasyWnd : hWnd, MB_ICONEXCLAMATION, _UU("CM_VPN_FILE_IMPORT_NG"));
+ }*/
+ }
+
+ // Apply the CM_SETTING
+ CmApplyCmSetting();
+
+ cm->StartupFinished = true;
+}
+
+// Start a thread of notification client
+void CmInitNotifyClientThread()
+{
+ cm->NotifyClient = CcConnectNotify(cm->Client);
+ if (cm->NotifyClient == false)
+ {
+ Close(cm->hMainWnd);
+ exit(0);
+ }
+ cm->NotifyClientThread = NewThread(CmNotifyClientThread, NULL);
+}
+
+// Notification client thread
+void CmNotifyClientThread(THREAD *thread, void *param)
+{
+ NOTIFY_CLIENT *nc;
+ // Validate arguments
+ if (thread == NULL)
+ {
+ return;
+ }
+
+ nc = cm->NotifyClient;
+
+ // Wait for the next notification
+ while (cm->Halt == false)
+ {
+ if (CcWaitNotify(nc))
+ {
+ // Send a message
+ PostMessage(cm->hMainWnd, WM_CM_NOTIFY, 0, 0);
+ }
+ else
+ {
+ // Disconnected
+ if (cm->Halt == false)
+ {
+ if (cm != NULL)
+ {
+ CmFreeTrayExternal((void *)cm->hMainWnd);
+ }
+ CncExit();
+ exit(0);
+ }
+ break;
+ }
+ }
+}
+
+// Stop the thread of the notification client
+void CmFreeNotifyClientThread()
+{
+ cm->Halt = true;
+
+ // Disconnect
+ CcStopNotify(cm->NotifyClient);
+
+ // Wait for the termination of the thread
+ WaitThread(cm->NotifyClientThread, INFINITE);
+
+ // Connection termination
+ CcDisconnectNotify(cm->NotifyClient);
+ ReleaseThread(cm->NotifyClientThread);
+}
+
+// Resize the main window
+void CmMainWindowOnSize(HWND hWnd)
+{
+ RECT r;
+ UINT client_width, client_height;
+ UINT status_height;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Get the size of the client area of the main window
+ GetClientRect(hWnd, &r);
+ client_width = MAX(r.right - r.left, 0);
+ client_height = MAX(r.bottom - r.top, 0);
+
+ SendMsg(hWnd, S_STATUSBAR, WM_SIZE, 0, 0);
+
+ // Get the size of the status bar
+ GetWindowRect(DlgItem(hWnd, S_STATUSBAR), &r);
+ status_height = MAX(r.bottom - r.top, 0);
+
+ if (cm->HideStatusBar == false)
+ {
+ client_height = MAX(client_height - status_height, 0);
+ }
+
+ MoveWindow(DlgItem(hWnd, L_ACCOUNT), 0, 0, client_width, client_height * 3 / 5 - 3, true);
+ MoveWindow(DlgItem(hWnd, L_VLAN), 0, client_height * 3 / 5, client_width, client_height * 2 / 5, true);
+
+ // Re-draw the status bar
+ CmRedrawStatusBar(hWnd);
+}
+
+// Disconnect all accounts currently connected
+void CmDisconnectAll(HWND hWnd)
+{
+ UINT i, num;
+ LIST *o;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Display a warning
+ num = CmGetNumConnected(hWnd);
+ if (num == 0)
+ {
+ return;
+ }
+
+ if (MsgBoxEx(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_DISCONNECT_ALL"), num) == IDNO)
+ {
+ return;
+ }
+
+ cm->PositiveDisconnectFlag = true;
+
+ // Create a list of connected items
+ o = NewListFast(NULL);
+
+ num = LvNum(hWnd, L_ACCOUNT);
+ for (i = 0;i < num;i++)
+ {
+ wchar_t *s = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+ if (s != NULL)
+ {
+ if (UniStrCmpi(s, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(s, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+ {
+ Add(o, LvGetStr(hWnd, L_ACCOUNT, i, 0));
+ }
+ Free(s);
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ wchar_t *s = LIST_DATA(o, i);
+ if (s != NULL)
+ {
+ CmDisconnect(hWnd, s);
+ Free(s);
+ }
+ }
+
+ ReleaseList(o);
+}
+
+// Get a number of currently connected connection settings
+UINT CmGetNumConnected(HWND hWnd)
+{
+ UINT i, num, num_active;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ num_active = 0;
+ num = LvNum(hWnd, L_ACCOUNT);
+ for (i = 0;i < num;i++)
+ {
+ wchar_t *s = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+ if (s != NULL)
+ {
+ if (UniStrCmpi(s, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(s, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+ {
+ num_active++;
+ }
+ Free(s);
+ }
+ }
+
+ return num_active;
+}
+
+// Update the status bar information
+void CmRefreshStatusBar(HWND hWnd)
+{
+ UINT num_active = CmGetNumConnected(hWnd);
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (num_active == 0)
+ {
+ UniStrCpy(cm->StatudBar2, sizeof(cm->StatudBar2), _UU("CM_CONN_NO"));
+ cm->Icon2 = LoadSmallIcon(ICO_SERVER_OFFLINE);
+ }
+ else
+ {
+ UniFormat(cm->StatudBar2, sizeof(cm->StatudBar2), _UU("CM_NUM_CONN_COUNT"), num_active);
+ cm->Icon2 = LoadSmallIcon(ICO_SERVER_ONLINE);
+ }
+
+ CmRedrawStatusBar(hWnd);
+}
+
+// Re-draw the status bar
+void CmRedrawStatusBar(HWND hWnd)
+{
+ HWND h;
+ RECT r;
+ int width;
+ int x1, x2, x3;
+ int xx[3];
+ wchar_t tmp[MAX_SIZE];
+ HICON icon;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ h = cm->hStatusBar;
+
+ // Get the width of the status bar
+ GetWindowRect(h, &r);
+ width = MAX(r.right - r.left, 0);
+ x2 = (UINT)(180.0 * GetTextScalingFactor());
+ x3 = (UINT)(245.0 * GetTextScalingFactor());
+ x1 = MAX(width - x2 - x3, 0);
+
+ // Divide into three parts
+ xx[0] = x1;
+ xx[1] = x2 + x1;
+ xx[2] = x3 + x2 + x1;
+ SendMsg(h, 0, SB_SETPARTS, 3, (LPARAM)xx);
+
+ // Set an icon
+ icon = (HICON)SendMsg(h, 0, SB_GETICON, 1, 0);
+ if (icon != cm->Icon2)
+ {
+ SendMsg(h, 0, SB_SETICON, 1, (LPARAM)cm->Icon2);
+ }
+
+ icon = (HICON)SendMsg(h, 0, SB_GETICON, 2, 0);
+ if (icon != cm->Icon3)
+ {
+ SendMsg(h, 0, SB_SETICON, 2, (LPARAM)cm->Icon3);
+ }
+
+ // Set a string
+ SendMsg(h, 0, SB_GETTEXTW, 0, (LPARAM)tmp);
+ if (UniStrCmp(tmp, cm->StatudBar1))
+ {
+ SendMsg(h, 0, SB_SETTEXTW, 0, (LPARAM)cm->StatudBar1);
+ }
+
+ SendMsg(h, 0, SB_GETTEXTW, 1, (LPARAM)tmp);
+ if (UniStrCmp(tmp, cm->StatudBar2))
+ {
+ SendMsg(h, 0, SB_SETTEXTW, 1, (LPARAM)cm->StatudBar2);
+ }
+
+ SendMsg(h, 0, SB_GETTEXTW, 2, (LPARAM)tmp);
+ if (UniStrCmp(tmp, cm->StatudBar3))
+ {
+ SendMsg(h, 0, SB_SETTEXTW, 2, (LPARAM)cm->StatudBar3);
+ }
+}
+
+// Save the position information of the main window
+void CmSaveMainWindowPos(HWND hWnd)
+{
+ WINDOWPLACEMENT p;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Save settings
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "HideStatusBar", cm->HideStatusBar);
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "HideTrayIcon", cm->HideTrayIcon);
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "IconView", cm->IconView);
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "ShowGrid", cm->ShowGrid);
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "DisableVoice", cm->DisableVoice);
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "VoiceId", cm->VoiceId);
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "VistaStyle", cm->VistaStyle);
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "ShowPort", cm->ShowPort);
+
+ // Save the window position
+ Zero(&p, sizeof(p));
+ p.length = sizeof(p);
+ GetWindowPlacement(hWnd, &p);
+
+ if (IsZero(&cm->FakeWindowPlacement, sizeof(cm->FakeWindowPlacement)) == false)
+ {
+ Copy(&p, &cm->FakeWindowPlacement, sizeof(cm->FakeWindowPlacement));
+ }
+
+ MsRegWriteBin(REG_CURRENT_USER, CM_REG_KEY, "WindowPlacement", &p, sizeof(p));
+
+ CmSaveAccountListPos(hWnd);
+ CmSaveVLanListPos(hWnd);
+}
+
+// Close the main window
+void CmMainWindowOnQuit(HWND hWnd)
+{
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (cm->TrayInited)
+ {
+ if (MsgBox(hWnd, MB_YESNO | MB_ICONQUESTION,
+ _UU("CM_EXIT_MESSAGE")) == IDNO)
+ {
+ return;
+ }
+ }
+
+ if (cm->OnCloseDispatched)
+ {
+ return;
+ }
+ cm->OnCloseDispatched = true;
+
+ CmCloseEasy();
+
+ // Release the tray icon
+ CmFreeTray(hWnd);
+
+ // Save the position information of the main window
+ CmSaveMainWindowPos(hWnd);
+
+ // Close the status window
+ for (i = 0;i < LIST_NUM(cm->StatusWindowList);i++)
+ {
+ HWND h = LIST_DATA(cm->StatusWindowList, i);
+ //EndDialog(h, 0);
+ PostMessage(h, WM_CLOSE, 0, 0);
+ }
+
+ ReleaseList(cm->StatusWindowList);
+ cm->StatusWindowList = NULL;
+
+ if (cm->WindowCount != 0)
+ {
+ // Abort
+ exit(0);
+ }
+
+ // Close
+ CmFreeNotifyClientThread();
+
+ EndDialog(hWnd, false);
+}
+
+// Start the mutex to be used in starting
+bool CmStartStartupMutex()
+{
+ INSTANCE *o = NewSingleInstance(STARTUP_MUTEX_NAME);
+
+ if (o == NULL)
+ {
+ return false;
+ }
+
+ cm->StartupMutex = o;
+
+ return true;
+}
+
+// Release the mutex to be used in starting
+void CmEndStartupMutex()
+{
+ if (cm->StartupMutex != NULL)
+ {
+ FreeSingleInstance(cm->StartupMutex);
+
+ cm->StartupMutex = NULL;
+ }
+}
+
+// Main window
+void MainCMWindow()
+{
+ HWND h;
+ wchar_t *s;
+ CM_SETTING a;
+
+ if (CmStartStartupMutex() == false)
+ {
+ return;
+ }
+
+ s = CmGenerateMainWindowTitle();
+ h = SearchWindow(s);
+ Free(s);
+
+ Zero(&a, sizeof(a));
+ CcGetCmSetting(cm->Client, &a);
+ if (cm->server_name != NULL && a.EasyMode)
+ {
+ CmEndStartupMutex();
+ MsgBox(NULL, MB_ICONEXCLAMATION, _UU("CM_EASY_MODE_NOT_ON_REMOTE"));
+ return;
+ }
+
+ // Change the operating mode
+ if (cm->CmSettingSupported)
+ {
+ if (cm->CmSettingInitialFlag == CM_SETTING_INIT_SELECT)
+ {
+ if (h != NULL)
+ {
+ CmEndStartupMutex();
+ }
+
+ // Show the selection screen
+ CmSetting(NULL);
+
+ if (h != NULL)
+ {
+ goto SEND_MESSAGES;
+ }
+ else
+ {
+ return;
+ }
+ }
+ else if ((cm->CmSettingInitialFlag == CM_SETTING_INIT_EASY && cm->CmEasyModeSupported) || cm->CmSettingInitialFlag == CM_SETTING_INIT_NORMAL)
+ {
+ // State transition
+ CM_SETTING a;
+
+ Zero(&a, sizeof(a));
+ CcGetCmSetting(cm->Client, &a);
+
+ if (cm->CmSettingInitialFlag == CM_SETTING_INIT_EASY)
+ {
+ a.EasyMode = true;
+ }
+ else
+ {
+ a.EasyMode = false;
+ }
+
+ CcSetCmSetting(cm->Client, &a);
+ }
+ }
+
+ if (h == NULL)
+ {
+ // Create a window because there is no window of the same title
+ if (cm->server_name == NULL)
+ {
+ CmInitTryToExecUiHelper();
+
+ if (IsDebug() == false)
+ {
+ CnWaitForCnServiceReady();
+ }
+ }
+ Dialog(NULL, D_CM_MAIN, CmMainWindowProc, NULL);
+ CmFreeTryToExecUiHelper();
+ }
+ else
+ {
+SEND_MESSAGES:
+ CmEndStartupMutex();
+
+ // If a window of the same title already exists, activate it and exit itself
+ SetForegroundWindow(h);
+ SendMessage(h, WM_CM_SHOW, 0, 0);
+ SetForegroundWindow(h);
+
+ if (cm->CmSettingInitialFlag != CM_SETTING_INIT_NONE && cm->CmSettingInitialFlag != CM_SETTING_INIT_CONNECT)
+ {
+ // Notify since CM_SETTING has been changed
+ SendMessage(h, WM_CM_SETTING_CHANGED_MESSAGE, 0, 0);
+ }
+
+ if (cm->import_file_name != NULL)
+ {
+ UINT msg;
+ if (cm->CmSettingInitialFlag == CM_SETTING_INIT_NONE)
+ {
+ msg = CM_IMPORT_FILENAME_MSG;
+ }
+ else
+ {
+ msg = CM_IMPORT_FILENAME_MSG_OVERWRITE;
+ }
+
+ CmSendImportMessage(h, cm->import_file_name, msg);
+ }
+ }
+
+ CmEndStartupMutex();
+}
+
+// Send an import message
+void CmSendImportMessage(HWND hWnd, wchar_t *filename, UINT msg)
+{
+ COPYDATASTRUCT cpy;
+ // Validate arguments
+ if (hWnd == NULL || filename == NULL)
+ {
+ return;
+ }
+
+ // Specify the file to be imported
+ Zero(&cpy, sizeof(cpy));
+
+ cpy.cbData = UniStrSize(filename);
+ cpy.lpData = filename;
+ cpy.dwData = msg;
+
+ SendMessage(hWnd, WM_COPYDATA, 0, (LPARAM)&cpy);
+}
+
+// Login dialog
+UINT CmLoginDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ // Validate arguments
+ wchar_t server_name[MAX_SIZE];
+ char password[MAX_PASSWORD_LEN + 1];
+ bool bad_pass;
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ if (cm->server_name != NULL)
+ {
+ StrToUni(server_name, sizeof(server_name), cm->server_name);
+ }
+ else
+ {
+ UniStrCpy(server_name, sizeof(server_name), _UU("CM_PW_LOCALMACHINE"));
+ }
+ FormatText(hWnd, S_TITLE, server_name);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ if (cm->server_name != NULL)
+ {
+ StrToUni(server_name, sizeof(server_name), cm->server_name);
+ }
+ else
+ {
+ UniStrCpy(server_name, sizeof(server_name), _UU("CM_PW_LOCALMACHINE"));
+ }
+ GetTxtA(hWnd, E_PASSWORD, password, sizeof(password));
+ cm->Client = CcConnectRpc(cm->server_name == NULL ? "127.0.0.1" : cm->server_name,
+ password, &bad_pass, NULL, 0);
+ if (cm->Client == NULL)
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("CM_BAD_PASSWORD"));
+ FocusEx(hWnd, E_PASSWORD);
+ }
+ else
+ {
+ EndDialog(hWnd, true);
+ }
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Login
+bool LoginCM()
+{
+ // Try to login with an empty password first
+ bool bad_pass, no_remote;
+ wchar_t server_name[MAX_SIZE];
+ RPC_CLIENT_VERSION a;
+
+RETRY:
+ if (cm->server_name != NULL)
+ {
+ StrToUni(server_name, sizeof(server_name), cm->server_name);
+ }
+ else
+ {
+ UniStrCpy(server_name, sizeof(server_name), _UU("CM_PW_LOCALMACHINE"));
+ }
+
+ // Attempt to connect
+ if ((cm->Client = CcConnectRpc(
+ cm->server_name == NULL ? "localhost" : cm->server_name,
+ "", &bad_pass, &no_remote, cm->StartupMode == false ? 0 : 60000)) == NULL)
+ {
+ if (no_remote)
+ {
+ // Remote connection was denied
+ if (MsgBoxEx(NULL, MB_ICONEXCLAMATION | MB_RETRYCANCEL, _UU("CM_NO_REMOTE"), server_name) == IDRETRY)
+ {
+ // Retry
+ goto RETRY;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if (bad_pass)
+ {
+ if (Dialog(NULL, D_CM_LOGIN, CmLoginDlgProc, NULL) == false)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // Connection failure
+ if (cm->StartupMode == false && MsgBoxEx(NULL, MB_ICONEXCLAMATION | MB_RETRYCANCEL, _UU("CM_CONNECT_FAILED"), server_name) == IDRETRY)
+ {
+ // Retry
+ goto RETRY;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ Zero(&a, sizeof(a));
+ CcGetClientVersion(cm->Client, &a);
+ if (a.ClientBuildInt >= 5192)
+ {
+ cm->CmSettingSupported = true;
+ cm->CmEasyModeSupported = true;
+ if (OS_IS_WINDOWS_9X(a.OsType))
+ {
+ cm->CmEasyModeSupported = false;
+ }
+ }
+
+ return true;
+}
+
+// Main process
+void MainCM()
+{
+ // If there is /remote in the argument, show the screen of the remote connection
+ char *cmdline = GetCommandLineStr();
+
+ if (StrCmpi(cmdline, "/remote") == 0)
+ {
+ char *hostname = RemoteDlg(NULL, CM_REG_KEY, ICO_VPN, _UU("CM_TITLE"), _UU("CM_REMOTE_TITLE"), NULL);
+ if (hostname == NULL)
+ {
+ return;
+ }
+ if (cm->server_name != NULL)
+ {
+ Free(cm->server_name);
+ }
+ cm->server_name = NULL;
+ if (StrCmpi(hostname, "localhost") != 0 && StrCmpi(hostname, "127.0.0.1") != 0 )
+ {
+ cm->server_name = hostname;
+ }
+ }
+
+ if (StrCmpi(cmdline, "/startup") == 0)
+ {
+ // Startup mode
+ cm->StartupMode = true;
+ }
+
+ Free(cmdline);
+
+ if (IsZero(cm->ShortcutKey, SHA1_SIZE) == false)
+ {
+ //if (MsGetCurrentTerminalSessionId() == 0)
+ {
+ // Start the shortcut connection
+ CmConnectShortcut(cm->ShortcutKey);
+ }/*
+ else
+ {
+ MsgBoxEx(NULL, MB_ICONEXCLAMATION, _UU("CM_SHORTCUT_DESKTOP_MSG"),
+ MsGetCurrentTerminalSessionId());
+ }*/
+ return;
+ }
+
+ // Login
+ if (LoginCM() == false)
+ {
+ return;
+ }
+
+ //Update the jump list
+ CmUpdateJumpList(0);
+
+ // Main window
+ MainCMWindow();
+
+ // Log out
+ LogoutCM();
+
+ if (cm->Update != NULL)
+ {
+ FreeUpdateUi(cm->Update);
+ cm->Update = NULL;
+ }
+}
+
+// Log out
+void LogoutCM()
+{
+ if (cm->Client != NULL)
+ {
+ CcDisconnectRpc(cm->Client);
+ }
+}
+
+// Client Connection Manager start function
+void CMExec()
+{
+ // Initialize
+ InitCM(true);
+
+ // Main process
+ MainCM();
+
+ // Release
+ FreeCM();
+}
+
+// HUB enumeration thread
+void CmEnumHubThread(THREAD *t, void *param)
+{
+ CM_ENUM_HUB *e = (CM_ENUM_HUB *)param;
+ HWND hWnd;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ e->Thread = t;
+ hWnd = e->hWnd;
+ LockList(cm->EnumHubList);
+ {
+ Add(cm->EnumHubList, e);
+ }
+ UnlockList(cm->EnumHubList);
+
+ // Thread initialization is completed
+ NoticeThreadInit(t);
+
+ // Create a session
+ e->Session = NewRpcSession(cm->Cedar, e->ClientOption);
+ if (e->Session)
+ {
+ // Enumeration of HUB
+ e->Hub = EnumHub(e->Session);
+
+ if (e->Hub != NULL)
+ {
+ // Enumeration completed
+ // Add to the combo box
+ if (CbNum(hWnd, C_HUBNAME) == 0)
+ {
+ UINT i;
+ wchar_t tmp[MAX_SIZE];
+ for (i = 0;i < e->Hub->NumTokens;i++)
+ {
+ StrToUni(tmp, sizeof(tmp), e->Hub->Token[i]);
+ CbAddStr(hWnd, C_HUBNAME, tmp, 0);
+ }
+ }
+
+ // Release the memory
+ FreeToken(e->Hub);
+ }
+
+ // Release the session
+ ReleaseSession(e->Session);
+ }
+
+ LockList(cm->EnumHubList);
+ {
+ Delete(cm->EnumHubList, e);
+ }
+ UnlockList(cm->EnumHubList);
+
+ Free(e->ClientOption);
+ Free(e);
+}
+
+// The start of the HUB enumeration
+void CmEnumHubStart(HWND hWnd, CLIENT_OPTION *o)
+{
+ CM_ENUM_HUB *e;
+ THREAD *t;
+ // Validate arguments
+ if (hWnd == NULL || o == NULL)
+ {
+ return;
+ }
+
+ if (StrLen(o->Hostname) == 0 ||
+ o->Port == 0)
+ {
+ return;
+ }
+
+ if (o->ProxyType != PROXY_DIRECT)
+ {
+ if (StrLen(o->ProxyName) == 0 ||
+ o->ProxyPort == 0)
+ {
+ return;
+ }
+ }
+
+ if (LvNum(hWnd, C_HUBNAME) != 0)
+ {
+ return;
+ }
+
+ e = ZeroMalloc(sizeof(CM_ENUM_HUB));
+ e->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ e->hWnd = hWnd;
+ Copy(e->ClientOption, o, sizeof(CLIENT_OPTION));
+
+ t = NewThread(CmEnumHubThread, e);
+ WaitThreadInit(t);
+ ReleaseThread(t);
+}
+
+// Initialize the HUB enumeration process
+void CmInitEnumHub()
+{
+ cm->EnumHubList = NewList(NULL);
+}
+
+// Release the HUB enumeration process
+void CmFreeEnumHub()
+{
+ LIST *o;
+ UINT i;
+ if (cm->EnumHubList == NULL)
+ {
+ return;
+ }
+
+ o = NewList(NULL);
+ LockList(cm->EnumHubList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(cm->EnumHubList);i++)
+ {
+ CM_ENUM_HUB *e = LIST_DATA(cm->EnumHubList, i);
+ Add(o, e->Thread);
+ AddRef(e->Thread->ref);
+ }
+ }
+ UnlockList(cm->EnumHubList);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ THREAD *t = LIST_DATA(o, i);
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+ }
+ ReleaseList(o);
+
+ ReleaseList(cm->EnumHubList);
+}
+
+// Initialize the Client Connection Manager
+
+void InitCM(bool set_app_id)
+{
+ UNI_TOKEN_LIST *ut;
+ if (cm != NULL)
+ {
+ return;
+ }
+
+ if (set_app_id)
+ {
+ if(JL_SetCurrentProcessExplicitAppUserModelID(APPID_CM) != S_OK)
+ {
+ }
+ }
+
+ CmDeleteOldStartupTrayFile();
+
+ MsSetShutdownParameters(0x4ff, SHUTDOWN_NORETRY);
+
+ // Memory allocation
+ cm = ZeroMalloc(sizeof(CM));
+
+ // If the command line argument is set treat it as a server name
+ ut = GetCommandLineUniToken();
+
+ if (ut->NumTokens >= 1)
+ {
+ if (UniStrLen(ut->Token[0]) != 0)
+ {
+ if (UniStrCmpi(ut->Token[0], L"cm") != 0 && ut->Token[0][0] != L'/')
+ {
+ BUF *b = UniStrToBin(ut->Token[0]);
+ if (b->Size == SHA1_SIZE)
+ {
+ // Treated as a shortcut key for the connection settings
+ Copy(cm->ShortcutKey, b->Buf, SHA1_SIZE);
+ }
+ else
+ {
+ if (UniEndWith(ut->Token[0], L".vpn") == false)
+ {
+ // Treated as a server name
+ cm->server_name = CopyUniToStr(ut->Token[0]);
+ }
+ else
+ {
+ // Treated as import file name
+ cm->import_file_name = CopyUniStr(ut->Token[0]);
+ }
+ }
+ FreeBuf(b);
+ }
+ else if (UniStrCmpi(ut->Token[0], L"/easy") == 0)
+ {
+ // Simple mode
+ if (ut->NumTokens >= 2)
+ {
+ // Connection settings to be imported is specified
+ cm->import_file_name = CopyUniStr(ut->Token[1]);
+ }
+
+ cm->CmSettingInitialFlag = CM_SETTING_INIT_EASY;
+ }
+ else if (UniStrCmpi(ut->Token[0], L"/normal") == 0)
+ {
+ // Normal mode
+ if (ut->NumTokens >= 2)
+ {
+ // Connection settings to be imported is specified
+ cm->import_file_name = CopyUniStr(ut->Token[1]);
+ }
+
+ cm->CmSettingInitialFlag = CM_SETTING_INIT_NORMAL;
+ }
+ else if (UniStrCmpi(ut->Token[0], L"/connect") == 0)
+ {
+ // Import process by the simple installer
+ if (ut->NumTokens >= 2)
+ {
+ // Connection settings to be imported is specified
+ cm->import_file_name = CopyUniStr(ut->Token[1]);
+ }
+
+ cm->CmSettingInitialFlag = CM_SETTING_INIT_CONNECT;
+ }
+ else if (UniStrCmpi(ut->Token[0], L"/select") == 0)
+ {
+ // Selection screen
+ cm->CmSettingInitialFlag = CM_SETTING_INIT_SELECT;
+ }
+ }
+ }
+
+ UniFreeToken(ut);
+
+ InitWinUi(_UU("CM_TITLE"), _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+
+ // Alpha blending related
+ UseAlpha = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "UseAlpha");
+ AlphaValue = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "AlphaValue");
+
+ cm->Cedar = NewCedar(NULL, NULL);
+ CmInitEnumHub();
+}
+
+// Stop the Client Connection Manager
+void FreeCM()
+{
+ if (cm == NULL)
+ {
+ return;
+ }
+
+ CmFreeEnumHub();
+ ReleaseCedar(cm->Cedar);
+
+ FreeWinUi();
+
+ // Release the memory
+ if (cm->server_name != NULL)
+ {
+ Free(cm->server_name);
+ }
+ Free(cm);
+ cm = NULL;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+//JumpList ToDo
+// By Takao Ito
+void *CmUpdateJumpList(UINT start_id)
+{
+ HMENU h = NULL;
+ UINT i;
+ RPC_CLIENT_ENUM_ACCOUNT a;
+ LIST *o;
+ bool easy;
+
+ JL_PCustomDestinationList pcdl;
+ JL_PObjectCollection poc;
+ JL_PShellLink shell;
+ JL_PObjectArray poaRemoved;
+
+ HRESULT hr;
+
+ if (cm->server_name != NULL)
+ {
+ // Is not used in the case of an external PC
+ return NULL;
+ }
+
+ //Try to add
+ if(SUCCEEDED(JL_CreateCustomDestinationList(&pcdl,APPID_CM)))
+ {
+
+ JL_DeleteJumpList(pcdl,APPID_CM);
+
+ easy = cm->CmSetting.EasyMode;
+
+ Zero(&a, sizeof(a));
+
+
+ if (CcEnumAccount(cm->Client, &a) == ERR_NO_ERROR)
+ {
+ o = NewListFast(CiCompareClientAccountEnumItemByLastConnectDateTime);
+
+ for (i = 0;i < a.NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = a.Items[i];
+
+ item->tmp1 = i;
+
+ if (item->LastConnectDateTime != 0)
+ {
+ Add(o, item);
+ }
+ }
+
+ Sort(o);
+
+ if(LIST_NUM(o) > 0)
+ {
+
+ if(SUCCEEDED(JL_BeginList(pcdl, &poaRemoved)))
+ {
+
+
+ //Create a collection
+ if(SUCCEEDED(JL_CreateObjectCollection(&poc)))
+ {
+
+ for (i = 0;i < MIN(LIST_NUM(o), CM_NUM_RECENT);i++)
+ {
+
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = (RPC_CLIENT_ENUM_ACCOUNT_ITEM *)LIST_DATA(o, i);
+// wchar_t tmp[MAX_PATH];
+ wchar_t *account_name;
+ char *server_name;
+ char *hub_name;
+// CM_ACCOUNT *a;
+ UCHAR key[SHA1_SIZE];
+ RPC_CLIENT_GET_ACCOUNT c;
+
+
+ account_name = item->AccountName;
+ server_name = item->ServerName;
+ hub_name = item->HubName;
+
+
+
+ //
+ //a = CmGetExistAccountObject(hWnd, account_name);
+
+
+ //if (a == NULL)
+ //{
+ //continue;
+ //}
+
+ //Copy(key, a->ShortcutKey, SHA1_SIZE);
+ //
+
+ Zero(&c, sizeof(c));
+ UniStrCpy(c.AccountName, sizeof(c.AccountName), account_name);
+ if (CALL(NULL, CcGetAccount(cm->Client, &c)) == false)
+ {
+ break;
+ }
+
+ Copy(key, c.ShortcutKey, SHA1_SIZE);
+
+ if (IsZero(key, SHA1_SIZE))
+ {
+ //MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_SHORTCUT_UNSUPPORTED"));
+ }
+ else
+ {
+
+ //wchar_t target[MAX_PATH];
+ ////wchar_t workdir[MAX_PATH];
+ //wchar_t args[MAX_PATH];
+ ////wchar_t comment[MAX_SIZE];
+ //wchar_t icon[MAX_PATH];
+
+ char key_str[64];
+ wchar_t target[MAX_PATH];
+ //wchar_t workdir[MAX_PATH];
+ wchar_t args[MAX_PATH];
+ wchar_t commentW[MAX_SIZE];
+ wchar_t icon[MAX_PATH];
+ int iconNum;
+
+ //char icon = "C:\\Server.ico";
+
+ BinToStr(key_str, sizeof(key_str), key, SHA1_SIZE);
+ UniStrCpy(target, sizeof(target), MsGetExeFileNameW());
+ StrToUni(args, sizeof(args), key_str);
+ UniStrCpy(icon, sizeof(icon), MsGetExeFileNameW());
+ UniFormat(commentW, sizeof(commentW), _UU("CM_SHORTCUT_COMMENT"), account_name);
+
+ if(item->Connected)
+ {
+ iconNum = 1;
+ }
+ else
+ {
+ iconNum = 2;
+ }
+
+ hr = JL_CreateShellLink(
+ target,
+ args,
+ account_name,
+ icon,iconNum,
+ commentW,
+ &shell);
+
+ if(SUCCEEDED(hr))
+ {
+
+ if(SUCCEEDED(JL_ObjectCollectionAddShellLink(poc, shell)))
+ {
+ //Print("Add JumpList %d c:%s\n",i, comment);
+ //wprintf(comment);
+ }
+ JL_ReleaseShellLink(shell);
+ }
+ }
+
+ CiFreeClientGetAccount(&c);
+ }
+
+ hr = JL_AddCategoryToList(pcdl,poc,_UU("CM_JUMPLIST_RCCONNECT"),poaRemoved);
+
+ if(SUCCEEDED(hr))
+ {
+ //wprintf(L"AddCategory\n");
+
+ hr = JL_CommitList(pcdl);
+ if(SUCCEEDED(hr))
+ {
+ //wprintf(L"JumpList Commit\n");
+ }
+ }
+ else
+ {
+ //wprintf(L"Erro JumpList AddCategory %x\n", hr);
+ }
+
+ //Release
+ JL_ReleaseObjectCollection(poc);
+ }
+ }
+
+ }
+
+
+ ReleaseList(o);
+
+ CiFreeClientEnumAccount(&a);
+ }
+
+
+
+
+ /*
+ JL_BeginList(pcdl, &poaRemoved);
+
+ JL_CreateObjectCollection(&poc);
+
+ // Tesht
+ for (i = 0; i < 5; i++)
+ {
+
+ JL_CreateShellLink(
+ "",
+ "",
+ L"Connect",
+ NULL,0,
+ NULL,
+ &shell);
+ JL_ObjectCollectionAddShellLink(poc, shell);
+
+ JL_ReleaseShellLink(shell);
+
+ }
+
+ JL_AddCategoryToList(pcdl,poc,_UU("CM_JUMPLIST_RCCONNECT"),poaRemoved);
+ JL_CommitList(pcdl);
+ JL_ReleaseObjectCollection(poc);
+
+ JL_ReleaseCustomDestinationList(pcdl);
+ */
+
+ }
+
+ return h;
+}
+
+
+
+#endif // WIN32
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/CM.h b/src/Cedar/CM.h
new file mode 100644
index 00000000..3aae95c0
--- /dev/null
+++ b/src/Cedar/CM.h
@@ -0,0 +1,132 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// CM.h
+// Header of CM.c
+
+#ifndef CM_H
+#define CM_H
+
+// Constants
+#define CM_REG_KEY "Software\\" GC_REG_COMPANY_NAME "\\" CEDAR_PRODUCT_STR " VPN\\Client Manager"
+#define SECURE_MANAGER_KEY "Software\\" GC_REG_COMPANY_NAME "\\" CEDAR_PRODUCT_STR " VPN\\SmartCard Manager"
+#define CM_TRAFFIC_REG_KEY "Software\\" GC_REG_COMPANY_NAME "\\" CEDAR_PRODUCT_STR " VPN\\Traffic Test Tool"
+#define CM_VGC_REG_KEY "Software\\University of Tsukuba\\VPN Gate Client Plugin"
+
+
+#define CM_TRY_EXEC_UI_HELPER_INTERVAL 5000
+
+#define CM_DEFAULT_WIDTH 800
+#define CM_DEFAULT_HEIGHT 600
+
+#define WM_CM_NOTIFY (WM_APP + 999)
+
+#define CM_IMPORT_FILENAME_MSG 1267
+#define CM_IMPORT_FILENAME_MSG_OVERWRITE 1268
+
+#define CM_NUM_RECENT 8
+
+#define PUBLIC_SERVER_HTML "http://www.softether.com/jp/special/se2hub.aspx"
+#define PUBLIC_SERVER_HTML_EN "http://www.softether.com/jp/special/se2hub_en.aspx"
+#define PUBLIC_SERVER_TAG L"help:no; status:no; DialogWidth:600px; dialogHeight=700px"
+#define PUBLIC_SERVER_NAME "public.softether.com"
+
+#define VOICE_SSK 0 // ssk
+#define VOICE_AHO 1 // aho
+
+// The code for external export
+
+// Structure
+
+// Function prototype
+void CMExec();
+void CmTraffic(HWND hWnd);
+void *CmStartUacHelper();
+void CmStopUacHelper(void *p);
+void *CmExecUiHelperMain();
+UINT CmGetSecureBitmapId(char *dest_hostname);
+
+#endif // CM_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/CMInner.h b/src/Cedar/CMInner.h
new file mode 100644
index 00000000..cc65d259
--- /dev/null
+++ b/src/Cedar/CMInner.h
@@ -0,0 +1,612 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// CMInner.h
+// Internal header for the CM.c
+
+#define STARTUP_MUTEX_NAME GC_SW_SOFTETHER_PREFIX "vpncmgr_startup_mutex"
+
+#define NAME_OF_VPN_CLIENT_MANAGER "vpncmgr"
+
+void CmVoice(char *name);
+
+typedef struct CM_UAC_HELPER
+{
+ THREAD *Thread;
+ volatile bool Halt;
+ EVENT *HaltEvent;
+} CM_UAC_HELPER;
+
+typedef struct CM_VOICE
+{
+ UINT voice_id;
+ char *perfix;
+} CM_VOICE;
+
+static CM_VOICE cm_voice[] =
+{
+ {VOICE_SSK, "ssk" },
+ {VOICE_AHO, "aho" },
+};
+
+typedef struct CM_ENUM_HUB
+{
+ HWND hWnd;
+ THREAD *Thread;
+ SESSION *Session;
+ CLIENT_OPTION *ClientOption;
+ TOKEN_LIST *Hub;
+} CM_ENUM_HUB;
+
+#define CM_SETTING_INIT_NONE 0
+#define CM_SETTING_INIT_EASY 1 // Transition to the simple mode
+#define CM_SETTING_INIT_NORMAL 2 // Transition to the normal mode
+#define CM_SETTING_INIT_SELECT 3 // Show a selection screen
+#define CM_SETTING_INIT_CONNECT 4 // Import process by the simple installer
+
+typedef struct CM
+{
+ HWND hMainWnd;
+ HWND hStatusBar;
+ REMOTE_CLIENT *Client;
+ char *server_name;
+ wchar_t *import_file_name;
+ bool HideStatusBar;
+ bool HideTrayIcon;
+ bool ShowGrid;
+ bool VistaStyle;
+ bool ShowPort;
+ wchar_t StatudBar1[MAX_SIZE];
+ wchar_t StatudBar2[MAX_SIZE];
+ wchar_t StatudBar3[MAX_SIZE];
+ HICON Icon2, Icon3;
+ bool IconView;
+ THREAD *NotifyClientThread;
+ NOTIFY_CLIENT *NotifyClient;
+ volatile bool Halt;
+ bool OnCloseDispatched;
+ LIST *StatusWindowList;
+ CEDAR *Cedar;
+ LIST *EnumHubList;
+ UINT WindowCount;
+ bool DisableVoice;
+ UINT VoiceId;
+ UINT OldConnectedNum;
+ bool UpdateConnectedNumFlag;
+ UCHAR ShortcutKey[SHA1_SIZE];
+ bool TrayInited;
+ bool TraySucceed;
+ bool TrayAnimation;
+ bool TraySpeedAnimation;
+ UINT TrayAnimationCounter;
+ bool StartupMode;
+ THREAD *TryExecUiHelperThread;
+ volatile bool TryExecUiHelperHalt;
+ HANDLE TryExecUiHelperProcessHandle;
+ EVENT *TryExecUiHelperHaltEvent;
+ bool WindowsShutdowning;
+ bool CmSettingSupported;
+ bool CmEasyModeSupported;
+ bool CmSettingInitialFlag;
+ CM_SETTING CmSetting;
+ HWND hEasyWnd;
+ bool StartupFinished;
+ bool ConnectStartedFlag;
+ bool PositiveDisconnectFlag;
+ wchar_t EasyLastSelectedAccountName[MAX_ACCOUNT_NAME_LEN + 1];
+ WINDOWPLACEMENT FakeWindowPlacement;
+ bool CheckedAndShowedAdminPackMessage;
+ INSTANCE *StartupMutex;
+ bool BadProcessChecked;
+ bool MenuPopuping;
+ WINUI_UPDATE *Update;
+} CM;
+
+typedef struct CM_STATUS
+{
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+ HWND hWndPolicy; // Policy dialog
+} CM_STATUS;
+
+typedef struct CM_POLICY
+{
+ HWND hWnd;
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+ POLICY *Policy; // Policy dialog
+ CM_STATUS *CmStatus; // CM_STATUS
+ bool Extension; // Extension
+} CM_POLICY;
+
+typedef struct CM_ACCOUNT
+{
+ bool EditMode; // Edit mode (false: New mode)
+ bool LinkMode; // Link mode
+ bool NatMode; // NAT mode
+ CLIENT_OPTION *ClientOption; // Client option
+ CLIENT_AUTH *ClientAuth; // Authentication data
+ bool Startup; // Startup account
+ bool CheckServerCert; // Check the server certificate
+ X *ServerCert; // Server certificate
+ char old_server_name[MAX_HOST_NAME_LEN + 1]; // Old server name
+ bool Inited; // Initialization flag
+ POLICY Policy; // Policy (only link mode)
+ struct SM_HUB *Hub; // HUB
+ RPC *Rpc; // RPC
+ bool OnlineFlag; // Online flag
+ bool Flag1; // Flag 1
+ bool HideClientCertAuth; // Hide the client authentication
+ bool HideSecureAuth; // Hide the smart card authentication
+ bool HideTrustCert; // Hide the trusted certificate authority button
+ UCHAR ShortcutKey[SHA1_SIZE]; // Shortcut key
+ bool LockMode; // Setting lock mode
+ bool Link_ConnectNow; // Start the connection immediately
+ UINT PolicyVer; // Policy version
+} CM_ACCOUNT;
+
+typedef struct CM_CHANGE_PASSWORD
+{
+ CLIENT_OPTION *ClientOption; // Client Option
+ char Username[MAX_USERNAME_LEN + 1]; // User name
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB name
+} CM_CHANGE_PASSWORD;
+
+typedef struct CM_TRAFFIC
+{
+ bool ServerMode; // Server mode
+ bool Double; // 2x mode
+ bool Raw; // Raw data mode
+ UINT Port; // Port number
+ char Host[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT NumTcp; // Number of TCP connections
+ UINT Type; // Type
+ UINT Span; // Period
+} CM_TRAFFIC;
+
+typedef struct CM_TRAFFIC_DLG
+{
+ HWND hWnd; // Window handle
+ CM_TRAFFIC *Setting; // Setting
+ TTS *Tts; // Measurement server
+ TTC *Ttc; // Measurement client
+ THREAD *HaltThread; // Thread for stopping
+ THREAD *ClientEndWaitThread; // Thread to wait for the client to finish
+ bool Started; // Started flag
+ bool Stopping; // Stopping
+ UINT RetCode; // Return value
+ TT_RESULT Result; // Result
+ EVENT *ResultShowEvent; // Display result event
+ bool CloseDialogAfter; // Flag of whether or not to close the dialog
+} CM_TRAFFIC_DLG;
+
+// Internet connection settings
+typedef struct CM_INTERNET_SETTING
+{
+ UINT ProxyType; // Type of proxy server
+ char ProxyHostName[MAX_HOST_NAME_LEN + 1]; // Proxy server host name
+ UINT ProxyPort; // Proxy server port number
+ char ProxyUsername[MAX_USERNAME_LEN + 1]; // Proxy server user name
+ char ProxyPassword[MAX_USERNAME_LEN + 1]; // Proxy server password
+} CM_INTERNET_SETTING;
+
+static CM *cm = NULL;
+
+void CmFreeTrayExternal(void *hWnd);
+
+// Normal RPC call macro
+__forceinline static bool CALL(HWND hWnd, UINT code)
+{
+ UINT ret = code;
+ if (ret != ERR_NO_ERROR)
+ {
+ if (ret == ERR_DISCONNECTED)
+ {
+ if (cm != NULL)
+ {
+ Close(cm->hMainWnd);
+ }
+ else
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("SM_DISCONNECTED"));
+ }
+
+ if (cm != NULL)
+ {
+ CmFreeTrayExternal((void *)cm->hMainWnd);
+ }
+ exit(0);
+ }
+ else
+ {
+ UINT flag = MB_ICONEXCLAMATION;
+ if (ret == ERR_VLAN_IS_USED)
+ {
+ CmVoice("using_vlan");
+ }
+ if (hWnd != NULL && cm != NULL && cm->hEasyWnd != NULL)
+ {
+ hWnd = cm->hEasyWnd;
+ }
+ if (hWnd != NULL && cm != NULL && hWnd == cm->hEasyWnd)
+ {
+ flag |= MB_SETFOREGROUND | MB_TOPMOST;
+ }
+ MsgBox(hWnd, flag, _E(ret));
+ }
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// Extended RPC call macro (get an error value)
+__forceinline static UINT CALLEX(HWND hWnd, UINT code)
+{
+ UINT ret = code;
+ if (ret != ERR_NO_ERROR)
+ {
+ if (ret == ERR_DISCONNECTED)
+ {
+ if (cm != NULL)
+ {
+ Close(cm->hMainWnd);
+ }
+ else
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("SM_DISCONNECTED"));
+ }
+ if (cm != NULL)
+ {
+ CmFreeTrayExternal((void *)cm->hMainWnd);
+ }
+ exit(0);
+ }
+ }
+
+ return ret;
+}
+
+typedef struct CM_LOADX
+{
+ X *x;
+} CM_LOADX;
+
+typedef struct CM_SETTING_DLG
+{
+ bool CheckPassword;
+ UCHAR HashedPassword[SHA1_SIZE];
+} CM_SETTING_DLG;
+
+typedef struct CM_EASY_DLG
+{
+ bool EndDialogCalled;
+} CM_EASY_DLG;
+
+
+
+// Task tray related
+#define WM_CM_TRAY_MESSAGE (WM_APP + 44)
+#define WM_CM_SETTING_CHANGED_MESSAGE (WM_APP + 45)
+#define WM_CM_EASY_REFRESH (WM_APP + 46)
+#define WM_CM_SHOW (WM_APP + 47)
+#define CMD_EASY_DBLCLICK 40697
+#define CMD_VGC_CONNECT 40698
+#define CM_TRAY_ANIMATION_INTERVAL 3000
+#define CM_TRAY_MAX_ITEMS 4096
+#define CM_TRAY_MENU_ID_START 12000
+#define CM_TRAY_MENU_CONNECT_ID_START (CM_TRAY_MENU_ID_START + CM_TRAY_MAX_ITEMS)
+#define CM_TRAY_MENU_STATUS_ID_START (CM_TRAY_MENU_CONNECT_ID_START + CM_TRAY_MAX_ITEMS)
+#define CM_TRAY_MENU_DISCONNECT_ID_START (CM_TRAY_MENU_STATUS_ID_START + CM_TRAY_MAX_ITEMS)
+#define CM_TRAY_MENU_RECENT_ID_START (CM_TRAY_MENU_DISCONNECT_ID_START + CM_TRAY_MAX_ITEMS)
+#define CM_TRAY_IS_CONNECT_ID(id) (((id) >= CM_TRAY_MENU_CONNECT_ID_START) && (id) < CM_TRAY_MENU_STATUS_ID_START)
+#define CM_TRAY_IS_STATUS_ID(id) (((id) >= CM_TRAY_MENU_STATUS_ID_START) && (id) < CM_TRAY_MENU_DISCONNECT_ID_START)
+#define CM_TRAY_IS_DISCONNECT_ID(id) (((id) >= CM_TRAY_MENU_DISCONNECT_ID_START) && (id) < (CM_TRAY_MENU_DISCONNECT_ID_START + CM_TRAY_MAX_ITEMS))
+#define CM_TRAY_IS_RECENT_ID(id) (((id) >= CM_TRAY_MENU_RECENT_ID_START) && (id) < (CM_TRAY_MENU_RECENT_ID_START + CM_TRAY_MAX_ITEMS))
+
+
+// Function prototype
+void InitCM(bool set_app_id);
+void FreeCM();
+void MainCM();
+bool LoginCM();
+void LogoutCM();
+UINT CmLoginDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void MainCMWindow();
+void CmSendImportMessage(HWND hWnd, wchar_t *filename, UINT msg);
+UINT CmMainWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmMainWindowOnSize(HWND hWnd);
+void CmMainWindowOnInit(HWND hWnd);
+void CmMainWindowOnQuit(HWND hWnd);
+void CmSaveMainWindowPos(HWND hWnd);
+void CmMainWindowOnCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
+void CmMainWindowOnCommandEx(HWND hWnd, WPARAM wParam, LPARAM lParam, bool easy);
+bool CmIsEnabled(HWND hWnd, UINT id);
+bool CmIsChecked(UINT id);
+bool CmIsBold(UINT id);
+void CmMainWindowOnPopupMenu(HWND hWnd, HMENU hMenu, UINT pos);
+void CmSaveMainWindowPos(HWND hWnd);
+void CmRedrawStatusBar(HWND hWnd);
+void CmRefresh(HWND hWnd);
+void CmRefreshEx(HWND hWnd, bool style_changed);
+void CmSetForegroundProcessToCnService();
+void CmInitAccountList(HWND hWnd);
+void CmInitAccountListEx(HWND hWnd, bool easy);
+void CmInitVLanList(HWND hWnd);
+void CmRefreshAccountList(HWND hWnd);
+void CmRefreshAccountListEx(HWND hWnd, bool easy);
+void CmRefreshAccountListEx2(HWND hWnd, bool easy, bool style_changed);
+void CmRefreshVLanList(HWND hWnd);
+void CmRefreshVLanListEx(HWND hWnd, bool style_changed);
+void CmSaveAccountListPos(HWND hWnd);
+void CmSaveVLanListPos(HWND hWnd);
+wchar_t *CmGetProtocolName(UINT n);
+void CmVLanNameToPrintName(char *str, UINT size, char *name);
+bool CmPrintNameToVLanName(char *name, UINT size, char *str);
+void CmMainWindowOnNotify(HWND hWnd, NMHDR *n);
+void CmOnKey(HWND hWnd, bool ctrl, bool alt, UINT key);
+void CmAccountListRightClick(HWND hWnd);
+void CmVLanListRightClick(HWND hWnd);
+void CmConnect(HWND hWnd, wchar_t *account_name);
+void CmDisconnect(HWND hWnd, wchar_t *account_name);
+void CmInitNotifyClientThread();
+void CmFreeNotifyClientThread();
+void CmNotifyClientThread(THREAD *thread, void *param);
+void CmDeleteAccount(HWND hWnd, wchar_t *account_name);
+void CmStatus(HWND hWnd, wchar_t *account_name);
+void CmStatusDlg(HWND hWnd, wchar_t *account_name);
+UINT CmStatusDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmStatusDlgPrint(HWND hWnd, CM_STATUS *cmst);
+void CmPrintStatusToListView(LVB *b, RPC_CLIENT_GET_CONNECTION_STATUS *s);
+void CmPrintStatusToListViewEx(LVB *b, RPC_CLIENT_GET_CONNECTION_STATUS *s, bool server_mode);
+void CmStatusDlgPrintCert(HWND hWnd, CM_STATUS *st, bool server);
+void CmPolicyDlg(HWND hWnd, CM_STATUS *st);
+UINT CmPolicyDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmPolicyDlgPrint(HWND hWnd, CM_POLICY *p);
+void CmPolicyDlgPrintEx(HWND hWnd, CM_POLICY *p, bool cascade_mode);
+void CmPolicyDlgPrintEx2(HWND hWnd, CM_POLICY *p, bool cascade_mode, bool ver);
+void CmNewAccount(HWND hWnd);
+void CmEditAccount(HWND hWnd, wchar_t *account_name);
+void CmGenerateNewAccountName(HWND hWnd, wchar_t *name, UINT size);
+void CmGenerateCopyName(HWND hWnd, wchar_t *name, UINT size, wchar_t *old_name);
+void CmGenerateImportName(HWND hWnd, wchar_t *name, UINT size, wchar_t *old_name);
+CM_ACCOUNT *CmCreateNewAccountObject(HWND hWnd);
+CM_ACCOUNT *CmGetExistAccountObject(HWND hWnd, wchar_t *account_name);
+void CmEnumHubStart(HWND hWnd, CLIENT_OPTION *o);
+void CmInitEnumHub();
+void CmFreeEnumHub();
+void CmFreeAccountObject(HWND hWnd, CM_ACCOUNT *a);
+bool CmEditAccountDlg(HWND hWnd, CM_ACCOUNT *a);
+UINT CmEditAccountDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmEditAccountDlgUpdate(HWND hWnd, CM_ACCOUNT *a);
+void CmEditAccountDlgInit(HWND hWnd, CM_ACCOUNT *a);
+void CmEditAccountDlgOnOk(HWND hWnd, CM_ACCOUNT *a);
+void CmEditAccountDlgStartEnumHub(HWND hWnd, CM_ACCOUNT *a);
+bool CmLoadXAndK(HWND hWnd, X **x, K **k);
+bool CmLoadK(HWND hWnd, K **k);
+bool CmLoadKEx(HWND hWnd, K **k, char *filename, UINT size);
+bool CmLoadKExW(HWND hWnd, K **k, wchar_t *filename, UINT size);
+bool CmLoadXFromFileOrSecureCard(HWND hWnd, X **x);
+void CmLoadXFromFileOrSecureCardDlgInit(HWND hWnd, CM_LOADX *p);
+void CmLoadXFromFileOrSecureCardDlgUpdate(HWND hWnd, CM_LOADX *p);
+UINT CmLoadXFromFileOrSecureCardDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+bool CmLoadX(HWND hWnd, X **x);
+bool CmLoadXEx(HWND hWnd, X **x, char *filename, UINT size);
+bool CmLoadXExW(HWND hWnd, X **x, wchar_t *filename, UINT size);
+X *CmGetIssuer(X *x);
+bool CmProxyDlg(HWND hWnd, CLIENT_OPTION *a);
+void CmProxyDlgUpdate(HWND hWnd, CLIENT_OPTION *a);
+UINT CmProxyDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+bool CmDetailDlg(HWND hWnd, CM_ACCOUNT *a);
+UINT CmDetailDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+char *CmNewVLanDlg(HWND hWnd);
+UINT CmNewVLanDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmCopyAccount(HWND hWnd, wchar_t *account_name);
+void CmExportAccount(HWND hWnd, wchar_t *account_name);
+void CmSortcut(HWND hWnd, wchar_t *account_name);
+void CmImportAccount(HWND hWnd);
+void CmImportAccountMain(HWND hWnd, wchar_t *filename);
+void CmImportAccountMainEx(HWND hWnd, wchar_t *filename, bool overwrite);
+void CmTrustDlg(HWND hWnd);
+UINT CmTrustDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmTrustDlgUpdate(HWND hWnd);
+void CmTrustDlgRefresh(HWND hWnd);
+void CmTrustImport(HWND hWnd);
+void CmTrustExport(HWND hWnd);
+void CmTrustView(HWND hWnd);
+void CmPassword(HWND hWnd);
+UINT CmPasswordProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmPasswordRefresh(HWND hWnd);
+void CmRefreshStatusBar(HWND hWnd);
+UINT CmGetNumConnected(HWND hWnd);
+void CmDisconnectAll(HWND hWnd);
+wchar_t *CmGenerateMainWindowTitle();
+void CmConfigDlg(HWND hWnd);
+UINT CmConfigDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmConfigDlgInit(HWND hWnd);
+void CmConfigDlgRefresh(HWND hWnd);
+void CmConfigDlgOnOk(HWND hWnd);
+bool CmWarningDesktop(HWND hWnd, wchar_t *account_name);
+UINT CmDesktopDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmDesktopDlgInit(HWND hWnd, wchar_t *account_name);
+bool CmStopInstallVLan(HWND hWnd);
+void CmChangePassword(HWND hWnd, CLIENT_OPTION *o, char *hubname, char *username);
+UINT CmChangePasswordProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmChangePasswordUpdate(HWND hWnd, CM_CHANGE_PASSWORD *p);
+void SmShowPublicVpnServerHtml(HWND hWnd);
+void CmConnectShortcut(UCHAR *key);
+UINT CmSelectSecure(HWND hWnd, UINT current_id);
+void CmClientSecureManager(HWND hWnd);
+UINT CmClientSelectSecure(HWND hWnd);
+UINT CmSelectSecureDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmSelectSecureDlgInit(HWND hWnd, UINT default_id);
+void CmSelectSecureDlgUpdate(HWND hWnd);
+void CmSecureManager(HWND hWnd, UINT id);
+void CmSecureManagerEx(HWND hWnd, UINT id, bool no_new_cert);
+UINT CmSecureManagerDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmSecureManagerDlgInit(HWND hWnd, UINT id);
+void CmSecureManagerDlgUpdate(HWND hWnd, UINT id);
+void CmSecureManagerDlgRefresh(HWND hWnd, UINT id);
+void CmSecureManagerDlgPrintList(HWND hWnd, LIST *o);
+void CmSecureManagerDlgPrintListEx(HWND hWnd, UINT id, LIST *o, UINT type);
+wchar_t *CmSecureObjTypeToStr(UINT type);
+UINT CmSecureType(HWND hWnd);
+UINT CmSecureTypeDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmSecureManagerDlgImport(HWND hWnd, UINT id);
+void CmSecureManagerDlgDelete(HWND hWnd, UINT id);
+void CmSecureManagerDlgExport(HWND hWnd, UINT id);
+void CmSecureManagerDlgNewCert(HWND hWnd, UINT id);
+void CmSecurePin(HWND hWnd, UINT id);
+UINT CmSecurePinDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmSecurePinDlgUpdate(HWND hWnd);
+void CmInitTray(HWND hWnd);
+void CmPollingTray(HWND hWnd);
+void CmFreeTray(HWND hWnd);
+void CmChangeTrayString(HWND hWnd, wchar_t *str);
+UINT CmGetTrayIconId(bool animation, UINT animation_counter);
+void CmShowOrHideWindow(HWND hWnd);
+void CmShowTrayMenu(HWND hWnd);
+HMENU CmCreateTraySubMenu(HWND hWnd, bool flag, UINT start_id);
+HMENU CmCreateRecentSubMenu(HWND hWnd, UINT start_id);
+bool CmCheckPkcsEula(HWND hWnd, UINT id);
+UINT CmPkcsEulaDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmDeleteOldStartupTrayFile();
+UINT CmTrafficDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmTrafficDlgInit(HWND hWnd);
+bool CmTrafficDlgUpdate(HWND hWnd);
+void CmTrafficDlgOnOk(HWND hWnd);
+bool CmTrafficLoadFromReg(CM_TRAFFIC *t);
+void CmTrafficGetDefaultSetting(CM_TRAFFIC *t);
+void CmTrafficSaveToReg(CM_TRAFFIC *t);
+void CmTrafficDlgToStruct(HWND hWnd, CM_TRAFFIC *t);
+void CmExecTraffic(HWND hWnd, CM_TRAFFIC *t);
+UINT CmTrafficRunDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmTrafficRunDlgInit(HWND hWnd, CM_TRAFFIC_DLG *d);
+void CmTrafficRunDlgStart(HWND hWnd, CM_TRAFFIC_DLG *d);
+void CmTrafficRunDlgPrintProc(void *param, wchar_t *str);
+void CmTrafficRunDlgAddStr(HWND hWnd, wchar_t *str);
+void CmTrafficRunDlgHalt(HWND hWnd, CM_TRAFFIC_DLG *d);
+void CmTrafficRunDlgHaltThread(THREAD *t, void *param);
+void CmTrafficRunDlgClientWaitThread(THREAD *t, void *param);
+void CmTrafficResult(HWND hWnd, TT_RESULT *r);
+UINT CmTrafficResultDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmTrafficResultDlgInit(HWND hWnd, TT_RESULT *res);
+void CmTryToExecUiHelper();
+void CmInitTryToExecUiHelper();
+void CmFreeTryToExecUiHelper();
+void CmTryToExecUiHelperThread(THREAD *thread, void *param);
+bool CmSetting(HWND hWnd);
+UINT CmSettingDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmSettingDlgInit(HWND hWnd, CM_SETTING_DLG *d);
+void CmSettingDlgUpdate(HWND hWnd, CM_SETTING_DLG *d);
+void CmSettingDlgOnOk(HWND hWnd, CM_SETTING_DLG *d);
+void CmApplyCmSetting();
+void CmMainWindowOnTrayClicked(HWND hWnd, WPARAM wParam, LPARAM lParam);
+void CmShowEasy();
+void CmCloseEasy();
+void CmMainWindowOnShowEasy(HWND hWnd);
+UINT CmEasyDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmEasyDlgInit(HWND hWnd, CM_EASY_DLG *d);
+void CmEasyDlgUpdate(HWND hWnd, CM_EASY_DLG *d);
+void CmEasyDlgRefresh(HWND hWnd, CM_EASY_DLG *d);
+void CmRefreshEasy();
+void CmEasyDlgOnNotify(HWND hWnd, CM_EASY_DLG *d, NMHDR *n);
+void CmEasyDlgOnKey(HWND hWnd, CM_EASY_DLG *d, bool ctrl, bool alt, UINT key);
+void CmEasyDlgOnCommand(HWND hWnd, CM_EASY_DLG *d, WPARAM wParam, LPARAM lParam);
+
+bool CmStartStartupMutex();
+void CmEndStartupMutex();
+void CmSetUacWindowActive();
+void CmUacHelperThread(THREAD *thread, void *param);
+void CmProxyDlgUseForIE(HWND hWnd, CLIENT_OPTION *o);
+void CmGetSystemInternetSetting(CM_INTERNET_SETTING *setting);
+void CmProxyDlgSet(HWND hWnd, CLIENT_OPTION *o, CM_INTERNET_SETTING *setting);
+bool CmGetProxyServerNameAndPortFromIeProxyRegStr(char *name, UINT name_size, UINT *port, char *str, char *server_type);
+void *CmUpdateJumpList(UINT start_id);
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Cedar.c b/src/Cedar/Cedar.c
new file mode 100644
index 00000000..2505dcef
--- /dev/null
+++ b/src/Cedar/Cedar.c
@@ -0,0 +1,1708 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Cedar.c
+// Cedar Communication Module
+
+
+#include "CedarPch.h"
+
+static UINT init_cedar_counter = 0;
+static REF *cedar_log_ref = NULL;
+static LOG *cedar_log;
+
+// Get build date of current code
+UINT64 GetCurrentBuildDate()
+{
+ SYSTEMTIME st;
+
+ Zero(&st, sizeof(st));
+
+ st.wYear = BUILD_DATE_Y;
+ st.wMonth = BUILD_DATE_M;
+ st.wDay = BUILD_DATE_D;
+ st.wHour = BUILD_DATE_HO;
+ st.wMinute = BUILD_DATE_MI;
+ st.wSecond = BUILD_DATE_SE;
+
+ return SystemToUINT64(&st);
+}
+
+// Check current windows version is supported
+bool IsSupportedWinVer(RPC_WINVER *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return false;
+ }
+
+ if (v->IsWindows == false)
+ {
+ return true;
+ }
+
+ if (v->IsNT == false)
+ {
+ return true;
+ }
+
+ if (v->IsBeta)
+ {
+ return true;
+ }
+
+ if (v->VerMajor <= 4)
+ {
+ // Windows NT
+ return true;
+ }
+
+ if (v->VerMajor == 5 && v->VerMinor == 0)
+ {
+ // Windows 2000
+ if (v->ServicePack <= 4)
+ {
+ // SP4 or earlier
+ return true;
+ }
+ }
+
+ if (v->VerMajor == 5 && v->VerMinor == 1)
+ {
+ // Windows XP x86
+ if (v->ServicePack <= 3)
+ {
+ // SP3 or earlier
+ return true;
+ }
+ }
+
+ if (v->VerMajor == 5 && v->VerMinor == 2)
+ {
+ // Windows XP x64, Windows Server 2003
+ if (v->ServicePack <= 2)
+ {
+ // SP2 or earlier
+ return true;
+ }
+ }
+
+ if (v->VerMajor == 6 && v->VerMinor == 0)
+ {
+ // Windows Vista, Server 2008
+ if (v->ServicePack <= 2)
+ {
+ // SP2 or earlier
+ return true;
+ }
+ }
+
+ if (v->VerMajor == 6 && v->VerMinor == 1)
+ {
+ // Windows 7, Server 2008 R2
+ if (v->ServicePack <= 1)
+ {
+ // SP1 or earlier
+ return true;
+ }
+ }
+
+ if (v->VerMajor == 6 && v->VerMinor == 2)
+ {
+ // Windows 8, Server 2012
+ if (v->ServicePack <= 0)
+ {
+ // SP0 only
+ return true;
+ }
+ }
+
+ if (v->VerMajor == 6 && v->VerMinor == 3)
+ {
+ // Windows 8.1, Server 2012 R2
+ if (v->ServicePack <= 0)
+ {
+ // SP0 only
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Get version of Windows
+void GetWinVer(RPC_WINVER *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ Win32GetWinVer(v);
+#else // OS_WIN32
+ Zero(v, sizeof(RPC_WINVER));
+ StrCpy(v->Title, sizeof(v->Title), GetOsInfo()->OsProductName);
+#endif // OS_WIN32
+}
+
+// Close tiny log
+void FreeTinyLog(TINY_LOG *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FileClose(t->io);
+ DeleteLock(t->Lock);
+ Free(t);
+}
+
+// Write to tiny log
+void WriteTinyLog(TINY_LOG *t, char *str)
+{
+ BUF *b;
+ char dt[MAX_PATH];
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ GetDateTimeStrMilli64(dt, sizeof(dt), LocalTime64());
+ StrCat(dt, sizeof(dt), ": ");
+
+ b = NewBuf();
+
+ WriteBuf(b, dt, StrLen(dt));
+ WriteBuf(b, str, StrLen(str));
+ WriteBuf(b, "\r\n", 2);
+
+ Lock(t->Lock);
+ {
+ FileWrite(t->io, b->Buf, b->Size);
+ //FileFlush(t->io);
+ }
+ Unlock(t->Lock);
+
+ FreeBuf(b);
+}
+
+// Initialize tiny log
+TINY_LOG *NewTinyLog()
+{
+ char name[MAX_PATH];
+ SYSTEMTIME st;
+ TINY_LOG *t;
+
+ LocalTime(&st);
+
+ MakeDir(TINY_LOG_DIRNAME);
+
+ Format(name, sizeof(name), TINY_LOG_FILENAME,
+ st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
+
+ t = ZeroMalloc(sizeof(TINY_LOG));
+
+ StrCpy(t->FileName, sizeof(t->FileName), name);
+ t->io = FileCreate(name);
+ t->Lock = NewLock();
+
+ return t;
+}
+
+// Compare entries of No-SSL connection list
+int CompareNoSslList(void *p1, void *p2)
+{
+ NON_SSL *n1, *n2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ n1 = *(NON_SSL **)p1;
+ n2 = *(NON_SSL **)p2;
+ if (n1 == NULL || n2 == NULL)
+ {
+ return 0;
+ }
+ return CmpIpAddr(&n1->IpAddress, &n2->IpAddress);
+}
+
+// Check whether the specified IP address is in Non-SSL connection list
+bool IsInNoSsl(CEDAR *c, IP *ip)
+{
+ bool ret = false;
+ // Validate arguments
+ if (c == NULL || ip == NULL)
+ {
+ return false;
+ }
+
+ LockList(c->NonSslList);
+ {
+ NON_SSL *n = SearchNoSslList(c, ip);
+
+ if (n != NULL)
+ {
+ if (n->EntryExpires > Tick64() && n->Count > NON_SSL_MIN_COUNT)
+ {
+ n->EntryExpires = Tick64() + (UINT64)NON_SSL_ENTRY_EXPIRES;
+ ret = true;
+ }
+ }
+ }
+ UnlockList(c->NonSslList);
+
+ return ret;
+}
+
+// Decrement connection count of Non-SSL connection list entry
+void DecrementNoSsl(CEDAR *c, IP *ip, UINT num_dec)
+{
+ // Validate arguments
+ if (c == NULL || ip == NULL)
+ {
+ return;
+ }
+
+ LockList(c->NonSslList);
+ {
+ NON_SSL *n = SearchNoSslList(c, ip);
+
+ if (n != NULL)
+ {
+ if (n->Count >= num_dec)
+ {
+ n->Count -= num_dec;
+ }
+ }
+ }
+ UnlockList(c->NonSslList);
+}
+
+// Add new entry to Non-SSL connection list
+bool AddNoSsl(CEDAR *c, IP *ip)
+{
+ NON_SSL *n;
+ bool ret = true;
+ // Validate arguments
+ if (c == NULL || ip == NULL)
+ {
+ return true;
+ }
+
+ LockList(c->NonSslList);
+ {
+ DeleteOldNoSsl(c);
+
+ n = SearchNoSslList(c, ip);
+
+ if (n == NULL)
+ {
+ n = ZeroMalloc(sizeof(NON_SSL));
+ Copy(&n->IpAddress, ip, sizeof(IP));
+ n->Count = 0;
+
+ Add(c->NonSslList, n);
+ }
+
+ n->EntryExpires = Tick64() + (UINT64)NON_SSL_ENTRY_EXPIRES;
+
+ n->Count++;
+
+ if (n->Count > NON_SSL_MIN_COUNT)
+ {
+ ret = false;
+ }
+ }
+ UnlockList(c->NonSslList);
+
+ return ret;
+}
+
+// Delete old entries in Non-SSL connection list
+void DeleteOldNoSsl(CEDAR *c)
+{
+ UINT i;
+ LIST *o;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ o = NewListFast(NULL);
+
+ for (i = 0;i < LIST_NUM(c->NonSslList);i++)
+ {
+ NON_SSL *n = LIST_DATA(c->NonSslList, i);
+
+ if (n->EntryExpires <= Tick64())
+ {
+ Add(o, n);
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ NON_SSL *n = LIST_DATA(o, i);
+
+ Delete(c->NonSslList, n);
+ Free(n);
+ }
+
+ ReleaseList(o);
+}
+
+// Search entry in Non-SSL connection list
+NON_SSL *SearchNoSslList(CEDAR *c, IP *ip)
+{
+ NON_SSL *n, t;
+ // Validate arguments
+ if (c == NULL || ip == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&t, sizeof(t));
+ Copy(&t.IpAddress, ip, sizeof(IP));
+
+ n = Search(c->NonSslList, &t);
+
+ if (n == NULL)
+ {
+ return NULL;
+ }
+
+ return n;
+}
+
+// Initialize Non-SSL connection list
+void InitNoSslList(CEDAR *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->NonSslList = NewList(CompareNoSslList);
+}
+
+// Free Non-SSL connection list
+void FreeNoSslList(CEDAR *c)
+{
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(c->NonSslList);i++)
+ {
+ NON_SSL *n = LIST_DATA(c->NonSslList, i);
+
+ Free(n);
+ }
+
+ ReleaseList(c->NonSslList);
+ c->NonSslList = NULL;
+}
+
+// Write a message into Cedar log
+void CedarLog(char *str)
+{
+ char *tmp;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return;
+ }
+ if (cedar_log_ref == NULL)
+ {
+ return;
+ }
+
+ tmp = CopyStr(str);
+
+ if (StrLen(tmp) > 1)
+ {
+ if (tmp[StrLen(tmp) - 1] == '\n')
+ {
+ tmp[StrLen(tmp) - 1] = 0;
+ }
+ if (StrLen(tmp) > 1)
+ {
+ if (tmp[StrLen(tmp) - 1] == '\r')
+ {
+ tmp[StrLen(tmp) - 1] = 0;
+ }
+ }
+ }
+
+ InsertStringRecord(cedar_log, tmp);
+
+ Free(tmp);
+}
+
+// Start Cedar log
+void StartCedarLog()
+{
+ if (cedar_log_ref == NULL)
+ {
+ cedar_log_ref = NewRef();
+ }
+ else
+ {
+ AddRef(cedar_log_ref);
+ }
+
+ cedar_log = NewLog("debug_log", "debug", LOG_SWITCH_DAY);
+}
+
+// Stop Cedar log
+void StopCedarLog()
+{
+ if (cedar_log_ref == NULL)
+ {
+ return;
+ }
+
+ if (Release(cedar_log_ref) == 0)
+ {
+ FreeLog(cedar_log);
+ cedar_log = NULL;
+ cedar_log_ref = NULL;
+ }
+}
+
+
+// Get sum of traffic data size
+UINT64 GetTrafficPacketSize(TRAFFIC *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return 0;
+ }
+
+ return t->Recv.BroadcastBytes + t->Recv.UnicastBytes +
+ t->Send.BroadcastBytes + t->Send.UnicastBytes;
+}
+
+// Get sum of the number of packets in traffic
+UINT64 GetTrafficPacketNum(TRAFFIC *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return 0;
+ }
+
+ return t->Recv.BroadcastCount + t->Recv.UnicastCount +
+ t->Send.BroadcastCount + t->Send.UnicastCount;
+}
+
+// Get whether hidden password is changed in UI
+bool IsHiddenPasswordChanged(char *str)
+{
+ // Validate arguments
+ if (str == NULL)
+ {
+ return true;
+ }
+
+ if (StrCmpi(str, HIDDEN_PASSWORD) == 0)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// Initialize hidden password in UI
+void InitHiddenPassword(char *str, UINT size)
+{
+ // Validate arguments
+ if (str == NULL)
+ {
+ return;
+ }
+
+ StrCpy(str, size, HIDDEN_PASSWORD);
+}
+
+// Check whether the certificate is signed by CA which is trusted by the hub
+bool CheckSignatureByCaLinkMode(SESSION *s, X *x)
+{
+ LINK *k;
+ HUB *h;
+ bool ret = false;
+ // Validate arguments
+ if (s == NULL || x == NULL)
+ {
+ return false;
+ }
+
+ if (s->LinkModeClient == false || (k = s->Link) == NULL)
+ {
+ return false;
+ }
+
+ h = k->Hub;
+
+ if (h->HubDb != NULL)
+ {
+ LockList(h->HubDb->RootCertList);
+ {
+ X *root_cert;
+ root_cert = GetIssuerFromList(h->HubDb->RootCertList, x);
+ if (root_cert != NULL)
+ {
+ ret = true;
+ }
+ }
+ UnlockList(h->HubDb->RootCertList);
+ }
+
+ return ret;
+}
+
+// Check whether the certificate is signed by CA which is trusted by Cedar
+bool CheckSignatureByCa(CEDAR *cedar, X *x)
+{
+ X *ca;
+ // Validate arguments
+ if (cedar == NULL || x == NULL)
+ {
+ return false;
+ }
+
+ // Get the CA which signed the certificate
+ ca = FindCaSignedX(cedar->CaList, x);
+ if (ca == NULL)
+ {
+ // Not found
+ return false;
+ }
+
+ // Found
+ FreeX(ca);
+ return true;
+}
+
+// Get the CA which signed the certificate
+X *FindCaSignedX(LIST *o, X *x)
+{
+ X *ret;
+ // Validate arguments
+ if (o == NULL || x == NULL)
+ {
+ return NULL;
+ }
+
+ ret = NULL;
+
+ LockList(o);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ X *ca = LIST_DATA(o, i);
+ if (CheckXDateNow(ca))
+ {
+ if (CompareName(ca->subject_name, x->issuer_name))
+ {
+ K *k = GetKFromX(ca);
+ if (k != NULL)
+ {
+ if (CheckSignature(x, k))
+ {
+ ret = CloneX(ca);
+ }
+ FreeK(k);
+ }
+ }
+ else if (CompareX(ca, x))
+ {
+ ret = CloneX(ca);
+ }
+ }
+
+ if (ret != NULL)
+ {
+ break;
+ }
+ }
+ }
+ UnlockList(o);
+
+ return ret;
+}
+
+// Delete trusted CA from Cedar
+bool DeleteCa(CEDAR *cedar, UINT ptr)
+{
+ bool b = false;
+ // Validate arguments
+ if (cedar == NULL || ptr == 0)
+ {
+ return false;
+ }
+
+ LockList(cedar->CaList);
+ {
+ UINT i;
+
+ for (i = 0;i < LIST_NUM(cedar->CaList);i++)
+ {
+ X *x = LIST_DATA(cedar->CaList, i);
+
+ if (POINTER_TO_KEY(x) == ptr)
+ {
+ Delete(cedar->CaList, x);
+ FreeX(x);
+
+ b = true;
+
+ break;
+ }
+ }
+ }
+ UnlockList(cedar->CaList);
+
+ return b;
+}
+
+// Add trusted CA to Cedar
+void AddCa(CEDAR *cedar, X *x)
+{
+ // Validate arguments
+ if (cedar == NULL || x == NULL)
+ {
+ return;
+ }
+
+ LockList(cedar->CaList);
+ {
+ UINT i;
+ bool ok = true;
+
+ for (i = 0;i < LIST_NUM(cedar->CaList);i++)
+ {
+ X *exist_x = LIST_DATA(cedar->CaList, i);
+ if (CompareX(exist_x, x))
+ {
+ ok = false;
+ break;
+ }
+ }
+
+ if (ok)
+ {
+ Insert(cedar->CaList, CloneX(x));
+ }
+ }
+ UnlockList(cedar->CaList);
+}
+
+// Delete connection from Cedar
+void DelConnection(CEDAR *cedar, CONNECTION *c)
+{
+ // Validate arguments
+ if (cedar == NULL || c == NULL)
+ {
+ return;
+ }
+
+ LockList(cedar->ConnectionList);
+ {
+ Debug("Connection %s Deleted from Cedar.\n", c->Name);
+ if (Delete(cedar->ConnectionList, c))
+ {
+ ReleaseConnection(c);
+ }
+ }
+ UnlockList(cedar->ConnectionList);
+}
+
+// Get the number of unestablished connections
+UINT GetUnestablishedConnections(CEDAR *cedar)
+{
+ UINT i, ret;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return 0;
+ }
+
+ ret = 0;
+
+ LockList(cedar->ConnectionList);
+ {
+ for (i = 0;i < LIST_NUM(cedar->ConnectionList);i++)
+ {
+ CONNECTION *c = LIST_DATA(cedar->ConnectionList, i);
+
+ switch (c->Type)
+ {
+ case CONNECTION_TYPE_CLIENT:
+ case CONNECTION_TYPE_INIT:
+ case CONNECTION_TYPE_LOGIN:
+ case CONNECTION_TYPE_ADDITIONAL:
+ switch (c->Status)
+ {
+ case CONNECTION_STATUS_ACCEPTED:
+ case CONNECTION_STATUS_NEGOTIATION:
+ case CONNECTION_STATUS_USERAUTH:
+ ret++;
+ break;
+ }
+ break;
+ }
+ }
+ }
+ UnlockList(cedar->ConnectionList);
+
+ return ret + Count(cedar->AcceptingSockets);
+}
+
+// Add connection to Cedar
+void AddConnection(CEDAR *cedar, CONNECTION *c)
+{
+ char tmp[MAX_SIZE];
+ UINT i;
+ // Validate arguments
+ if (cedar == NULL || c == NULL)
+ {
+ return;
+ }
+
+ // Determine the name of the connection
+ i = Inc(cedar->ConnectionIncrement);
+ Format(tmp, sizeof(tmp), "CID-%u", i);
+ Lock(c->lock);
+ {
+ Free(c->Name);
+ c->Name = CopyStr(tmp);
+ }
+ Unlock(c->lock);
+
+ LockList(cedar->ConnectionList);
+ {
+ Add(cedar->ConnectionList, c);
+ AddRef(c->ref);
+ Debug("Connection %s Inserted to Cedar.\n", c->Name);
+ }
+ UnlockList(cedar->ConnectionList);
+}
+
+// Stop all connections
+void StopAllConnection(CEDAR *c)
+{
+ UINT num;
+ UINT i;
+ CONNECTION **connections;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ LockList(c->ConnectionList);
+ {
+ connections = ToArray(c->ConnectionList);
+ num = LIST_NUM(c->ConnectionList);
+ DeleteAll(c->ConnectionList);
+ }
+ UnlockList(c->ConnectionList);
+
+ for (i = 0;i < num;i++)
+ {
+ StopConnection(connections[i], false);
+ ReleaseConnection(connections[i]);
+ }
+ Free(connections);
+}
+
+// Delete a hub in Cedar
+void DelHub(CEDAR *c, HUB *h)
+{
+ DelHubEx(c, h, false);
+}
+void DelHubEx(CEDAR *c, HUB *h, bool no_lock)
+{
+ // Validate arguments
+ if (c == NULL || h == NULL)
+ {
+ return;
+ }
+
+ if (no_lock == false)
+ {
+ LockHubList(c);
+ }
+
+ if (Delete(c->HubList, h))
+ {
+ ReleaseHub(h);
+ }
+
+ if (no_lock == false)
+ {
+ UnlockHubList(c);
+ }
+}
+
+// Add a new hub to Cedar
+void AddHub(CEDAR *c, HUB *h)
+{
+ // Validate arguments
+ if (c == NULL || h == NULL)
+ {
+ return;
+ }
+
+ LockHubList(c);
+ {
+#if 0
+ // We shall not check here the number of hub
+ if (LIST_NUM(c->HubList) >= MAX_HUBS)
+ {
+ // over limit
+ UnlockHubList(c);
+ return;
+ }
+#endif
+
+ // Confirm there is no hub which have same name
+ if (IsHub(c, h->Name))
+ {
+ // exist
+ UnlockHubList(c);
+ return;
+ }
+
+ // Register the hub
+ Insert(c->HubList, h);
+ AddRef(h->ref);
+ }
+ UnlockHubList(c);
+}
+
+// Stop all hubs in Cedar
+void StopAllHub(CEDAR *c)
+{
+ HUB **hubs;
+ UINT i, num;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ LockHubList(c);
+ {
+ hubs = ToArray(c->HubList);
+ num = LIST_NUM(c->HubList);
+ DeleteAll(c->HubList);
+ }
+ UnlockHubList(c);
+
+ for (i = 0;i < num;i++)
+ {
+ StopHub(hubs[i]);
+ ReleaseHub(hubs[i]);
+ }
+
+ Free(hubs);
+}
+
+// Get reverse listener socket in Cedar
+SOCK *GetReverseListeningSock(CEDAR *c)
+{
+ SOCK *s = NULL;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ LockList(c->ListenerList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(c->ListenerList);i++)
+ {
+ LISTENER *r = LIST_DATA(c->ListenerList, i);
+
+ if (r->Protocol == LISTENER_REVERSE)
+ {
+ Lock(r->lock);
+ {
+ s = r->Sock;
+
+ AddRef(s->ref);
+ }
+ Unlock(r->lock);
+ break;
+ }
+ }
+ }
+ UnlockList(c->ListenerList);
+
+ return s;
+}
+
+// Get in-process listener socket in Cedar
+SOCK *GetInProcListeningSock(CEDAR *c)
+{
+ SOCK *s = NULL;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ LockList(c->ListenerList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(c->ListenerList);i++)
+ {
+ LISTENER *r = LIST_DATA(c->ListenerList, i);
+
+ if (r->Protocol == LISTENER_INPROC)
+ {
+ Lock(r->lock);
+ {
+ s = r->Sock;
+
+ if (s != NULL)
+ {
+ AddRef(s->ref);
+ }
+ }
+ Unlock(r->lock);
+ break;
+ }
+ }
+ }
+ UnlockList(c->ListenerList);
+
+ return s;
+}
+
+// Add a new listener to Cedar
+void AddListener(CEDAR *c, LISTENER *r)
+{
+ // Validate arguments
+ if (c == NULL || r == NULL)
+ {
+ return;
+ }
+
+ LockList(c->ListenerList);
+ {
+ Add(c->ListenerList, r);
+ AddRef(r->ref);
+ }
+ UnlockList(c->ListenerList);
+}
+
+// Stop all listener in Cedar
+void StopAllListener(CEDAR *c)
+{
+ LISTENER **array;
+ UINT i, num;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ LockList(c->ListenerList);
+ {
+ array = ToArray(c->ListenerList);
+ num = LIST_NUM(c->ListenerList);
+ DeleteAll(c->ListenerList);
+ }
+ UnlockList(c->ListenerList);
+
+ for (i = 0;i < num;i++)
+ {
+ StopListener(array[i]);
+ ReleaseListener(array[i]);
+ }
+ Free(array);
+}
+
+// Stop Cedar
+void StopCedar(CEDAR *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Stop flag
+ c->Halt = true;
+
+ // Stop all listener
+ StopAllListener(c);
+ // Stop all connections
+ StopAllConnection(c);
+ // Stop all hubs
+ StopAllHub(c);
+ // Free all virtual L3 switch
+ L3FreeAllSw(c);
+}
+
+// Clean up Cedar
+void CleanupCedar(CEDAR *c)
+{
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ WuFreeWebUI(c->WebUI);
+ FreeCedarLayer3(c);
+
+/*
+ for (i = 0;i < LIST_NUM(c->HubList);i++)
+ {
+ HUB *h = LIST_DATA(c->HubList, i);
+ }
+*/
+ for (i = 0;i < LIST_NUM(c->CaList);i++)
+ {
+ X *x = LIST_DATA(c->CaList, i);
+ FreeX(x);
+ }
+ ReleaseList(c->CaList);
+
+ ReleaseList(c->ListenerList);
+ ReleaseList(c->HubList);
+ ReleaseList(c->ConnectionList);
+ //CleanupUDPEntry(c);
+ ReleaseList(c->UDPEntryList);
+ DeleteLock(c->lock);
+ DeleteCounter(c->ConnectionIncrement);
+ DeleteCounter(c->CurrentSessions);
+
+ if (c->DebugLog != NULL)
+ {
+ FreeLog(c->DebugLog);
+ }
+
+ if (c->ServerX)
+ {
+ FreeX(c->ServerX);
+ }
+ if (c->ServerK)
+ {
+ FreeK(c->ServerK);
+ }
+
+ if (c->CipherList)
+ {
+ Free(c->CipherList);
+ }
+
+ for (i = 0;i < LIST_NUM(c->TrafficDiffList);i++)
+ {
+ TRAFFIC_DIFF *d = LIST_DATA(c->TrafficDiffList, i);
+ Free(d->Name);
+ Free(d->HubName);
+ Free(d);
+ }
+
+ ReleaseList(c->TrafficDiffList);
+
+ Free(c->ServerStr);
+ Free(c->MachineName);
+
+ Free(c->HttpUserAgent);
+ Free(c->HttpAccept);
+ Free(c->HttpAcceptLanguage);
+ Free(c->HttpAcceptEncoding);
+
+ FreeTraffic(c->Traffic);
+
+ DeleteLock(c->TrafficLock);
+
+ FreeNetSvcList(c);
+
+ Free(c->VerString);
+ Free(c->BuildInfo);
+
+ FreeLocalBridgeList(c);
+
+ DeleteCounter(c->AssignedBridgeLicense);
+ DeleteCounter(c->AssignedClientLicense);
+
+ FreeNoSslList(c);
+
+ DeleteLock(c->CedarSuperLock);
+
+ DeleteCounter(c->AcceptingSockets);
+
+ ReleaseIntList(c->UdpPortList);
+
+ DeleteLock(c->OpenVPNPublicPortsLock);
+
+ Free(c);
+}
+
+// Release reference of the Cedar
+void ReleaseCedar(CEDAR *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ if (Release(c->ref) == 0)
+ {
+ CleanupCedar(c);
+ }
+}
+
+// Set cipher list entry
+void SetCedarCipherList(CEDAR *cedar, char *name)
+{
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return;
+ }
+
+ if (cedar->CipherList != NULL)
+ {
+ Free(cedar->CipherList);
+ }
+ if (name != NULL)
+ {
+ cedar->CipherList = CopyStr(name);
+ }
+ else
+ {
+ cedar->CipherList = NULL;
+ }
+}
+
+// Compare net service list entries
+int CompareNetSvc(void *p1, void *p2)
+{
+ NETSVC *n1, *n2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ n1 = *(NETSVC **)p1;
+ n2 = *(NETSVC **)p2;
+ if (n1 == NULL || n2 == NULL)
+ {
+ return 0;
+ }
+ if (n1->Port > n2->Port)
+ {
+ return 1;
+ }
+ else if (n1->Port < n2->Port)
+ {
+ return -1;
+ }
+ else if (n1->Udp > n2->Udp)
+ {
+ return 1;
+ }
+ else if (n1->Udp < n2->Udp)
+ {
+ return -1;
+ }
+ return 0;
+}
+
+// Initialize net service list
+void InitNetSvcList(CEDAR *cedar)
+{
+ char filename[MAX_PATH] = "/etc/services";
+ BUF *b;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ Format(filename, sizeof(filename), "%s\\drivers\\etc\\services", MsGetSystem32Dir());
+#endif
+
+ cedar->NetSvcList = NewList(CompareNetSvc);
+
+ b = ReadDump(filename);
+ if (b == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ char *s = CfgReadNextLine(b);
+ if (s == NULL)
+ {
+ break;
+ }
+
+ Trim(s);
+ if (s[0] != '#')
+ {
+ TOKEN_LIST *t = ParseToken(s, " \t/");
+ if (t->NumTokens >= 3)
+ {
+ NETSVC *n = ZeroMalloc(sizeof(NETSVC));
+ n->Name = CopyStr(t->Token[0]);
+ n->Udp = (StrCmpi(t->Token[2], "udp") == 0 ? true : false);
+ n->Port = ToInt(t->Token[1]);
+ Add(cedar->NetSvcList, n);
+ }
+ FreeToken(t);
+ }
+ Free(s);
+ }
+
+ FreeBuf(b);
+}
+
+// Get net service name
+char *GetSvcName(CEDAR *cedar, bool udp, UINT port)
+{
+ char *ret = NULL;
+ NETSVC t;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ t.Udp = (udp == 0 ? false : true);
+ t.Port = port;
+
+ LockList(cedar->NetSvcList);
+ {
+ NETSVC *n = Search(cedar->NetSvcList, &t);
+ if (n != NULL)
+ {
+ ret = n->Name;
+ }
+ }
+ UnlockList(cedar->NetSvcList);
+
+ return ret;
+}
+
+// Free net service list
+void FreeNetSvcList(CEDAR *cedar)
+{
+ UINT i;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(cedar->NetSvcList);i++)
+ {
+ NETSVC *n = LIST_DATA(cedar->NetSvcList, i);
+ Free(n->Name);
+ Free(n);
+ }
+ ReleaseList(cedar->NetSvcList);
+}
+
+// Change certificate of Cedar
+void SetCedarCert(CEDAR *c, X *server_x, K *server_k)
+{
+ // Validate arguments
+ if (server_x == NULL || server_k == NULL)
+ {
+ return;
+ }
+
+ Lock(c->lock);
+ {
+ if (c->ServerX != NULL)
+ {
+ FreeX(c->ServerX);
+ }
+
+ if (c->ServerK != NULL)
+ {
+ FreeK(c->ServerK);
+ }
+
+ c->ServerX = CloneX(server_x);
+ c->ServerK = CloneK(server_k);
+ }
+ Unlock(c->lock);
+}
+
+// Enable debug log
+void EnableDebugLog(CEDAR *c)
+{
+ // Validate arguments
+ if (c == NULL || c->DebugLog != NULL)
+ {
+ return;
+ }
+
+ c->DebugLog = NewLog("cedar_debug_log", "cedar", LOG_SWITCH_NO);
+}
+
+// Set the Cedar into VPN Bridge mode
+void SetCedarVpnBridge(CEDAR *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->Bridge = true;
+
+ Free(c->ServerStr);
+ c->ServerStr = CopyStr(CEDAR_BRIDGE_STR);
+}
+
+void CedarForceLink()
+{
+}
+
+// Get version of the Cedar
+void GetCedarVersion(char *tmp, UINT size)
+{
+ // Validate arguments
+ if (tmp == NULL)
+ {
+ return;
+ }
+
+ Format(tmp, size, "%u.%02u.%u",
+ CEDAR_VER / 100, CEDAR_VER - (CEDAR_VER / 100) * 100,
+ CEDAR_BUILD);
+}
+
+// Create Cedar object
+CEDAR *NewCedar(X *server_x, K *server_k)
+{
+ CEDAR *c;
+ char tmp[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ char *beta_str;
+
+ CedarForceLink();
+
+ c = ZeroMalloc(sizeof(CEDAR));
+
+ c->AcceptingSockets = NewCounter();
+
+ c->CedarSuperLock = NewLock();
+
+#ifdef BETA_NUMBER
+ c->Beta = BETA_NUMBER;
+#endif // BETA_NUMBER
+
+ InitNoSslList(c);
+
+ c->AssignedBridgeLicense = NewCounter();
+ c->AssignedClientLicense = NewCounter();
+
+ Rand(c->UniqueId, sizeof(c->UniqueId));
+
+ c->CreatedTick = Tick64();
+
+ c->lock = NewLock();
+ c->ref = NewRef();
+
+ c->OpenVPNPublicPortsLock = NewLock();
+ c->CurrentTcpConnections = GetNumTcpConnectionsCounter();
+
+ c->ListenerList = NewList(CompareListener);
+ c->UDPEntryList = NewList(CompareUDPEntry);
+ c->HubList = NewList(CompareHub);
+ c->ConnectionList = NewList(CompareConnection);
+
+ c->ConnectionIncrement = NewCounter();
+ c->CurrentSessions = NewCounter();
+
+ if (server_k && server_x)
+ {
+ c->ServerK = CloneK(server_k);
+ c->ServerX = CloneX(server_x);
+ }
+
+ c->Version = CEDAR_VER;
+ c->Build = CEDAR_BUILD;
+ c->ServerStr = CopyStr(CEDAR_SERVER_STR);
+
+ GetMachineName(tmp, sizeof(tmp));
+ c->MachineName = CopyStr(tmp);
+
+ c->HttpUserAgent = CopyStr(DEFAULT_USER_AGENT);
+ c->HttpAccept = CopyStr(DEFAULT_ACCEPT);
+ c->HttpAcceptLanguage = CopyStr("ja");
+ c->HttpAcceptEncoding = CopyStr(DEFAULT_ENCODING);
+
+ c->Traffic = NewTraffic();
+ c->TrafficLock = NewLock();
+ c->CaList = NewList(CompareCert);
+
+ c->TrafficDiffList = NewList(NULL);
+
+ SetCedarCipherList(c, "RC4-MD5");
+
+ c->ClientId = _II("CLIENT_ID");
+
+ c->UdpPortList = NewIntList(false);
+
+ InitNetSvcList(c);
+
+ InitLocalBridgeList(c);
+
+ InitCedarLayer3(c);
+
+ c->WebUI = WuNewWebUI(c);
+
+#ifdef ALPHA_VERSION
+ beta_str = "Alpha";
+#else // ALPHA_VERSION
+#ifndef RELEASE_CANDIDATE
+ beta_str = "Beta";
+#else // RELEASE_CANDIDATE
+ beta_str = "Release Candidate";
+#endif // RELEASE_CANDIDATE
+#endif // ALPHA_VERSION
+
+ ToStr(tmp2, c->Beta);
+
+ Format(tmp, sizeof(tmp), "Version %u.%02u Build %u %s %s (%s)",
+ CEDAR_VER / 100, CEDAR_VER - (CEDAR_VER / 100) * 100,
+ CEDAR_BUILD,
+ c->Beta == 0 ? "" : beta_str,
+ c->Beta == 0 ? "" : tmp2,
+ _SS("LANGSTR"));
+ Trim(tmp);
+
+ if (true)
+ {
+ SYSTEMTIME st;
+ Zero(&st, sizeof(st));
+
+ st.wYear = BUILD_DATE_Y;
+ st.wMonth = BUILD_DATE_M;
+ st.wDay = BUILD_DATE_D;
+
+ c->BuiltDate = SystemToUINT64(&st);
+ }
+
+ c->VerString = CopyStr(tmp);
+
+ Format(tmp, sizeof(tmp), "Compiled %04u/%02u/%02u %02u:%02u:%02u by %s at %s",
+ BUILD_DATE_Y, BUILD_DATE_M, BUILD_DATE_D, BUILD_DATE_HO, BUILD_DATE_MI, BUILD_DATE_SE, BUILDER_NAME, BUILD_PLACE);
+
+ c->BuildInfo = CopyStr(tmp);
+
+ return c;
+}
+
+// Check whether the Cedar was build after the specified date
+bool IsLaterBuild(CEDAR *c, UINT64 t)
+{
+ SYSTEMTIME sb, st;
+ UINT64 b;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ Zero(&sb, sizeof(sb));
+ Zero(&st, sizeof(st));
+
+ UINT64ToSystem(&sb, c->BuiltDate);
+ UINT64ToSystem(&st, t);
+
+ // Ignore time of the day
+ sb.wHour = sb.wMinute = sb.wSecond = sb.wMilliseconds = 0;
+ st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
+
+ b = SystemToUINT64(&sb);
+ t = SystemToUINT64(&st);
+
+ if (b > t)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// Cumulate traffic size
+void AddTraffic(TRAFFIC *dst, TRAFFIC *diff)
+{
+ // Validate arguments
+ if (dst == NULL || diff == NULL)
+ {
+ return;
+ }
+
+ dst->Recv.BroadcastBytes += diff->Recv.BroadcastBytes;
+ dst->Recv.BroadcastCount += diff->Recv.BroadcastCount;
+ dst->Recv.UnicastBytes += diff->Recv.UnicastBytes;
+ dst->Recv.UnicastCount += diff->Recv.UnicastCount;
+
+ dst->Send.BroadcastBytes += diff->Send.BroadcastBytes;
+ dst->Send.BroadcastCount += diff->Send.BroadcastCount;
+ dst->Send.UnicastBytes += diff->Send.UnicastBytes;
+ dst->Send.UnicastCount += diff->Send.UnicastCount;
+}
+
+// Create new traffic size object
+TRAFFIC *NewTraffic()
+{
+ TRAFFIC *t;
+
+ t = ZeroMalloc(sizeof(TRAFFIC));
+ return t;
+}
+
+// Free traffic size object
+void FreeTraffic(TRAFFIC *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t);
+}
+
+// Initialize Cedar communication module
+void InitCedar()
+{
+ if ((init_cedar_counter++) > 0)
+ {
+ return;
+ }
+
+ // Initialize protocol module
+ InitProtocol();
+}
+
+// Free Cedar communication module
+void FreeCedar()
+{
+ if ((--init_cedar_counter) > 0)
+ {
+ return;
+ }
+
+ // Free protocol module
+ FreeProtocol();
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Cedar.h b/src/Cedar/Cedar.h
new file mode 100644
index 00000000..bdb725bf
--- /dev/null
+++ b/src/Cedar/Cedar.h
@@ -0,0 +1,1194 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Cedar.h
+// Header of Cedar.c
+
+#ifndef CEDAR_H
+#define CEDAR_H
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Products related constants
+//
+//////////////////////////////////////////////////////////////////////
+
+// Replace the function name
+#ifdef VPN_SPEED
+
+#define DecryptSecurePacket __dsp
+#define CreateSecurePacket __csp
+#define GetSecureRandomSize __gsrs
+
+#endif // VPN_SPEED
+
+#define bool UINT
+#define BOOL UINT
+
+
+// Version number
+#define CEDAR_VER 403
+
+// Build Number
+#define CEDAR_BUILD 9408
+
+// Beta number
+//#define BETA_NUMBER 3
+
+// RC or not
+#define RELEASE_CANDIDATE
+
+// Specify the name of the person in charge building
+#ifndef BUILDER_NAME
+#define BUILDER_NAME "yagi"
+#endif // BUILDER_NAME
+
+// Specify the location to build
+#ifndef BUILD_PLACE
+#define BUILD_PLACE "pc25"
+#endif // BUILD_PLACE
+
+// Specifies the build date
+#define BUILD_DATE_Y 2014
+#define BUILD_DATE_M 1
+#define BUILD_DATE_D 4
+#define BUILD_DATE_HO 19
+#define BUILD_DATE_MI 10
+#define BUILD_DATE_SE 55
+
+// Tolerable time difference
+#define ALLOW_TIMESTAMP_DIFF (UINT64)(3 * 24 * 60 * 60 * 1000)
+
+
+// Configuration of communication related control switch
+#define USE_DOS_ATTACK_DETECTION // Enable the DOS attack detection
+//#define USE_SECURE_PACKET // Enable the scrambled packet
+
+// Designate the IDS detection signatures
+#define CEDAR_SIGNATURE_STR "SE-VPN4-PROTOCOL"
+
+// Default RSA certificate name of the smart card
+#define SECURE_DEFAULT_CERT_NAME "VPN_RSA_CERT"
+
+// Default RSA private key name of the smart card
+#define SECURE_DEFAULT_KEY_NAME "VPN_RSA_KEY"
+
+// Hidden password string of 8 characters
+#define HIDDEN_PASSWORD "********"
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Definition of the maximum length of various string
+//
+//////////////////////////////////////////////////////////////////////
+
+#define MAX_ACCOUNT_NAME_LEN 255 // Maximum account name length
+#define MAX_USERNAME_LEN 255 // User name maximum length
+#define MAX_PASSWORD_LEN 255 // Password name maximum length
+#define MAX_PROXY_USERNAME_LEN 255 // Proxy user name maximum length
+#define MAX_PROXY_PASSWORD_LEN 255 // Proxy Password maximum length
+#define MAX_SERVER_STR_LEN 255 // Maximum length of server string
+#define MAX_CLIENT_STR_LEN 255 // Maximum length of client string
+#define MAX_HUBNAME_LEN 255 // Maximum length of HUB name
+#define MAX_SESSION_NAME_LEN 255 // Session name maximum length
+#define MAX_CONNECTION_NAME_LEN 255 // Maximum length of connection name
+#define MAX_DEVICE_NAME_LEN 31 // Device name maximum length
+#define MAX_DEVICE_NAME_LEN_9X 4 // Maximum length of Virtual LAN card name in Win9x
+#define MAX_ACCESSLIST_NOTE_LEN 255 // Maximum length of the note of access list entry
+#define MAX_SECURE_DEVICE_FILE_LEN 255 // Secure device file name maximum length
+#define MAX_ADMIN_OPTION_NAME_LEN 63 // Management option name
+#define MAX_REDIRECT_URL_LEN 255 // URL length to redirect
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Server and session management related constants
+//
+//////////////////////////////////////////////////////////////////////
+
+#define SERVER_MAX_SESSIONS 4096 // Maximum number of sessions that the server supports
+#define SERVER_MAX_SESSIONS_FOR_CARRIER_EDITION 100000 // Maximum number of sessions that the server supports (Carrier Edition)
+#define NAT_MAX_SESSIONS 4096 // Maximum number of sessions that are supported by NAT
+#define NAT_MAX_SESSIONS_KERNEL 65536 // Maximum number of sessions that are supported by NAT (In the case of kernel-mode NAT)
+#define MAX_HUBS 4096 // The maximum number of virtual HUB
+#define MAX_HUBS_FOR_CARRIER_EDITION 100000 // The maximum number of virtual HUB (Carrier Edition)
+#define MAX_ACCESSLISTS (4096 * 8) // Maximum number of access list entries
+#define MAX_USERS 10000 // The maximum number of users
+#define MAX_GROUPS 10000 // Maximum number of groups
+#define MAX_MAC_TABLES 65536 // Maximum number of MAC address table entries
+#define MAX_IP_TABLES 65536 // Maximum number of IP address table entries
+#define MAX_HUB_CERTS 4096 // Maximum number of Root CA that can be registered
+#define MAX_HUB_CRLS 4096 // Maximum number of CRL that can be registered
+#define MAX_HUB_ACS 4096 // Maximum number of AC that can be registered
+#define MAX_HUB_LINKS 128 // Maximum number of Cascade that can be registered
+#define MAX_HUB_ADMIN_OPTIONS 4096 // Maximum number of Virtual HUB management options that can be registered
+
+#define MAX_PACKET_SIZE 1560 // Maximum packet size
+#define UDP_BUF_SIZE (32 * 1024) // Aim of the UDP packet size
+
+#define MAX_SEND_SOCKET_QUEUE_SIZE (1600 * 1600 * 1) // Maximum transmit queue size
+#define MIN_SEND_SOCKET_QUEUE_SIZE (1600 * 200 * 1)
+#define MAX_SEND_SOCKET_QUEUE_NUM 128 // Maximum transmission queue items
+#define MAX_TCP_CONNECTION 32 // The maximum number of TCP connections
+#define NUM_TCP_CONNECTION_FOR_UDP_RECOVERY 2 // Maximum number of connections when using UDP recovery
+#define SELECT_TIME 256
+#define SELECT_TIME_FOR_NAT 30
+#define SELECT_TIME_FOR_DELAYED_PKT 1 // If there is a delayed packet
+#define MAX_STORED_QUEUE_NUM 1024 // The number of queues that can be stored in each session
+#define MAX_BUFFERING_PACKET_SIZE (1600 * 1600) // Maximum packet size can be buffered
+
+#define TIMEOUT_MIN (5 * 1000) // Minimum timeout in seconds
+#define TIMEOUT_MAX (60 * 1000) // Maximum timeout in seconds
+#define TIMEOUT_DEFAULT (30 * 1000) // Default number of seconds to timeout
+#define CONNECTING_TIMEOUT (15 * 1000) // Timeout in seconds of being connected
+#define CONNECTING_TIMEOUT_PROXY (4 * 1000) // Timeout in seconds of being connected (Proxy)
+#define CONNECTING_POOLING_SPAN (3 * 1000) // Polling interval of connected
+#define MIN_RETRY_INTERVAL (5 * 1000) // Minimum retry interval
+#define MAX_RETRY_INTERVAL (300 * 1000) // Maximum retry interval
+#define RETRY_INTERVAL_SPECIAL (60 * 1000) // Reconnection interval of a special case
+
+#define MAX_ADDITONAL_CONNECTION_FAILED_COUNTER 16 // Allowable number that can be serially failed to additional connection
+#define ADDITIONAL_CONNECTION_COUNTER_RESET_INTERVAL (30 * 60 * 1000) // Reset period of additional connection failure counter
+
+#define MAC_MIN_LIMIT_COUNT 3 // Minimum number of MAC addresses
+#define IP_MIN_LIMIT_COUNT 4 // Number of IPv4 addresses minimum
+#define IP_MIN_LIMIT_COUNT_V6 5 // Number of IPv6 addresses minimum
+#define IP_LIMIT_WHEN_NO_ROUTING_V6 15 // Maximum number of IPv6 addresses when NoRouting policy is enabled
+
+#define MAC_TABLE_EXCLUSIVE_TIME (13 * 1000) // Period that can occupy the MAC address
+#define IP_TABLE_EXCLUSIVE_TIME (13 * 1000) // Period that can occupy the IP address
+#define MAC_TABLE_EXPIRE_TIME (600 * 1000) // MAC address table expiration date
+#define IP_TABLE_EXPIRE_TIME (60 * 1000) // IP address table expiration date
+#define IP_TABLE_EXPIRE_TIME_DHCP (5 * 60 * 1000) // IP address table expiration date (In the case of DHCP)
+#define HUB_ARP_SEND_INTERVAL (5 * 1000) // ARP packet transmission interval (alive check)
+
+#define LIMITER_SAMPLING_SPAN 1000 // Sampling interval of the traffic limiting device
+
+#define STORM_CHECK_SPAN 500 // Broadcast storm check interval
+#define STORM_DISCARD_VALUE_START 3 // Broadcast packet discard value start value
+#define STORM_DISCARD_VALUE_END 1024 // Broadcast packet discard value end value
+
+#define KEEP_INTERVAL_MIN 5 // Packet transmission interval minimum value
+#define KEEP_INTERVAL_DEFAULT 50 // Packet transmission interval default value
+#define KEEP_INTERVAL_MAX 600 // Packet transmission interval maximum value
+#define KEEP_TCP_TIMEOUT 1000 // TCP time-out value
+
+#define TICKET_EXPIRES (60 * 1000) // Expiration date of ticket
+
+#define SEND_KILL_NUM_X 256 // Number of 'X' characters to send the Kill
+
+
+#define FARM_BASE_POINT 100000 // Reference value of the cluster score
+#define FARM_DEFAULT_WEIGHT 100 // Standard performance ratio
+
+
+
+#define SE_UDP_SIGN "SE2P" // Not used (only old UDP mode)
+
+// R-UDP service name
+#define VPN_RUDP_SVC_NAME "SoftEther_VPN"
+
+// Traffic information update interval
+#define INCREMENT_TRAFFIC_INTERVAL (10 * 1000)
+
+// State of the client session
+#define CLIENT_STATUS_CONNECTING 0 // Connecting
+#define CLIENT_STATUS_NEGOTIATION 1 // Negotiating
+#define CLIENT_STATUS_AUTH 2 // During user authentication
+#define CLIENT_STATUS_ESTABLISHED 3 // Connection complete
+#define CLIENT_STATUS_RETRY 4 // Wait to retry
+#define CLIENT_STATUS_IDLE 5 // Idle state
+
+// Expiration date of the black list
+#define BLACK_LIST_EXPIRES (30 * 10000)
+
+// Number Blacklist entries
+#define MAX_BLACK_LIST 4096
+#define BLACK_LIST_CHECK_SPAN 1000
+
+// Blocks to be transmitted at one during the file transfer
+#define FTP_BLOCK_SIZE (640 * 1024)
+
+// Syslog configuration
+#define SYSLOG_NONE 0 // Do not use syslog
+#define SYSLOG_SERVER_LOG 1 // Only server log
+#define SYSLOG_SERVER_AND_HUB_SECURITY_LOG 2 // Server and Virtual HUB security log
+#define SYSLOG_SERVER_AND_HUB_ALL_LOG 3 // Server, Virtual HUB security, and packet log
+
+#define SYSLOG_PORT 514 // Syslog port number
+#define SYSLOG_POLL_IP_INTERVAL (UINT64)(3600 * 1000) // Interval to examine the IP address
+#define SYSLOG_POLL_IP_INTERVAL_NG (UINT64)(60 * 1000) // Interval to examine the IP address (previous failure)
+
+//////////////////////////////////////////////////////////////////////
+//
+// Connection-related constant
+//
+//////////////////////////////////////////////////////////////////////
+
+// Internet connection maintenance function (KeepAlive)
+
+#define KEEP_RETRY_INTERVAL (60 * 1000) // Reconnection interval on connection failure
+#define KEEP_MIN_PACKET_SIZE 1 // Minimum packet size
+#define KEEP_MAX_PACKET_SIZE 128 // Maximum packet size
+#define KEEP_POLLING_INTERVAL 250 // KEEP polling interval
+
+// Constants
+#define RECV_BUF_SIZE 65536 // Buffer size to be received at a time
+
+// Type of proxy
+#define PROXY_DIRECT 0 // Direct TCP connection
+#define PROXY_HTTP 1 // Connection via HTTP proxy server
+#define PROXY_SOCKS 2 // Connection via SOCKS proxy server
+
+// Direction of data flow
+#define TCP_BOTH 0 // Bi-directional
+#define TCP_SERVER_TO_CLIENT 1 // Only server -> client direction
+#define TCP_CLIENT_TO_SERVER 2 // Only client -> server direction
+
+// Type of connection
+#define CONNECTION_TYPE_CLIENT 0 // Client
+#define CONNECTION_TYPE_INIT 1 // During initialization
+#define CONNECTION_TYPE_LOGIN 2 // Login connection
+#define CONNECTION_TYPE_ADDITIONAL 3 // Additional connection
+#define CONNECTION_TYPE_FARM_RPC 4 // RPC for server farm
+#define CONNECTION_TYPE_ADMIN_RPC 5 // RPC for Management
+#define CONNECTION_TYPE_ENUM_HUB 6 // HUB enumeration
+#define CONNECTION_TYPE_PASSWORD 7 // Password change
+#define CONNECTION_TYPE_SSTP 8 // SSTP
+#define CONNECTION_TYPE_OPENVPN 9 // OpenVPN
+
+// Protocol
+#define CONNECTION_TCP 0 // TCP protocol
+#define CONNECTION_UDP 1 // UDP protocol
+#define CONNECTION_HUB_LAYER3 6 // Layer-3 switch session
+#define CONNECTION_HUB_BRIDGE 7 // Bridge session
+#define CONNECTION_HUB_SECURE_NAT 8 // Secure NAT session
+#define CONNECTION_HUB_LINK_SERVER 9 // HUB link session
+
+
+// Status
+#define CONNECTION_STATUS_ACCEPTED 0 // The connection is accepted (client side)
+#define CONNECTION_STATUS_NEGOTIATION 1 // Negotiating
+#define CONNECTION_STATUS_USERAUTH 2 // During user authentication
+#define CONNECTION_STATUS_ESTABLISHED 3 // Connection has been established
+#define CONNECTION_STATUS_CONNECTING 0 // Connecting (client side)
+
+// Magic number of KeepAlive packet
+#define KEEP_ALIVE_MAGIC 0xffffffff
+#define MAX_KEEPALIVE_SIZE 512
+
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Virtual HUB-related constant
+//
+//////////////////////////////////////////////////////////////////////
+
+#define SE_HUB_MAC_ADDR_SIGN 0xAE // Sign virtual HUB MAC address
+
+// Traffic difference value
+#define TRAFFIC_DIFF_USER 0 // User
+#define TRAFFIC_DIFF_HUB 1 // Virtual HUB
+#define MAX_TRAFFIC_DIFF 30000 // Maximum number of items
+
+// Type of HUB
+#define HUB_TYPE_STANDALONE 0 // Stand-alone HUB
+#define HUB_TYPE_FARM_STATIC 1 // Static HUB
+#define HUB_TYPE_FARM_DYNAMIC 2 // Dynamic HUB
+
+// Related to delay, jitter, packet loss in the access list
+#define HUB_ACCESSLIST_DELAY_MAX 10000 // Maximum delay
+#define HUB_ACCESSLIST_JITTER_MAX 100 // Maximum jitter
+#define HUB_ACCESSLIST_LOSS_MAX 100 // Maximum packet loss
+
+// Message related
+#define HUB_MAXMSG_LEN 20000 // The maximum number of characters in a message
+
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Type of user authentication
+//
+//////////////////////////////////////////////////////////////////////
+
+// Constant in the server-side
+#define AUTHTYPE_ANONYMOUS 0 // Anonymous authentication
+#define AUTHTYPE_PASSWORD 1 // Password authentication
+#define AUTHTYPE_USERCERT 2 // User certificate authentication
+#define AUTHTYPE_ROOTCERT 3 // Root certificate which is issued by trusted Certificate Authority
+#define AUTHTYPE_RADIUS 4 // Radius authentication
+#define AUTHTYPE_NT 5 // Windows NT authentication
+#define AUTHTYPE_TICKET 99 // Ticket authentication
+
+// Constant of the client side
+#define CLIENT_AUTHTYPE_ANONYMOUS 0 // Anonymous authentication
+#define CLIENT_AUTHTYPE_PASSWORD 1 // Password authentication
+#define CLIENT_AUTHTYPE_PLAIN_PASSWORD 2 // Plain password authentication
+#define CLIENT_AUTHTYPE_CERT 3 // Certificate authentication
+#define CLIENT_AUTHTYPE_SECURE 4 // Secure device authentication
+
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// TCP listener related constants
+//
+//////////////////////////////////////////////////////////////////////
+
+// Retries in case it fails to Listen
+#define LISTEN_RETRY_TIME (2 * 1000) // If fail to Listen normally
+#define LISTEN_RETRY_TIME_NOIPV6 (60 * 1000) // If IPv6 support is disabled
+
+#define DOS_TABLE_EXPIRES_FIRST 250 // Initial value of the expiration date of DOS attack list
+#define DOS_TABLE_EXPIRES_MAX 1000 // Maximum value of the expiration date of DOS attack list
+#define DOS_TABLE_REFRESH_INTERVAL (10 * 1000) // Interval to update the DOS attack list
+#define DOS_TABLE_MAX_LIMIT_PER_IP 16 // Accessible number per an IP
+#define DOS_TABLE_EXPIRES_TOTAL (3000 * 1000) // Time to force delete the entry
+
+
+// Protocol to be used for the listener
+#define LISTENER_TCP 0 // TCP/IP
+#define LISTENER_UDP 1 // UDP/IP (not being used)
+#define LISTENER_INPROC 2 // In-process communication
+#define LISTENER_RUDP 3 // R-UDP with NAT-T
+#define LISTENER_ICMP 4 // VPN over ICMP
+#define LISTENER_DNS 5 // VPN over DNS
+#define LISTENER_REVERSE 6 // Reverse socket
+
+// Status of the listener
+#define LISTENER_STATUS_TRYING 0 // While attempting
+#define LISTENER_STATUS_LISTENING 1 // Listening
+
+// Largest packet size of UDP
+#define UDP_PACKET_SIZE 65536
+
+// Number of standard connections per IP address
+#define DEFAULT_MAX_CONNECTIONS_PER_IP 256
+#define MIN_MAX_CONNECTIONS_PER_IP 10 // Minimum value
+
+// Allowed number of outstanding connections
+#define DEFAULT_MAX_UNESTABLISHED_CONNECTIONS 1000
+#define MIN_MAX_UNESTABLISHED_CONNECTIONS 30 // Minimum value
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Log related constant
+//
+//////////////////////////////////////////////////////////////////////
+
+#define LOG_ENGINE_SAVE_START_CACHE_COUNT 100000 // Number to start saving forcibly
+#define LOG_ENGINE_BUFFER_CACHE_SIZE_MAX (10 * 1024 * 1024) // Write cache size
+
+// Constant such as a file name
+#define SERVER_LOG_DIR_NAME "@server_log"
+#define BRIDGE_LOG_DIR_NAME SERVER_LOG_DIR_NAME
+#define SERVER_LOG_PERFIX "vpn"
+
+#define HUB_SECURITY_LOG_DIR_NAME "@security_log"
+#define HUB_SECURITY_LOG_FILE_NAME "@security_log/%s"
+#define HUB_SECURITY_LOG_PREFIX "sec"
+#define HUB_PACKET_LOG_DIR_NAME "@packet_log"
+#define HUB_PACKET_LOG_FILE_NAME "@packet_log/%s"
+#define HUB_PACKET_LOG_PREFIX "pkt"
+
+#define NAT_LOG_DIR_NAME "@secure_nat_log"
+#define NAT_LOG_FILE_NAME "@secure_nat_log/%s"
+#define NAT_LOG_PREFIX "snat"
+
+#define CLIENT_LOG_DIR_NAME "@client_log"
+#define CLIENT_LOG_PREFIX "client"
+
+// Packet log settings
+#define NUM_PACKET_LOG 16
+#define PACKET_LOG_TCP_CONN 0 // TCP connection log
+#define PACKET_LOG_TCP 1 // TCP packet log
+#define PACKET_LOG_DHCP 2 // DHCP Log
+#define PACKET_LOG_UDP 3 // UDP log
+#define PACKET_LOG_ICMP 4 // ICMP log
+#define PACKET_LOG_IP 5 // IP log
+#define PACKET_LOG_ARP 6 // ARP log
+#define PACKET_LOG_ETHERNET 7 // Ethernet log
+
+#define PACKET_LOG_NONE 0 // Not save
+#define PACKET_LOG_HEADER 1 // Only header
+#define PACKET_LOG_ALL 2 // Store also data
+
+// Timing of log switching
+#define LOG_SWITCH_NO 0 // Without switching
+#define LOG_SWITCH_SECOND 1 // Secondly basis
+#define LOG_SWITCH_MINUTE 2 // Minutely basis
+#define LOG_SWITCH_HOUR 3 // Hourly basis
+#define LOG_SWITCH_DAY 4 // Daily basis
+#define LOG_SWITCH_MONTH 5 // Monthly basis
+
+// Minimum amount of free disk space
+#define DISK_FREE_SPACE_MIN 1048576 // 1 MBytes
+#define DISK_FREE_SPACE_DEFAULT (DISK_FREE_SPACE_MIN * 100) // 100 Mbytes
+#define DISK_FREE_SPACE_DEFAULT_WINDOWS ((UINT64)(8ULL * 1024ULL * 1024ULL * 1024ULL)) // 8GBytes
+
+// Interval to check the free space
+#define DISK_FREE_CHECK_INTERVAL (5 * 60 * 1000)
+
+// Simple log
+#define TINY_LOG_DIRNAME "@tiny_log"
+#define TINY_LOG_FILENAME "@tiny_log/%04u%02u%02u_%02u%02u%02u.log"
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Constant related to Carrier Edition
+//
+//////////////////////////////////////////////////////////////////////
+
+#define CE_SNAPSHOT_INTERVAL ((UINT64)(3600 * 1000))
+//#define CE_SNAPSHOT_INTERVAL ((UINT64)(3000))
+#define CE_SNAPSHOT_POLLING_INTERVAL (1 * 1000)
+#define CE_SNAPSHOT_POLLING_INTERVAL_LICENSE (30 * 1000)
+#define CE_SNAPSHOT_DIR_NAME "@carrier_log"
+#define CE_SNAPSHOT_PREFIX "carrier"
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Communication protocol related constant
+//
+//////////////////////////////////////////////////////////////////////
+
+// Administrator Username
+#define ADMINISTRATOR_USERNAME "administrator"
+// Maximum value of random size
+#define RAND_SIZE_MAX 4096
+// Expiration date of random size cache
+#define RAND_SIZE_CACHE_EXPIRE (24 * 60 * 60 * 1000)
+// Management allowed IP address list file name
+#define ADMINIP_TXT "@adminip.txt"
+
+#define NON_SSL_MIN_COUNT 60
+#define NON_SSL_ENTRY_EXPIRES (10 * 60 * 1000)
+
+//////////////////////////////////////////////////////////////////////
+//
+// The cascade related constants
+//
+//////////////////////////////////////////////////////////////////////
+
+#define LINK_DEVICE_NAME "_SEHUBLINKCLI_"
+#define LINK_USER_NAME "link"
+#define LINK_USER_NAME_PRINT "Cascade"
+
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Constant related to SecureNAT connection
+//
+//////////////////////////////////////////////////////////////////////
+
+#define SNAT_DEVICE_NAME "_SEHUBSECURENAT_"
+#define SNAT_USER_NAME "securenat"
+#define SNAT_USER_NAME_PRINT "SecureNAT"
+
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Constant related to bridge connection
+//
+//////////////////////////////////////////////////////////////////////
+
+#define BRIDGE_DEVICE_NAME "_SEHUBBRIDGE_"
+#define BRIDGE_USER_NAME "localbridge"
+#define BRIDGE_USER_NAME_PRINT "Local Bridge"
+#define BRIDGE_TRY_SPAN 1000
+#define BRIDGE_NUM_DEVICE_CHECK_SPAN (5 * 60 * 1000)
+#define BRIDGE_NETWORK_CONNECTION_STR L"%s [%S]"
+
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// EtherLogger related constants
+//
+//////////////////////////////////////////////////////////////////////
+
+#define EL_ADMIN_PORT 22888
+#define EL_CONFIG_FILENAME "@etherlogger.config"
+#define EL_PACKET_LOG_DIR_NAME "@etherlogger_log"
+#define EL_PACKET_LOG_FILE_NAME "@etherlogger_log/%s"
+#define EL_PACKET_LOG_PREFIX "pkt"
+#define EL_LICENSE_CHECK_SPAN (10 * 1000)
+
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Layer-3 Switch related constants
+//
+//////////////////////////////////////////////////////////////////////
+
+#define MAX_NUM_L3_SWITCH 4096
+#define MAX_NUM_L3_IF 4096
+#define MAX_NUM_L3_TABLE 4096
+
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Constant related to User-mode Router
+//
+//////////////////////////////////////////////////////////////////////
+
+#define ARP_ENTRY_EXPIRES (30 * 1000) // ARP table expiration date
+#define ARP_ENTRY_POLLING_TIME (1 * 1000) // ARP table cleaning timer
+#define ARP_REQUEST_TIMEOUT (200) // ARP request time-out period
+#define ARP_REQUEST_GIVEUP (5 * 1000) // Time to give up sending the ARP request
+#define IP_WAIT_FOR_ARP_TIMEOUT (5 * 1000) // Total time that an IP packet waiting for ARP table
+#define IP_COMBINE_TIMEOUT (10 * 1000) // Time-out of IP packet combining
+#define NAT_TCP_MAX_TIMEOUT (2000000 * 1000) // Maximum TCP session timeout in seconds
+#define NAT_UDP_MAX_TIMEOUT (2000000 * 1000) // Maximum UDP session timeout in seconds
+#define NAT_TCP_MIN_TIMEOUT (1 * 60 * 1000) // Minimum TCP session timeout in seconds
+#define NAT_UDP_MIN_TIMEOUT (10 * 1000) // Minimum UDP session timeout in seconds
+#define NAT_TCP_RECV_WINDOW_SIZE 64512 // TCP receive window size
+#define NAT_TCP_SYNACK_SEND_TIMEOUT 250 // Sending TCP SYN+ACK interval
+#define NAT_ICMP_TIMEOUT (10 * 1000) // ICMP timeout in seconds
+#define NAT_ICMP_TIMEOUT_WITH_API (3 * 1000) // Timeout in seconds in the case of using the ICMP API
+#define NAT_SEND_BUF_SIZE (64 * 1024) // TCP send buffer size
+#define NAT_RECV_BUF_SIZE (64 * 1024) // TCP receive buffer size
+#define NAT_TMPBUF_SIZE (128 * 1024) // TCP temporally memory area size
+#define NAT_ACK_KEEPALIVE_SPAN (5 * 1000) // ACK transmission interval for TCP keep alive
+#define NAT_INITIAL_RTT_VALUE 500 // Initial RTT value
+#define NAT_FIN_SEND_INTERVAL 1000 // FIN transmission interval
+#define NAT_FIN_SEND_MAX_COUNT 5 // Total number of FIN transmissions
+#define NAT_DNS_PROXY_PORT 53 // DNS proxy port number
+#define NAT_DNS_RESPONSE_TTL (20 * 60) // TTL of the DNS response
+#define NAT_DHCP_SERVER_PORT 67 // DHCP server port number
+#define NAT_DHCP_CLIENT_PORT 68 // DHCP client port number
+#define DHCP_MIN_EXPIRE_TIMESPAN (15 * 1000) // DHCP minimum expiration date
+#define DHCP_POLLING_INTERVAL 1000 // DHCP polling interval
+#define X32 ((UINT64)4294967296ULL) // 32bit + 1
+#define NAT_DNS_QUERY_TIMEOUT (512) // Time-out value of DNS queries
+
+// Beacon transmission interval
+#define BEACON_SEND_INTERVAL (5 * 1000)
+
+// Total size quota allowed in the queue for the combining the IP packet
+#define IP_COMBINE_WAIT_QUEUE_SIZE_QUOTA (50 * 1024 * 1024)
+
+// Header size constant
+#define MAC_HEADER_SIZE (sizeof(MAC_HEADER))
+#define ARP_HEADER_SIZE (sizeof(ARP_HEADER))
+#define IP_HEADER_SIZE (sizeof(IPV4_HEADER))
+#define TCP_HEADER_SIZE (sizeof(TCP_HEADER))
+#define UDP_HEADER_SIZE (sizeof(UDP_HEADER))
+
+// Data maximum size constant
+#define MAX_L3_DATA_SIZE (1500)
+#define MAX_IP_DATA_SIZE (MAX_L3_DATA_SIZE - IP_HEADER_SIZE)
+#define MAX_TCP_DATA_SIZE (MAX_IP_DATA_SIZE - TCP_HEADER_SIZE)
+#define MAX_UDP_DATA_SIZE (MAX_IP_DATA_SIZE - UDP_HEADER_SIZE)
+#define MAX_IP_DATA_SIZE_TOTAL (65535)
+
+// IP packet option constant
+#define DEFAULT_IP_TOS 0 // TOS in the IP header
+#define DEFAULT_IP_TTL 128 // TTL in the IP header
+
+// Type of NAT session
+#define NAT_TCP 0 // TCP NAT
+#define NAT_UDP 1 // UDP NAT
+#define NAT_DNS 2 // DNS NAT
+#define NAT_ICMP 3 // ICMP NAT
+
+// State of NAT session
+#define NAT_TCP_CONNECTING 0 // Connecting
+#define NAT_TCP_SEND_RESET 1 // Send the RST (Connection failure or disconnected)
+#define NAT_TCP_CONNECTED 2 // Connection complete
+#define NAT_TCP_ESTABLISHED 3 // Connection established
+#define NAT_TCP_WAIT_DISCONNECT 4 // Wait for socket disconnection
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// For UNIX virtual LAN card related constant
+//
+//////////////////////////////////////////////////////////////////////
+
+#define TAP_FILENAME_1 "/dev/net/tun"
+#define TAP_FILENAME_2 "/dev/tun"
+#define TAP_MACOS_FILENAME "/dev/tap0"
+
+
+
+
+
+#define LICENSE_EDITION_VPN3_NO_LICENSE 0 // Without license
+
+#define LICENSE_MAX_PRODUCT_NAME_LEN 255 // Maximum length of license product name
+#define LICENSE_NUM_SHA 10000 // Number of times to hash with SHA
+#define LICENSE_SYSTEM_KEY_NUM 2048 // Key number for system
+#define LICENSE_SYSTEM_KEYSIZE_BIT 144 // Number of key bits for system
+#define LICENSE_PRODUCT_KEY_NUM 16384 // Number of keys for product
+#define LICENSE_PRODUCT_KEYSIZE_BIT 56 // Number of key bits for product
+#define LICENSE_PRODUCT_COMMON_KEYSIZE_BIT 48 // Number of common key bits for product
+#define LICENSE_MASTER_KEYSIZE_BIT 1024 // Number of master key bits
+#define LICENSE_SYSTEM_ID_MIN 0ULL // System ID minimum value
+#define LICENSE_SYSTEM_ID_MAX 549755813887ULL // System ID maximum value
+#define LICENSE_SERIAL_ID_MIN 0 // Serial ID minimum value
+#define LICENSE_SERIAL_ID_MAX 65535 // Serial ID maximum value
+#define LICENSE_EXPIRES_MIN 0 // Expiration date minimum
+#define LICENSE_EXPIRES_MAX 16383 // Expiration date maximum
+#define LICENSE_KEYSTR_LEN 41 // Length of the license key
+#define LICENSE_LICENSEID_STR_LEN 33 // Length of the license ID
+
+#define LICENSE_STATUS_OK 0 // Enabled
+#define LICENSE_STATUS_EXPIRED 1 // Invalid (expired)
+#define LICENSE_STATUS_ID_DIFF 2 // Invalid (System ID mismatch)
+#define LICENSE_STATUS_DUP 3 // Invalid (duplicated)
+#define LICENSE_STATUS_INSUFFICIENT 4 // Invalid (other necessary license shortage)
+#define LICENSE_STATUS_COMPETITION 5 // Invalid (conflict with other licenses)
+#define LICENSE_STATUS_NONSENSE 6 // Invalid (meaningless in the current edition)
+#define LICENSE_STATUS_CPU 7 // Invalid (CPU type mismatch)
+
+#define BIT_TO_BYTE(x) (((x) + 7) / 8)
+#define BYTE_TO_BIT(x) ((x) * 8)
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Error code
+//
+//////////////////////////////////////////////////////////////////////
+
+#define ERR_NO_ERROR 0 // No error
+#define ERR_CONNECT_FAILED 1 // Connection to the server has failed
+#define ERR_SERVER_IS_NOT_VPN 2 // The destination server is not a VPN server
+#define ERR_DISCONNECTED 3 // The connection has been interrupted
+#define ERR_PROTOCOL_ERROR 4 // Protocol error
+#define ERR_CLIENT_IS_NOT_VPN 5 // Connecting client is not a VPN client
+#define ERR_USER_CANCEL 6 // User cancel
+#define ERR_AUTHTYPE_NOT_SUPPORTED 7 // Specified authentication method is not supported
+#define ERR_HUB_NOT_FOUND 8 // The HUB does not exist
+#define ERR_AUTH_FAILED 9 // Authentication failure
+#define ERR_HUB_STOPPING 10 // HUB is stopped
+#define ERR_SESSION_REMOVED 11 // Session has been deleted
+#define ERR_ACCESS_DENIED 12 // Access denied
+#define ERR_SESSION_TIMEOUT 13 // Session times out
+#define ERR_INVALID_PROTOCOL 14 // Protocol is invalid
+#define ERR_TOO_MANY_CONNECTION 15 // Too many connections
+#define ERR_HUB_IS_BUSY 16 // Too many sessions of the HUB
+#define ERR_PROXY_CONNECT_FAILED 17 // Connection to the proxy server fails
+#define ERR_PROXY_ERROR 18 // Proxy Error
+#define ERR_PROXY_AUTH_FAILED 19 // Failed to authenticate on the proxy server
+#define ERR_TOO_MANY_USER_SESSION 20 // Too many sessions of the same user
+#define ERR_LICENSE_ERROR 21 // License error
+#define ERR_DEVICE_DRIVER_ERROR 22 // Device driver error
+#define ERR_INTERNAL_ERROR 23 // Internal error
+#define ERR_SECURE_DEVICE_OPEN_FAILED 24 // The secure device cannot be opened
+#define ERR_SECURE_PIN_LOGIN_FAILED 25 // PIN code is incorrect
+#define ERR_SECURE_NO_CERT 26 // Specified certificate is not stored
+#define ERR_SECURE_NO_PRIVATE_KEY 27 // Specified private key is not stored
+#define ERR_SECURE_CANT_WRITE 28 // Write failure
+#define ERR_OBJECT_NOT_FOUND 29 // Specified object can not be found
+#define ERR_VLAN_ALREADY_EXISTS 30 // Virtual LAN card with the specified name already exists
+#define ERR_VLAN_INSTALL_ERROR 31 // Specified virtual LAN card cannot be created
+#define ERR_VLAN_INVALID_NAME 32 // Specified name of the virtual LAN card is invalid
+#define ERR_NOT_SUPPORTED 33 // Unsupported
+#define ERR_ACCOUNT_ALREADY_EXISTS 34 // Account already exists
+#define ERR_ACCOUNT_ACTIVE 35 // Account is operating
+#define ERR_ACCOUNT_NOT_FOUND 36 // Specified account doesn't exist
+#define ERR_ACCOUNT_INACTIVE 37 // Account is offline
+#define ERR_INVALID_PARAMETER 38 // Parameter is invalid
+#define ERR_SECURE_DEVICE_ERROR 39 // Error has occurred in the operation of the secure device
+#define ERR_NO_SECURE_DEVICE_SPECIFIED 40 // Secure device is not specified
+#define ERR_VLAN_IS_USED 41 // Virtual LAN card in use by account
+#define ERR_VLAN_FOR_ACCOUNT_NOT_FOUND 42 // Virtual LAN card of the account can not be found
+#define ERR_VLAN_FOR_ACCOUNT_USED 43 // Virtual LAN card of the account is already in use
+#define ERR_VLAN_FOR_ACCOUNT_DISABLED 44 // Virtual LAN card of the account is disabled
+#define ERR_INVALID_VALUE 45 // Value is invalid
+#define ERR_NOT_FARM_CONTROLLER 46 // Not a farm controller
+#define ERR_TRYING_TO_CONNECT 47 // Attempting to connect
+#define ERR_CONNECT_TO_FARM_CONTROLLER 48 // Failed to connect to the farm controller
+#define ERR_COULD_NOT_HOST_HUB_ON_FARM 49 // A virtual HUB on farm could not be created
+#define ERR_FARM_MEMBER_HUB_ADMIN 50 // HUB cannot be managed on a farm member
+#define ERR_NULL_PASSWORD_LOCAL_ONLY 51 // Accepting only local connections for an empty password
+#define ERR_NOT_ENOUGH_RIGHT 52 // Right is insufficient
+#define ERR_LISTENER_NOT_FOUND 53 // Listener can not be found
+#define ERR_LISTENER_ALREADY_EXISTS 54 // Listener already exists
+#define ERR_NOT_FARM_MEMBER 55 // Not a farm member
+#define ERR_CIPHER_NOT_SUPPORTED 56 // Encryption algorithm is not supported
+#define ERR_HUB_ALREADY_EXISTS 57 // HUB already exists
+#define ERR_TOO_MANY_HUBS 58 // Too many HUBs
+#define ERR_LINK_ALREADY_EXISTS 59 // Link already exists
+#define ERR_LINK_CANT_CREATE_ON_FARM 60 // The link can not be created on the server farm
+#define ERR_LINK_IS_OFFLINE 61 // Link is off-line
+#define ERR_TOO_MANY_ACCESS_LIST 62 // Too many access list
+#define ERR_TOO_MANY_USER 63 // Too many users
+#define ERR_TOO_MANY_GROUP 64 // Too many Groups
+#define ERR_GROUP_NOT_FOUND 65 // Group can not be found
+#define ERR_USER_ALREADY_EXISTS 66 // User already exists
+#define ERR_GROUP_ALREADY_EXISTS 67 // Group already exists
+#define ERR_USER_AUTHTYPE_NOT_PASSWORD 68 // Authentication method of the user is not a password authentication
+#define ERR_OLD_PASSWORD_WRONG 69 // The user does not exist or the old password is wrong
+#define ERR_LINK_CANT_DISCONNECT 73 // Cascade session cannot be disconnected
+#define ERR_ACCOUNT_NOT_PRESENT 74 // Not completed configure the connection to the VPN server
+#define ERR_ALREADY_ONLINE 75 // It is already online
+#define ERR_OFFLINE 76 // It is offline
+#define ERR_NOT_RSA_1024 77 // The certificate is not RSA 1024bit
+#define ERR_SNAT_CANT_DISCONNECT 78 // SecureNAT session cannot be disconnected
+#define ERR_SNAT_NEED_STANDALONE 79 // SecureNAT works only in stand-alone HUB
+#define ERR_SNAT_NOT_RUNNING 80 // SecureNAT function is not working
+#define ERR_SE_VPN_BLOCK 81 // Stopped by PacketiX VPN Block
+#define ERR_BRIDGE_CANT_DISCONNECT 82 // Bridge session can not be disconnected
+#define ERR_LOCAL_BRIDGE_STOPPING 83 // Bridge function is stopped
+#define ERR_LOCAL_BRIDGE_UNSUPPORTED 84 // Bridge feature is not supported
+#define ERR_CERT_NOT_TRUSTED 85 // Certificate of the destination server can not be trusted
+#define ERR_PRODUCT_CODE_INVALID 86 // Product code is different
+#define ERR_VERSION_INVALID 87 // Version is different
+#define ERR_CAPTURE_DEVICE_ADD_ERROR 88 // Adding capture device failure
+#define ERR_VPN_CODE_INVALID 89 // VPN code is different
+#define ERR_CAPTURE_NOT_FOUND 90 // Capture device can not be found
+#define ERR_LAYER3_CANT_DISCONNECT 91 // Layer-3 session cannot be disconnected
+#define ERR_LAYER3_SW_EXISTS 92 // L3 switch of the same already exists
+#define ERR_LAYER3_SW_NOT_FOUND 93 // Layer-3 switch can not be found
+#define ERR_INVALID_NAME 94 // Name is invalid
+#define ERR_LAYER3_IF_ADD_FAILED 95 // Failed to add interface
+#define ERR_LAYER3_IF_DEL_FAILED 96 // Failed to delete the interface
+#define ERR_LAYER3_IF_EXISTS 97 // Interface that you specified already exists
+#define ERR_LAYER3_TABLE_ADD_FAILED 98 // Failed to add routing table
+#define ERR_LAYER3_TABLE_DEL_FAILED 99 // Failed to delete the routing table
+#define ERR_LAYER3_TABLE_EXISTS 100 // Routing table entry that you specified already exists
+#define ERR_BAD_CLOCK 101 // Time is queer
+#define ERR_LAYER3_CANT_START_SWITCH 102 // The Virtual Layer 3 Switch can not be started
+#define ERR_CLIENT_LICENSE_NOT_ENOUGH 103 // Client connection licenses shortage
+#define ERR_BRIDGE_LICENSE_NOT_ENOUGH 104 // Bridge connection licenses shortage
+#define ERR_SERVER_CANT_ACCEPT 105 // Not Accept on the technical issues
+#define ERR_SERVER_CERT_EXPIRES 106 // Destination VPN server has expired
+#define ERR_MONITOR_MODE_DENIED 107 // Monitor port mode was rejected
+#define ERR_BRIDGE_MODE_DENIED 108 // Bridge-mode or Routing-mode was rejected
+#define ERR_IP_ADDRESS_DENIED 109 // Client IP address is denied
+#define ERR_TOO_MANT_ITEMS 110 // Too many items
+#define ERR_MEMORY_NOT_ENOUGH 111 // Out of memory
+#define ERR_OBJECT_EXISTS 112 // Object already exists
+#define ERR_FATAL 113 // A fatal error occurred
+#define ERR_SERVER_LICENSE_FAILED 114 // License violation has occurred on the server side
+#define ERR_SERVER_INTERNET_FAILED 115 // Server side is not connected to the Internet
+#define ERR_CLIENT_LICENSE_FAILED 116 // License violation occurs on the client side
+#define ERR_BAD_COMMAND_OR_PARAM 117 // Command or parameter is invalid
+#define ERR_INVALID_LICENSE_KEY 118 // License key is invalid
+#define ERR_NO_VPN_SERVER_LICENSE 119 // There is no valid license for the VPN Server
+#define ERR_NO_VPN_CLUSTER_LICENSE 120 // There is no cluster license
+#define ERR_NOT_ADMINPACK_SERVER 121 // Not trying to connect to a server with the Administrator Pack license
+#define ERR_NOT_ADMINPACK_SERVER_NET 122 // Not trying to connect to a server with the Administrator Pack license (for .NET)
+#define ERR_BETA_EXPIRES 123 // Destination Beta VPN Server has expired
+#define ERR_BRANDED_C_TO_S 124 // Branding string of connection limit is different (Authentication on the server side)
+#define ERR_BRANDED_C_FROM_S 125 // Branding string of connection limit is different (Authentication for client-side)
+#define ERR_AUTO_DISCONNECTED 126 // VPN session is disconnected for a certain period of time has elapsed
+#define ERR_CLIENT_ID_REQUIRED 127 // Client ID does not match
+#define ERR_TOO_MANY_USERS_CREATED 128 // Too many created users
+#define ERR_SUBSCRIPTION_IS_OLDER 129 // Subscription expiration date Is earlier than the build date of the VPN Server
+#define ERR_ILLEGAL_TRIAL_VERSION 130 // Many trial license is used continuously
+#define ERR_NAT_T_TWO_OR_MORE 131 // There are multiple servers in the back of a global IP address in the NAT-T connection
+#define ERR_DUPLICATE_DDNS_KEY 132 // DDNS host key duplicate
+#define ERR_DDNS_HOSTNAME_EXISTS 133 // Specified DDNS host name already exists
+#define ERR_DDNS_HOSTNAME_INVALID_CHAR 134 // Characters that can not be used for the host name is included
+#define ERR_DDNS_HOSTNAME_TOO_LONG 135 // Host name is too long
+#define ERR_DDNS_HOSTNAME_IS_EMPTY 136 // Host name is not specified
+#define ERR_DDNS_HOSTNAME_TOO_SHORT 137 // Host name is too short
+#define ERR_MSCHAP2_PASSWORD_NEED_RESET 138 // Necessary that password is changed
+#define ERR_DDNS_DISCONNECTED 139 // Communication to the dynamic DNS server is disconnected
+#define ERR_SPECIAL_LISTENER_ICMP_ERROR 140 // The ICMP socket can not be opened
+#define ERR_SPECIAL_LISTENER_DNS_ERROR 141 // Socket for DNS port can not be opened
+#define ERR_OPENVPN_IS_NOT_ENABLED 142 // OpenVPN server feature is not enabled
+#define ERR_NOT_SUPPORTED_AUTH_ON_OPENSOURCE 143 // It is the type of user authentication that are not supported in the open source version
+#define ERR_VPNGATE 144 // Operation on VPN Gate Server is not available
+#define ERR_VPNGATE_CLIENT 145 // Operation on VPN Gate Client is not available
+#define ERR_VPNGATE_INCLIENT_CANT_STOP 146 // Can not be stopped if operating within VPN Client mode
+#define ERR_NOT_SUPPORTED_FUNCTION_ON_OPENSOURCE 147 // It is a feature that is not supported in the open source version
+
+
+////////////////////////////
+// Generally used structure
+
+// Network Services
+typedef struct NETSVC
+{
+ bool Udp; // false=TCP, true=UDP
+ UINT Port; // Port number
+ char *Name; // Name
+} NETSVC;
+
+// Traffic data entry
+typedef struct TRAFFIC_ENTRY
+{
+ UINT64 BroadcastCount; // Number of broadcast packets
+ UINT64 BroadcastBytes; // Broadcast bytes
+ UINT64 UnicastCount; // Unicast count
+ UINT64 UnicastBytes; // Unicast bytes
+} TRAFFIC_ENTRY;
+
+// Traffic data
+typedef struct TRAFFIC
+{
+ TRAFFIC_ENTRY Send; // Transmitted data
+ TRAFFIC_ENTRY Recv; // Received data
+} TRAFFIC;
+
+// Non-SSL connection source
+typedef struct NON_SSL
+{
+ IP IpAddress; // IP address
+ UINT64 EntryExpires; // Expiration date of entry
+ UINT Count; // Number of connection count
+} NON_SSL;
+
+// Simple log storage
+typedef struct TINY_LOG
+{
+ char FileName[MAX_PATH]; // File name
+ IO *io; // File
+ LOCK *Lock; // Lock
+} TINY_LOG;
+
+// CEDAR structure
+typedef struct CEDAR
+{
+ LOCK *lock; // Lock
+ REF *ref; // Reference counter
+ COUNTER *AcceptingSockets; // Number of sockets in Accept
+ UINT Type; // Type
+ LIST *ListenerList; // Listener list
+ LIST *HubList; // HUB list
+ LIST *ConnectionList; // Negotiating connection list
+ LIST *CaList; // List of CA
+ volatile bool Halt; // Halt flag
+ COUNTER *ConnectionIncrement; // Connection increment counter
+ X *ServerX; // Server certificate
+ K *ServerK; // Private key of the server certificate
+ char *CipherList; // List of encryption algorithms
+ UINT Version; // Version information
+ UINT Build; // Build Number
+ char *ServerStr; // Server string
+ char *MachineName; // Computer name
+ char *HttpUserAgent; // HTTP user agent
+ char *HttpAccept; // HTTP Accept
+ char *HttpAcceptLanguage; // HTTP Accept Language
+ char *HttpAcceptEncoding; // HTTP Accept Encoding
+ TRAFFIC *Traffic; // Traffic information
+ LOCK *TrafficLock; // Traffic information lock
+ LIST *UDPEntryList; // UDP entry list
+ COUNTER *CurrentSessions; // The current number of sessions
+ COUNTER *CurrentTcpConnections; // Number of current TCP connections
+ LIST *NetSvcList; // Network service list
+ char *VerString; // Version string
+ char *BuildInfo; // Build Information
+ struct CLIENT *Client; // Client
+ struct SERVER *Server; // Server
+ UINT64 CreatedTick; // Generation date and time
+ bool CheckExpires; // Check the expiration date
+ LIST *TrafficDiffList; // Traffic difference list
+ struct LOG *DebugLog; // Debug log
+ UCHAR UniqueId[16]; // Unique ID
+ LIST *LocalBridgeList; // Local bridge list
+ bool Bridge; // Bridge version
+ LIST *L3SwList; // Layer-3 switch list
+ COUNTER *AssignedClientLicense; // Number of assigned client licenses
+ COUNTER *AssignedBridgeLicense; // Number of assigned bridge licenses
+ UINT64 LicenseViolationTick; // License violation occurs
+ LIST *NonSslList; // Non-SSL connection list
+ struct WEBUI *WebUI; // Data for WebUI service
+ UINT Beta; // Beta number
+ LOCK *CedarSuperLock; // Cedar super lock!
+ bool DisableIPv6Listener; // Disable IPv6 listener
+ UINT ClientId; // Client ID
+ UINT64 BuiltDate; // Build Date
+ LIST *UdpPortList; // UDP port list in use
+ char CurrentDDnsFqdn[MAX_SIZE]; // FQDN of the current DDNS
+ char OpenVPNPublicPorts[MAX_SIZE]; // OpenVPN public UDP port list
+ LOCK *OpenVPNPublicPortsLock; // Lock of OpenVPN public UDP port list
+} CEDAR;
+
+// Type of CEDAR
+#define CEDAR_CLIENT 0 // Client
+#define CEDAR_STANDALONE_SERVER 1 // Stand-alone server
+#define CEDAR_FARM_CONTROLLER 2 // Server farm controller
+#define CEDAR_FARM_MEMBER 3 // Server farm member
+
+
+////////////////////////////
+// Read the header file
+
+// Type
+#include
+// Account Manager
+#include
+// Listener module
+#include
+// Log storage module
+#include
+// Connection management
+#include
+// Session Management
+#include
+// RPC
+#include
+// HUB management
+#include
+// Security Accounts Manager
+#include
+// Radius authentication module
+#include
+// Protocol
+#include
+// Inter-HUB link
+#include
+// User-mode virtual host
+#include
+// SecureNAT
+#include
+// Digital watermark
+#include
+// Secure data
+#include
+// Console service
+#include
+// Vpncmd utility
+#include
+// RPC over HTTP
+#include
+// IPsec
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+// SSTP
+#include
+// OpenVPN
+#include
+// UDP Acceleration
+#include
+// DDNS Client
+#include
+// VPN Azure Client
+#include
+// VPN Azure Server
+#include
+// Native IP Stack
+#include
+
+#ifdef OS_WIN32
+// Neo device driver
+#include
+// SeLow User-mode
+#include
+#endif // OS_WIN32
+
+// Neo device driver manipulation library
+#include
+// Bridge
+#include
+// Layer-3 switch
+#include
+// Virtual LAN card for test
+#include
+// Client
+#include
+// Server
+#include
+// License database
+#include
+// EtherLogger
+#include
+// Management RPC
+#include
+// User-mode Router
+#include
+
+// Web UI
+#include
+
+// VPN Gate Plugin DLL
+#include
+
+// VPN Gate Main Implementation
+#include
+
+
+#ifdef OS_WIN32
+
+// Win32 user interface
+#include
+// Win32 Client Connection Manager
+#include
+// Win32 Server Manager
+#include
+// Win32 User-mode Router Manager
+#include
+// Win32 EtherLogger Manager
+#include
+// Win32 Network Utility
+#include
+// Win32 Setup Wizard
+#include
+// Win32 COM calling module
+#include
+
+#endif
+
+
+
+
+////////////////////////////
+// Function prototype
+
+TRAFFIC *NewTraffic();
+void FreeTraffic(TRAFFIC *t);
+CEDAR *NewCedar(X *server_x, K *server_k);
+void CedarForceLink();
+void SetCedarVpnBridge(CEDAR *c);
+void SetCedarCert(CEDAR *c, X *server_x, K *server_k);
+void ReleaseCedar(CEDAR *c);
+void CleanupCedar(CEDAR *c);
+void StopCedar(CEDAR *c);
+void AddListener(CEDAR *c, LISTENER *r);
+void StopAllListener(CEDAR *c);
+void AddTraffic(TRAFFIC *dst, TRAFFIC *diff);
+void AddHub(CEDAR *c, HUB *h);
+void DelHub(CEDAR *c, HUB *h);
+void DelHubEx(CEDAR *c, HUB *h, bool no_lock);
+void StopAllHub(CEDAR *c);
+void StopAllConnection(CEDAR *c);
+void AddConnection(CEDAR *cedar, CONNECTION *c);
+UINT GetUnestablishedConnections(CEDAR *cedar);
+void DelConnection(CEDAR *cedar, CONNECTION *c);
+void SetCedarCipherList(CEDAR *cedar, char *name);
+void InitCedar();
+void FreeCedar();
+void AddCa(CEDAR *cedar, X *x);
+bool DeleteCa(CEDAR *cedar, UINT ptr);
+bool CheckSignatureByCa(CEDAR *cedar, X *x);
+bool CheckSignatureByCaLinkMode(SESSION *s, X *x);
+X *FindCaSignedX(LIST *o, X *x);
+void InitNetSvcList(CEDAR *cedar);
+void FreeNetSvcList(CEDAR *cedar);
+int CompareNetSvc(void *p1, void *p2);
+char *GetSvcName(CEDAR *cedar, bool udp, UINT port);
+void InitHiddenPassword(char *str, UINT size);
+bool IsHiddenPasswordChanged(char *str);
+UINT64 GetTrafficPacketSize(TRAFFIC *t);
+UINT64 GetTrafficPacketNum(TRAFFIC *t);
+void EnableDebugLog(CEDAR *c);
+void StartCedarLog();
+void StopCedarLog();
+void CedarLog(char *str);
+int CompareNoSslList(void *p1, void *p2);
+void InitNoSslList(CEDAR *c);
+void FreeNoSslList(CEDAR *c);
+bool AddNoSsl(CEDAR *c, IP *ip);
+void DecrementNoSsl(CEDAR *c, IP *ip, UINT num_dec);
+void DeleteOldNoSsl(CEDAR *c);
+NON_SSL *SearchNoSslList(CEDAR *c, IP *ip);
+bool IsInNoSsl(CEDAR *c, IP *ip);
+void FreeTinyLog(TINY_LOG *t);
+void WriteTinyLog(TINY_LOG *t, char *str);
+TINY_LOG *NewTinyLog();
+void GetWinVer(RPC_WINVER *v);
+bool IsSupportedWinVer(RPC_WINVER *v);
+bool IsLaterBuild(CEDAR *c, UINT64 t);
+SOCK *GetInProcListeningSock(CEDAR *c);
+SOCK *GetReverseListeningSock(CEDAR *c);
+void GetCedarVersion(char *tmp, UINT size);
+UINT64 GetCurrentBuildDate();
+
+
+
+#endif // CEDAR_H
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Cedar.vcproj b/src/Cedar/Cedar.vcproj
new file mode 100644
index 00000000..c84d7379
--- /dev/null
+++ b/src/Cedar/Cedar.vcproj
@@ -0,0 +1,1529 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Cedar/CedarPch.c b/src/Cedar/CedarPch.c
new file mode 100644
index 00000000..af2b83c7
--- /dev/null
+++ b/src/Cedar/CedarPch.c
@@ -0,0 +1,89 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// CedarPch.c
+// Cedar Pre-compile Header Generating Code
+
+#include "CedarPch.h"
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/CedarPch.h b/src/Cedar/CedarPch.h
new file mode 100644
index 00000000..c71673b3
--- /dev/null
+++ b/src/Cedar/CedarPch.h
@@ -0,0 +1,100 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// CedarPch.h
+// Header file for grecompile header generation for Cedar
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/CedarType.h b/src/Cedar/CedarType.h
new file mode 100644
index 00000000..0937db60
--- /dev/null
+++ b/src/Cedar/CedarType.h
@@ -0,0 +1,720 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// CedarType.h
+// List of types that Cedar using
+
+#ifndef CEDARTYPE_H
+#define CEDARTYPE_H
+
+
+// ==============================================================
+// Remote Procedure Call
+// ==============================================================
+
+typedef struct RPC RPC;
+
+
+// ==============================================================
+// Account
+// ==============================================================
+
+typedef struct POLICY_ITEM POLICY_ITEM;
+typedef struct POLICY POLICY;
+typedef struct USERGROUP USERGROUP;
+typedef struct USER USER;
+typedef struct AUTHPASSWORD AUTHPASSWORD;
+typedef struct AUTHUSERCERT AUTHUSERCERT;
+typedef struct AUTHROOTCERT AUTHROOTCERT;
+typedef struct AUTHRADIUS AUTHRADIUS;
+typedef struct AUTHNT AUTHNT;
+
+
+// ==============================================================
+// Listener
+// ==============================================================
+
+typedef struct DOS DOS;
+typedef struct LISTENER LISTENER;
+typedef struct TCP_ACCEPTED_PARAM TCP_ACCEPTED_PARAM;
+typedef struct UDP_ENTRY UDP_ENTRY;
+typedef struct DYNAMIC_LISTENER DYNAMIC_LISTENER;
+
+
+// ==============================================================
+// Logging
+// ==============================================================
+
+typedef struct PACKET_LOG PACKET_LOG;
+typedef struct HUB_LOG HUB_LOG;
+typedef struct RECORD RECORD;
+typedef struct LOG LOG;
+typedef struct ERASER ERASER;
+typedef struct SLOG SLOG;
+
+
+// ==============================================================
+// Connection
+// ==============================================================
+
+typedef struct KEEP KEEP;
+typedef struct SECURE_SIGN SECURE_SIGN;
+typedef struct RC4_KEY_PAIR RC4_KEY_PAIR;
+typedef struct CLIENT_OPTION CLIENT_OPTION;
+typedef struct CLIENT_AUTH CLIENT_AUTH;
+typedef struct TCPSOCK TCPSOCK;
+typedef struct TCP TCP;
+typedef struct UDP UDP;
+typedef struct BLOCK BLOCK;
+typedef struct CONNECTION CONNECTION;
+
+
+// ==============================================================
+// Session
+// ==============================================================
+
+typedef struct NODE_INFO NODE_INFO;
+typedef struct PACKET_ADAPTER PACKET_ADAPTER;
+typedef struct SESSION SESSION;
+typedef struct UI_PASSWORD_DLG UI_PASSWORD_DLG;
+typedef struct UI_MSG_DLG UI_MSG_DLG;
+typedef struct UI_NICINFO UI_NICINFO;
+typedef struct UI_CONNECTERROR_DLG UI_CONNECTERROR_DLG;
+typedef struct UI_CHECKCERT UI_CHECKCERT;
+
+
+// ==============================================================
+// Hub
+// ==============================================================
+
+typedef struct SE_LINK SE_LINK;
+typedef struct TEST_HISTORY TEST_HISTORY;
+typedef struct SE_TEST SE_TEST;
+typedef struct HUBDB HUBDB;
+typedef struct TRAFFIC_LIMITER TRAFFIC_LIMITER;
+typedef struct STORM STORM;
+typedef struct HUB_PA HUB_PA;
+typedef struct HUB_OPTION HUB_OPTION;
+typedef struct MAC_TABLE_ENTRY MAC_TABLE_ENTRY;
+typedef struct IP_TABLE_ENTRY IP_TABLE_ENTRY;
+typedef struct LOOP_LIST LOOP_LIST;
+typedef struct ACCESS ACCESS;
+typedef struct TICKET TICKET;
+typedef struct TRAFFIC_DIFF TRAFFIC_DIFF;
+typedef struct HUB HUB;
+typedef struct ADMIN_OPTION ADMIN_OPTION;
+typedef struct CRL CRL;
+typedef struct AC AC;
+typedef struct USERLIST USERLIST;
+
+
+// ==============================================================
+// Protocol
+// ==============================================================
+
+typedef struct CHECK_CERT_THREAD_PROC CHECK_CERT_THREAD_PROC;
+typedef struct SECURE_SIGN_THREAD_PROC SECURE_SIGN_THREAD_PROC;
+typedef struct RAND_CACHE RAND_CACHE;
+typedef struct BLACK BLACK;
+typedef struct SEND_SIGNATURE_PARAM SEND_SIGNATURE_PARAM;
+typedef struct UPDATE_CLIENT UPDATE_CLIENT;
+typedef struct UPDATE_CLIENT_SETTING UPDATE_CLIENT_SETTING;
+
+
+// ==============================================================
+// Link
+// ==============================================================
+
+typedef struct LINK LINK;
+
+
+// ==============================================================
+// Virtual
+// ==============================================================
+
+typedef struct ARP_ENTRY ARP_ENTRY;
+typedef struct ARP_WAIT ARP_WAIT;
+typedef struct IP_WAIT IP_WAIT;
+typedef struct IP_PART IP_PART;
+typedef struct IP_COMBINE IP_COMBINE;
+typedef struct NAT_ENTRY NAT_ENTRY;
+typedef struct TCP_OPTION TCP_OPTION;
+typedef struct VH VH;
+typedef struct VH_OPTION VH_OPTION;
+typedef struct DHCP_LEASE DHCP_LEASE;
+typedef struct NATIVE_NAT NATIVE_NAT;
+typedef struct NATIVE_NAT_ENTRY NATIVE_NAT_ENTRY;
+typedef struct DNS_PARSED_PACKET DNS_PARSED_PACKET;
+
+
+// ==============================================================
+// WPC
+// ==============================================================
+
+typedef struct INTERNET_SETTING INTERNET_SETTING;
+typedef struct URL_DATA URL_DATA;
+typedef struct WPC_ENTRY WPC_ENTRY;
+typedef struct WPC_PACKET WPC_PACKET;
+typedef struct WPC_CONNECT WPC_CONNECT;
+
+// ==============================================================
+// VLAN
+// ==============================================================
+
+typedef struct ROUTE_TRACKING ROUTE_TRACKING;
+typedef struct VLAN VLAN;
+typedef struct INSTANCE_LIST INSTANCE_LIST;
+typedef struct VLAN_PARAM VLAN_PARAM;
+
+#ifdef OS_UNIX
+typedef struct UNIX_VLAN_LIST UNIX_VLAN_LIST;
+#endif // OS_UNIX
+
+// ==============================================================
+// Null LAN
+// ==============================================================
+
+typedef struct NULL_LAN NULL_LAN;
+
+
+// ==============================================================
+// Bridge
+// ==============================================================
+
+typedef struct ETH ETH;
+typedef struct BRIDGE BRIDGE;
+typedef struct LOCALBRIDGE LOCALBRIDGE;
+
+
+// ==============================================================
+// Layer-3 Switch
+// ==============================================================
+
+typedef struct L3IF L3IF;
+typedef struct L3SW L3SW;
+typedef struct L3TABLE L3TABLE;
+typedef struct L3ARPENTRY L3ARPENTRY;
+typedef struct L3ARPWAIT L3ARPWAIT;
+typedef struct L3PACKET L3PACKET;
+
+
+// ==============================================================
+// Client
+// ==============================================================
+
+typedef struct ACCOUNT ACCOUNT;
+typedef struct CLIENT_CONFIG CLIENT_CONFIG;
+typedef struct RPC_CLIENT_VERSION RPC_CLIENT_VERSION;
+typedef struct RPC_CLIENT_PASSWORD RPC_CLIENT_PASSWORD;
+typedef struct RPC_CLIENT_PASSWORD_SETTING RPC_CLIENT_PASSWORD_SETTING;
+typedef struct RPC_CLIENT_ENUM_CA_ITEM RPC_CLIENT_ENUM_CA_ITEM;
+typedef struct RPC_CLIENT_ENUM_CA RPC_CLIENT_ENUM_CA;
+typedef struct RPC_CERT RPC_CERT;
+typedef struct RPC_CLIENT_DELETE_CA RPC_CLIENT_DELETE_CA;
+typedef struct RPC_GET_CA RPC_GET_CA;
+typedef struct RPC_GET_ISSUER RPC_GET_ISSUER;
+typedef struct RPC_CLIENT_ENUM_SECURE_ITEM RPC_CLIENT_ENUM_SECURE_ITEM;
+typedef struct RPC_CLIENT_ENUM_SECURE RPC_CLIENT_ENUM_SECURE;
+typedef struct RPC_USE_SECURE RPC_USE_SECURE;
+typedef struct RPC_ENUM_OBJECT_IN_SECURE RPC_ENUM_OBJECT_IN_SECURE;
+typedef struct RPC_CLIENT_CREATE_VLAN RPC_CLIENT_CREATE_VLAN;
+typedef struct RPC_CLIENT_GET_VLAN RPC_CLIENT_GET_VLAN;
+typedef struct RPC_CLIENT_SET_VLAN RPC_CLIENT_SET_VLAN;
+typedef struct RPC_CLIENT_ENUM_VLAN_ITEM RPC_CLIENT_ENUM_VLAN_ITEM;
+typedef struct RPC_CLIENT_ENUM_VLAN RPC_CLIENT_ENUM_VLAN;
+typedef struct RPC_CLIENT_CREATE_ACCOUNT RPC_CLIENT_CREATE_ACCOUNT;
+typedef struct RPC_CLIENT_ENUM_ACCOUNT_ITEM RPC_CLIENT_ENUM_ACCOUNT_ITEM;
+typedef struct RPC_CLIENT_ENUM_ACCOUNT RPC_CLIENT_ENUM_ACCOUNT;
+typedef struct RPC_CLIENT_DELETE_ACCOUNT RPC_CLIENT_DELETE_ACCOUNT;
+typedef struct RPC_RENAME_ACCOUNT RPC_RENAME_ACCOUNT;
+typedef struct RPC_CLIENT_GET_ACCOUNT RPC_CLIENT_GET_ACCOUNT;
+typedef struct RPC_CLIENT_CONNECT RPC_CLIENT_CONNECT;
+typedef struct RPC_CLIENT_GET_CONNECTION_STATUS RPC_CLIENT_GET_CONNECTION_STATUS;
+typedef struct CLIENT_RPC_CONNECTION CLIENT_RPC_CONNECTION;
+typedef struct CLIENT CLIENT;
+typedef struct RPC_CLIENT_NOTIFY RPC_CLIENT_NOTIFY;
+typedef struct REMOTE_CLIENT REMOTE_CLIENT;
+typedef struct NOTIFY_CLIENT NOTIFY_CLIENT;
+typedef struct UNIX_VLAN UNIX_VLAN;
+typedef struct CM_SETTING CM_SETTING;
+
+
+// ==============================================================
+// Server
+// ==============================================================
+
+typedef struct HUB_LIST HUB_LIST;
+typedef struct FARM_TASK FARM_TASK;
+typedef struct FARM_MEMBER FARM_MEMBER;
+typedef struct FARM_CONTROLLER FARM_CONTROLLER;
+typedef struct SERVER_LISTENER SERVER_LISTENER;
+typedef struct SERVER SERVER;
+typedef struct RPC_ENUM_SESSION RPC_ENUM_SESSION;
+typedef struct RPC_SESSION_STATUS RPC_SESSION_STATUS;
+typedef struct CAPS CAPS;
+typedef struct CAPSLIST CAPSLIST;
+typedef struct LOG_FILE LOG_FILE;
+typedef struct SYSLOG_SETTING SYSLOG_SETTING;
+typedef struct HUB_SNAPSHOT HUB_SNAPSHOT;
+typedef struct SERVER_SNAPSHOT SERVER_SNAPSHOT;
+typedef struct SERVER_HUB_CREATE_HISTORY SERVER_HUB_CREATE_HISTORY;
+typedef struct OPENVPN_SSTP_CONFIG OPENVPN_SSTP_CONFIG;
+
+// ==============================================================
+// Server Admin Tool
+// ==============================================================
+
+typedef struct ADMIN ADMIN;
+typedef struct RPC_TEST RPC_TEST;
+typedef struct RPC_SERVER_INFO RPC_SERVER_INFO;
+typedef struct RPC_SERVER_STATUS RPC_SERVER_STATUS;
+typedef struct RPC_LISTENER RPC_LISTENER;
+typedef struct RPC_LISTENER_LIST RPC_LISTENER_LIST;
+typedef struct RPC_STR RPC_STR;
+typedef struct RPC_SET_PASSWORD RPC_SET_PASSWORD;
+typedef struct RPC_FARM RPC_FARM;
+typedef struct RPC_FARM_HUB RPC_FARM_HUB;
+typedef struct RPC_FARM_INFO RPC_FARM_INFO;
+typedef struct RPC_ENUM_FARM_ITEM RPC_ENUM_FARM_ITEM;
+typedef struct RPC_ENUM_FARM RPC_ENUM_FARM;
+typedef struct RPC_FARM_CONNECTION_STATUS RPC_FARM_CONNECTION_STATUS;
+typedef struct RPC_KEY_PAIR RPC_KEY_PAIR;
+typedef struct RPC_HUB_OPTION RPC_HUB_OPTION;
+typedef struct RPC_RADIUS RPC_RADIUS;
+typedef struct RPC_HUB RPC_HUB;
+typedef struct RPC_CREATE_HUB RPC_CREATE_HUB;
+typedef struct RPC_ENUM_HUB_ITEM RPC_ENUM_HUB_ITEM;
+typedef struct RPC_ENUM_HUB RPC_ENUM_HUB;
+typedef struct RPC_DELETE_HUB RPC_DELETE_HUB;
+typedef struct RPC_ENUM_CONNECTION_ITEM RPC_ENUM_CONNECTION_ITEM;
+typedef struct RPC_ENUM_CONNECTION RPC_ENUM_CONNECTION;
+typedef struct RPC_DISCONNECT_CONNECTION RPC_DISCONNECT_CONNECTION;
+typedef struct RPC_CONNECTION_INFO RPC_CONNECTION_INFO;
+typedef struct RPC_SET_HUB_ONLINE RPC_SET_HUB_ONLINE;
+typedef struct RPC_HUB_STATUS RPC_HUB_STATUS;
+typedef struct RPC_HUB_LOG RPC_HUB_LOG;
+typedef struct RPC_HUB_ADD_CA RPC_HUB_ADD_CA;
+typedef struct RPC_HUB_ENUM_CA_ITEM RPC_HUB_ENUM_CA_ITEM;
+typedef struct RPC_HUB_ENUM_CA RPC_HUB_ENUM_CA;
+typedef struct RPC_HUB_GET_CA RPC_HUB_GET_CA;
+typedef struct RPC_HUB_DELETE_CA RPC_HUB_DELETE_CA;
+typedef struct RPC_CREATE_LINK RPC_CREATE_LINK;
+typedef struct RPC_ENUM_LINK_ITEM RPC_ENUM_LINK_ITEM;
+typedef struct RPC_ENUM_LINK RPC_ENUM_LINK;
+typedef struct RPC_LINK_STATUS RPC_LINK_STATUS;
+typedef struct RPC_LINK RPC_LINK;
+typedef struct RPC_ENUM_ACCESS_LIST RPC_ENUM_ACCESS_LIST;
+typedef struct RPC_ADD_ACCESS RPC_ADD_ACCESS;
+typedef struct RPC_DELETE_ACCESS RPC_DELETE_ACCESS;
+typedef struct RPC_SET_USER RPC_SET_USER;
+typedef struct RPC_ENUM_USER_ITEM RPC_ENUM_USER_ITEM;
+typedef struct RPC_ENUM_USER RPC_ENUM_USER;
+typedef struct RPC_SET_GROUP RPC_SET_GROUP;
+typedef struct RPC_ENUM_GROUP_ITEM RPC_ENUM_GROUP_ITEM;
+typedef struct RPC_ENUM_GROUP RPC_ENUM_GROUP;
+typedef struct RPC_DELETE_USER RPC_DELETE_USER;
+typedef struct RPC_ENUM_SESSION_ITEM RPC_ENUM_SESSION_ITEM;
+typedef struct RPC_DELETE_SESSION RPC_DELETE_SESSION;
+typedef struct RPC_ENUM_MAC_TABLE_ITEM RPC_ENUM_MAC_TABLE_ITEM;
+typedef struct RPC_ENUM_MAC_TABLE RPC_ENUM_MAC_TABLE;
+typedef struct RPC_ENUM_IP_TABLE_ITEM RPC_ENUM_IP_TABLE_ITEM;
+typedef struct RPC_ENUM_IP_TABLE RPC_ENUM_IP_TABLE;
+typedef struct RPC_DELETE_TABLE RPC_DELETE_TABLE;
+typedef struct RPC_KEEP RPC_KEEP;
+typedef struct RPC_ENUM_ETH_ITEM RPC_ENUM_ETH_ITEM;
+typedef struct RPC_ENUM_ETH RPC_ENUM_ETH;
+typedef struct RPC_LOCALBRIDGE RPC_LOCALBRIDGE;
+typedef struct RPC_ENUM_LOCALBRIDGE RPC_ENUM_LOCALBRIDGE;
+typedef struct RPC_BRIDGE_SUPPORT RPC_BRIDGE_SUPPORT;
+typedef struct RPC_CONFIG RPC_CONFIG;
+typedef struct RPC_ADMIN_OPTION RPC_ADMIN_OPTION;
+typedef struct RPC_L3SW RPC_L3SW;
+typedef struct RPC_L3IF RPC_L3IF;
+typedef struct RPC_L3TABLE RPC_L3TABLE;
+typedef struct RPC_ENUM_L3SW_ITEM RPC_ENUM_L3SW_ITEM;
+typedef struct RPC_ENUM_L3SW RPC_ENUM_L3SW;
+typedef struct RPC_ENUM_L3IF RPC_ENUM_L3IF;
+typedef struct RPC_ENUM_L3TABLE RPC_ENUM_L3TABLE;
+typedef struct RPC_CRL RPC_CRL;
+typedef struct RPC_ENUM_CRL_ITEM RPC_ENUM_CRL_ITEM;
+typedef struct RPC_ENUM_CRL RPC_ENUM_CRL;
+typedef struct RPC_INT RPC_INT;
+typedef struct RPC_AC_LIST RPC_AC_LIST;
+typedef struct RPC_ENUM_LOG_FILE_ITEM RPC_ENUM_LOG_FILE_ITEM;
+typedef struct RPC_ENUM_LOG_FILE RPC_ENUM_LOG_FILE;
+typedef struct RPC_READ_LOG_FILE RPC_READ_LOG_FILE;
+typedef struct DOWNLOAD_PROGRESS DOWNLOAD_PROGRESS;
+typedef struct RPC_RENAME_LINK RPC_RENAME_LINK;
+typedef struct RPC_ENUM_LICENSE_KEY RPC_ENUM_LICENSE_KEY;
+typedef struct RPC_ENUM_LICENSE_KEY_ITEM RPC_ENUM_LICENSE_KEY_ITEM;
+typedef struct RPC_LICENSE_STATUS RPC_LICENSE_STATUS;
+typedef struct RPC_ENUM_ETH_VLAN_ITEM RPC_ENUM_ETH_VLAN_ITEM;
+typedef struct RPC_ENUM_ETH_VLAN RPC_ENUM_ETH_VLAN;
+typedef struct RPC_MSG RPC_MSG;
+typedef struct RPC_WINVER RPC_WINVER;
+typedef struct RPC_ENUM_ETHERIP_ID RPC_ENUM_ETHERIP_ID;
+typedef struct RPC_SPECIAL_LISTENER RPC_SPECIAL_LISTENER;
+typedef struct RPC_AZURE_STATUS RPC_AZURE_STATUS;
+
+
+// ==============================================================
+// NAT
+// ==============================================================
+
+typedef struct NAT NAT;
+typedef struct NAT_ADMIN NAT_ADMIN;
+typedef struct RPC_DUMMY RPC_DUMMY;
+typedef struct RPC_NAT_STATUS RPC_NAT_STATUS;
+typedef struct RPC_NAT_INFO RPC_NAT_INFO;
+typedef struct RPC_ENUM_NAT_ITEM RPC_ENUM_NAT_ITEM;
+typedef struct RPC_ENUM_NAT RPC_ENUM_NAT;
+typedef struct RPC_ENUM_DHCP_ITEM RPC_ENUM_DHCP_ITEM;
+typedef struct RPC_ENUM_DHCP RPC_ENUM_DHCP;
+
+
+// ==============================================================
+// SecureNAT
+// ==============================================================
+
+typedef struct SNAT SNAT;
+
+
+// ==============================================================
+// WinUI
+// ==============================================================
+
+typedef struct LED LED;
+typedef struct WIZARD WIZARD;
+typedef struct WIZARD_PAGE WIZARD_PAGE;
+typedef struct WINUI_UPDATE WINUI_UPDATE;
+typedef struct WINUI_UPDATE_DLG_PARAM WINUI_UPDATE_DLG_PARAM;
+
+
+
+// ==============================================================
+// Console
+// ==============================================================
+
+typedef struct PARAM PARAM;
+typedef struct PARAM_VALUE PARAM_VALUE;
+typedef struct CONSOLE CONSOLE;
+typedef struct LOCAL_CONSOLE_PARAM LOCAL_CONSOLE_PARAM;
+typedef struct CMD CMD;
+typedef struct CMD_EVAL_MIN_MAX CMD_EVAL_MIN_MAX;
+
+
+// ==============================================================
+// Command
+// ==============================================================
+
+typedef struct PS PS;
+typedef struct PC PC;
+typedef struct CT CT;
+typedef struct CTC CTC;
+typedef struct CTR CTR;
+typedef struct TTC TTC;
+typedef struct TTS TTS;
+typedef struct TT_RESULT TT_RESULT;
+typedef struct TTS_SOCK TTS_SOCK;
+typedef struct TTC_SOCK TTC_SOCK;
+typedef struct PT PT;
+
+// ==============================================================
+// EtherLogger
+// ==============================================================
+
+typedef struct EL EL;
+typedef struct EL_DEVICE EL_DEVICE;
+typedef struct EL_LICENSE_STATUS EL_LICENSE_STATUS;
+typedef struct RPC_ADD_DEVICE RPC_ADD_DEVICE;
+typedef struct RPC_DELETE_DEVICE RPC_DELETE_DEVICE;
+typedef struct RPC_ENUM_DEVICE_ITEM RPC_ENUM_DEVICE_ITEM;
+typedef struct RPC_ENUM_DEVICE RPC_ENUM_DEVICE;
+typedef struct RPC_EL_LICENSE_STATUS RPC_EL_LICENSE_STATUS;
+
+
+// ==============================================================
+// Database
+// ==============================================================
+
+typedef struct LICENSE_PRODUCT LICENSE_PRODUCT;
+typedef struct LICENSE_SYSTEM LICENSE_SYSTEM;
+typedef struct LICENSE_DATA LICENSE_DATA;
+typedef struct LICENSE LICENSE;
+typedef struct LICENSE_STATUS LICENSE_STATUS;
+typedef struct SECURE_PACK_FOLDER SECURE_PACK_FOLDER;
+typedef struct WIDE_MACHINE_ID WIDE_MACHINE_ID;
+typedef struct TRIAL_INFO TRIAL_INFO;
+
+
+// ==============================================================
+// IPsec
+// ==============================================================
+
+typedef struct IPSEC_SERVER IPSEC_SERVER;
+typedef struct IPSEC_SERVICES IPSEC_SERVICES;
+typedef struct ETHERIP_ID ETHERIP_ID;
+
+
+// ==============================================================
+// L2TP
+// ==============================================================
+
+typedef struct L2TP_SERVER L2TP_SERVER;
+typedef struct L2TP_TUNNEL L2TP_TUNNEL;
+typedef struct L2TP_SESSION L2TP_SESSION;
+typedef struct L2TP_PACKET L2TP_PACKET;
+typedef struct L2TP_AVP L2TP_AVP;
+typedef struct L2TP_QUEUE L2TP_QUEUE;
+
+
+// ==============================================================
+// PPP
+// ==============================================================
+
+typedef struct PPP_SESSION PPP_SESSION;
+typedef struct PPP_OPTION PPP_OPTION;
+typedef struct PPP_LCP PPP_LCP;
+typedef struct PPP_PACKET PPP_PACKET;
+typedef struct PPP_IPOPTION PPP_IPOPTION;
+
+
+// ==============================================================
+// EtherIP
+// ==============================================================
+
+typedef struct ETHERIP_SERVER ETHERIP_SERVER;
+
+
+// ==============================================================
+// IKE
+// ==============================================================
+
+typedef struct IKE_SERVER IKE_SERVER;
+typedef struct IKE_SA IKE_SA;
+typedef struct IKE_SA_TRANSFORM_SETTING IKE_SA_TRANSFORM_SETTING;
+typedef struct IKE_CLIENT IKE_CLIENT;
+typedef struct IPSECSA IPSECSA;
+typedef struct IKE_CAPS IKE_CAPS;
+
+// ==============================================================
+// IPSec Packet
+// ==============================================================
+
+typedef struct IKE_COMMON_HEADER IKE_COMMON_HEADER;
+typedef struct IKE_SA_HEADER IKE_SA_HEADER;
+typedef struct IKE_PROPOSAL_HEADER IKE_PROPOSAL_HEADER;
+typedef struct IKE_TRANSFORM_HEADER IKE_TRANSFORM_HEADER;
+typedef struct IKE_TRANSFORM_VALUE IKE_TRANSFORM_VALUE;
+typedef struct IKE_ID_HEADER IKE_ID_HEADER;
+typedef struct IKE_CERT_HEADER IKE_CERT_HEADER;
+typedef struct IKE_CERT_REQUEST_HEADER IKE_CERT_REQUEST_HEADER;
+typedef struct IKE_NOTICE_HEADER IKE_NOTICE_HEADER;
+typedef struct IKE_DELETE_HEADER IKE_DELETE_HEADER;
+typedef struct IKE_NAT_OA_HEADER IKE_NAT_OA_HEADER;
+typedef struct IPSEC_SA_TRANSFORM_SETTING IPSEC_SA_TRANSFORM_SETTING;
+
+typedef struct IKE_PACKET_SA_PAYLOAD IKE_PACKET_SA_PAYLOAD;
+typedef struct IKE_PACKET_PROPOSAL_PAYLOAD IKE_PACKET_PROPOSAL_PAYLOAD;
+typedef struct IKE_PACKET_TRANSFORM_PAYLOAD IKE_PACKET_TRANSFORM_PAYLOAD;
+typedef struct IKE_PACKET_TRANSFORM_VALUE IKE_PACKET_TRANSFORM_VALUE;
+typedef struct IKE_PACKET_DATA_PAYLOAD IKE_PACKET_DATA_PAYLOAD;
+typedef struct IKE_PACKET_ID_PAYLOAD IKE_PACKET_ID_PAYLOAD;
+typedef struct IKE_PACKET_CERT_PAYLOAD IKE_PACKET_CERT_PAYLOAD;
+typedef struct IKE_PACKET_CERT_REQUEST_PAYLOAD IKE_PACKET_CERT_REQUEST_PAYLOAD;
+typedef struct IKE_PACKET_NOTICE_PAYLOAD IKE_PACKET_NOTICE_PAYLOAD;
+typedef struct IKE_PACKET_DELETE_PAYLOAD IKE_PACKET_DELETE_PAYLOAD;
+typedef struct IKE_PACKET_NAT_OA_PAYLOAD IKE_PACKET_NAT_OA_PAYLOAD;
+
+typedef struct IKE_PACKET_PAYLOAD IKE_PACKET_PAYLOAD;
+typedef struct IKE_PACKET IKE_PACKET;
+
+typedef struct IKE_P1_KEYSET IKE_P1_KEYSET;
+
+typedef struct IKE_CRYPTO IKE_CRYPTO;
+typedef struct IKE_HASH IKE_HASH;
+typedef struct IKE_DH IKE_DH;
+typedef struct IKE_ENGINE IKE_ENGINE;
+typedef struct IKE_CRYPTO_KEY IKE_CRYPTO_KEY;
+typedef struct IKE_CRYPTO_PARAM IKE_CRYPTO_PARAM;
+
+
+// ==============================================================
+// IPSec for Windows 7 / Vista / 2008 / 2008 R2
+// ==============================================================
+
+typedef struct IPSEC_WIN7 IPSEC_WIN7;
+
+
+// ==============================================================
+// In-Process VPN Client
+// ==============================================================
+
+typedef struct IPC IPC;
+typedef struct IPC_ARP IPC_ARP;
+typedef struct IPC_ASYNC IPC_ASYNC;
+typedef struct IPC_PARAM IPC_PARAM;
+typedef struct IPC_DHCP_RELESAE_QUEUE IPC_DHCP_RELESAE_QUEUE;
+typedef struct IPC_MSCHAP_V2_AUTHINFO IPC_MSCHAP_V2_AUTHINFO;
+
+
+// ==============================================================
+// UDP Acceleration
+// ==============================================================
+
+typedef struct UDP_ACCEL UDP_ACCEL;
+
+
+// ==============================================================
+// SSTP (Microsoft Secure Socket Tunneling Protocol) Stack
+// ==============================================================
+
+typedef struct SSTP_SERVER SSTP_SERVER;
+typedef struct SSTP_PACKET SSTP_PACKET;
+typedef struct SSTP_ATTRIBUTE SSTP_ATTRIBUTE;
+
+
+// ==============================================================
+// OpenVPN Protocol Stack
+// ==============================================================
+
+typedef struct OPENVPN_SERVER OPENVPN_SERVER;
+typedef struct OPENVPN_SERVER_UDP OPENVPN_SERVER_UDP;
+typedef struct OPENVPN_SESSION OPENVPN_SESSION;
+typedef struct OPENVPN_CHANNEL OPENVPN_CHANNEL;
+typedef struct OPENVPN_PACKET OPENVPN_PACKET;
+typedef struct OPENVPN_CONTROL_PACKET OPENVPN_CONTROL_PACKET;
+typedef struct OPENVPN_KEY_METHOD_2 OPENVPN_KEY_METHOD_2;
+
+
+// ==============================================================
+// Dynamic DNS Client
+// ==============================================================
+
+typedef struct DDNS_CLIENT DDNS_CLIENT;
+typedef struct DDNS_REGISTER_PARAM DDNS_REGISTER_PARAM;
+typedef struct DDNS_CLIENT_STATUS DDNS_CLIENT_STATUS;
+
+
+// ==============================================================
+// VPN Azure Client
+// ==============================================================
+typedef struct AZURE_CLIENT AZURE_CLIENT;
+typedef struct AZURE_PARAM AZURE_PARAM;
+
+
+// ==============================================================
+// VPN Gate Service
+// ==============================================================
+
+typedef struct VGS VGS;
+typedef struct VGS_CONFIG VGS_CONFIG;
+typedef struct VGC VGC;
+typedef struct VGHOST VGHOST;
+typedef struct VGHOSTLIST VGHOSTLIST;
+typedef struct VGHOSTDAT VGHOSTDAT;
+typedef struct VGCPOLLTASK VGCPOLLTASK;
+typedef struct VGS_LOG VGS_LOG;
+typedef struct VGC_UDPHOST VGC_UDPHOST;
+typedef struct MIRROR_SERVER MIRROR_SERVER;
+
+
+// ==============================================================
+// Native Stack
+// ==============================================================
+
+typedef struct NATIVE_STACK NATIVE_STACK;
+
+
+// ==============================================================
+// SeLow User-mode
+// ==============================================================
+
+typedef struct SU SU;
+typedef struct SU_ADAPTER SU_ADAPTER;
+typedef struct SU_ADAPTER_LIST SU_ADAPTER_LIST;
+
+
+
+#endif // CEDARTYPE_H
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Client.c b/src/Cedar/Client.c
new file mode 100644
index 00000000..16062e7f
--- /dev/null
+++ b/src/Cedar/Client.c
@@ -0,0 +1,11005 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Client.c
+// Client Manager
+
+#include "CedarPch.h"
+
+static CLIENT *client = NULL;
+static LISTENER *cn_listener = NULL;
+static LOCK *cn_listener_lock = NULL;
+static UINT64 cn_next_allow = 0;
+static LOCK *ci_active_sessions_lock = NULL;
+static UINT ci_num_active_sessions = 0;
+
+
+// In Windows 8 or later, change unreasonable setting of WCM to ensure normal VPN communication
+void CiDisableWcmNetworkMinimize(CLIENT *c)
+{
+#ifdef OS_WIN32
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ if (c->Config.NoChangeWcmNetworkSettingOnWindows8)
+ {
+ return;
+ }
+
+ MsDisableWcmNetworkMinimize();
+#endif // OS_WIN32
+}
+
+// Compare RPC_CLIENT_ENUM_ACCOUNT_ITEM items by last connected date (Reverse)
+int CiCompareClientAccountEnumItemByLastConnectDateTime(void *p1, void *p2)
+{
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *a1, *a2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ a1 = *(RPC_CLIENT_ENUM_ACCOUNT_ITEM **)p1;
+ a2 = *(RPC_CLIENT_ENUM_ACCOUNT_ITEM **)p2;
+ if (a1 == NULL || a2 == NULL)
+ {
+ return 0;
+ }
+ if (a1->LastConnectDateTime > a2->LastConnectDateTime)
+ {
+ return -1;
+ }
+ else if (a1->LastConnectDateTime < a2->LastConnectDateTime)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+// If machine changed, reshuffle MAC address for all virtual NIC
+void CiChangeAllVLanMacAddressIfMachineChanged(CLIENT *c)
+{
+ UCHAR current_hash_new[SHA1_SIZE];
+ UCHAR current_hash[SHA1_SIZE];
+ UCHAR current_hash_old[SHA1_SIZE];
+ UCHAR saved_hash[SHA1_SIZE];
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ if (MsIsAdmin() == false)
+ {
+ return;
+ }
+#endif
+
+ CiGetCurrentMachineHashNew(current_hash_new);
+ CiGetCurrentMachineHash(current_hash);
+ CiGetCurrentMachineHashOld(current_hash_old);
+
+ if (CiReadLastMachineHash(saved_hash) == false)
+ {
+ CiWriteLastMachineHash(current_hash_new);
+ return;
+ }
+
+ if (Cmp(saved_hash, current_hash_old, SHA1_SIZE) == 0)
+ {
+ CiWriteLastMachineHash(current_hash_new);
+ return;
+ }
+
+ if (Cmp(saved_hash, current_hash, SHA1_SIZE) == 0)
+ {
+ CiWriteLastMachineHash(current_hash_new);
+ return;
+ }
+
+ if (Cmp(saved_hash, current_hash_new, SHA1_SIZE) == 0)
+ {
+ return;
+ }
+
+ if (CiWriteLastMachineHash(current_hash_new) == false)
+ {
+ return;
+ }
+
+ CiChangeAllVLanMacAddress(c);
+}
+
+// Get current machine hash (Old)
+void CiGetCurrentMachineHashOld(void *data)
+{
+ char name[MAX_PATH];
+ char *product_id = NULL;
+ // Validate arguments
+ if (data == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ // Priduct ID
+ product_id = MsRegReadStr(REG_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "ProductId");
+ if (product_id == NULL)
+ {
+ product_id = MsRegReadStr(REG_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion", "ProductId");
+ }
+
+ StrCpy(name, sizeof(name), product_id);
+
+ Free(product_id);
+
+#else // OS_WIN32
+ GetMachineName(name, sizeof(name));
+#endif // OS_WIN32
+
+ Trim(name);
+ StrUpper(name);
+
+ Hash(data, name, StrLen(name), true);
+}
+
+// Get current machine hash
+void CiGetCurrentMachineHash(void *data)
+{
+ char name[MAX_PATH];
+ char *product_id = NULL;
+ // Validate arguments
+ if (data == NULL)
+ {
+ return;
+ }
+
+ GetMachineName(name, sizeof(name));
+
+ Trim(name);
+ StrUpper(name);
+
+ Hash(data, name, StrLen(name), true);
+}
+
+// Get current machine hash (without using domain name)
+void CiGetCurrentMachineHashNew(void *data)
+{
+ char name[MAX_PATH];
+ char *p;
+
+ // Validate arguments
+ if (data == NULL)
+ {
+ return;
+ }
+
+ GetMachineName(name, sizeof(name));
+
+ // Ignore after first period(.)
+ for(p=name; *p; p++)
+ if(*p == '.')
+ *p = 0;
+
+ Trim(name);
+ StrUpper(name);
+
+ Hash(data, name, StrLen(name), true);
+}
+
+
+// Write machine hash
+bool CiWriteLastMachineHash(void *data)
+{
+ // Validate arguments
+ if (data == NULL)
+ {
+ return false;
+ }
+
+#ifdef OS_WIN32
+ if (MsRegWriteBinEx(REG_LOCAL_MACHINE, MS_REG_TCP_SETTING_KEY, "LastMachineHash", data, SHA1_SIZE, true) == false)
+ {
+ return false;
+ }
+
+ return true;
+#else // OS_WIN32
+ return false;
+#endif // OS_WIN32
+}
+
+// Get previous machine hash
+bool CiReadLastMachineHash(void *data)
+{
+ BUF *b = NULL;
+ // Validate arguments
+ if (data == NULL)
+ {
+ return false;
+ }
+
+#ifdef OS_WIN32
+ b = MsRegReadBinEx(REG_LOCAL_MACHINE, MS_REG_TCP_SETTING_KEY, "LastMachineHash", true);
+ if (b == NULL)
+ {
+ return false;
+ }
+ if (b->Size == SHA1_SIZE)
+ {
+ Copy(data, b->Buf, b->Size);
+ FreeBuf(b);
+
+ return true;
+ }
+
+ FreeBuf(b);
+ return false;
+#else // OS_WIN32
+ return false;
+#endif // OS_WIN32
+}
+
+// If the MAC address of each virtual LAN card has been eliminated, set it to random numbers
+// (measures for Windows 8 -> 8.1 upgrade problem)
+void CiChangeAllVLanMacAddressIfCleared(CLIENT *c)
+{
+#ifdef OS_WIN32
+ RPC_CLIENT_ENUM_VLAN t;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ if (MsIsInfCatalogRequired() == false)
+ {
+ // Not required for other than Windows 8
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ if (CtEnumVLan(c, &t))
+ {
+ UINT i;
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_VLAN_ITEM *e = t.Items[i];
+ UCHAR mac[6];
+
+ if (StrToMac(mac, e->MacAddress))
+ {
+ if (mac[0] == 0x00 &&
+ mac[1] == 0x00 &&
+ mac[2] == 0x01 &&
+ mac[3] == 0x00 &&
+ mac[4] == 0x00 &&
+ mac[5] == 0x01)
+ {
+ char *name = e->DeviceName;
+ RPC_CLIENT_SET_VLAN s;
+ UCHAR mac[6];
+
+ GenMacAddress(mac);
+
+ Zero(&s, sizeof(s));
+ StrCpy(s.DeviceName, sizeof(s.DeviceName), name);
+
+ MacToStr(s.MacAddress, sizeof(s.MacAddress), mac);
+
+ CtSetVLan(c, &s);
+ }
+ }
+ }
+
+ CiFreeClientEnumVLan(&t);
+ }
+#endif // OS_WIN32
+}
+
+// Set the MAC address of all virtual LAN cards to random number
+void CiChangeAllVLanMacAddress(CLIENT *c)
+{
+ RPC_CLIENT_ENUM_VLAN t;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ if (CtEnumVLan(c, &t))
+ {
+ UINT i;
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_VLAN_ITEM *e = t.Items[i];
+ UCHAR mac[6];
+
+ if (StrToMac(mac, e->MacAddress) && mac[1] == 0xAC)
+ {
+ char *name = e->DeviceName;
+ RPC_CLIENT_SET_VLAN s;
+ UCHAR mac[6];
+
+ GenMacAddress(mac);
+
+ Zero(&s, sizeof(s));
+ StrCpy(s.DeviceName, sizeof(s.DeviceName), name);
+
+ MacToStr(s.MacAddress, sizeof(s.MacAddress), mac);
+
+ CtSetVLan(c, &s);
+ }
+ }
+
+ CiFreeClientEnumVLan(&t);
+ }
+}
+
+// Wait for preparation of notification service to complete
+void CnWaitForCnServiceReady()
+{
+ UINT64 start_time = Tick64();
+
+ while ((start_time + (UINT64)CLIENT_WAIT_CN_READY_TIMEOUT) >= Tick64())
+ {
+ if (CnIsCnServiceReady())
+ {
+ break;
+ }
+
+ SleepThread(100);
+ }
+}
+
+// Check whether preparation of notification service completed
+bool CnIsCnServiceReady()
+{
+ SOCK *s;
+ // Confirm running the notification service
+ if (CnCheckAlreadyExists(false) == false)
+ {
+ // Not running
+ return false;
+ }
+
+ // Try to connect to the TCP port
+ s = ConnectEx("localhost", CLIENT_NOTIFY_PORT, 500);
+ if (s == NULL)
+ {
+ // The TCP port is not opened
+ return false;
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+
+ // Running
+ return true;
+}
+
+// Check whether the notification service is already running
+bool CnCheckAlreadyExists(bool lock)
+{
+ bool ret = false;
+
+#ifdef OS_WIN32
+ ret = Win32CnCheckAlreadyExists(lock);
+#endif
+
+ return ret;
+}
+
+typedef struct CNC_STATUS_PRINTER_WINDOW_PARAM
+{
+ THREAD *Thread;
+ SESSION *Session;
+ SOCK *Sock;
+} CNC_STATUS_PRINTER_WINDOW_PARAM;
+
+typedef struct CNC_CONNECT_ERROR_DLG_THREAD_PARAM
+{
+ SESSION *Session;
+ SOCK *Sock;
+ bool HaltThread;
+ EVENT *Event;
+} CNC_CONNECT_ERROR_DLG_THREAD_PARAM;
+
+
+// Get the file name of vpnclient.exe in Win32
+char *CiGetVpnClientExeFileName()
+{
+ if (Is64() == false)
+ {
+ return CLIENT_WIN32_EXE_FILENAME;
+ }
+ else
+ {
+ if (IsX64())
+ {
+ return CLIENT_WIN32_EXE_FILENAME_X64;
+ }
+ else
+ {
+ return CLIENT_WIN32_EXE_FILENAME_IA64;
+ }
+ }
+}
+
+// Thread to stop forcibly the Certificate check dialog client
+void CncCheckCertHaltThread(THREAD *thread, void *param)
+{
+ CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp = (CNC_CONNECT_ERROR_DLG_THREAD_PARAM *)param;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ if (dp->Session->Halt || dp->HaltThread)
+ {
+ break;
+ }
+
+ Wait(dp->Event, 100);
+ }
+
+ Disconnect(dp->Sock);
+}
+
+// Show the certification check dialog
+void CncCheckCert(SESSION *session, UI_CHECKCERT *dlg)
+{
+ SOCK *s;
+ PACK *p;
+ CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp;
+ THREAD *t;
+ // Validate arguments
+ if (dlg == NULL || session == NULL)
+ {
+ return;
+ }
+
+ s = CncConnect();
+ if (s == NULL)
+ {
+ return;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "check_cert");
+ PackAddUniStr(p, "AccountName", dlg->AccountName);
+ PackAddStr(p, "ServerName", dlg->ServerName);
+ PackAddX(p, "x", dlg->x);
+ PackAddX(p, "parent_x", dlg->parent_x);
+ PackAddX(p, "old_x", dlg->old_x);
+ PackAddBool(p, "DiffWarning", dlg->DiffWarning);
+ PackAddBool(p, "Ok", dlg->Ok);
+ PackAddBool(p, "SaveServerCert", dlg->SaveServerCert);
+
+ SendPack(s, p);
+ FreePack(p);
+
+ dp = ZeroMalloc(sizeof(CNC_CONNECT_ERROR_DLG_THREAD_PARAM));
+ dp->Sock = s;
+ dp->Event = NewEvent();
+ dp->Session = session;
+
+ t = NewThread(CncCheckCertHaltThread, dp);
+
+ p = RecvPack(s);
+ if (p != NULL)
+ {
+ dlg->Ok = PackGetBool(p, "Ok");
+ dlg->DiffWarning = PackGetBool(p, "DiffWarning");
+ dlg->SaveServerCert = PackGetBool(p, "SaveServerCert");
+
+ FreePack(p);
+ }
+
+ dp->HaltThread = true;
+ Set(dp->Event);
+
+ WaitThread(t, INFINITE);
+
+ ReleaseEvent(dp->Event);
+ Free(dp);
+ ReleaseThread(t);
+
+ Disconnect(s);
+ ReleaseSock(s);
+}
+
+// Smart card signature dialog
+bool CncSecureSignDlg(SECURE_SIGN *sign)
+{
+ SOCK *s;
+ PACK *p;
+ bool ret = false;
+ // Validate arguments
+ if (sign == NULL)
+ {
+ return false;
+ }
+
+ s = CncConnect();
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "secure_sign");
+ OutRpcSecureSign(p, sign);
+
+ SendPack(s, p);
+ FreePack(p);
+
+ p = RecvPack(s);
+ if (p != NULL)
+ {
+ ret = PackGetBool(p, "ret");
+
+ if (ret)
+ {
+ FreeRpcSecureSign(sign);
+
+ Zero(sign, sizeof(SECURE_SIGN));
+ InRpcSecureSign(sign, p);
+ }
+
+ FreePack(p);
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+
+ return ret;
+}
+
+// Show the NIC information dialog
+SOCK *CncNicInfo(UI_NICINFO *info)
+{
+ SOCK *s;
+ PACK *p;
+ bool ret = false;
+ // Validate arguments
+ if (info == NULL)
+ {
+ return NULL;
+ }
+
+ s = CncConnectEx(200);
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "nicinfo");
+ PackAddStr(p, "NicName", info->NicName);
+ PackAddUniStr(p, "AccountName", info->AccountName);
+
+ SendPack(s, p);
+ FreePack(p);
+
+ return s;
+}
+
+// Close the NIC information dialog
+void CncNicInfoFree(SOCK *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+}
+
+// Show the message dialog
+SOCK *CncMsgDlg(UI_MSG_DLG *dlg)
+{
+ SOCK *s;
+ PACK *p;
+ bool ret = false;
+ char *utf;
+ // Validate arguments
+ if (dlg == NULL)
+ {
+ return NULL;
+ }
+
+ s = CncConnectEx(200);
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "msg_dialog");
+ PackAddStr(p, "ServerName", dlg->ServerName);
+ PackAddStr(p, "HubName", dlg->HubName);
+ utf = CopyUniToUtf(dlg->Msg);
+ PackAddData(p, "Msg", utf, StrLen(utf));
+ Free(utf);
+
+ SendPack(s, p);
+ FreePack(p);
+
+ return s;
+}
+
+// Close the message dialog
+void CndMsgDlgFree(SOCK *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+}
+
+// The thread to stop the password input dialog client forcibly
+void CncPasswordDlgHaltThread(THREAD *thread, void *param)
+{
+ CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp = (CNC_CONNECT_ERROR_DLG_THREAD_PARAM *)param;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ if (dp->Session->Halt || dp->HaltThread)
+ {
+ break;
+ }
+
+ Wait(dp->Event, 100);
+ }
+
+ Disconnect(dp->Sock);
+}
+
+// Show the password input dialog
+bool CncPasswordDlg(SESSION *session, UI_PASSWORD_DLG *dlg)
+{
+ SOCK *s;
+ PACK *p;
+ CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp;
+ THREAD *t;
+ bool ret = false;
+ // Validate arguments
+ if (dlg == NULL || session == NULL)
+ {
+ return false;
+ }
+
+ s = CncConnect();
+ if (s == NULL)
+ {
+ Wait(session->HaltEvent, session->RetryInterval);
+ return true;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "password_dialog");
+ PackAddInt(p, "Type", dlg->Type);
+ PackAddStr(p, "Username", dlg->Username);
+ PackAddStr(p, "Password", dlg->Password);
+ PackAddStr(p, "ServerName", dlg->ServerName);
+ PackAddInt(p, "RetryIntervalSec", dlg->RetryIntervalSec);
+ PackAddBool(p, "ProxyServer", dlg->ProxyServer);
+ PackAddBool(p, "AdminMode", dlg->AdminMode);
+ PackAddBool(p, "ShowNoSavePassword", dlg->ShowNoSavePassword);
+ PackAddBool(p, "NoSavePassword", dlg->NoSavePassword);
+
+ SendPack(s, p);
+ FreePack(p);
+
+ dp = ZeroMalloc(sizeof(CNC_CONNECT_ERROR_DLG_THREAD_PARAM));
+ dp->Session = session;
+ dp->Sock = s;
+ dp->Event = NewEvent();
+
+ t = NewThread(CncConnectErrorDlgHaltThread, dp);
+
+ p = RecvPack(s);
+ if (p != NULL)
+ {
+ ret = PackGetBool(p, "ok");
+ dlg->NoSavePassword = PackGetBool(p, "NoSavePassword");
+ dlg->ProxyServer = PackGetBool(p, "ProxyServer");
+ dlg->Type = PackGetInt(p, "Type");
+ PackGetStr(p, "Username", dlg->Username, sizeof(dlg->Username));
+ PackGetStr(p, "Password", dlg->Password, sizeof(dlg->Password));
+
+ FreePack(p);
+ }
+
+ dp->HaltThread = true;
+ Set(dp->Event);
+
+ WaitThread(t, INFINITE);
+
+ ReleaseEvent(dp->Event);
+ Free(dp);
+ ReleaseThread(t);
+
+ Disconnect(s);
+ ReleaseSock(s);
+
+ return ret;
+}
+
+// Thread to stop the connection error dialog client forcibly
+void CncConnectErrorDlgHaltThread(THREAD *thread, void *param)
+{
+ CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp = (CNC_CONNECT_ERROR_DLG_THREAD_PARAM *)param;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ if (dp->Session->Halt || dp->HaltThread)
+ {
+ break;
+ }
+
+ Wait(dp->Event, 100);
+ }
+
+ Disconnect(dp->Sock);
+}
+
+// Show the connection error dialog
+bool CncConnectErrorDlg(SESSION *session, UI_CONNECTERROR_DLG *dlg)
+{
+ SOCK *s;
+ PACK *p;
+ CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp;
+ THREAD *t;
+ bool ret = false;
+ // Validate arguments
+ if (dlg == NULL || session == NULL)
+ {
+ return false;
+ }
+
+ s = CncConnect();
+ if (s == NULL)
+ {
+ Wait(session->HaltEvent, session->RetryInterval);
+ return true;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "connecterror_dialog");
+ PackAddUniStr(p, "AccountName", dlg->AccountName);
+ PackAddStr(p, "ServerName", dlg->ServerName);
+ PackAddInt(p, "Err", dlg->Err);
+ PackAddInt(p, "CurrentRetryCount", dlg->CurrentRetryCount);
+ PackAddInt(p, "RetryLimit", dlg->RetryLimit);
+ PackAddInt(p, "RetryIntervalSec", dlg->RetryIntervalSec);
+ PackAddBool(p, "HideWindow", dlg->HideWindow);
+
+ SendPack(s, p);
+ FreePack(p);
+
+ dp = ZeroMalloc(sizeof(CNC_CONNECT_ERROR_DLG_THREAD_PARAM));
+ dp->Session = session;
+ dp->Sock = s;
+ dp->Event = NewEvent();
+
+ t = NewThread(CncConnectErrorDlgHaltThread, dp);
+
+ p = RecvPack(s);
+ if (p != NULL)
+ {
+ ret = PackGetBool(p, "ok");
+ dlg->HideWindow = PackGetBool(p, "HideWindow");
+
+ FreePack(p);
+ }
+
+ dp->HaltThread = true;
+ Set(dp->Event);
+
+ WaitThread(t, INFINITE);
+
+ ReleaseEvent(dp->Event);
+ Free(dp);
+ ReleaseThread(t);
+
+ Disconnect(s);
+ ReleaseSock(s);
+
+ return ret;
+}
+
+// Thread for the status indicator client
+void CncStatusPrinterWindowThreadProc(THREAD *thread, void *param)
+{
+ CNC_STATUS_PRINTER_WINDOW_PARAM *pp;
+ SOCK *sock;
+ PACK *p;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ pp = (CNC_STATUS_PRINTER_WINDOW_PARAM *)param;
+ sock = pp->Sock;
+ pp->Thread = thread;
+ AddRef(pp->Thread->ref);
+
+ NoticeThreadInit(thread);
+
+ p = RecvPack(sock);
+ if (p != NULL)
+ {
+ // Stop the session
+ StopSessionEx(pp->Session, true);
+
+ FreePack(p);
+ }
+}
+
+// Create a status indicator client
+SOCK *CncStatusPrinterWindowStart(SESSION *s)
+{
+ SOCK *sock;
+ PACK *p;
+ THREAD *t;
+ CNC_STATUS_PRINTER_WINDOW_PARAM *param;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ sock = CncConnect();
+
+ if (sock == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "status_printer");
+ PackAddUniStr(p, "account_name", s->Account->ClientOption->AccountName);
+
+ if (SendPack(sock, p) == false)
+ {
+ FreePack(p);
+ ReleaseSock(sock);
+
+ return NULL;
+ }
+
+ FreePack(p);
+
+ param = ZeroMalloc(sizeof(CNC_STATUS_PRINTER_WINDOW_PARAM));
+ param->Sock = sock;
+ param->Session = s;
+
+ sock->Param = param;
+
+ t = NewThread(CncStatusPrinterWindowThreadProc, param);
+ WaitThreadInit(t);
+
+ ReleaseThread(t);
+
+ return sock;
+}
+
+// Send a string to the status indicator
+void CncStatusPrinterWindowPrint(SOCK *s, wchar_t *str)
+{
+ CNC_STATUS_PRINTER_WINDOW_PARAM *param;
+ PACK *p;
+ // Validate arguments
+ if (s == NULL || str == NULL)
+ {
+ return;
+ }
+
+ param = (CNC_STATUS_PRINTER_WINDOW_PARAM *)s->Param;
+
+ p = NewPack();
+ PackAddUniStr(p, "string", str);
+ SendPack(s, p);
+ FreePack(p);
+}
+
+// Stop the status indicator client
+void CncStatusPrinterWindowStop(SOCK *s)
+{
+ CNC_STATUS_PRINTER_WINDOW_PARAM *param;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ param = (CNC_STATUS_PRINTER_WINDOW_PARAM *)s->Param;
+
+ // Disconnect the client socket
+ Disconnect(s);
+
+ // Terminate the thread
+ WaitThread(param->Thread, INFINITE);
+ ReleaseThread(param->Thread);
+
+ Free(param);
+ ReleaseSock(s);
+}
+
+// Start the driver installer for Windows Vista
+bool CncExecDriverInstaller(char *arg)
+{
+ SOCK *s = CncConnect();
+ PACK *p;
+ bool ret;
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "exec_driver_installer");
+ PackAddStr(p, "arg", arg);
+
+ SendPack(s, p);
+ FreePack(p);
+
+ p = RecvPack(s);
+ if (p == NULL)
+ {
+ Disconnect(s);
+ ReleaseSock(s);
+ return false;
+ }
+
+ ret = PackGetBool(p, "ret");
+
+ FreePack(p);
+
+ Disconnect(s);
+ ReleaseSock(s);
+
+ return ret;
+}
+
+// Let the current running client notification services releasing the socket
+void CncReleaseSocket()
+{
+ SOCK *s = CncConnect();
+ PACK *p;
+ if (s == NULL)
+ {
+ return;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "release_socket");
+
+#ifdef OS_WIN32
+ PackAddInt(p, "pid", MsGetProcessId());
+#endif // OS_WIN32
+
+ SendPack(s, p);
+ FreePack(p);
+
+ Disconnect(s);
+ ReleaseSock(s);
+}
+
+// Get the Session ID of the client notification service
+UINT CncGetSessionId()
+{
+ SOCK *s = CncConnect();
+ PACK *p;
+ UINT ret;
+ if (s == NULL)
+ {
+ return INFINITE;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "get_session_id");
+
+ SendPack(s, p);
+ FreePack(p);
+
+ p = RecvPack(s);
+ if (p == NULL)
+ {
+ Disconnect(s);
+ ReleaseSock(s);
+ return INFINITE;
+ }
+
+ ret = PackGetInt(p, "session_id");
+
+ FreePack(p);
+
+ Disconnect(s);
+ ReleaseSock(s);
+
+ return ret;
+}
+
+// Terminate the process of the client notification service
+void CncExit()
+{
+ SOCK *s = CncConnectEx(256);
+ PACK *p;
+ if (s != NULL)
+ {
+ p = NewPack();
+ PackAddStr(p, "function", "exit");
+
+ SendPack(s, p);
+
+ FreePack(p);
+
+ FreePack(RecvPack(s));
+
+ Disconnect(s);
+ ReleaseSock(s);
+ }
+
+#ifdef OS_WIN32
+ MsKillOtherInstanceEx("vpnclient");
+#endif // OS_WIN32
+}
+
+// Connect to the client notification service
+SOCK *CncConnect()
+{
+ return CncConnectEx(0);
+}
+SOCK *CncConnectEx(UINT timeout)
+{
+ SOCK *s = ConnectEx("localhost", CLIENT_NOTIFY_PORT, timeout);
+
+ return s;
+}
+
+#ifdef OS_WIN32
+
+// Thread for the certificate check dialog
+void Win32CnCheckCertThreadProc(THREAD *thread, void *param)
+{
+ UI_CHECKCERT *dlg;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ dlg = (UI_CHECKCERT *)param;
+
+ CheckCertDlg(dlg);
+ {
+ PACK *p = NewPack();
+
+ PackAddBool(p, "Ok", dlg->Ok);
+ PackAddBool(p, "SaveServerCert", dlg->SaveServerCert);
+
+ SendPack(dlg->Sock, p);
+ FreePack(p);
+
+ FreePack(RecvPack(dlg->Sock));
+ }
+
+ Disconnect(dlg->Sock);
+}
+
+// Certificate check dialog
+void Win32CnCheckCert(SOCK *s, PACK *p)
+{
+ UI_CHECKCERT dlg;
+ THREAD *t;
+ Zero(&dlg, sizeof(dlg));
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackGetUniStr(p, "AccountName", dlg.AccountName, sizeof(dlg.AccountName));
+ PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName));
+ dlg.x = PackGetX(p, "x");
+ dlg.parent_x = PackGetX(p, "parent_x");
+ dlg.old_x = PackGetX(p, "old_x");
+ dlg.DiffWarning = PackGetBool(p, "DiffWarning");
+ dlg.Ok = PackGetBool(p, "Ok");
+ dlg.SaveServerCert = PackGetBool(p, "SaveServerCert");
+ dlg.Sock = s;
+
+ t = NewThread(Win32CnCheckCertThreadProc, &dlg);
+
+ FreePack(RecvPack(s));
+
+ dlg.Halt = true;
+
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+
+ FreeX(dlg.parent_x);
+ FreeX(dlg.old_x);
+ FreeX(dlg.x);
+}
+
+// Message display dialog thread procedure
+void Win32CnMsgDlgThreadProc(THREAD *thread, void *param)
+{
+ UI_MSG_DLG *dlg = (UI_MSG_DLG *)param;
+ wchar_t tmp[MAX_SIZE];
+ char url[MAX_SIZE];
+ // Validate arguments
+ if (thread == NULL || dlg == NULL)
+ {
+ return;
+ }
+
+ UniFormat(tmp, sizeof(tmp), _UU("CM_MSG_TITLE"),
+ dlg->ServerName, dlg->HubName);
+
+ if (IsURLMsg(dlg->Msg, url, sizeof(url)) == false)
+ {
+ OnceMsgEx(NULL, tmp, dlg->Msg, true, 167, &dlg->Halt);
+ }
+ else
+ {
+ if (MsExecute(url, NULL) == false)
+ {
+ OnceMsgEx(NULL, tmp, dlg->Msg, true, 167, &dlg->Halt);
+ }
+ }
+
+ Disconnect(dlg->Sock);
+}
+
+// NIC information dialog thread procedure
+void Win32CnNicInfoThreadProc(THREAD *thread, void *param)
+{
+ UI_NICINFO *info = (UI_NICINFO *)param;
+ // Validate arguments
+ if (thread == NULL || info == NULL)
+ {
+ return;
+ }
+
+ if (MsIsNt())
+ {
+ // Do not show a dialog on Windows 9x system
+ NicInfo(info);
+ }
+
+ Disconnect(info->Sock);
+}
+
+// NIC information dialog
+void Win32CnNicInfo(SOCK *s, PACK *p)
+{
+ UI_NICINFO info;
+ THREAD *t;
+ Zero(&info, sizeof(info));
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackGetStr(p, "NicName", info.NicName, sizeof(info.NicName));
+ PackGetUniStr(p, "AccountName", info.AccountName, sizeof(info.AccountName));
+
+ info.Sock = s;
+
+ t = NewThread(Win32CnNicInfoThreadProc, &info);
+
+ FreePack(RecvPack(s));
+
+ info.Halt = true;
+
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+}
+
+// Message display dialog
+void Win32CnMsgDlg(SOCK *s, PACK *p)
+{
+ UI_MSG_DLG dlg;
+ THREAD *t;
+ UINT utf_size;
+ char *utf;
+ wchar_t *msg;
+ Zero(&dlg, sizeof(dlg));
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName));
+ PackGetStr(p, "HubName", dlg.HubName, sizeof(dlg.HubName));
+
+ utf_size = PackGetDataSize(p, "Msg");
+ utf = ZeroMalloc(utf_size + 8);
+
+ PackGetData(p, "Msg", utf);
+
+ msg = CopyUtfToUni(utf);
+ Free(utf);
+
+ dlg.Sock = s;
+ dlg.Msg = msg;
+
+ t = NewThread(Win32CnMsgDlgThreadProc, &dlg);
+
+ FreePack(RecvPack(s));
+
+ dlg.Halt = true;
+
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+
+ Free(msg);
+}
+
+// Thread for Password input dialog
+void Win32CnPasswordDlgThreadProc(THREAD *thread, void *param)
+{
+ UI_PASSWORD_DLG *dlg;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ dlg = (UI_PASSWORD_DLG *)param;
+
+ if (PasswordDlg(NULL, dlg))
+ {
+ PACK *p = NewPack();
+
+ PackAddBool(p, "ok", true);
+ PackAddStr(p, "Username", dlg->Username);
+ PackAddStr(p, "Password", dlg->Password);
+ PackAddInt(p, "Type", dlg->Type);
+ PackAddBool(p, "ProxyServer", dlg->ProxyServer);
+ PackAddBool(p, "NoSavePassword", dlg->NoSavePassword);
+
+ SendPack(dlg->Sock, p);
+ FreePack(p);
+
+ FreePack(RecvPack(dlg->Sock));
+ }
+
+ Disconnect(dlg->Sock);
+}
+
+// Password input dialog
+void Win32CnPasswordDlg(SOCK *s, PACK *p)
+{
+ UI_PASSWORD_DLG dlg;
+ THREAD *t = NULL;
+ Zero(&dlg, sizeof(dlg));
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ dlg.Type = PackGetInt(p, "Type");
+ PackGetStr(p, "Username", dlg.Username, sizeof(dlg.Username));
+ PackGetStr(p, "Password", dlg.Password, sizeof(dlg.Password));
+ PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName));
+ dlg.RetryIntervalSec = PackGetInt(p, "RetryIntervalSec");
+ dlg.ProxyServer = PackGetBool(p, "ProxyServer");
+ dlg.AdminMode = PackGetBool(p, "AdminMode");
+ dlg.ShowNoSavePassword = PackGetBool(p, "ShowNoSavePassword");
+ dlg.NoSavePassword = PackGetBool(p, "NoSavePassword");
+ dlg.CancelEvent = NewEvent();
+ dlg.Sock = s;
+
+ t = NewThread(Win32CnPasswordDlgThreadProc, &dlg);
+
+ FreePack(RecvPack(s));
+
+ Set(dlg.CancelEvent);
+
+ WaitThread(t, INFINITE);
+ ReleaseEvent(dlg.CancelEvent);
+ ReleaseThread(t);
+}
+
+// Thread for the connection error dialog
+void Win32CnConnectErrorDlgThreadProc(THREAD *thread, void *param)
+{
+ UI_CONNECTERROR_DLG *dlg;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ dlg = (UI_CONNECTERROR_DLG *)param;
+
+ if (ConnectErrorDlg(dlg))
+ {
+ PACK *p = NewPack();
+
+ PackAddBool(p, "ok", true);
+ PackAddBool(p, "HideWindow", dlg->HideWindow);
+
+ SendPack(dlg->Sock, p);
+ FreePack(p);
+
+ FreePack(RecvPack(dlg->Sock));
+ }
+
+ Disconnect(dlg->Sock);
+}
+
+// Connection Error dialog (Win32)
+void Win32CnConnectErrorDlg(SOCK *s, PACK *p)
+{
+ UI_CONNECTERROR_DLG dlg;
+ THREAD *t;
+ Zero(&dlg, sizeof(dlg));
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackGetUniStr(p, "AccountName", dlg.AccountName, sizeof(dlg.AccountName));
+ PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName));
+ dlg.Err = PackGetInt(p, "Err");
+ dlg.CurrentRetryCount = PackGetInt(p, "CurrentRetryCount");
+ dlg.RetryLimit = PackGetInt(p, "RetryLimit");
+ dlg.RetryIntervalSec = PackGetInt(p, "RetryIntervalSec");
+ dlg.HideWindow = PackGetBool(p, "HideWindow");
+ dlg.CancelEvent = NewEvent();
+ dlg.Sock = s;
+
+ t = NewThread(Win32CnConnectErrorDlgThreadProc, &dlg);
+
+ FreePack(RecvPack(s));
+
+ Set(dlg.CancelEvent);
+
+ WaitThread(t, INFINITE);
+ ReleaseEvent(dlg.CancelEvent);
+ ReleaseThread(t);
+}
+
+// Status indicator (Win32)
+void Win32CnStatusPrinter(SOCK *s, PACK *p)
+{
+ STATUS_WINDOW *w;
+ wchar_t account_name[MAX_ACCOUNT_NAME_LEN + 1];
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackGetUniStr(p, "account_name", account_name, sizeof(account_name));
+
+ w = StatusPrinterWindowStart(s, account_name);
+
+ while (true)
+ {
+ PACK *p = RecvPack(s);
+
+ if (p == NULL)
+ {
+ // Exit the dialog because it is disconnected
+ break;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ // Rewrite the string
+ PackGetUniStr(p, "string", tmp, sizeof(tmp));
+
+ StatusPrinterWindowPrint(w, tmp);
+
+ FreePack(p);
+ }
+ }
+
+ StatusPrinterWindowStop(w);
+}
+
+// Start the driver installer (for Windows Vista)
+void Win32CnExecDriverInstaller(SOCK *s, PACK *p)
+{
+ char arg[MAX_SIZE];
+ bool ret;
+ void *helper = NULL;
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (PackGetStr(p, "arg", arg, sizeof(arg)) == false)
+ {
+ return;
+ }
+
+ if (MsIsVista())
+ {
+ helper = CmStartUacHelper();
+ }
+
+ ret = MsExecDriverInstaller(arg);
+
+ CmStopUacHelper(helper);
+
+ p = NewPack();
+ PackAddBool(p, "ret", ret);
+ SendPack(s, p);
+
+ FreePack(p);
+}
+
+#endif // OS_WIN32
+
+// Start the driver installer
+void CnExecDriverInstaller(SOCK *s, PACK *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ Win32CnExecDriverInstaller(s, p);
+#endif // OS_WIN32
+}
+
+// Certificate confirmation dialog
+void CnCheckCert(SOCK *s, PACK *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ Win32CnCheckCert(s, p);
+#endif // OS_WIN32
+}
+
+// NIC information dialog
+void CnNicInfo(SOCK *s, PACK *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ Win32CnNicInfo(s, p);
+#endif // OS_WIN32
+}
+
+// Message display dialog
+void CnMsgDlg(SOCK *s, PACK *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ Win32CnMsgDlg(s, p);
+#endif // OS_WIN32
+}
+
+// Password input dialog
+void CnPasswordDlg(SOCK *s, PACK *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ Win32CnPasswordDlg(s, p);
+#endif // OS_WIN32
+}
+
+// Connection Error dialog
+void CnConnectErrorDlg(SOCK *s, PACK *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ Win32CnConnectErrorDlg(s, p);
+#endif // OS_WIN32
+}
+
+// Status indicator
+void CnStatusPrinter(SOCK *s, PACK *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ Win32CnStatusPrinter(s, p);
+#endif // OS_WIN32
+}
+// Client notification service listener thread
+void CnListenerProc(THREAD *thread, void *param)
+{
+ TCP_ACCEPTED_PARAM *data = (TCP_ACCEPTED_PARAM *)param;
+ SOCK *s;
+ PACK *p;
+ // Validate arguments
+ if (data == NULL || thread == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ //Set Application ID
+ JL_SetCurrentProcessExplicitAppUserModelID(APPID_CM);
+#endif // OS_WIN32
+
+ s = data->s;
+ AddRef(s->ref);
+ NoticeThreadInit(thread);
+
+ if (s->LocalIP.addr[0] == 127)
+ {
+ p = RecvPack(s);
+
+ if (p != NULL)
+ {
+ char function[MAX_SIZE];
+
+ if (PackGetStr(p, "function", function, sizeof(function)))
+ {
+ if (StrCmpi(function, "status_printer") == 0)
+ {
+ CnStatusPrinter(s, p);
+ }
+ else if (StrCmpi(function, "connecterror_dialog") == 0)
+ {
+ CnConnectErrorDlg(s, p);
+ }
+ else if (StrCmpi(function, "msg_dialog") == 0)
+ {
+ CnMsgDlg(s, p);
+ }
+ else if (StrCmpi(function, "nicinfo") == 0)
+ {
+ CnNicInfo(s, p);
+ }
+ else if (StrCmpi(function, "password_dialog") == 0)
+ {
+ CnPasswordDlg(s, p);
+ }
+ else if (StrCmpi(function, "secure_sign") == 0)
+ {
+ CnSecureSign(s, p);
+ }
+ else if (StrCmpi(function, "check_cert") == 0)
+ {
+ CnCheckCert(s, p);
+ }
+ else if (StrCmpi(function, "exit") == 0)
+ {
+#ifdef OS_WIN32
+ MsTerminateProcess();
+#else // OS_WIN32
+ _exit(0);
+#endif // OS_WIN32
+ }
+ else if (StrCmpi(function, "get_session_id") == 0)
+ {
+ PACK *p = NewPack();
+#ifdef OS_WIN32
+ PackAddInt(p, "session_id", MsGetCurrentTerminalSessionId());
+#endif // OS_WIN32
+ SendPack(s, p);
+ FreePack(p);
+ }
+ else if (StrCmpi(function, "exec_driver_installer") == 0)
+ {
+ CnExecDriverInstaller(s, p);
+ }
+ else if (StrCmpi(function, "release_socket") == 0)
+ {
+ // Stop the listener
+ CnReleaseSocket(s, p);
+ }
+ }
+
+ FreePack(p);
+ }
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+}
+
+// Do the Secure Sign
+void CnSecureSign(SOCK *s, PACK *p)
+{
+ SECURE_SIGN sign;
+ bool ret = false;
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(&sign, sizeof(sign));
+ InRpcSecureSign(&sign, p);
+
+#ifdef OS_WIN32
+ // Win32: Show dialog
+ ret = Win32CiSecureSign(&sign);
+#else // OS_WIN32
+ // UNIX: not implemented
+ ret = false;
+#endif // OS_WIN32
+
+ p = NewPack();
+
+ OutRpcSecureSign(p, &sign);
+ FreeRpcSecureSign(&sign);
+
+ PackAddBool(p, "ret", ret);
+
+ SendPack(s, p);
+ FreePack(p);
+}
+
+// Stop the listener
+void CnReleaseSocket(SOCK *s, PACK *p)
+{
+ UINT pid = 0;
+ UINT current_pid = 0;
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ pid = PackGetInt(p, "pid");
+
+#ifdef OS_WIN32
+ current_pid = MsGetProcessId();
+#endif // OS_WIN32
+
+ if (current_pid == pid)
+ {
+ return;
+ }
+
+ Lock(cn_listener_lock);
+ {
+ if (cn_listener != NULL)
+ {
+ if (cn_listener->Halt == false)
+ {
+ StopListener(cn_listener);
+
+ cn_next_allow = Tick64() + (6 * 1000);
+ }
+ }
+ }
+ Unlock(cn_listener_lock);
+}
+
+// Start the client notification service
+void CnStart()
+{
+ CEDAR *cedar;
+ LISTENER *o;
+ UINT last_cursor_hash = 0;
+ bool last_session_active = false;
+
+ cn_next_allow = 0;
+ cn_listener_lock = NewLock();
+
+#ifdef OS_WIN32
+ MsSetShutdownParameters(0xff, 0x00000001);
+ InitWinUi(_UU("CN_TITLE"), _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+#endif // OS_WIN32
+
+ cedar = NewCedar(NULL, NULL);
+
+ if (CnCheckAlreadyExists(true))
+ {
+ // Already started
+ ReleaseCedar(cedar);
+#ifdef OS_WIN32
+ FreeWinUi();
+#endif // OS_WIN32
+ return;
+ }
+
+#ifdef OS_WIN32
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY,
+ "NotifyServerProcessId", MsGetProcessId());
+#endif // OS_WIN32
+
+ DisableDosProtect();
+
+BEGIN_LISTENER:
+ Lock(cn_listener_lock);
+ cn_listener = o = NewListenerEx(cedar, LISTENER_TCP, CLIENT_NOTIFY_PORT, CnListenerProc, NULL);
+ Unlock(cn_listener_lock);
+
+ while (true)
+ {
+ UINT current_cursor_hash = 0;
+ bool cursor_changed = false;
+
+#ifdef OS_WIN32
+ // Get the current cursor position
+ current_cursor_hash = MsGetCursorPosHash();
+#endif // OS_WIN32
+
+ if (last_cursor_hash != current_cursor_hash)
+ {
+ // Check the cursor position
+ cursor_changed = true;
+ last_cursor_hash = current_cursor_hash;
+ }
+
+ Lock(cn_listener_lock);
+
+ // Check the status periodically after that the listener has started
+ if (cn_listener->Status == LISTENER_STATUS_TRYING || cn_listener->Halt)
+ {
+ bool session_active = false;
+#ifdef OS_WIN32
+ session_active = MsIsCurrentTerminalSessionActive();
+ if (cursor_changed)
+ {
+ // If the cursor position is changed but the terminal session is
+ // not active, the cursor position is regarded as not changed.
+ if (session_active == false)
+ {
+ cursor_changed = false;
+ }
+ }
+ if (last_session_active != session_active)
+ {
+ //If the cursor position doesn't changed but the terminal session
+ // became active than previous, the cursor position is regarded as changed.
+ last_session_active = session_active;
+
+ if (session_active)
+ {
+ cursor_changed = true;
+ }
+ }
+#endif // OS_WIN32
+
+ // If the port cannot be opened
+ if (cn_next_allow <= Tick64())
+ {
+ if (cursor_changed || cn_listener->Halt)
+ {
+ if (cursor_changed)
+ {
+ // It can be judged to have the rights to open the port
+ // since the mouse cursor is moving.
+ // So, take over the port which is owned by other process forcibly
+ CncReleaseSocket();
+ }
+
+ if (cn_listener->Halt)
+ {
+ ReleaseListener(cn_listener);
+ cn_listener = NULL;
+
+ Unlock(cn_listener_lock);
+ goto BEGIN_LISTENER;
+ }
+ }
+ }
+ }
+
+ Unlock(cn_listener_lock);
+
+ SleepThread(1000);
+ }
+}
+
+// Confirm whether the account file is parsed successfully
+bool CiTryToParseAccount(BUF *b)
+{
+ RPC_CLIENT_CREATE_ACCOUNT *a;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return false;
+ }
+
+ a = CiCfgToAccount(b);
+ if (a != NULL)
+ {
+ CiFreeClientCreateAccount(a);
+ Free(a);
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+bool CiTryToParseAccountFile(wchar_t *name)
+{
+ bool ret;
+ BUF *b;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return false;
+ }
+
+ b = ReadDumpW(name);
+ if (b == NULL)
+ {
+ return false;
+ }
+
+ ret = CiTryToParseAccount(b);
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Confirm whether the account information includes sensitive information
+bool CiHasAccountSensitiveInformation(BUF *b)
+{
+ RPC_CLIENT_CREATE_ACCOUNT *a;
+ bool ret = false;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return false;
+ }
+
+ a = CiCfgToAccount(b);
+ if (a == NULL)
+ {
+ return false;
+ }
+
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_PASSWORD)
+ {
+ ret = true;
+ }
+ else if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_PLAIN_PASSWORD)
+ {
+ ret = true;
+ }
+
+ CiFreeClientCreateAccount(a);
+ Free(a);
+
+ return ret;
+}
+bool CiHasAccountSensitiveInformationFile(wchar_t *name)
+{
+ bool ret = false;
+ BUF *b;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return false;
+ }
+
+ b = ReadDumpW(name);
+ if (b == NULL)
+ {
+ return false;
+ }
+
+ ret = CiHasAccountSensitiveInformation(b);
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Delete the sensitive information in the account information
+bool CiEraseSensitiveInAccount(BUF *b)
+{
+ RPC_CLIENT_CREATE_ACCOUNT *a;
+ BUF *b2;
+ bool ret = false;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return false;
+ }
+
+ a = CiCfgToAccount(b);
+ if (a == NULL)
+ {
+ return false;
+ }
+
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_PASSWORD)
+ {
+ Zero(a->ClientAuth->HashedPassword, sizeof(a->ClientAuth->HashedPassword));
+ ClearStr(a->ClientAuth->Username, sizeof(a->ClientAuth->Username));
+ }
+ else if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_PLAIN_PASSWORD)
+ {
+ ClearStr(a->ClientAuth->PlainPassword, sizeof(a->ClientAuth->PlainPassword));
+ ClearStr(a->ClientAuth->Username, sizeof(a->ClientAuth->Username));
+ }
+
+ b2 = CiAccountToCfg(a);
+ if (b2 != NULL)
+ {
+ ret = true;
+
+ ClearBuf(b);
+
+ WriteBuf(b, b2->Buf, b2->Size);
+ SeekBuf(b, 0, 0);
+
+ FreeBuf(b2);
+ }
+
+ CiFreeClientCreateAccount(a);
+ Free(a);
+
+ return ret;
+}
+
+// Read the account information from the buffer
+RPC_CLIENT_CREATE_ACCOUNT *CiCfgToAccount(BUF *b)
+{
+ RPC_CLIENT_CREATE_ACCOUNT *t;
+ FOLDER *f;
+ ACCOUNT *a;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return NULL;
+ }
+
+ f = CfgBufTextToFolder(b);
+ if (f == NULL)
+ {
+ return NULL;
+ }
+
+ a = CiLoadClientAccount(f);
+
+ CfgDeleteFolder(f);
+
+ if (a == NULL)
+ {
+ return NULL;
+ }
+
+ DeleteLock(a->lock);
+
+ t = ZeroMalloc(sizeof(RPC_CLIENT_CREATE_ACCOUNT));
+ t->ClientOption = a->ClientOption;
+ t->ClientAuth = a->ClientAuth;
+ t->StartupAccount = a->StartupAccount;
+ t->CheckServerCert = a->CheckServerCert;
+ t->ServerCert = a->ServerCert;
+ Free(a);
+
+ return t;
+}
+
+// Write the account information to a buffer
+BUF *CiAccountToCfg(RPC_CLIENT_CREATE_ACCOUNT *t)
+{
+ BUF *b;
+ FOLDER *root;
+ ACCOUNT a;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ root = CfgCreateFolder(NULL, TAG_ROOT);
+ Zero(&a, sizeof(a));
+ a.ClientOption = t->ClientOption;
+ a.ClientAuth = t->ClientAuth;
+ a.CheckServerCert = t->CheckServerCert;
+ a.ServerCert = t->ServerCert;
+ a.StartupAccount = t->StartupAccount;
+
+ CiWriteAccountData(root, &a);
+
+ b = CfgFolderToBufEx(root, true, true);
+ CfgDeleteFolder(root);
+
+ return b;
+}
+
+// RPC dispatch routine
+PACK *CiRpcDispatch(RPC *rpc, char *name, PACK *p)
+{
+ CLIENT *c = rpc->Param;
+ PACK *ret;
+ // Validate arguments
+ if (rpc == NULL || name == NULL || p == NULL)
+ {
+ return NULL;
+ }
+
+ ret = NewPack();
+
+ if (StrCmpi(name, "GetClientVersion") == 0)
+ {
+ RPC_CLIENT_VERSION a;
+ if (CtGetClientVersion(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientVersion(ret, &a);
+ }
+ }
+ else if (StrCmpi(name, "GetCmSetting") == 0)
+ {
+ CM_SETTING a;
+ if (CtGetCmSetting(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcCmSetting(ret, &a);
+ }
+ }
+ else if (StrCmpi(name, "SetCmSetting") == 0)
+ {
+ CM_SETTING a;
+ Zero(&a, sizeof(a));
+ InRpcCmSetting(&a, p);
+ if (CtSetCmSetting(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "SetPassword") == 0)
+ {
+ RPC_CLIENT_PASSWORD a;
+ InRpcClientPassword(&a, p);
+ if (CtSetPassword(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "GetPasswordSetting") == 0)
+ {
+ RPC_CLIENT_PASSWORD_SETTING a;
+ if (CtGetPasswordSetting(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientPasswordSetting(ret, &a);
+ }
+ }
+ else if (StrCmpi(name, "EnumCa") == 0)
+ {
+ RPC_CLIENT_ENUM_CA a;
+ if (CtEnumCa(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientEnumCa(ret, &a);
+ CiFreeClientEnumCa(&a);
+ }
+ }
+ else if (StrCmpi(name, "AddCa") == 0)
+ {
+ RPC_CERT a;
+ InRpcCert(&a, p);
+ if (CtAddCa(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ FreeX(a.x);
+ }
+ else if (StrCmpi(name, "DeleteCa") == 0)
+ {
+ RPC_CLIENT_DELETE_CA a;
+ InRpcClientDeleteCa(&a, p);
+ if (CtDeleteCa(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "GetCa") == 0)
+ {
+ RPC_GET_CA a;
+ InRpcGetCa(&a, p);
+ if (CtGetCa(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcGetCa(ret, &a);
+ }
+ CiFreeGetCa(&a);
+ }
+ else if (StrCmpi(name, "EnumSecure") == 0)
+ {
+ RPC_CLIENT_ENUM_SECURE a;
+ if (CtEnumSecure(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientEnumSecure(ret, &a);
+ CiFreeClientEnumSecure(&a);
+ }
+ }
+ else if (StrCmpi(name, "UseSecure") == 0)
+ {
+ RPC_USE_SECURE a;
+ InRpcUseSecure(&a, p);
+ if (CtUseSecure(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "GetUseSecure") == 0)
+ {
+ RPC_USE_SECURE a;
+ Zero(&a, sizeof(a));
+ if (CtGetUseSecure(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcUseSecure(ret, &a);
+ }
+ }
+ else if (StrCmpi(name, "EnumObjectInSecure") == 0)
+ {
+ RPC_ENUM_OBJECT_IN_SECURE a;
+ if (CtEnumObjectInSecure(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcEnumObjectInSecure(ret, &a);
+ CiFreeEnumObjectInSecure(&a);
+ }
+ }
+ else if (StrCmpi(name, "CreateVLan") == 0)
+ {
+ RPC_CLIENT_CREATE_VLAN a;
+ InRpcCreateVLan(&a, p);
+ if (CtCreateVLan(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "UpgradeVLan") == 0)
+ {
+ RPC_CLIENT_CREATE_VLAN a;
+ InRpcCreateVLan(&a, p);
+ if (CtUpgradeVLan(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "GetVLan") == 0)
+ {
+ RPC_CLIENT_GET_VLAN a;
+ InRpcClientGetVLan(&a, p);
+ if (CtGetVLan(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientGetVLan(ret, &a);
+ }
+ }
+ else if (StrCmpi(name, "SetVLan") == 0)
+ {
+ RPC_CLIENT_SET_VLAN a;
+ InRpcClientSetVLan(&a, p);
+ if (CtSetVLan(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "EnumVLan") == 0)
+ {
+ RPC_CLIENT_ENUM_VLAN a;
+ if (CtEnumVLan(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientEnumVLan(ret, &a);
+ CiFreeClientEnumVLan(&a);
+ }
+ }
+ else if (StrCmpi(name, "DeleteVLan") == 0)
+ {
+ RPC_CLIENT_CREATE_VLAN a;
+ InRpcCreateVLan(&a, p);
+ if (CtDeleteVLan(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "EnableVLan") == 0)
+ {
+ RPC_CLIENT_CREATE_VLAN a;
+ InRpcCreateVLan(&a, p);
+ if (CtEnableVLan(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "DisableVLan") == 0)
+ {
+ RPC_CLIENT_CREATE_VLAN a;
+ InRpcCreateVLan(&a, p);
+ if (CtDisableVLan(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "CreateAccount") == 0)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT a;
+ InRpcClientCreateAccount(&a, p);
+ if (CtCreateAccount(c, &a, false) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ CiFreeClientCreateAccount(&a);
+ }
+ else if (StrCmpi(name, "EnumAccount") == 0)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT a;
+ if (CtEnumAccount(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientEnumAccount(ret, &a);
+ CiFreeClientEnumAccount(&a);
+ }
+ }
+ else if (StrCmpi(name, "DeleteAccount") == 0)
+ {
+ RPC_CLIENT_DELETE_ACCOUNT a;
+ InRpcClientDeleteAccount(&a, p);
+ if (CtDeleteAccount(c, &a, false) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "SetStartupAccount") == 0)
+ {
+ RPC_CLIENT_DELETE_ACCOUNT a;
+ InRpcClientDeleteAccount(&a, p);
+ if (CtSetStartupAccount(c, &a, false) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "RemoveStartupAccount") == 0)
+ {
+ RPC_CLIENT_DELETE_ACCOUNT a;
+ InRpcClientDeleteAccount(&a, p);
+ if (CtRemoveStartupAccount(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "GetIssuer") == 0)
+ {
+ RPC_GET_ISSUER a;
+ InRpcGetIssuer(&a, p);
+ if (CtGetIssuer(c, &a))
+ {
+ OutRpcGetIssuer(ret, &a);
+ }
+ else
+ {
+ RpcError(ret, c->Err);
+ }
+ CiFreeGetIssuer(&a);
+ }
+ else if (StrCmpi(name, "GetCommonProxySetting") == 0)
+ {
+ INTERNET_SETTING t;
+ InRpcInternetSetting(&t, p);
+ if (CtGetCommonProxySetting(c, &t))
+ {
+ OutRpcInternetSetting(ret, &t);
+ }
+ else
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "SetCommonProxySetting") == 0)
+ {
+ INTERNET_SETTING t;
+ InRpcInternetSetting(&t, p);
+ if (CtSetCommonProxySetting(c, &t))
+ {
+ OutRpcInternetSetting(ret, &t);
+ }
+ else
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "SetAccount") == 0)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT a;
+ InRpcClientCreateAccount(&a, p);
+ if (CtSetAccount(c, &a, false) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ CiFreeClientCreateAccount(&a);
+ }
+ else if (StrCmpi(name, "GetAccount") == 0)
+ {
+ RPC_CLIENT_GET_ACCOUNT a;
+ InRpcClientGetAccount(&a, p);
+ if (CtGetAccount(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientGetAccount(ret, &a);
+ }
+ CiFreeClientGetAccount(&a);
+ }
+ else if (StrCmpi(name, "RenameAccount") == 0)
+ {
+ RPC_RENAME_ACCOUNT a;
+ InRpcRenameAccount(&a, p);
+ if (CtRenameAccount(c, &a, false) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "SetClientConfig") == 0)
+ {
+ CLIENT_CONFIG a;
+ InRpcClientConfig(&a, p);
+ if (CtSetClientConfig(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "GetClientConfig") == 0)
+ {
+ CLIENT_CONFIG a;
+ if (CtGetClientConfig(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientConfig(ret, &a);
+ }
+ }
+ else if (StrCmpi(name, "Connect") == 0)
+ {
+ RPC_CLIENT_CONNECT a;
+ InRpcClientConnect(&a, p);
+ if (CtConnect(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "Disconnect") == 0)
+ {
+ RPC_CLIENT_CONNECT a;
+ InRpcClientConnect(&a, p);
+ if (CtDisconnect(c, &a, false) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "GetAccountStatus") == 0)
+ {
+ RPC_CLIENT_GET_CONNECTION_STATUS a;
+ InRpcClientGetConnectionStatus(&a, p);
+ if (CtGetAccountStatus(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientGetConnectionStatus(ret, &a);
+ }
+ CiFreeClientGetConnectionStatus(&a);
+ }
+ else
+ {
+ FreePack(ret);
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+// Set the CM_SETTING
+UINT CcSetCmSetting(REMOTE_CLIENT *r, CM_SETTING *a)
+{
+ PACK *ret, *p;
+ UINT err;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcCmSetting(p, a);
+
+ ret = RpcCall(r->Rpc, "SetCmSetting", p);
+
+ if (RpcIsOk(ret))
+ {
+ FreePack(ret);
+ return 0;
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ FreePack(ret);
+ return err;
+ }
+}
+
+// Get the CM_SETTING
+UINT CcGetCmSetting(REMOTE_CLIENT *r, CM_SETTING *a)
+{
+ PACK *ret;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = RpcCall(r->Rpc, "GetCmSetting", NULL);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcCmSetting(a, ret);
+ FreePack(ret);
+ return 0;
+ }
+ else
+ {
+ UINT err = RpcGetError(ret);
+ FreePack(ret);
+ return err;
+ }
+}
+
+// Get the client version
+UINT CcGetClientVersion(REMOTE_CLIENT *r, RPC_CLIENT_VERSION *a)
+{
+ PACK *ret;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = RpcCall(r->Rpc, "GetClientVersion", NULL);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcClientVersion(a, ret);
+ FreePack(ret);
+ return 0;
+ }
+ else
+ {
+ UINT err = RpcGetError(ret);
+ FreePack(ret);
+ return err;
+ }
+}
+
+// Set the password
+UINT CcSetPassword(REMOTE_CLIENT *r, RPC_CLIENT_PASSWORD *pass)
+{
+ PACK *ret, *p;
+ // Validate arguments
+ if (r == NULL || pass == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+
+ OutRpcClientPassword(p, pass);
+
+ ret = RpcCall(r->Rpc, "SetPassword", p);
+
+ if (RpcIsOk(ret))
+ {
+ FreePack(ret);
+ return 0;
+ }
+ else
+ {
+ UINT err = RpcGetError(ret);
+ FreePack(ret);
+ return err;
+ }
+}
+
+// Get the password setting
+UINT CcGetPasswordSetting(REMOTE_CLIENT *r, RPC_CLIENT_PASSWORD_SETTING *a)
+{
+ PACK *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = RpcCall(r->Rpc, "GetPasswordSetting", NULL);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcClientPasswordSetting(a, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+ return err;
+}
+
+// Enumerate the CA
+UINT CcEnumCa(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_CA *e)
+{
+ PACK *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || e == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = RpcCall(r->Rpc, "EnumCa", NULL);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcClientEnumCa(e, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Add the CA
+UINT CcAddCa(REMOTE_CLIENT *r, RPC_CERT *cert)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || cert == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcCert(p, cert);
+
+ ret = RpcCall(r->Rpc, "AddCa", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Delete the CA
+UINT CcDeleteCa(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_CA *c)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || c == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientDeleteCa(p, c);
+
+ ret = RpcCall(r->Rpc, "DeleteCa", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+
+// Get the proxy setting
+UINT CcGetCommonProxySetting(REMOTE_CLIENT *r, INTERNET_SETTING *a)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcInternetSetting(p, a);
+
+ ret = RpcCall(r->Rpc, "GetCommonProxySetting", p);
+
+ if (RpcIsOk(ret))
+ {
+ Zero(a, sizeof(INTERNET_SETTING));
+ InRpcInternetSetting(a, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Set the proxy setting
+UINT CcSetCommonProxySetting(REMOTE_CLIENT *r, INTERNET_SETTING *a)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcInternetSetting(p, a);
+
+ ret = RpcCall(r->Rpc, "SetCommonProxySetting", p);
+
+ if (RpcIsOk(ret))
+ {
+ Zero(a, sizeof(INTERNET_SETTING));
+ InRpcInternetSetting(a, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Get the issuer
+UINT CcGetIssuer(REMOTE_CLIENT *r, RPC_GET_ISSUER *a)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcGetIssuer(p, a);
+
+ ret = RpcCall(r->Rpc, "GetIssuer", p);
+
+ if (RpcIsOk(ret))
+ {
+ if (a->x != NULL)
+ {
+ FreeX(a->x);
+ a->x = NULL;
+ }
+ InRpcGetIssuer(a, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Get the CA
+UINT CcGetCa(REMOTE_CLIENT *r, RPC_GET_CA *get)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || get == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcGetCa(p, get);
+
+ ret = RpcCall(r->Rpc, "GetCa", p);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcGetCa(get, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Enumeration of the secure devices
+UINT CcEnumSecure(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_SECURE *e)
+{
+ PACK *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || e == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = RpcCall(r->Rpc, "EnumSecure", NULL);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcClientEnumSecure(e, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Get the secure device that the user is using
+UINT CcGetUseSecure(REMOTE_CLIENT *r, RPC_USE_SECURE *sec)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || sec == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+
+ ret = RpcCall(r->Rpc, "GetUseSecure", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+ else
+ {
+ InRpcUseSecure(sec, ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Use the secure device
+UINT CcUseSecure(REMOTE_CLIENT *r, RPC_USE_SECURE *sec)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || sec == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcUseSecure(p, sec);
+
+ ret = RpcCall(r->Rpc, "UseSecure", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Enumerate objects in the secure device
+UINT CcEnumObjectInSecure(REMOTE_CLIENT *r, RPC_ENUM_OBJECT_IN_SECURE *e)
+{
+ PACK *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || e == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = RpcCall(r->Rpc, "EnumObjectInSecure", NULL);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcEnumObjectInSecure(e, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Get a next recommended virtual LAN card name
+bool CiGetNextRecommendedVLanName(REMOTE_CLIENT *r, char *name, UINT size)
+{
+ RPC_CLIENT_ENUM_VLAN t;
+ UINT i;
+ bool b;
+ UINT j;
+ bool ok = false;
+ // Validate arguments
+ if (r == NULL || name == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+
+ if (CcEnumVLan(r, &t) != ERR_NO_ERROR)
+ {
+ return false;
+ }
+
+ for (i = 1;i < 128;i++)
+ {
+ char tmp[MAX_SIZE];
+
+ CiGenerateVLanRegulatedName(tmp, sizeof(tmp), i);
+
+ b = false;
+
+ for (j = 0;j < t.NumItem;j++)
+ {
+ if (StrCmpi(t.Items[j]->DeviceName, tmp) == 0)
+ {
+ b = true;
+ break;
+ }
+ }
+
+ if (b == false)
+ {
+ ok = true;
+
+ StrCpy(name, size, tmp);
+ break;
+ }
+ }
+
+ if (ok)
+ {
+ CiFreeClientEnumVLan(&t);
+ }
+
+ return true;
+}
+
+// Generate a virtual LAN card name automatically
+void CiGenerateVLanRegulatedName(char *name, UINT size, UINT i)
+{
+ // Validate arguments
+ if (name == NULL)
+ {
+ return;
+ }
+
+ if (i == 1)
+ {
+ StrCpy(name, size, "VPN");
+ }
+ else
+ {
+ Format(name, size, "VPN%u", i);
+ }
+}
+
+// Examine whether the specified name is valid as a virtual LAN card name of Windows 8 and later?
+bool CiIsValidVLanRegulatedName(char *name)
+{
+ UINT i;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return false;
+ }
+
+ for (i = 1;i < 128;i++)
+ {
+ char tmp[MAX_SIZE];
+
+ CiGenerateVLanRegulatedName(tmp, sizeof(tmp), i);
+
+ if (StrCmpi(name, tmp) == 0)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Create a VLAN
+UINT CcCreateVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *create)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ char *s = NULL;
+ // Validate arguments
+ if (r == NULL || create == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcCreateVLan(p, create);
+
+#ifdef OS_WIN32
+ s = MsNoWarningSoundInit();
+#endif // OS_WIN32
+
+ ret = RpcCall(r->Rpc, "CreateVLan", p);
+
+#ifdef OS_WIN32
+ MsNoWarningSoundFree(s);
+#endif // OS_WIN32
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Upgrade the VLAN
+UINT CcUpgradeVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *create)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ char *s = NULL;
+ // Validate arguments
+ if (r == NULL || create == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcCreateVLan(p, create);
+
+#ifdef OS_WIN32
+ s = MsNoWarningSoundInit();
+#endif // OS_WIN32
+
+ ret = RpcCall(r->Rpc, "UpgradeVLan", p);
+
+#ifdef OS_WIN32
+ MsNoWarningSoundFree(s);
+#endif // OS_WIN32
+
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Get the VLAN
+UINT CcGetVLan(REMOTE_CLIENT *r, RPC_CLIENT_GET_VLAN *get)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || get == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientGetVLan(p, get);
+
+ ret = RpcCall(r->Rpc, "GetVLan", p);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcClientGetVLan(get, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// VLAN configuration
+UINT CcSetVLan(REMOTE_CLIENT *r, RPC_CLIENT_SET_VLAN *set)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || set == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientSetVLan(p, set);
+
+ ret = RpcCall(r->Rpc, "SetVLan", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Enumeration of VLAN
+UINT CcEnumVLan(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_VLAN *e)
+{
+ PACK *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || e == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = RpcCall(r->Rpc, "EnumVLan", NULL);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcClientEnumVLan(e, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Delete the VLAN
+UINT CcDeleteVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *d)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || d == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcCreateVLan(p, d);
+
+ ret = RpcCall(r->Rpc, "DeleteVLan", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Enable the VLAN
+UINT CcEnableVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *vlan)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || vlan == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcCreateVLan(p, vlan);
+
+ ret = RpcCall(r->Rpc, "EnableVLan", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Disable the VLAN
+UINT CcDisableVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *vlan)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || vlan == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcCreateVLan(p, vlan);
+
+ ret = RpcCall(r->Rpc, "DisableVLan", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Create an Account
+UINT CcCreateAccount(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_ACCOUNT *a)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientCreateAccount(p, a);
+
+ ret = RpcCall(r->Rpc, "CreateAccount", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Enumeration of accounts
+UINT CcEnumAccount(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_ACCOUNT *e)
+{
+ PACK *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || e == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = RpcCall(r->Rpc, "EnumAccount", NULL);
+
+ if (RpcIsOk(ret))
+ {
+ UINT i;
+ InRpcClientEnumAccount(e, ret);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *t = e->Items[i];
+
+ if (IsEmptyStr(t->HubName) && t->Port == 0)
+ {
+ UINT err2;
+ RPC_CLIENT_GET_ACCOUNT a;
+
+ // Because the Client Manager can not get the port number and HUB name
+ // when enumerating in the VPN Client of the old version, get these separately.
+ Zero(&a, sizeof(a));
+ UniStrCpy(a.AccountName, sizeof(a.AccountName), t->AccountName);
+ err2 = CcGetAccount(r, &a);
+ if (err2 == ERR_NO_ERROR)
+ {
+ StrCpy(t->HubName, sizeof(t->HubName), a.ClientOption->HubName);
+ t->Port = a.ClientOption->Port;
+
+ CiFreeClientGetAccount(&a);
+ }
+ }
+ }
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Unset the startup flag of the accout
+UINT CcRemoveStartupAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientDeleteAccount(p, a);
+
+ ret = RpcCall(r->Rpc, "RemoveStartupAccount", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Set to start-up flag of the account
+UINT CcSetStartupAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientDeleteAccount(p, a);
+
+ ret = RpcCall(r->Rpc, "SetStartupAccount", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Delete the account
+UINT CcDeleteAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientDeleteAccount(p, a);
+
+ ret = RpcCall(r->Rpc, "DeleteAccount", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Account setting
+UINT CcSetAccount(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_ACCOUNT *a)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientCreateAccount(p, a);
+
+ ret = RpcCall(r->Rpc, "SetAccount", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Get the account
+UINT CcGetAccount(REMOTE_CLIENT *r, RPC_CLIENT_GET_ACCOUNT *a)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientGetAccount(p, a);
+
+ ret = RpcCall(r->Rpc, "GetAccount", p);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcClientGetAccount(a, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Change the account name
+UINT CcRenameAccount(REMOTE_CLIENT *r, RPC_RENAME_ACCOUNT *rename)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || rename == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcRenameAccount(p, rename);
+
+ ret = RpcCall(r->Rpc, "RenameAccount", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Set the Client configuration
+UINT CcSetClientConfig(REMOTE_CLIENT *r, CLIENT_CONFIG *o)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || o == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientConfig(p, o);
+
+ ret = RpcCall(r->Rpc, "SetClientConfig", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Get the client configuration
+UINT CcGetClientConfig(REMOTE_CLIENT *r, CLIENT_CONFIG *o)
+{
+ PACK *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || o == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = RpcCall(r->Rpc, "GetClientConfig", NULL);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcClientConfig(o, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Set the service to foreground process
+void CcSetServiceToForegroundProcess(REMOTE_CLIENT *r)
+{
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+ // Abolition
+/*
+ if (r->Rpc != NULL && r->Rpc->Sock != NULL && r->Rpc->Sock->RemoteIP.addr[0] == 127)
+ {
+ if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) &&
+ GET_KETA(GetOsInfo()->OsType, 100) >= 2)
+ {
+ // Only on a Windows 2000 or later
+ RPC_CLIENT_VERSION v;
+ Zero(&v, sizeof(v));
+
+ if (r->ClientBuildInt == 0)
+ {
+ CcGetClientVersion(r, &v);
+ r->ClientBuildInt = v.ClientBuildInt;
+ r->ProcessId = v.ProcessId;
+ }
+ if (r->ProcessId != 0 && r->ClientBuildInt <= 5080)
+ {
+#ifdef OS_WIN32
+ // Set the service process as a foreground window
+ AllowFGWindow(v.ProcessId);
+#endif // OS_WIN32
+ }
+ }
+ }*/
+}
+
+// Connect
+UINT CcConnect(REMOTE_CLIENT *r, RPC_CLIENT_CONNECT *connect)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || connect == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ CcSetServiceToForegroundProcess(r);
+
+ p = NewPack();
+ OutRpcClientConnect(p, connect);
+
+ ret = RpcCall(r->Rpc, "Connect", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Disconnect
+UINT CcDisconnect(REMOTE_CLIENT *r, RPC_CLIENT_CONNECT *connect)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || connect == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ CcSetServiceToForegroundProcess(r);
+
+ p = NewPack();
+ OutRpcClientConnect(p, connect);
+
+ ret = RpcCall(r->Rpc, "Disconnect", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Get the account status
+UINT CcGetAccountStatus(REMOTE_CLIENT *r, RPC_CLIENT_GET_CONNECTION_STATUS *st)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || st == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientGetConnectionStatus(p, st);
+
+ ret = RpcCall(r->Rpc, "GetAccountStatus", p);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcClientGetConnectionStatus(st, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+
+// Client service sends a notification to the connection manager
+void CiNotify(CLIENT *c)
+{
+ CiNotifyInternal(c);
+}
+void CiNotifyInternal(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Set all the notification event
+ LockList(c->NotifyCancelList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(c->NotifyCancelList);i++)
+ {
+ CANCEL *cancel = LIST_DATA(c->NotifyCancelList, i);
+ Cancel(cancel);
+ }
+ }
+ UnlockList(c->NotifyCancelList);
+}
+
+// Release the RPC_CLIENT_ENUM_ACCOUNT
+void CiFreeClientEnumAccount(RPC_CLIENT_ENUM_ACCOUNT *a)
+{
+ UINT i;
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < a->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *e = a->Items[i];
+ Free(e);
+ }
+ Free(a->Items);
+}
+
+
+// Thread to save the configuration file periodically
+void CiSaverThread(THREAD *t, void *param)
+{
+ CLIENT *c = (CLIENT *)param;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ NoticeThreadInit(t);
+
+ // Wait for a certain period of time
+ while (c->Halt == false)
+ {
+ Wait(c->SaverHalter, CLIENT_SAVER_INTERVAL);
+
+ // Save
+ CiSaveConfigurationFile(c);
+ }
+}
+
+// Initialize the Saver
+void CiInitSaver(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->SaverHalter = NewEvent();
+
+ c->SaverThread = NewThread(CiSaverThread, c);
+ WaitThreadInit(c->SaverThread);
+}
+
+// Release the Saver
+void CiFreeSaver(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->Halt = true;
+ Set(c->SaverHalter);
+ WaitThread(c->SaverThread, INFINITE);
+ ReleaseThread(c->SaverThread);
+
+ ReleaseEvent(c->SaverHalter);
+}
+
+// CM_SETTING
+void InRpcCmSetting(CM_SETTING *c, PACK *p)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(CM_SETTING));
+ c->EasyMode = PackGetBool(p, "EasyMode");
+ c->LockMode = PackGetBool(p, "LockMode");
+ PackGetData2(p, "HashedPassword", c->HashedPassword, sizeof(c->HashedPassword));
+}
+void OutRpcCmSetting(PACK *p, CM_SETTING *c)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "EasyMode", c->EasyMode);
+ PackAddBool(p, "LockMode", c->LockMode);
+ PackAddData(p, "HashedPassword", c->HashedPassword, sizeof(c->HashedPassword));
+}
+
+// CLIENT_CONFIG
+void InRpcClientConfig(CLIENT_CONFIG *c, PACK *p)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(CLIENT_CONFIG));
+ c->UseKeepConnect = PackGetInt(p, "UseKeepConnect") == 0 ? false : true;
+ c->KeepConnectPort = PackGetInt(p, "KeepConnectPort");
+ c->KeepConnectProtocol = PackGetInt(p, "KeepConnectProtocol");
+ c->KeepConnectInterval = PackGetInt(p, "KeepConnectInterval");
+ c->AllowRemoteConfig = PackGetInt(p, "AllowRemoteConfig") == 0 ? false : true;
+ PackGetStr(p, "KeepConnectHost", c->KeepConnectHost, sizeof(c->KeepConnectHost));
+}
+void OutRpcClientConfig(PACK *p, CLIENT_CONFIG *c)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "UseKeepConnect", c->UseKeepConnect);
+ PackAddInt(p, "KeepConnectPort", c->KeepConnectPort);
+ PackAddInt(p, "KeepConnectProtocol", c->KeepConnectProtocol);
+ PackAddInt(p, "KeepConnectInterval", c->KeepConnectInterval);
+ PackAddInt(p, "AllowRemoteConfig", c->AllowRemoteConfig);
+ PackAddStr(p, "KeepConnectHost", c->KeepConnectHost);
+}
+
+// RPC_CLIENT_VERSION
+void InRpcClientVersion(RPC_CLIENT_VERSION *ver, PACK *p)
+{
+ // Validate arguments
+ if (ver == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(ver, sizeof(RPC_CLIENT_VERSION));
+ PackGetStr(p, "ClientProductName", ver->ClientProductName, sizeof(ver->ClientProductName));
+ PackGetStr(p, "ClientVersionString", ver->ClientVersionString, sizeof(ver->ClientVersionString));
+ PackGetStr(p, "ClientBuildInfoString", ver->ClientBuildInfoString, sizeof(ver->ClientBuildInfoString));
+ ver->ClientVerInt = PackGetInt(p, "ClientVerInt");
+ ver->ClientBuildInt = PackGetInt(p, "ClientBuildInt");
+ ver->ProcessId = PackGetInt(p, "ProcessId");
+ ver->OsType = PackGetInt(p, "OsType");
+ ver->IsVLanNameRegulated = PackGetBool(p, "IsVLanNameRegulated");
+ ver->IsVgcSupported = PackGetBool(p, "IsVgcSupported");
+ ver->ShowVgcLink = PackGetBool(p, "ShowVgcLink");
+ PackGetStr(p, "ClientId", ver->ClientId, sizeof(ver->ClientId));
+}
+void OutRpcClientVersion(PACK *p, RPC_CLIENT_VERSION *ver)
+{
+ // Validate arguments
+ if (ver == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "ClientProductName", ver->ClientProductName);
+ PackAddStr(p, "ClientVersionString", ver->ClientVersionString);
+ PackAddStr(p, "ClientBuildInfoString", ver->ClientBuildInfoString);
+ PackAddInt(p, "ClientVerInt", ver->ClientVerInt);
+ PackAddInt(p, "ClientBuildInt", ver->ClientBuildInt);
+ PackAddInt(p, "ProcessId", ver->ProcessId);
+ PackAddInt(p, "OsType", ver->OsType);
+ PackAddBool(p, "IsVLanNameRegulated", ver->IsVLanNameRegulated);
+ PackAddBool(p, "IsVgcSupported", ver->IsVgcSupported);
+ PackAddBool(p, "ShowVgcLink", ver->ShowVgcLink);
+ PackAddStr(p, "ClientId", ver->ClientId);
+}
+
+// RPC_CLIENT_PASSWORD
+void InRpcClientPassword(RPC_CLIENT_PASSWORD *pw, PACK *p)
+{
+ // Validate arguments
+ if (pw == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(pw, sizeof(RPC_CLIENT_PASSWORD));
+ PackGetStr(p, "Password", pw->Password, sizeof(pw->Password));
+ pw->PasswordRemoteOnly = PackGetInt(p, "PasswordRemoteOnly");
+}
+void OutRpcClientPassword(PACK *p, RPC_CLIENT_PASSWORD *pw)
+{
+ // Validate arguments
+ if (pw == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "Password", pw->Password);
+ PackAddInt(p, "PasswordRemoteOnly", pw->PasswordRemoteOnly);
+}
+
+// RPC_CLIENT_PASSWORD_SETTING
+void InRpcClientPasswordSetting(RPC_CLIENT_PASSWORD_SETTING *a, PACK *p)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(a, sizeof(RPC_CLIENT_PASSWORD_SETTING));
+
+ a->IsPasswordPresented = PackGetInt(p, "IsPasswordPresented") == 0 ? false : true;
+ a->PasswordRemoteOnly = PackGetInt(p, "PasswordRemoteOnly") == 0 ? false : true;
+}
+void OutRpcClientPasswordSetting(PACK *p, RPC_CLIENT_PASSWORD_SETTING *a)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "IsPasswordPresented", a->IsPasswordPresented);
+ PackAddInt(p, "PasswordRemoteOnly", a->PasswordRemoteOnly);
+}
+
+// RPC_CLIENT_ENUM_CA
+void InRpcClientEnumCa(RPC_CLIENT_ENUM_CA *e, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(e, sizeof(RPC_CLIENT_ENUM_CA));
+ e->NumItem = PackGetNum(p, "NumItem");
+
+ e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM *) * e->NumItem);
+ for (i = 0;i < e->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_CA_ITEM *item = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM));
+ e->Items[i] = item;
+
+ item->Key = PackGetIntEx(p, "Key", i);
+ PackGetUniStrEx(p, "SubjectName", item->SubjectName, sizeof(item->SubjectName), i);
+ PackGetUniStrEx(p, "IssuerName", item->IssuerName, sizeof(item->IssuerName), i);
+ item->Expires = PackGetInt64Ex(p, "Expires", i);
+ }
+}
+void OutRpcClientEnumCa(PACK *p, RPC_CLIENT_ENUM_CA *e)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddNum(p, "NumItem", e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_CA_ITEM *item = e->Items[i];
+ PackAddIntEx(p, "Key", item->Key, i, e->NumItem);
+ PackAddUniStrEx(p, "SubjectName", item->SubjectName, i, e->NumItem);
+ PackAddUniStrEx(p, "IssuerName", item->IssuerName, i, e->NumItem);
+ PackAddInt64Ex(p, "Expires", item->Expires, i, e->NumItem);
+ }
+}
+
+// RPC_GET_ISSUER
+void InRpcGetIssuer(RPC_GET_ISSUER *c, PACK *p)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(RPC_GET_ISSUER));
+ b = PackGetBuf(p, "x");
+ if (b != NULL)
+ {
+ if (c->x != NULL)
+ {
+ FreeX(c->x);
+ }
+ c->x = BufToX(b, false);
+ FreeBuf(b);
+ }
+
+ b = PackGetBuf(p, "issuer_x");
+ if (b != NULL)
+ {
+ c->issuer_x = BufToX(b, false);
+ FreeBuf(b);
+ }
+}
+void OutRpcGetIssuer(PACK *p, RPC_GET_ISSUER *c)
+{
+ BUF *b;
+ // Validate arguments
+ if (p == NULL || c == NULL)
+ {
+ return;
+ }
+
+ if (c->x != NULL)
+ {
+ b = XToBuf(c->x, false);
+
+ PackAddBuf(p, "x", b);
+ FreeBuf(b);
+ }
+
+ if (c->issuer_x != NULL)
+ {
+ b = XToBuf(c->issuer_x, false);
+
+ PackAddBuf(p, "issuer_x", b);
+ FreeBuf(b);
+ }
+}
+
+// TRAFFIC_EX
+void InRpcTrafficEx(TRAFFIC *t, PACK *p, UINT i)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(TRAFFIC));
+ t->Recv.BroadcastBytes = PackGetInt64Ex(p, "Ex.Recv.BroadcastBytes", i);
+ t->Recv.BroadcastCount = PackGetInt64Ex(p, "Ex.Recv.BroadcastCount", i);
+ t->Recv.UnicastBytes = PackGetInt64Ex(p, "Ex.Recv.UnicastBytes", i);
+ t->Recv.UnicastCount = PackGetInt64Ex(p, "Ex.Recv.UnicastCount", i);
+ t->Send.BroadcastBytes = PackGetInt64Ex(p, "Ex.Send.BroadcastBytes", i);
+ t->Send.BroadcastCount = PackGetInt64Ex(p, "Ex.Send.BroadcastCount", i);
+ t->Send.UnicastBytes = PackGetInt64Ex(p, "Ex.Send.UnicastBytes", i);
+ t->Send.UnicastCount = PackGetInt64Ex(p, "Ex.Send.UnicastCount", i);
+}
+void OutRpcTrafficEx(TRAFFIC *t, PACK *p, UINT i, UINT num)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt64Ex(p, "Ex.Recv.BroadcastBytes", t->Recv.BroadcastBytes, i, num);
+ PackAddInt64Ex(p, "Ex.Recv.BroadcastCount", t->Recv.BroadcastCount, i, num);
+ PackAddInt64Ex(p, "Ex.Recv.UnicastBytes", t->Recv.UnicastBytes, i, num);
+ PackAddInt64Ex(p, "Ex.Recv.UnicastCount", t->Recv.UnicastCount, i, num);
+ PackAddInt64Ex(p, "Ex.Send.BroadcastBytes", t->Send.BroadcastBytes, i, num);
+ PackAddInt64Ex(p, "Ex.Send.BroadcastCount", t->Send.BroadcastCount, i, num);
+ PackAddInt64Ex(p, "Ex.Send.UnicastBytes", t->Send.UnicastBytes, i, num);
+ PackAddInt64Ex(p, "Ex.Send.UnicastCount", t->Send.UnicastCount, i, num);
+}
+
+// TRAFFIC
+void InRpcTraffic(TRAFFIC *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(TRAFFIC));
+ t->Recv.BroadcastBytes = PackGetInt64(p, "Recv.BroadcastBytes");
+ t->Recv.BroadcastCount = PackGetInt64(p, "Recv.BroadcastCount");
+ t->Recv.UnicastBytes = PackGetInt64(p, "Recv.UnicastBytes");
+ t->Recv.UnicastCount = PackGetInt64(p, "Recv.UnicastCount");
+ t->Send.BroadcastBytes = PackGetInt64(p, "Send.BroadcastBytes");
+ t->Send.BroadcastCount = PackGetInt64(p, "Send.BroadcastCount");
+ t->Send.UnicastBytes = PackGetInt64(p, "Send.UnicastBytes");
+ t->Send.UnicastCount = PackGetInt64(p, "Send.UnicastCount");
+}
+void OutRpcTraffic(PACK *p, TRAFFIC *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt64(p, "Recv.BroadcastBytes", t->Recv.BroadcastBytes);
+ PackAddInt64(p, "Recv.BroadcastCount", t->Recv.BroadcastCount);
+ PackAddInt64(p, "Recv.UnicastBytes", t->Recv.UnicastBytes);
+ PackAddInt64(p, "Recv.UnicastCount", t->Recv.UnicastCount);
+ PackAddInt64(p, "Send.BroadcastBytes", t->Send.BroadcastBytes);
+ PackAddInt64(p, "Send.BroadcastCount", t->Send.BroadcastCount);
+ PackAddInt64(p, "Send.UnicastBytes", t->Send.UnicastBytes);
+ PackAddInt64(p, "Send.UnicastCount", t->Send.UnicastCount);
+}
+
+// RPC_CERT
+void InRpcCert(RPC_CERT *c, PACK *p)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(RPC_CERT));
+ b = PackGetBuf(p, "x");
+ if (b == NULL)
+ {
+ return;
+ }
+
+ c->x = BufToX(b, false);
+ FreeBuf(b);
+}
+void OutRpcCert(PACK *p, RPC_CERT *c)
+{
+ BUF *b;
+ // Validate arguments
+ if (p == NULL || c == NULL)
+ {
+ return;
+ }
+
+ if (c->x != NULL)
+ {
+ b = XToBuf(c->x, false);
+
+ PackAddBuf(p, "x", b);
+
+ FreeBuf(b);
+ }
+}
+
+// RPC_CLIENT_DELETE_CA
+void InRpcClientDeleteCa(RPC_CLIENT_DELETE_CA *c, PACK *p)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(RPC_CLIENT_DELETE_CA));
+ c->Key = PackGetInt(p, "Key");
+}
+void OutRpcClientDeleteCa(PACK *p, RPC_CLIENT_DELETE_CA *c)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "Key", c->Key);
+}
+
+// RPC_GET_CA
+void InRpcGetCa(RPC_GET_CA *c, PACK *p)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(RPC_GET_CA));
+
+ c->Key = PackGetInt(p, "Key");
+
+ b = PackGetBuf(p, "x");
+ if (b != NULL)
+ {
+ c->x = BufToX(b, false);
+
+ FreeBuf(b);
+ }
+}
+void OutRpcGetCa(PACK *p, RPC_GET_CA *c)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "Key", c->Key);
+
+ if (c->x != NULL)
+ {
+ BUF *b = XToBuf(c->x, false);
+
+ PackAddBuf(p, "x", b);
+
+ FreeBuf(b);
+ }
+}
+
+// RPC_CLIENT_ENUM_SECURE
+void InRpcClientEnumSecure(RPC_CLIENT_ENUM_SECURE *e, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(e, sizeof(RPC_CLIENT_ENUM_SECURE));
+
+ e->NumItem = PackGetNum(p, "NumItem");
+ e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM *) * e->NumItem);
+ for (i = 0;i < e->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_SECURE_ITEM *item = e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM));
+
+ item->DeviceId = PackGetIntEx(p, "DeviceId", i);
+ item->Type = PackGetIntEx(p, "Type", i);
+ PackGetStrEx(p, "DeviceName", item->DeviceName, sizeof(item->DeviceName), i);
+ PackGetStrEx(p, "Manufacturer", item->Manufacturer, sizeof(item->Manufacturer), i);
+ }
+}
+void OutRpcClientEnumSecure(PACK *p, RPC_CLIENT_ENUM_SECURE *e)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddNum(p, "NumItem", e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_SECURE_ITEM *item = e->Items[i];
+
+ PackAddIntEx(p, "DeviceId", item->DeviceId, i, e->NumItem);
+ PackAddIntEx(p, "Type", item->Type, i, e->NumItem);
+ PackAddStrEx(p, "DeviceName", item->DeviceName, i, e->NumItem);
+ PackAddStrEx(p, "Manufacturer", item->Manufacturer, i, e->NumItem);
+ }
+}
+
+// RPC_USE_SECURE
+void InRpcUseSecure(RPC_USE_SECURE *u, PACK *p)
+{
+ // Validate arguments
+ if (u == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(u, sizeof(RPC_USE_SECURE));
+ u->DeviceId = PackGetInt(p, "DeviceId");
+}
+void OutRpcUseSecure(PACK *p, RPC_USE_SECURE *u)
+{
+ // Validate arguments
+ if (u == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "DeviceId", u->DeviceId);
+}
+
+// Release the RPC_ENUM_OBJECT_IN_SECURE
+void CiFreeEnumObjectInSecure(RPC_ENUM_OBJECT_IN_SECURE *a)
+{
+ UINT i;
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < a->NumItem;i++)
+ {
+ Free(a->ItemName[i]);
+ }
+ Free(a->ItemName);
+ Free(a->ItemType);
+}
+
+// RPC_ENUM_OBJECT_IN_SECURE
+void InRpcEnumObjectInSecure(RPC_ENUM_OBJECT_IN_SECURE *e, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(e, sizeof(RPC_ENUM_OBJECT_IN_SECURE));
+
+ e->NumItem = PackGetNum(p, "NumItem");
+ e->hWnd = PackGetInt(p, "hWnd");
+ e->ItemName = ZeroMalloc(sizeof(char *) * e->NumItem);
+ e->ItemType = ZeroMalloc(sizeof(bool) * e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ char name[MAX_SIZE];
+
+ Zero(name, sizeof(name));
+ PackGetStrEx(p, "ItemName", name, sizeof(name), i);
+ e->ItemName[i] = CopyStr(name);
+
+ e->ItemType[i] = PackGetIntEx(p, "ItemType", i) ? true : false;
+ }
+}
+void OutRpcEnumObjectInSecure(PACK *p, RPC_ENUM_OBJECT_IN_SECURE *e)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddNum(p, "NumItem", e->NumItem);
+ PackAddInt(p, "hWnd", e->hWnd);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ PackAddStrEx(p, "ItemName", e->ItemName[i], i, e->NumItem);
+ PackAddIntEx(p, "ItemType", e->ItemType[i], i, e->NumItem);
+ }
+}
+
+// RPC_CLIENT_CREATE_VLAN
+void InRpcCreateVLan(RPC_CLIENT_CREATE_VLAN *v, PACK *p)
+{
+ // Validate arguments
+ if (v == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(v, sizeof(RPC_CLIENT_CREATE_VLAN));
+ PackGetStr(p, "DeviceName", v->DeviceName, sizeof(v->DeviceName));
+}
+void OutRpcCreateVLan(PACK *p, RPC_CLIENT_CREATE_VLAN *v)
+{
+ // Validate arguments
+ if (v == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "DeviceName", v->DeviceName);
+}
+
+// RPC_CLIENT_GET_VLAN
+void InRpcClientGetVLan(RPC_CLIENT_GET_VLAN *v, PACK *p)
+{
+ // Validate arguments
+ if (v == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(v, sizeof(RPC_CLIENT_GET_VLAN));
+ PackGetStr(p, "DeviceName", v->DeviceName, sizeof(v->DeviceName));
+ v->Enabled = PackGetInt(p, "Enabled") ? true : false;
+ PackGetStr(p, "MacAddress", v->MacAddress, sizeof(v->MacAddress));
+ PackGetStr(p, "Version", v->Version, sizeof(v->Version));
+ PackGetStr(p, "FileName", v->FileName, sizeof(v->FileName));
+ PackGetStr(p, "Guid", v->Guid, sizeof(v->Guid));
+}
+void OutRpcClientGetVLan(PACK *p, RPC_CLIENT_GET_VLAN *v)
+{
+ // Validate arguments
+ if (v == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "DeviceName", v->DeviceName);
+ PackAddInt(p, "Enabled", v->Enabled);
+ PackAddStr(p, "MacAddress", v->MacAddress);
+ PackAddStr(p, "Version", v->Version);
+ PackAddStr(p, "FileName", v->FileName);
+ PackAddStr(p, "Guid", v->Guid);
+}
+
+// RPC_CLIENT_SET_VLAN
+void InRpcClientSetVLan(RPC_CLIENT_SET_VLAN *v, PACK *p)
+{
+ // Validate arguments
+ if (v == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(v, sizeof(RPC_CLIENT_SET_VLAN));
+ PackGetStr(p, "DeviceName", v->DeviceName, sizeof(v->DeviceName));
+ PackGetStr(p, "MacAddress", v->MacAddress, sizeof(v->MacAddress));
+}
+void OutRpcClientSetVLan(PACK *p, RPC_CLIENT_SET_VLAN *v)
+{
+ // Validate arguments
+ if (v == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "DeviceName", v->DeviceName);
+ PackAddStr(p, "MacAddress", v->MacAddress);
+}
+
+// RPC_CLIENT_ENUM_VLAN
+void InRpcClientEnumVLan(RPC_CLIENT_ENUM_VLAN *v, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (v == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(v, sizeof(RPC_CLIENT_ENUM_VLAN));
+ v->NumItem = PackGetNum(p, "NumItem");
+ v->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM *) * v->NumItem);
+
+ for (i = 0;i < v->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_VLAN_ITEM *item = v->Items[i] =
+ ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM));
+
+ PackGetStrEx(p, "DeviceName", item->DeviceName, sizeof(item->DeviceName), i);
+ item->Enabled = PackGetIntEx(p, "Enabled", i) ? true : false;
+ PackGetStrEx(p, "MacAddress", item->MacAddress, sizeof(item->MacAddress), i);
+ PackGetStrEx(p, "Version", item->Version, sizeof(item->Version), i);
+ }
+}
+void OutRpcClientEnumVLan(PACK *p, RPC_CLIENT_ENUM_VLAN *v)
+{
+ UINT i;
+ // Validate arguments
+ if (v == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddNum(p, "NumItem", v->NumItem);
+
+ for (i = 0;i < v->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_VLAN_ITEM *item = v->Items[i];
+
+ PackAddStrEx(p, "DeviceName", item->DeviceName, i, v->NumItem);
+ PackAddIntEx(p, "Enabled", item->Enabled, i, v->NumItem);
+ PackAddStrEx(p, "MacAddress", item->MacAddress, i, v->NumItem);
+ PackAddStrEx(p, "Version", item->Version, i, v->NumItem);
+ }
+}
+
+// CLIENT_OPTION
+void InRpcClientOption(CLIENT_OPTION *c, PACK *p)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(CLIENT_OPTION));
+
+ PackGetUniStr(p, "AccountName", c->AccountName, sizeof(c->AccountName));
+ PackGetStr(p, "Hostname", c->Hostname, sizeof(c->Hostname));
+ c->Port = PackGetInt(p, "Port");
+ c->PortUDP = PackGetInt(p, "PortUDP");
+ c->ProxyType = PackGetInt(p, "ProxyType");
+ c->ProxyPort = PackGetInt(p, "ProxyPort");
+ c->NumRetry = PackGetInt(p, "NumRetry");
+ c->RetryInterval = PackGetInt(p, "RetryInterval");
+ c->MaxConnection = PackGetInt(p, "MaxConnection");
+ c->AdditionalConnectionInterval = PackGetInt(p, "AdditionalConnectionInterval");
+ c->ConnectionDisconnectSpan = PackGetInt(p, "ConnectionDisconnectSpan");
+ c->HideStatusWindow = PackGetBool(p, "HideStatusWindow");
+ c->HideNicInfoWindow = PackGetBool(p, "HideNicInfoWindow");
+ c->DisableQoS = PackGetBool(p, "DisableQoS");
+ PackGetStr(p, "ProxyName", c->ProxyName, sizeof(c->ProxyName));
+ PackGetStr(p, "ProxyUsername", c->ProxyUsername, sizeof(c->ProxyUsername));
+ PackGetStr(p, "ProxyPassword", c->ProxyPassword, sizeof(c->ProxyPassword));
+ PackGetStr(p, "HubName", c->HubName, sizeof(c->HubName));
+ PackGetStr(p, "DeviceName", c->DeviceName, sizeof(c->DeviceName));
+ c->UseEncrypt = PackGetInt(p, "UseEncrypt") ? true : false;
+ c->UseCompress = PackGetInt(p, "UseCompress") ? true : false;
+ c->HalfConnection = PackGetInt(p, "HalfConnection") ? true : false;
+ c->NoRoutingTracking = PackGetInt(p, "NoRoutingTracking") ? true : false;
+ c->RequireMonitorMode = PackGetBool(p, "RequireMonitorMode");
+ c->RequireBridgeRoutingMode = PackGetBool(p, "RequireBridgeRoutingMode");
+ c->FromAdminPack = PackGetBool(p, "FromAdminPack");
+ c->NoTls1 = PackGetBool(p, "NoTls1");
+ c->NoUdpAcceleration = PackGetBool(p, "NoUdpAcceleration");
+ PackGetData2(p, "HostUniqueKey", c->HostUniqueKey, SHA1_SIZE);
+}
+void OutRpcClientOption(PACK *p, CLIENT_OPTION *c)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddUniStr(p, "AccountName", c->AccountName);
+ PackAddStr(p, "Hostname", c->Hostname);
+ PackAddStr(p, "ProxyName", c->ProxyName);
+ PackAddStr(p, "ProxyUsername", c->ProxyUsername);
+ PackAddStr(p, "ProxyPassword", c->ProxyPassword);
+ PackAddStr(p, "HubName", c->HubName);
+ PackAddStr(p, "DeviceName", c->DeviceName);
+ PackAddInt(p, "Port", c->Port);
+ PackAddInt(p, "PortUDP", c->PortUDP);
+ PackAddInt(p, "ProxyType", c->ProxyType);
+ PackAddInt(p, "ProxyPort", c->ProxyPort);
+ PackAddInt(p, "NumRetry", c->NumRetry);
+ PackAddInt(p, "RetryInterval", c->RetryInterval);
+ PackAddInt(p, "MaxConnection", c->MaxConnection);
+ PackAddInt(p, "UseEncrypt", c->UseEncrypt);
+ PackAddInt(p, "UseCompress", c->UseCompress);
+ PackAddInt(p, "HalfConnection", c->HalfConnection);
+ PackAddInt(p, "NoRoutingTracking", c->NoRoutingTracking);
+ PackAddInt(p, "AdditionalConnectionInterval", c->AdditionalConnectionInterval);
+ PackAddInt(p, "ConnectionDisconnectSpan", c->ConnectionDisconnectSpan);
+ PackAddBool(p, "HideStatusWindow", c->HideStatusWindow);
+ PackAddBool(p, "HideNicInfoWindow", c->HideNicInfoWindow);
+ PackAddBool(p, "RequireMonitorMode", c->RequireMonitorMode);
+ PackAddBool(p, "RequireBridgeRoutingMode", c->RequireBridgeRoutingMode);
+ PackAddBool(p, "DisableQoS", c->DisableQoS);
+ PackAddBool(p, "FromAdminPack", c->FromAdminPack);
+ PackAddBool(p, "NoTls1", c->NoTls1);
+ PackAddBool(p, "NoUdpAcceleration", c->NoUdpAcceleration);
+ PackAddData(p, "HostUniqueKey", c->HostUniqueKey, SHA1_SIZE);
+}
+
+// CLIENT_AUTH
+void InRpcClientAuth(CLIENT_AUTH *c, PACK *p)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(CLIENT_AUTH));
+ c->AuthType = PackGetInt(p, "AuthType");
+ PackGetStr(p, "Username", c->Username, sizeof(c->Username));
+
+ switch (c->AuthType)
+ {
+ case CLIENT_AUTHTYPE_ANONYMOUS:
+ break;
+
+ case CLIENT_AUTHTYPE_PASSWORD:
+ if (PackGetDataSize(p, "HashedPassword") == SHA1_SIZE)
+ {
+ PackGetData(p, "HashedPassword", c->HashedPassword);
+ }
+ break;
+
+ case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+ PackGetStr(p, "PlainPassword", c->PlainPassword, sizeof(c->PlainPassword));
+ break;
+
+ case CLIENT_AUTHTYPE_CERT:
+ b = PackGetBuf(p, "ClientX");
+ if (b != NULL)
+ {
+ c->ClientX = BufToX(b, false);
+ FreeBuf(b);
+ }
+ b = PackGetBuf(p, "ClientK");
+ if (b != NULL)
+ {
+ c->ClientK = BufToK(b, true, false, NULL);
+ FreeBuf(b);
+ }
+ break;
+
+ case CLIENT_AUTHTYPE_SECURE:
+ PackGetStr(p, "SecurePublicCertName", c->SecurePublicCertName, sizeof(c->SecurePublicCertName));
+ PackGetStr(p, "SecurePrivateKeyName", c->SecurePrivateKeyName, sizeof(c->SecurePrivateKeyName));
+ break;
+ }
+}
+void OutRpcClientAuth(PACK *p, CLIENT_AUTH *c)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "AuthType", c->AuthType);
+ PackAddStr(p, "Username", c->Username);
+
+ switch (c->AuthType)
+ {
+ case CLIENT_AUTHTYPE_ANONYMOUS:
+ break;
+
+ case CLIENT_AUTHTYPE_PASSWORD:
+ PackAddData(p, "HashedPassword", c->HashedPassword, SHA1_SIZE);
+ break;
+
+ case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+ PackAddStr(p, "PlainPassword", c->PlainPassword);
+ break;
+
+ case CLIENT_AUTHTYPE_CERT:
+ b = XToBuf(c->ClientX, false);
+ if (b != NULL)
+ {
+ PackAddBuf(p, "ClientX", b);
+ FreeBuf(b);
+ }
+ b = KToBuf(c->ClientK, false, NULL);
+ if (b != NULL)
+ {
+ PackAddBuf(p, "ClientK", b);
+ FreeBuf(b);
+ }
+ break;
+
+ case CLIENT_AUTHTYPE_SECURE:
+ PackAddStr(p, "SecurePublicCertName", c->SecurePublicCertName);
+ PackAddStr(p, "SecurePrivateKeyName", c->SecurePrivateKeyName);
+ break;
+ }
+}
+
+// RPC_CLIENT_CREATE_ACCOUNT
+void InRpcClientCreateAccount(RPC_CLIENT_CREATE_ACCOUNT *c, PACK *p)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(RPC_CLIENT_CREATE_ACCOUNT));
+ c->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ c->ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+
+ InRpcClientOption(c->ClientOption, p);
+ InRpcClientAuth(c->ClientAuth, p);
+
+ c->StartupAccount = PackGetInt(p, "StartupAccount") ? true : false;
+ c->CheckServerCert = PackGetInt(p, "CheckServerCert") ? true : false;
+ b = PackGetBuf(p, "ServerCert");
+ if (b != NULL)
+ {
+ c->ServerCert = BufToX(b, false);
+ FreeBuf(b);
+ }
+ PackGetData2(p, "ShortcutKey", c->ShortcutKey, sizeof(c->ShortcutKey));
+}
+void OutRpcClientCreateAccount(PACK *p, RPC_CLIENT_CREATE_ACCOUNT *c)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ OutRpcClientOption(p, c->ClientOption);
+ OutRpcClientAuth(p, c->ClientAuth);
+
+ PackAddInt(p, "StartupAccount", c->StartupAccount);
+ PackAddInt(p, "CheckServerCert", c->CheckServerCert);
+ if (c->ServerCert != NULL)
+ {
+ b = XToBuf(c->ServerCert, false);
+ if (b != NULL)
+ {
+ PackAddBuf(p, "ServerCert", b);
+ FreeBuf(b);
+ }
+ }
+ PackAddData(p, "ShortcutKey", c->ShortcutKey, sizeof(c->ShortcutKey));
+}
+
+// RPC_CLIENT_ENUM_ACCOUNT
+void InRpcClientEnumAccount(RPC_CLIENT_ENUM_ACCOUNT *e, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(e, sizeof(RPC_CLIENT_ENUM_ACCOUNT));
+
+ e->NumItem = PackGetNum(p, "NumItem");
+ e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM *) * e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = e->Items[i] =
+ ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM));
+
+ PackGetUniStrEx(p, "AccountName", item->AccountName, sizeof(item->AccountName), i);
+ PackGetStrEx(p, "UserName", item->UserName, sizeof(item->UserName), i);
+ PackGetStrEx(p, "ServerName", item->ServerName, sizeof(item->ServerName), i);
+ PackGetStrEx(p, "ProxyName", item->ProxyName, sizeof(item->ProxyName), i);
+ PackGetStrEx(p, "DeviceName", item->DeviceName, sizeof(item->DeviceName), i);
+ item->ProxyType = PackGetIntEx(p, "ProxyType", i);
+ item->Active = PackGetIntEx(p, "Active", i) ? true : false;
+ item->StartupAccount = PackGetIntEx(p, "StartupAccount", i) ? true : false;
+ item->Connected = PackGetBoolEx(p, "Connected", i);
+ item->Port = PackGetIntEx(p, "Port", i);
+ PackGetStrEx(p, "HubName", item->HubName, sizeof(item->HubName), i);
+ item->CreateDateTime = PackGetInt64Ex(p, "CreateDateTime", i);
+ item->UpdateDateTime = PackGetInt64Ex(p, "UpdateDateTime", i);
+ item->LastConnectDateTime = PackGetInt64Ex(p, "LastConnectDateTime", i);
+ }
+}
+void OutRpcClientEnumAccount(PACK *p, RPC_CLIENT_ENUM_ACCOUNT *e)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddNum(p, "NumItem", e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = e->Items[i];
+
+ PackAddUniStrEx(p, "AccountName", item->AccountName, i, e->NumItem);
+ PackAddStrEx(p, "UserName", item->UserName, i, e->NumItem);
+ PackAddStrEx(p, "ServerName", item->ServerName, i, e->NumItem);
+ PackAddStrEx(p, "ProxyName", item->ProxyName, i, e->NumItem);
+ PackAddStrEx(p, "DeviceName", item->DeviceName, i, e->NumItem);
+ PackAddIntEx(p, "ProxyType", item->ProxyType, i, e->NumItem);
+ PackAddIntEx(p, "Active", item->Active, i, e->NumItem);
+ PackAddIntEx(p, "StartupAccount", item->StartupAccount, i, e->NumItem);
+ PackAddBoolEx(p, "Connected", item->Connected, i, e->NumItem);
+ PackAddIntEx(p, "Port", item->Port, i, e->NumItem);
+ PackAddStrEx(p, "HubName", item->HubName, i, e->NumItem);
+ PackAddInt64Ex(p, "CreateDateTime", item->CreateDateTime, i, e->NumItem);
+ PackAddInt64Ex(p, "UpdateDateTime", item->UpdateDateTime, i, e->NumItem);
+ PackAddInt64Ex(p, "LastConnectDateTime", item->LastConnectDateTime, i, e->NumItem);
+ }
+}
+
+// RPC_CLIENT_DELETE_ACCOUNT
+void InRpcClientDeleteAccount(RPC_CLIENT_DELETE_ACCOUNT *a, PACK *p)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(a, sizeof(RPC_CLIENT_DELETE_ACCOUNT));
+ PackGetUniStr(p, "AccountName", a->AccountName, sizeof(a->AccountName));
+}
+void OutRpcClientDeleteAccount(PACK *p, RPC_CLIENT_DELETE_ACCOUNT *a)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddUniStr(p, "AccountName", a->AccountName);
+}
+
+// RPC_RENAME_ACCOUNT
+void InRpcRenameAccount(RPC_RENAME_ACCOUNT *a, PACK *p)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(a, sizeof(RPC_RENAME_ACCOUNT));
+
+ PackGetUniStr(p, "OldName", a->OldName, sizeof(a->OldName));
+ PackGetUniStr(p, "NewName", a->NewName, sizeof(a->NewName));
+}
+void OutRpcRenameAccount(PACK *p, RPC_RENAME_ACCOUNT *a)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddUniStr(p, "OldName", a->OldName);
+ PackAddUniStr(p, "NewName", a->NewName);
+}
+
+// RPC_CLIENT_GET_ACCOUNT
+void InRpcClientGetAccount(RPC_CLIENT_GET_ACCOUNT *c, PACK *p)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(RPC_CLIENT_GET_ACCOUNT));
+
+ c->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ c->ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+
+ PackGetUniStr(p, "AccountName", c->AccountName, sizeof(c->AccountName));
+ c->StartupAccount = PackGetInt(p, "StartupAccount") ? true : false;
+ c->CheckServerCert = PackGetInt(p, "CheckServerCert") ? true : false;
+ b = PackGetBuf(p, "ServerCert");
+ if (b != NULL)
+ {
+ c->ServerCert = BufToX(b, false);
+ FreeBuf(b);
+ }
+
+ InRpcClientOption(c->ClientOption, p);
+ InRpcClientAuth(c->ClientAuth, p);
+
+ c->CreateDateTime = PackGetInt64(p, "CreateDateTime");
+ c->UpdateDateTime = PackGetInt64(p, "UpdateDateTime");
+ c->LastConnectDateTime = PackGetInt64(p, "LastConnectDateTime");
+
+ PackGetData2(p, "ShortcutKey", c->ShortcutKey, SHA1_SIZE);
+}
+void OutRpcClientGetAccount(PACK *p, RPC_CLIENT_GET_ACCOUNT *c)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddUniStr(p, "AccountName", c->AccountName);
+ PackAddInt(p, "StartupAccount", c->StartupAccount);
+ PackAddInt(p, "CheckServerCert", c->CheckServerCert);
+
+ if (c->ServerCert != NULL)
+ {
+ b = XToBuf(c->ServerCert, false);
+ if (b != NULL)
+ {
+ PackAddBuf(p, "ServerCert", b);
+ FreeBuf(b);
+ }
+ }
+
+ OutRpcClientOption(p, c->ClientOption);
+ OutRpcClientAuth(p, c->ClientAuth);
+
+ PackAddData(p, "ShortcutKey", c->ShortcutKey, SHA1_SIZE);
+
+ PackAddInt64(p, "CreateDateTime", c->CreateDateTime);
+ PackAddInt64(p, "UpdateDateTime", c->UpdateDateTime);
+ PackAddInt64(p, "LastConnectDateTime", c->LastConnectDateTime);
+}
+
+// RPC_CLIENT_CONNECT
+void InRpcClientConnect(RPC_CLIENT_CONNECT *c, PACK *p)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(RPC_CLIENT_CONNECT));
+
+ PackGetUniStr(p, "AccountName", c->AccountName, sizeof(c->AccountName));
+}
+void OutRpcClientConnect(PACK *p, RPC_CLIENT_CONNECT *c)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddUniStr(p, "AccountName", c->AccountName);
+}
+
+// POLICY
+void InRpcPolicy(POLICY *o, PACK *p)
+{
+ POLICY *pol;
+ // Validate arguments
+ if (o == NULL || p == NULL)
+ {
+ return;
+ }
+
+ pol = PackGetPolicy(p);
+ Copy(o, pol, sizeof(POLICY));
+ Free(pol);
+}
+void OutRpcPolicy(PACK *p, POLICY *o)
+{
+ // Validate arguments
+ if (o == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddPolicy(p, o);
+}
+
+// RPC_CLIENT_GET_CONNECTION_STATUS
+void InRpcClientGetConnectionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *s, PACK *p)
+{
+ BUF *b;
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(s, sizeof(RPC_CLIENT_GET_CONNECTION_STATUS));
+
+ PackGetUniStr(p, "AccountName", s->AccountName, sizeof(s->AccountName));
+
+ PackGetStr(p, "ServerName", s->ServerName, sizeof(s->ServerName));
+ PackGetStr(p, "ServerProductName", s->ServerProductName, sizeof(s->ServerProductName));
+ PackGetStr(p, "CipherName", s->CipherName, sizeof(s->CipherName));
+ PackGetStr(p, "SessionName", s->SessionName, sizeof(s->SessionName));
+ PackGetStr(p, "ConnectionName", s->ConnectionName, sizeof(s->ConnectionName));
+
+ if (PackGetDataSize(p, "SessionKey") == SHA1_SIZE)
+ {
+ PackGetData(p, "SessionKey", s->SessionKey);
+ }
+
+ s->SessionStatus = PackGetInt(p, "SessionStatus");
+ s->ServerPort = PackGetInt(p, "ServerPort");
+ s->ServerProductVer = PackGetInt(p, "ServerProductVer");
+ s->ServerProductBuild = PackGetInt(p, "ServerProductBuild");
+ s->NumConnectionsEatablished = PackGetInt(p, "NumConnectionsEatablished");
+ s->MaxTcpConnections = PackGetInt(p, "MaxTcpConnections");
+ s->NumTcpConnections = PackGetInt(p, "NumTcpConnections");
+ s->NumTcpConnectionsUpload = PackGetInt(p, "NumTcpConnectionsUpload");
+ s->NumTcpConnectionsDownload = PackGetInt(p, "NumTcpConnectionsDownload");
+
+ s->StartTime = PackGetInt64(p, "StartTime");
+ s->FirstConnectionEstablisiedTime = PackGetInt64(p, "FirstConnectionEstablisiedTime");
+ s->CurrentConnectionEstablishTime = PackGetInt64(p, "CurrentConnectionEstablishTime");
+ s->TotalSendSize = PackGetInt64(p, "TotalSendSize");
+ s->TotalRecvSize = PackGetInt64(p, "TotalRecvSize");
+ s->TotalSendSizeReal = PackGetInt64(p, "TotalSendSizeReal");
+ s->TotalRecvSizeReal = PackGetInt64(p, "TotalRecvSizeReal");
+
+ s->Active = PackGetInt(p, "Active") ? true : false;
+ s->Connected = PackGetInt(p, "Connected") ? true : false;
+ s->HalfConnection = PackGetInt(p, "HalfConnection") ? true : false;
+ s->QoS = PackGetInt(p, "QoS") ? true : false;
+ s->UseEncrypt = PackGetInt(p, "UseEncrypt") ? true : false;
+ s->UseCompress = PackGetInt(p, "UseCompress") ? true : false;
+ s->IsRUDPSession = PackGetInt(p, "IsRUDPSession") ? true : false;
+ PackGetStr(p, "UnderlayProtocol", s->UnderlayProtocol, sizeof(s->UnderlayProtocol));
+ s->IsUdpAccelerationEnabled = PackGetInt(p, "IsUdpAccelerationEnabled") ? true : false;
+ s->IsUsingUdpAcceleration = PackGetInt(p, "IsUsingUdpAcceleration") ? true : false;
+
+ s->IsBridgeMode = PackGetBool(p, "IsBridgeMode");
+ s->IsMonitorMode = PackGetBool(p, "IsMonitorMode");
+
+ s->VLanId = PackGetInt(p, "VLanId");
+
+ b = PackGetBuf(p, "ServerX");
+ if (b != NULL)
+ {
+ s->ServerX = BufToX(b, false);
+ FreeBuf(b);
+ }
+
+ b = PackGetBuf(p, "ClientX");
+ if (b != NULL)
+ {
+ s->ClientX = BufToX(b, false);
+ FreeBuf(b);
+ }
+
+ InRpcPolicy(&s->Policy, p);
+
+ InRpcTraffic(&s->Traffic, p);
+}
+void OutRpcClientGetConnectionStatus(PACK *p, RPC_CLIENT_GET_CONNECTION_STATUS *c)
+{
+ BUF *b;
+ // Validate arguments
+ if (p == NULL || c == NULL)
+ {
+ return;
+ }
+
+ PackAddUniStr(p, "AccountName", c->AccountName);
+
+ PackAddStr(p, "ServerName", c->ServerName);
+ PackAddStr(p, "ServerProductName", c->ServerProductName);
+ PackAddStr(p, "CipherName", c->CipherName);
+ PackAddStr(p, "SessionName", c->SessionName);
+ PackAddStr(p, "ConnectionName", c->ConnectionName);
+
+ PackAddData(p, "SessionKey", c->SessionKey, SHA1_SIZE);
+
+ PackAddInt(p, "Active", c->Active);
+ PackAddInt(p, "Connected", c->Connected);
+ PackAddInt(p, "SessionStatus", c->SessionStatus);
+ PackAddInt(p, "ServerPort", c->ServerPort);
+ PackAddInt(p, "ServerProductVer", c->ServerProductVer);
+ PackAddInt(p, "ServerProductBuild", c->ServerProductBuild);
+ PackAddInt(p, "NumConnectionsEatablished", c->NumConnectionsEatablished);
+ PackAddInt(p, "HalfConnection", c->HalfConnection);
+ PackAddInt(p, "QoS", c->QoS);
+ PackAddInt(p, "MaxTcpConnections", c->MaxTcpConnections);
+ PackAddInt(p, "NumTcpConnections", c->NumTcpConnections);
+ PackAddInt(p, "NumTcpConnectionsUpload", c->NumTcpConnectionsUpload);
+ PackAddInt(p, "NumTcpConnectionsDownload", c->NumTcpConnectionsDownload);
+ PackAddInt(p, "UseEncrypt", c->UseEncrypt);
+ PackAddInt(p, "UseCompress", c->UseCompress);
+ PackAddInt(p, "IsRUDPSession", c->IsRUDPSession);
+ PackAddStr(p, "UnderlayProtocol", c->UnderlayProtocol);
+ PackAddInt(p, "IsUdpAccelerationEnabled", c->IsUdpAccelerationEnabled);
+ PackAddInt(p, "IsUsingUdpAcceleration", c->IsUsingUdpAcceleration);
+
+ PackAddBool(p, "IsBridgeMode", c->IsBridgeMode);
+ PackAddBool(p, "IsMonitorMode", c->IsMonitorMode);
+
+ PackAddInt64(p, "StartTime", c->StartTime);
+ PackAddInt64(p, "FirstConnectionEstablisiedTime", c->FirstConnectionEstablisiedTime);
+ PackAddInt64(p, "CurrentConnectionEstablishTime", c->CurrentConnectionEstablishTime);
+ PackAddInt64(p, "TotalSendSize", c->TotalSendSize);
+ PackAddInt64(p, "TotalRecvSize", c->TotalRecvSize);
+ PackAddInt64(p, "TotalSendSizeReal", c->TotalSendSizeReal);
+ PackAddInt64(p, "TotalRecvSizeReal", c->TotalRecvSizeReal);
+
+ PackAddInt(p, "VLanId", c->VLanId);
+
+ OutRpcPolicy(p, &c->Policy);
+
+ OutRpcTraffic(p, &c->Traffic);
+
+ if (c->ServerX != NULL)
+ {
+ b = XToBuf(c->ServerX, false);
+ PackAddBuf(p, "ServerX", b);
+ FreeBuf(b);
+ }
+
+ if (c->ClientX != NULL)
+ {
+ b = XToBuf(c->ClientX, false);
+ PackAddBuf(p, "ClientX", b);
+ FreeBuf(b);
+ }
+}
+
+void InRpcClientNotify(RPC_CLIENT_NOTIFY *n, PACK *p)
+{
+ // Validate arguments
+ if (n == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(n, sizeof(RPC_CLIENT_NOTIFY));
+
+ n->NotifyCode = PackGetInt(p, "NotifyCode");
+}
+void OutRpcClientNotify(PACK *p, RPC_CLIENT_NOTIFY *n)
+{
+ // Validate arguments
+ if (n == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NotifyCode", n->NotifyCode);
+}
+
+// Notification main
+void CiNotifyMain(CLIENT *c, SOCK *s)
+{
+ CANCEL *cancel;
+ // Validate arguments
+ if (c == NULL || s == NULL)
+ {
+ return;
+ }
+
+ // Register a Cencel
+ cancel = NewCancel();
+ LockList(c->NotifyCancelList);
+ {
+ Add(c->NotifyCancelList, cancel);
+ }
+ UnlockList(c->NotifyCancelList);
+
+ // Wait
+ while (true)
+ {
+ char ch = '@';
+ SOCKSET set;
+ InitSockSet(&set);
+ AddSockSet(&set, s);
+ Select(&set, INFINITE, cancel, NULL);
+
+ if (c->Halt)
+ {
+ // Abort
+ break;
+ }
+
+ // 1 byte transmission
+ if (Send(s, &ch, 1, false) == 0)
+ {
+ // Disconnected
+ break;
+ }
+ }
+
+ // Disconnect
+ Disconnect(s);
+
+ // Unregister the Cancel
+ LockList(c->NotifyCancelList);
+ {
+ Delete(c->NotifyCancelList, cancel);
+ }
+ UnlockList(c->NotifyCancelList);
+
+ ReleaseCancel(cancel);
+}
+
+// RPC acceptance code
+void CiRpcAccepted(CLIENT *c, SOCK *s)
+{
+ UCHAR hashed_password[SHA1_SIZE];
+ UINT rpc_mode;
+ UINT retcode;
+ RPC *rpc;
+ // Validate arguments
+ if (c == NULL || s == NULL)
+ {
+ return;
+ }
+
+ // Receive the RPC mode
+ if (RecvAll(s, &rpc_mode, sizeof(UINT), false) == false)
+ {
+ return;
+ }
+
+ rpc_mode = Endian32(rpc_mode);
+
+ if (rpc_mode == CLIENT_RPC_MODE_NOTIFY)
+ {
+ // Notification mode
+ CiNotifyMain(c, s);
+ return;
+ }
+ else if (rpc_mode == CLIENT_RPC_MODE_SHORTCUT || rpc_mode == CLIENT_RPC_MODE_SHORTCUT_DISCONNECT)
+ {
+ // Shortcut key received
+ UCHAR key[SHA1_SIZE];
+ UINT err = ERR_NO_ERROR;
+ if (RecvAll(s, key, SHA1_SIZE, false))
+ {
+ UINT i;
+ wchar_t title[MAX_ACCOUNT_NAME_LEN + 1];
+ bool ok = false;
+ // Connect to the specified setting
+ LockList(c->AccountList);
+ {
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+ Lock(a->lock);
+ {
+ if (Cmp(a->ShortcutKey, key, SHA1_SIZE) == 0)
+ {
+ ok = true;
+ UniStrCpy(title, sizeof(title), a->ClientOption->AccountName);
+ }
+ }
+ Unlock(a->lock);
+ }
+ }
+ UnlockList(c->AccountList);
+
+ if (ok == false)
+ {
+ err = ERR_ACCOUNT_NOT_FOUND;
+ }
+ else
+ {
+ RPC_CLIENT_CONNECT t;
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), title);
+
+ if (rpc_mode == CLIENT_RPC_MODE_SHORTCUT)
+ {
+ // Connect
+ if (CtConnect(c, &t))
+ {
+ err = ERR_NO_ERROR;
+ }
+ else
+ {
+ err = c->Err;
+ }
+ }
+ else
+ {
+ // Connect
+ if (CtDisconnect(c, &t, false))
+ {
+ err = ERR_NO_ERROR;
+ }
+ else
+ {
+ err = c->Err;
+ }
+ }
+ }
+
+ err = Endian32(err);
+ SendAll(s, &err, sizeof(UINT), false);
+ RecvAll(s, &err, sizeof(UINT), false);
+ }
+ return;
+ }
+
+ // Password reception
+ if (RecvAll(s, hashed_password, SHA1_SIZE, false) == false)
+ {
+ return;
+ }
+
+ retcode = 0;
+
+ // Password comparison
+ if (Cmp(hashed_password, c->EncryptedPassword, SHA1_SIZE) != 0)
+ {
+ retcode = 1;
+ }
+
+ if (c->PasswordRemoteOnly && s->RemoteIP.addr[0] == 127)
+ {
+ // If in a mode that requires a password only remote,
+ // the password sent from localhost is considered to be always correct
+ retcode = 0;
+ }
+
+ Lock(c->lock);
+ {
+ if (c->Config.AllowRemoteConfig == false)
+ {
+ // If the remote control is prohibited,
+ // identify whether this connection is from remote
+ if (s->RemoteIP.addr[0] != 127)
+ {
+ retcode = 2;
+ }
+ }
+ }
+ Unlock(c->lock);
+
+ retcode = Endian32(retcode);
+ // Error code transmission
+ if (SendAll(s, &retcode, sizeof(UINT), false) == false)
+ {
+ return;
+ }
+
+
+
+ if (retcode != 0)
+ {
+ // Disconnect due to an error
+ return;
+ }
+
+ // Create a RPC server
+ rpc = StartRpcServer(s, CiRpcDispatch, c);
+
+ // RPC server operation
+ RpcServer(rpc);
+
+ // Release the RPC server
+ EndRpc(rpc);
+}
+
+// RPC acceptance thread
+void CiRpcAcceptThread(THREAD *thread, void *param)
+{
+ CLIENT_RPC_CONNECTION *conn;
+ CLIENT *c;
+ SOCK *s;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ conn = (CLIENT_RPC_CONNECTION *)param;
+ s = conn->Sock;
+ c = conn->Client;
+ AddRef(s->ref);
+
+ // Add to the RPC connection list
+ LockList(c->RpcConnectionList);
+ {
+ Add(c->RpcConnectionList, conn);
+ }
+ UnlockList(c->RpcConnectionList);
+
+ NoticeThreadInit(thread);
+
+ // Main process
+ CiRpcAccepted(c, s);
+
+ // Release from the connection list
+ LockList(c->RpcConnectionList);
+ {
+ Delete(c->RpcConnectionList, conn);
+ }
+ UnlockList(c->RpcConnectionList);
+
+ ReleaseSock(conn->Sock);
+ ReleaseThread(conn->Thread);
+ Free(conn);
+
+ Disconnect(s);
+ ReleaseSock(s);
+}
+
+// RPC server thread
+void CiRpcServerThread(THREAD *thread, void *param)
+{
+ CLIENT *c;
+ SOCK *listener;
+ UINT i;
+ LIST *thread_list;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ c = (CLIENT *)param;
+
+ // RPC connection list
+ c->RpcConnectionList = NewList(NULL);
+
+ // Open the port
+ listener = NULL;
+ for (i = CLIENT_CONFIG_PORT;i < (CLIENT_CONFIG_PORT + 5);i++)
+ {
+ listener = Listen(i);
+ if (listener != NULL)
+ {
+ break;
+ }
+ }
+
+ if (listener == NULL)
+ {
+ // Error
+ Alert(CEDAR_PRODUCT_STR " VPN Client RPC Port Open Failed.", CEDAR_CLIENT_STR);
+ return;
+ }
+
+ c->RpcListener = listener;
+ AddRef(listener->ref);
+
+ NoticeThreadInit(thread);
+
+ while (true)
+ {
+ // Wait for client connection
+ CLIENT_RPC_CONNECTION *conn;
+ SOCK *s = Accept(listener);
+ if (s == NULL)
+ {
+ // Stop
+ break;
+ }
+
+ // Create a client processing thread
+ conn = ZeroMalloc(sizeof(CLIENT_RPC_CONNECTION));
+ conn->Client = c;
+ conn->Sock = s;
+ AddRef(s->ref);
+
+ conn->Thread = NewThread(CiRpcAcceptThread, (void *)conn);
+ WaitThreadInit(conn->Thread);
+
+ ReleaseSock(s);
+ }
+
+ // Release the listener
+ ReleaseSock(listener);
+
+ thread_list = NewListFast(NULL);
+
+ // Set all the event notification
+ LockList(c->NotifyCancelList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(c->NotifyCancelList);i++)
+ {
+ CANCEL *cancel = LIST_DATA(c->NotifyCancelList, i);
+ Cancel(cancel);
+ }
+ }
+ UnlockList(c->NotifyCancelList);
+
+ // Disconnect all the connections of connected yet
+ LockList(c->RpcConnectionList);
+ {
+ for (i = 0;i < LIST_NUM(c->RpcConnectionList);i++)
+ {
+ CLIENT_RPC_CONNECTION *cc = LIST_DATA(c->RpcConnectionList, i);
+ AddRef(cc->Thread->ref);
+ Add(thread_list, cc->Thread);
+ Disconnect(cc->Sock);
+ }
+ }
+ UnlockList(c->RpcConnectionList);
+
+ for (i = 0;i < LIST_NUM(thread_list);i++)
+ {
+ THREAD *t = LIST_DATA(thread_list, i);
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+ }
+
+ ReleaseList(c->RpcConnectionList);
+ ReleaseList(thread_list);
+}
+
+// Start the Keep
+void CiInitKeep(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->Keep = StartKeep();
+
+ // Apply settings
+ if (c->Config.UseKeepConnect)
+ {
+ KEEP *k = c->Keep;
+ Lock(k->lock);
+ {
+ StrCpy(k->ServerName, sizeof(k->ServerName), c->Config.KeepConnectHost);
+ k->ServerPort = c->Config.KeepConnectPort;
+ k->Interval = c->Config.KeepConnectInterval * 1000;
+ k->UdpMode = (c->Config.KeepConnectProtocol == CONNECTION_UDP) ? true : false;
+ k->Enable = true;
+ }
+ Unlock(k->lock);
+ }
+}
+
+// Stop the Keep
+void CiFreeKeep(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ StopKeep(c->Keep);
+ c->Keep = NULL;
+}
+
+// Start the RPC
+void CiStartRpcServer(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->RpcThread = NewThread(CiRpcServerThread, (void *)c);
+ WaitThreadInit(c->RpcThread);
+}
+
+// Stop the RPC
+void CiStopRpcServer(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ Disconnect(c->RpcListener);
+ ReleaseSock(c->RpcListener);
+
+ WaitThread(c->RpcThread, INFINITE);
+ ReleaseThread(c->RpcThread);
+}
+
+// Wait for the next notification
+bool CcWaitNotify(NOTIFY_CLIENT *n)
+{
+ UCHAR c;
+ // Validate arguments
+ if (n == NULL)
+ {
+ return false;
+ }
+
+ // 1 character reception
+ if (RecvAll(n->Sock, &c, 1, false) == false)
+ {
+ // Disconnected
+ return false;
+ }
+
+ return true;
+}
+
+// Connect as a notification client
+NOTIFY_CLIENT *CcConnectNotify(REMOTE_CLIENT *rc)
+{
+ NOTIFY_CLIENT *n;
+ SOCK *s;
+ char tmp[MAX_SIZE];
+ bool rpc_mode = false;
+ UINT port;
+ // Validate arguments
+ if (rc == NULL || rc->Rpc == NULL || rc->Rpc->Sock == NULL)
+ {
+ return NULL;
+ }
+
+ // Connect
+ IPToStr(tmp, sizeof(tmp), &rc->Rpc->Sock->RemoteIP);
+ port = rc->Rpc->Sock->RemotePort;
+
+ s = Connect(tmp, port);
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ rpc_mode = Endian32(rpc_mode);
+ if (SendAll(s, &rpc_mode, sizeof(rpc_mode), false) == false)
+ {
+ ReleaseSock(s);
+ return NULL;
+ }
+
+ n = ZeroMalloc(sizeof(NOTIFY_CLIENT));
+ n->Sock = s;
+
+ return n;
+}
+
+// Stop the notification client
+void CcStopNotify(NOTIFY_CLIENT *n)
+{
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ Disconnect(n->Sock);
+}
+
+// Delete the notification client
+void CcDisconnectNotify(NOTIFY_CLIENT *n)
+{
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ // Disconnect
+ Disconnect(n->Sock);
+ ReleaseSock(n->Sock);
+
+ // Memory release
+ Free(n);
+}
+
+// Disconnect the remote connection
+void CcDisconnectRpc(REMOTE_CLIENT *rc)
+{
+ // Validate arguments
+ if (rc == NULL)
+ {
+ return;
+ }
+
+ RpcFree(rc->Rpc);
+ Free(rc);
+}
+
+// Connect to the client to start the shortcut connection setting
+UINT CcShortcut(UCHAR *key)
+{
+ UINT ret;
+ // Validate arguments
+ if (key == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ CcConnectRpcEx("localhost", NULL, NULL, NULL, key, &ret, false, 0);
+
+ return ret;
+}
+
+// Disconnect the connected shortcut connection
+UINT CcShortcutDisconnect(UCHAR *key)
+{
+ UINT ret;
+ // Validate arguments
+ if (key == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ CcConnectRpcEx("localhost", NULL, NULL, NULL, key, &ret, true, 0);
+
+ return ret;
+}
+
+// Connect to the remote client
+REMOTE_CLIENT *CcConnectRpc(char *server_name, char *password, bool *bad_pass, bool *no_remote, UINT wait_retry)
+{
+ return CcConnectRpcEx(server_name, password, bad_pass, no_remote, NULL, NULL, false, wait_retry);
+}
+REMOTE_CLIENT *CcConnectRpcEx(char *server_name, char *password, bool *bad_pass, bool *no_remote, UCHAR *key, UINT *key_error_code, bool shortcut_disconnect, UINT wait_retry)
+{
+ SOCK *s;
+ UINT i;
+ UINT retcode;
+ UINT rpc_mode = CLIENT_RPC_MODE_MANAGEMENT;
+ RPC *rpc;
+ REMOTE_CLIENT *ret;
+ UCHAR hash_password[SHA1_SIZE];
+ UINT port_start;
+ UINT64 try_started = 0;
+ bool ok;
+ // Validate arguments
+ if (server_name == NULL)
+ {
+ return NULL;
+ }
+ if (password == NULL)
+ {
+ password = "";
+ }
+
+ if (key_error_code != NULL)
+ {
+ *key_error_code = ERR_NO_ERROR;
+ }
+
+ if (bad_pass != NULL)
+ {
+ *bad_pass = false;
+ }
+
+ if (no_remote != NULL)
+ {
+ *no_remote = false;
+ }
+
+ port_start = CLIENT_CONFIG_PORT - 1;
+
+RETRY:
+ port_start++;
+
+ if (port_start >= (CLIENT_CONFIG_PORT + 5))
+ {
+ return NULL;
+ }
+
+ ok = false;
+
+ while (true)
+ {
+ for (i = port_start;i < (CLIENT_CONFIG_PORT + 5);i++)
+ {
+ if (CheckTCPPort(server_name, i))
+ {
+ ok = true;
+ break;
+ }
+ }
+
+ if (ok)
+ {
+ break;
+ }
+
+ if (wait_retry == 0)
+ {
+ break;
+ }
+
+ if (try_started == 0)
+ {
+ try_started = Tick64();
+ }
+
+ if ((try_started + (UINT64)wait_retry) <= Tick64())
+ {
+ break;
+ }
+ }
+
+ if (ok == false)
+ {
+ if (key_error_code)
+ {
+ *key_error_code = ERR_CONNECT_FAILED;
+ }
+ return NULL;
+ }
+
+ port_start = i;
+
+ s = Connect(server_name, i);
+ if (s == NULL)
+ {
+ if (key_error_code)
+ {
+ *key_error_code = ERR_CONNECT_FAILED;
+ }
+ goto RETRY;
+ }
+
+ Hash(hash_password, password, StrLen(password), true);
+
+ if (key != NULL)
+ {
+ if (shortcut_disconnect == false)
+ {
+ rpc_mode = CLIENT_RPC_MODE_SHORTCUT;
+ }
+ else
+ {
+ rpc_mode = CLIENT_RPC_MODE_SHORTCUT_DISCONNECT;
+ }
+ }
+
+ rpc_mode = Endian32(rpc_mode);
+ SendAdd(s, &rpc_mode, sizeof(UINT));
+
+ if (key != NULL)
+ {
+ SendAdd(s, key, SHA1_SIZE);
+ }
+ else
+ {
+ SendAdd(s, hash_password, SHA1_SIZE);
+ }
+
+ if (SendNow(s, false) == false)
+ {
+ ReleaseSock(s);
+ goto RETRY;
+ }
+
+ if (RecvAll(s, &retcode, sizeof(UINT), false) == false)
+ {
+ ReleaseSock(s);
+ goto RETRY;
+ }
+
+ retcode = Endian32(retcode);
+
+ if (retcode >= 1024)
+ {
+ goto RETRY;
+ }
+
+ if (key != NULL)
+ {
+ if (key_error_code)
+ {
+ *key_error_code = retcode;
+ }
+ SendAll(s, &retcode, sizeof(UINT), false);
+ ReleaseSock(s);
+ return NULL;
+ }
+
+ switch (retcode)
+ {
+ case 1:
+ if (bad_pass != NULL)
+ {
+ *bad_pass = true;
+ }
+ break;
+ case 2:
+ if (no_remote != NULL)
+ {
+ *no_remote = true;
+ }
+ break;
+ }
+
+ if (retcode != 0)
+ {
+ ReleaseSock(s);
+ return NULL;
+ }
+
+ rpc = StartRpcClient(s, NULL);
+
+ ReleaseSock(s);
+
+ ret = ZeroMalloc(sizeof(REMOTE_CLIENT));
+ ret->Rpc = rpc;
+ rpc->Param = ret;
+
+ if (ret != NULL)
+ {
+ RPC_CLIENT_VERSION t;
+ Zero(&t, sizeof(t));
+ CcGetClientVersion(ret, &t);
+ ret->OsType = t.OsType;
+ ret->Unix = OS_IS_UNIX(ret->OsType);
+ ret->Win9x = OS_IS_WINDOWS_9X(ret->OsType);
+ ret->IsVgcSupported = t.IsVgcSupported;
+ ret->ShowVgcLink = t.ShowVgcLink;
+ StrCpy(ret->ClientId, sizeof(ret->ClientId), t.ClientId);
+ }
+
+ return ret;
+}
+
+// Get a RPC_CLIENT_GET_CONNECTION_STATUS from the session
+void CiGetSessionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *st, SESSION *s)
+{
+ // Validate arguments
+ if (st == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Lock(s->lock);
+ {
+ // Operation flag
+ st->Active = true;
+
+ // Session status
+ st->SessionStatus = s->ClientStatus;
+
+ // Account name
+ UniStrCpy(st->AccountName, sizeof(st->AccountName), s->ClientOption->AccountName);
+
+ if (s->ClientStatus == CLIENT_STATUS_ESTABLISHED && s->Connection != NULL)
+ {
+ Lock(s->Connection->lock);
+ {
+ // Connected flag
+ st->Connected = true;
+ // Product name
+ StrCpy(st->ServerProductName, sizeof(st->ServerProductName), s->Connection->ServerStr);
+ // Version
+ st->ServerProductVer = s->Connection->ServerVer;
+ // Build Number
+ st->ServerProductBuild = s->Connection->ServerBuild;
+ // Server certificate
+ st->ServerX = CloneX(s->Connection->ServerX);
+ // Client certificate
+ st->ClientX = CloneX(s->Connection->ClientX);
+ // Connection completion time of this connection
+ st->CurrentConnectionEstablishTime = TickToTime(s->CurrentConnectionEstablishTime);
+ // Maximum number of the TCP connections
+ st->MaxTcpConnections = s->MaxConnection;
+ // Half-connection
+ st->HalfConnection = s->HalfConnection;
+ // VLAN
+ st->VLanId = s->VLanId;
+ // VoIP / QoS
+ st->QoS = s->QoS;
+ if (s->Connection->Protocol == CONNECTION_TCP)
+ {
+ UINT i;
+ // Number of current TCP connections
+ LockList(s->Connection->Tcp->TcpSockList);
+ {
+ st->NumTcpConnections = LIST_NUM(s->Connection->Tcp->TcpSockList);
+ if (st->HalfConnection)
+ {
+ for (i = 0;i < st->NumTcpConnections;i++)
+ {
+ TCPSOCK *ts = LIST_DATA(s->Connection->Tcp->TcpSockList, i);
+ if (ts->Direction & TCP_SERVER_TO_CLIENT)
+ {
+ st->NumTcpConnectionsDownload++;
+ }
+ else
+ {
+ st->NumTcpConnectionsUpload++;
+ }
+ }
+ }
+ }
+ UnlockList(s->Connection->Tcp->TcpSockList);
+ }
+ // Use of encryption
+ st->UseEncrypt = s->UseEncrypt;
+ if (st->UseEncrypt)
+ {
+ StrCpy(st->CipherName, sizeof(st->CipherName), s->Connection->CipherName);
+ }
+ // Use of compression
+ st->UseCompress = s->UseCompress;
+ // R-UDP
+ st->IsRUDPSession = s->IsRUDPSession;
+ // Physical communication protocol
+ StrCpy(st->UnderlayProtocol, sizeof(st->UnderlayProtocol), s->UnderlayProtocol);
+ // UDP acceleration function
+ st->IsUdpAccelerationEnabled = s->UseUdpAcceleration;
+ st->IsUsingUdpAcceleration = s->IsUsingUdpAcceleration;
+ // Session key
+ Copy(st->SessionKey, s->SessionKey, SHA1_SIZE);
+ // Policy
+ Copy(&st->Policy, s->Policy, sizeof(POLICY));
+ // Data size
+ if (s->ServerMode == false)
+ {
+ st->TotalSendSize = s->TotalSendSize;
+ st->TotalRecvSize = s->TotalRecvSize;
+ st->TotalRecvSizeReal = s->TotalRecvSizeReal;
+ st->TotalSendSizeReal = s->TotalSendSizeReal;
+ }
+ else
+ {
+ st->TotalSendSize = s->TotalRecvSize;
+ st->TotalRecvSize = s->TotalSendSize;
+ st->TotalRecvSizeReal = s->TotalSendSizeReal;
+ st->TotalSendSizeReal = s->TotalRecvSizeReal;
+ }
+ // Session name
+ StrCpy(st->SessionName, sizeof(st->SessionName), s->Name);
+ // Connection name
+ StrCpy(st->ConnectionName, sizeof(st->ConnectionName), s->Connection->Name);
+ // Server name
+ StrCpy(st->ServerName, sizeof(st->ServerName), s->Connection->ServerName);
+ // Port number
+ st->ServerPort = s->Connection->ServerPort;
+ // Traffic data
+ Lock(s->TrafficLock);
+ {
+ Copy(&st->Traffic, s->Traffic, sizeof(TRAFFIC));
+ }
+ Unlock(s->TrafficLock);
+
+ st->IsBridgeMode = s->IsBridgeMode;
+ st->IsMonitorMode = s->IsMonitorMode;
+ }
+ Unlock(s->Connection->lock);
+ }
+ // Connection start time
+ st->StartTime = TickToTime(s->CreatedTime);
+ // Connection completion time of the first connection
+ st->FirstConnectionEstablisiedTime = TickToTime(s->FirstConnectionEstablisiedTime);
+ // Number of connections have been established so far
+ st->NumConnectionsEatablished = s->NumConnectionsEatablished;
+ }
+ Unlock(s->lock);
+}
+
+// Get the connection status
+bool CtGetAccountStatus(CLIENT *c, RPC_CLIENT_GET_CONNECTION_STATUS *st)
+{
+ // Validate arguments
+ if (c == NULL || st == NULL)
+ {
+ return false;
+ }
+
+ LockList(c->AccountList);
+ {
+ ACCOUNT t, *r;
+
+ // Search for account
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), st->AccountName);
+
+ r = Search(c->AccountList, &t);
+ if (r == NULL)
+ {
+ // Specified account is not found
+ UnlockList(c->AccountList);
+
+ Free(t.ClientOption);
+ CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+ Lock(r->lock);
+ {
+ Zero(st, sizeof(RPC_CLIENT_GET_CONNECTION_STATUS));
+ if (r->ClientSession != NULL)
+ {
+ SESSION *s = r->ClientSession;
+ CiGetSessionStatus(st, s);
+ }
+ }
+ Unlock(r->lock);
+ }
+ UnlockList(c->AccountList);
+
+ return true;
+}
+
+// Release the connection status
+void CiFreeClientGetConnectionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *st)
+{
+ // Validate arguments
+ if (st == NULL)
+ {
+ return;
+ }
+
+ if (st->ServerX != NULL)
+ {
+ FreeX(st->ServerX);
+ }
+
+ if (st->ClientX != NULL)
+ {
+ FreeX(st->ClientX);
+ }
+}
+
+// Verification procedure of the server certificate
+bool CiCheckCertProc(SESSION *s, CONNECTION *c, X *server_x, bool *expired)
+{
+#ifdef OS_WIN32
+ ACCOUNT *a;
+ X *old_x = NULL;
+ UI_CHECKCERT dlg;
+ // Validate arguments
+ if (s == NULL || c == NULL || server_x == NULL)
+ {
+ return false;
+ }
+
+ if (expired != NULL)
+ {
+ *expired = false;
+ }
+
+ Zero(&dlg, sizeof(dlg));
+
+ a = s->Account;
+ if (a == NULL)
+ {
+ return false;
+ }
+
+ Lock(a->lock);
+ {
+ if (a->CheckServerCert == false)
+ {
+ // Not to validate the server certificate
+ Unlock(a->lock);
+ return true;
+ }
+
+ if (a->ServerCert != NULL)
+ {
+ old_x = CloneX(a->ServerCert);
+ }
+ }
+ Unlock(a->lock);
+
+ if (CheckXDateNow(server_x) == false)
+ {
+ // Expired
+ if (old_x != NULL)
+ {
+ FreeX(old_x);
+ }
+
+ if (expired != NULL)
+ {
+ *expired = true;
+ }
+
+ return false;
+ }
+
+ if (old_x != NULL)
+ {
+ if (CompareX(old_x, server_x))
+ {
+ // Matched exactly to the certificate that is already registered
+ if (old_x != NULL)
+ {
+ FreeX(old_x);
+ }
+ return true;
+ }
+ else
+ {
+ dlg.DiffWarning = true;
+ }
+ }
+
+ // Because this certificate can not be trusted, confirm to be trusted by showing a dialog box
+ UniStrCpy(dlg.AccountName, sizeof(dlg.AccountName), a->ClientOption->AccountName);
+ StrCpy(dlg.ServerName, sizeof(dlg.ServerName), a->ClientOption->Hostname);
+ dlg.x = server_x;
+ dlg.old_x = old_x;
+
+ dlg.Session = s;
+ AddRef(s->ref);
+
+ CncCheckCert(s, &dlg);
+
+ ReleaseSession(s);
+
+ if (old_x != NULL)
+ {
+ FreeX(old_x);
+ }
+
+ if (dlg.Ok && dlg.SaveServerCert)
+ {
+ // Save the server certificate and trust it from the next time
+ Lock(a->lock);
+ {
+ if (a->ServerCert != NULL)
+ {
+ FreeX(a->ServerCert);
+ }
+
+ a->ServerCert = CloneX(server_x);
+ }
+ Unlock(a->lock);
+ CiSaveConfigurationFile(s->Cedar->Client);
+ }
+
+ return dlg.Ok;
+#else // OS_WIN32
+ ACCOUNT *a;
+ X *old_x = NULL;
+ // Validate arguments
+ if (s == NULL || c == NULL || server_x == NULL)
+ {
+ return false;
+ }
+
+ if (expired != NULL)
+ {
+ *expired = false;
+ }
+
+ a = s->Account;
+ if (a == NULL)
+ {
+ return false;
+ }
+
+ Lock(a->lock);
+ {
+ if (a->CheckServerCert == false)
+ {
+ // Not to validate the server certificate
+ Unlock(a->lock);
+ return true;
+ }
+
+ if (a->ServerCert != NULL)
+ {
+ old_x = CloneX(a->ServerCert);
+ }
+ }
+ Unlock(a->lock);
+
+ if (CheckXDateNow(server_x) == false)
+ {
+ // Expired
+ if (old_x != NULL)
+ {
+ FreeX(old_x);
+ }
+
+ if (expired != NULL)
+ {
+ *expired = true;
+ }
+
+ return false;
+ }
+
+ if (old_x != NULL)
+ {
+ if (CompareX(old_x, server_x))
+ {
+ // Exactly matched to the certificate that is already registered
+ if (old_x != NULL)
+ {
+ FreeX(old_x);
+ }
+ return true;
+ }
+ else
+ {
+ // Mismatch
+ if (old_x != NULL)
+ {
+ FreeX(old_x);
+ }
+ return false;
+ }
+ }
+
+ if (old_x != NULL)
+ {
+ FreeX(old_x);
+ }
+
+ return false;
+#endif // OS_WIN32
+}
+
+// Signature procedure with a secure device
+bool CiSecureSignProc(SESSION *s, CONNECTION *c, SECURE_SIGN *sign)
+{
+ // The UI is available in Win32
+ return CncSecureSignDlg(sign);
+}
+
+#ifdef OS_WIN32
+// Signing procedure (for Win32)
+bool Win32CiSecureSign(SECURE_SIGN *sign)
+{
+ bool ret = false;
+ BUF *random;
+ // Validate arguments
+ if (sign == NULL)
+ {
+ return false;
+ }
+
+ random = NewBuf();
+ WriteBuf(random, sign->Random, SHA1_SIZE);
+
+ // Batch processing
+ {
+ WINUI_SECURE_BATCH batch[] =
+ {
+ {WINUI_SECURE_READ_CERT, sign->SecurePublicCertName, true, NULL, NULL, NULL, NULL, NULL, NULL},
+ {WINUI_SECURE_SIGN_WITH_KEY, sign->SecurePrivateKeyName, true, random, NULL, NULL, NULL, NULL, NULL}
+ };
+
+ if (SecureDeviceWindow(NULL, batch, sizeof(batch) / sizeof(batch[0]),
+ sign->UseSecureDeviceId, sign->BitmapId) == false)
+ {
+ // Failure
+ if (batch[0].OutputX != 0)
+ {
+ FreeX(batch[0].OutputX);
+ }
+ ret = false;
+ }
+ else
+ {
+ // Success
+ ret = true;
+ sign->ClientCert = batch[0].OutputX;
+ Copy(sign->Signature, batch[1].OutputSign, 128);
+ }
+ }
+
+ FreeBuf(random);
+
+ return ret;
+}
+#endif // OS_WIN32
+
+// Disconnect
+bool CtDisconnect(CLIENT *c, RPC_CLIENT_CONNECT *connect, bool inner)
+{
+ bool ret = false;
+ ACCOUNT t, *r;
+ SESSION *s = NULL;
+ // Validate arguments
+ if (c == NULL || connect == NULL)
+ {
+ return false;
+ }
+
+ LockList(c->AccountList);
+ {
+ // Search for account
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), connect->AccountName);
+
+ r = Search(c->AccountList, &t);
+ if (r == NULL)
+ {
+ // Specified account isn't found
+ UnlockList(c->AccountList);
+
+ Free(t.ClientOption);
+ CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+ Lock(r->lock);
+ {
+ if (r->ClientSession == NULL)
+ {
+ // Not connected
+ CiSetError(c, ERR_ACCOUNT_INACTIVE);
+ }
+ else
+ {
+ s = r->ClientSession;
+ AddRef(s->ref);
+ // Disconnect complete
+ r->ClientSession = NULL;
+ ret = true;
+ }
+ }
+ Unlock(r->lock);
+ }
+ UnlockList(c->AccountList);
+
+ if (s != NULL)
+ {
+ // Disconnect the connection (Wait until the disconnection is complete)
+ CLog(c, "LC_DISCONNECT", connect->AccountName);
+ StopSession(s);
+ ReleaseSession(s);
+ }
+
+
+ if (ret != false)
+ {
+ CiNotify(c);
+ }
+
+ return ret;
+}
+
+// Connect
+bool CtConnect(CLIENT *c, RPC_CLIENT_CONNECT *connect)
+{
+ bool ret = false;
+ RPC_CLIENT_ENUM_VLAN t;
+ // Validate arguments
+ if (c == NULL || connect == NULL)
+ {
+ return false;
+ }
+
+ Lock(c->lockForConnect);
+ {
+ Zero(&t, sizeof(t));
+ if (CtEnumVLan(c, &t))
+ {
+ if (t.NumItem == 0)
+ {
+ // There are no virtual LAN cards in the system
+ if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) || OS_IS_UNIX(GetOsInfo()->OsType))
+ {
+ // Only in Linux system or Windows NT system,
+ // create a new virtual LAN card which named as "VPN" automatically
+ RPC_CLIENT_CREATE_VLAN t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), "VPN");
+ CtCreateVLan(c, &t);
+ }
+ }
+
+ CiFreeClientEnumVLan(&t);
+ }
+ }
+ Unlock(c->lockForConnect);
+
+ CiNormalizeAccountVLan(c);
+
+ // Ensure successfully VPN communication by changing the irrational WCM settings in the case of Windows 8 or later
+ CiDisableWcmNetworkMinimize(c);
+
+ LockList(c->AccountList);
+ {
+ ACCOUNT t, *r;
+ bool unix_disabled = false;
+
+ // Search for account
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), connect->AccountName);
+
+ r = Search(c->AccountList, &t);
+ if (r == NULL)
+ {
+ // Specified account isn't found
+ UnlockList(c->AccountList);
+
+ Free(t.ClientOption);
+ CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+#ifndef OS_WIN32
+ // Search for the virtual LAN card
+ LockList(c->UnixVLanList);
+ {
+ UNIX_VLAN *v, t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), r->ClientOption->DeviceName);
+
+ v = Search(c->UnixVLanList, &t);
+ if (v == NULL)
+ {
+ UnlockList(c->UnixVLanList);
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ return false;
+ }
+
+ unix_disabled = v->Enabled ? false : true;
+ }
+ UnlockList(c->UnixVLanList);
+#endif // OS_WIN32
+
+ Lock(r->lock);
+ {
+ bool already_used = false;
+ UINT i;
+
+ if (r->ClientSession != NULL)
+ {
+ // Already in connecting
+ CiSetError(c, ERR_ACCOUNT_ACTIVE);
+ }
+ else if (r->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE &&
+ client->UseSecureDeviceId == 0)
+ {
+ // Secure device is not specified
+ CiSetError(c, ERR_NO_SECURE_DEVICE_SPECIFIED);
+ }
+#ifdef OS_WIN32
+ else if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, r->ClientOption->DeviceName) == false &&
+ MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, r->ClientOption->DeviceName) == false)
+ {
+ // Virtual LAN card can not be found
+ CiSetError(c, ERR_VLAN_FOR_ACCOUNT_NOT_FOUND);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ }
+ else if (MsIsVLanEnabled(r->ClientOption->DeviceName) == false)
+ {
+ // The virtual LAN card is disabled
+ CiSetError(c, ERR_VLAN_FOR_ACCOUNT_DISABLED);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ }
+#else // OS_WIN32
+ else if (unix_disabled)
+ {
+ // The virtual LAN card is disabled
+ CiSetError(c, ERR_VLAN_FOR_ACCOUNT_DISABLED);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ }
+#endif // OS_WIN32
+ else
+ {
+ // Check whether the virtual LAN card is being used by a different account already
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+ if (a != r)
+ {
+ if (StrCmpi(a->ClientOption->DeviceName,
+ r->ClientOption->DeviceName) == 0)
+ {
+ if (a->ClientSession != NULL)
+ {
+ already_used = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (already_used)
+ {
+ CiSetError(c, ERR_VLAN_FOR_ACCOUNT_USED);
+ }
+ else
+ {
+ // Start the connection
+ PACKET_ADAPTER *pa = VLanGetPacketAdapter();
+
+ if (r->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE)
+ {
+ // Register a procedure for secure device authentication
+ r->ClientAuth->SecureSignProc = CiSecureSignProc;
+ }
+ else
+ {
+ r->ClientAuth->SecureSignProc = NULL;
+ }
+
+ if (r->CheckServerCert)
+ {
+ // Register a procedure to validate the server certificate
+ r->ClientAuth->CheckCertProc = CiCheckCertProc;
+ }
+ else
+ {
+ r->ClientAuth->CheckCertProc = NULL;
+ }
+
+ r->StatusPrinter = CiClientStatusPrinter;
+ r->LastConnectDateTime = SystemTime64();
+
+ CLog(c, "LC_CONNECT", connect->AccountName);
+
+ r->ClientSession = NewClientSessionEx(c->Cedar, r->ClientOption, r->ClientAuth, pa, r);
+ Notify(r->ClientSession, CLIENT_NOTIFY_ACCOUNT_CHANGED);
+
+ ret = true;
+ }
+ }
+ }
+ Unlock(r->lock);
+
+ }
+ UnlockList(c->AccountList);
+
+ CiSaveConfigurationFile(c);
+
+ return ret;
+}
+
+// Get the account information
+bool CtGetAccount(CLIENT *c, RPC_CLIENT_GET_ACCOUNT *a)
+{
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+ LockList(c->AccountList);
+ {
+ ACCOUNT t, *r;
+
+ // Search for account
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName);
+
+ r = Search(c->AccountList, &t);
+ if (r == NULL)
+ {
+ // Specified account can not be found
+ UnlockList(c->AccountList);
+
+ Free(t.ClientOption);
+ CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+ Lock(r->lock);
+ {
+ // Copy the client option
+ if (a->ClientOption != NULL)
+ {
+ Free(a->ClientOption);
+ }
+ a->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(a->ClientOption, r->ClientOption, sizeof(CLIENT_OPTION));
+
+ // Copy the authentication data
+ if (a->ClientAuth != NULL)
+ {
+ CiFreeClientAuth(a->ClientAuth);
+ }
+ a->ClientAuth = CopyClientAuth(r->ClientAuth);
+
+ a->StartupAccount = r->StartupAccount;
+
+ a->CheckServerCert = r->CheckServerCert;
+ a->ServerCert = NULL;
+ if (r->ServerCert != NULL)
+ {
+ a->ServerCert = CloneX(r->ServerCert);
+ }
+
+ // Shortcut Key
+ Copy(a->ShortcutKey, r->ShortcutKey, SHA1_SIZE);
+
+ a->CreateDateTime = r->CreateDateTime;
+ a->LastConnectDateTime = r->LastConnectDateTime;
+ a->UpdateDateTime = r->UpdateDateTime;
+ }
+ Unlock(r->lock);
+
+ }
+ UnlockList(c->AccountList);
+
+ return true;
+}
+
+// Change the account name
+bool CtRenameAccount(CLIENT *c, RPC_RENAME_ACCOUNT *rename, bool inner)
+{
+ bool ret;
+ // Validate arguments
+ if (c == NULL || rename == NULL)
+ {
+ return false;
+ }
+
+
+ ret = false;
+
+ if (UniStrCmp(rename->NewName, rename->OldName) == 0)
+ {
+ // The name has not been changed
+ return true;
+ }
+
+ LockList(c->AccountList);
+ {
+ ACCOUNT t, *r, *r2;
+
+ if (UniStrLen(rename->NewName) == 0)
+ {
+ // Name is invalid
+ CiSetError(c, ERR_INVALID_VALUE);
+ UnlockList(c->AccountList);
+ return false;
+ }
+
+ // Search for old account name
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), rename->OldName);
+
+ r = Search(c->AccountList, &t);
+ if (r == NULL)
+ {
+ // Specified account can not be found
+ UnlockList(c->AccountList);
+
+ Free(t.ClientOption);
+ CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+ // Search for a new account name
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), rename->NewName);
+
+ r2 = Search(c->AccountList, &t);
+ if (r2 != NULL)
+ {
+ // Account with the specified name already exists
+ UnlockList(c->AccountList);
+
+ Free(t.ClientOption);
+ CiSetError(c, ERR_ACCOUNT_ALREADY_EXISTS);
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+ Lock(r->lock);
+ {
+ // Check the operating state of the account
+ if (r->ClientSession != NULL)
+ {
+ // The Account is working
+ Unlock(r->lock);
+ UnlockList(c->AccountList);
+ CiSetError(c, ERR_ACCOUNT_ACTIVE);
+
+ return false;
+ }
+
+ // Update the account name
+ UniStrCpy(r->ClientOption->AccountName, sizeof(r->ClientOption->AccountName),
+ rename->NewName);
+
+ CLog(c, "LC_RENAME_ACCOUNT", rename->OldName, rename->NewName);
+
+ ret = true;
+ }
+ Unlock(r->lock);
+
+ Sort(c->AccountList);
+
+ }
+ UnlockList(c->AccountList);
+
+ CiSaveConfigurationFile(c);
+
+ CiNotify(c);
+
+ return ret;
+}
+
+// Set the client configuration
+bool CtSetClientConfig(CLIENT *c, CLIENT_CONFIG *o)
+{
+ KEEP *k;
+ // Validate arguments
+ if (c == NULL || o == NULL)
+ {
+ return false;
+ }
+
+ if (o->UseKeepConnect)
+ {
+ if (IsEmptyStr(o->KeepConnectHost) ||
+ o->KeepConnectPort == 0 ||
+ o->KeepConnectPort >= 65536)
+ {
+ CiSetError(c, ERR_INVALID_PARAMETER);
+ return false;
+ }
+ }
+
+ Lock(c->lock);
+ {
+ Copy(&c->Config, o, sizeof(CLIENT_CONFIG));
+ }
+ Unlock(c->lock);
+
+ // Save the settings
+ CiSaveConfigurationFile(c);
+
+ // Apply the Keep Connect
+ k = c->Keep;
+ Lock(k->lock);
+ {
+ if (o->UseKeepConnect)
+ {
+ StrCpy(k->ServerName, sizeof(k->ServerName), c->Config.KeepConnectHost);
+ k->ServerPort = c->Config.KeepConnectPort;
+ k->Interval = c->Config.KeepConnectInterval * 1000;
+ k->UdpMode = (c->Config.KeepConnectProtocol == CONNECTION_UDP) ? true : false;
+ k->Enable = true;
+ }
+ else
+ {
+ k->Enable = false;
+ }
+ }
+ Unlock(k->lock);
+
+ return true;
+}
+
+// Get the network client configuration
+bool CtGetClientConfig(CLIENT *c, CLIENT_CONFIG *o)
+{
+ // Validate arguments
+ if (c == NULL || o == NULL)
+ {
+ return false;
+ }
+
+ Lock(c->lock);
+ {
+ Copy(o, &c->Config, sizeof(CLIENT_CONFIG));
+ }
+ Unlock(c->lock);
+
+ return true;
+}
+
+// Unset the startup attribute of the account
+bool CtRemoveStartupAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a)
+{
+ bool ret;
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+ ret = false;
+
+ LockList(c->AccountList);
+ {
+ ACCOUNT t, *r;
+ // Search for an Account
+
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName);
+
+ r = Search(c->AccountList, &t);
+ if (r == NULL)
+ {
+ // Specified account can not be found
+ UnlockList(c->AccountList);
+
+ Free(t.ClientOption);
+ CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+ Lock(r->lock);
+ {
+ // Unset the startup account
+ ret = true;
+ r->StartupAccount = false;
+ }
+ Unlock(r->lock);
+ }
+ UnlockList(c->AccountList);
+
+ if (ret)
+ {
+ CiSaveConfigurationFile(c);
+ CiNotify(c);
+ }
+
+ return ret;
+}
+
+// Set the account as a start-up account
+bool CtSetStartupAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a, bool inner)
+{
+ bool ret;
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+
+ ret = false;
+
+ LockList(c->AccountList);
+ {
+ ACCOUNT t, *r;
+ // Search for an account
+
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName);
+
+ r = Search(c->AccountList, &t);
+ if (r == NULL)
+ {
+ // Specified account can not be found
+ UnlockList(c->AccountList);
+
+ Free(t.ClientOption);
+ CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+ Lock(r->lock);
+ {
+ // Set to a start-up account
+ ret = true;
+ r->StartupAccount = true;
+ }
+ Unlock(r->lock);
+ }
+ UnlockList(c->AccountList);
+
+ if (ret)
+ {
+ CiSaveConfigurationFile(c);
+ CiNotify(c);
+ }
+
+ return ret;
+}
+
+// Delete the account
+bool CtDeleteAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a, bool inner)
+{
+ bool ret;
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+ ret = false;
+
+ if (c->Halt)
+ {
+ // Don't allow the removal of the account in the process of stopping
+ CiSetError(c, ERR_INTERNAL_ERROR);
+ return false;
+ }
+
+ LockList(c->AccountList);
+ {
+ ACCOUNT t, *r;
+ // Search for an Account
+
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName);
+
+ r = Search(c->AccountList, &t);
+ if (r == NULL)
+ {
+ // Specified account can not be found
+ UnlockList(c->AccountList);
+
+ Free(t.ClientOption);
+ CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+ Lock(r->lock);
+ {
+ // Check the operating state of the account
+ if (r->ClientSession != NULL)
+ {
+ // The account is active
+ Unlock(r->lock);
+ UnlockList(c->AccountList);
+ CiSetError(c, ERR_ACCOUNT_ACTIVE);
+
+ return false;
+ }
+
+ // Remove this account from the list
+ Delete(c->AccountList, r);
+ }
+ Unlock(r->lock);
+
+ // Free the memory of this account
+ CiFreeAccount(r);
+
+ CLog(c, "LC_DELETE_ACCOUNT", a->AccountName);
+ ret = true;
+
+ }
+ UnlockList(c->AccountList);
+
+ if (ret)
+ {
+ CiSaveConfigurationFile(c);
+ CiNotify(c);
+ }
+
+ return ret;
+}
+
+// Enumeration of accounts
+bool CtEnumAccount(CLIENT *c, RPC_CLIENT_ENUM_ACCOUNT *e)
+{
+ // Validate arguments
+ if (c == NULL || e == NULL)
+ {
+ return false;
+ }
+
+ LockList(c->AccountList);
+ {
+ UINT i;
+ // Number of accounts
+ e->NumItem = LIST_NUM(c->AccountList);
+ e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM *) * e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM));
+ e->Items[i] = item;
+
+ // Account name
+ UniStrCpy(item->AccountName, sizeof(item->AccountName), a->ClientOption->AccountName);
+
+ // User name
+ StrCpy(item->UserName, sizeof(item->UserName), a->ClientAuth->Username);
+
+ // Server name
+ StrCpy(item->ServerName, sizeof(item->ServerName), a->ClientOption->Hostname);
+
+ // Proxy type
+ item->ProxyType = a->ClientOption->ProxyType;
+
+ // Device name
+ StrCpy(item->DeviceName, sizeof(item->DeviceName), a->ClientOption->DeviceName);
+
+ // Proxy information
+ if (item->ProxyType != PROXY_DIRECT)
+ {
+ StrCpy(item->ProxyName, sizeof(item->ProxyName), a->ClientOption->ProxyName);
+ }
+
+ // Startup
+ item->StartupAccount = a->StartupAccount;
+
+ // Active flag
+ item->Active = (a->ClientSession == NULL ? false : true);
+
+ // Connection flag
+ item->Connected = (item->Active == false) ? false : a->ClientSession->ConnectSucceed;
+
+ // Port number
+ item->Port = a->ClientOption->Port;
+
+ // Virtual HUB name
+ StrCpy(item->HubName, sizeof(item->HubName), a->ClientOption->HubName);
+
+ item->CreateDateTime = a->CreateDateTime;
+ item->LastConnectDateTime = a->LastConnectDateTime;
+ item->UpdateDateTime = a->UpdateDateTime;
+ }
+ }
+ UnlockList(c->AccountList);
+
+ return true;
+}
+
+// Configure the account
+bool CtSetAccount(CLIENT *c, RPC_CLIENT_CREATE_ACCOUNT *a, bool inner)
+{
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+
+ // Check whether an account already exists
+ LockList(c->AccountList);
+ {
+ ACCOUNT t, *ret;
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName),
+ a->ClientOption->AccountName);
+
+ ret = Search(c->AccountList, &t);
+ if (ret == NULL)
+ {
+ // Not exist
+ UnlockList(c->AccountList);
+ Free(t.ClientOption);
+
+ CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+
+ return false;
+ }
+ Free(t.ClientOption);
+
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)
+ {
+ if (a->ClientAuth->ClientX == NULL ||
+ a->ClientAuth->ClientX->is_compatible_bit == false ||
+ a->ClientAuth->ClientK == NULL)
+ {
+ // Client certificate is invalid
+ UnlockList(c->AccountList);
+ CiSetError(c, ERR_NOT_RSA_1024);
+ return false;
+ }
+ }
+
+ if (a->ServerCert != NULL && a->ServerCert->is_compatible_bit == false)
+ {
+ // Server certificate is invalid
+ UnlockList(c->AccountList);
+ CiSetError(c, ERR_NOT_RSA_1024);
+ return false;
+ }
+
+ Lock(ret->lock);
+ {
+
+#if 0
+ // Rewriting of the configuration is done even account running in the current version
+ // (New setting isn't applied until connecting next time)
+ if (ret->ClientSession != NULL)
+ {
+ // The account is operating
+ Unlock(ret->lock);
+ UnlockList(c->AccountList);
+
+ CiSetError(c, ERR_ACCOUNT_ACTIVE);
+
+ return false;
+ }
+#endif
+
+ // Delete the client authentication data
+ CiFreeClientAuth(ret->ClientAuth);
+
+ // Copy the client authentication data
+ ret->ClientAuth = CopyClientAuth(a->ClientAuth);
+
+ // Delete the client option
+ Free(ret->ClientOption);
+
+ // Copy the client option
+ ret->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(ret->ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));
+
+ ret->StartupAccount = a->StartupAccount;
+
+ ret->CheckServerCert = a->CheckServerCert;
+
+ if (a->ServerCert != NULL)
+ {
+ if (ret->ServerCert != NULL)
+ {
+ FreeX(ret->ServerCert);
+ }
+ ret->ServerCert = CloneX(a->ServerCert);
+ }
+ else
+ {
+ if (ret->ServerCert != NULL)
+ {
+ FreeX(ret->ServerCert);
+ }
+ ret->ServerCert = false;
+ }
+
+ ret->UpdateDateTime = SystemTime64();
+ }
+ Unlock(ret->lock);
+ }
+ UnlockList(c->AccountList);
+
+ CiSaveConfigurationFile(c);
+
+ CiNotify(c);
+
+ return true;
+}
+
+// Create an account
+bool CtCreateAccount(CLIENT *c, RPC_CLIENT_CREATE_ACCOUNT *a, bool inner)
+{
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+
+ // Check whether an account already exists
+ LockList(c->AccountList);
+ {
+ ACCOUNT t, *ret, *new_account;
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName),
+ a->ClientOption->AccountName);
+
+ ret = Search(c->AccountList, &t);
+ if (ret != NULL)
+ {
+ // Already exist
+ UnlockList(c->AccountList);
+ Free(t.ClientOption);
+
+ CiSetError(c, ERR_ACCOUNT_ALREADY_EXISTS);
+
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+ if (UniStrLen(a->ClientOption->AccountName) == 0)
+ {
+ // The name is invalid
+ UnlockList(c->AccountList);
+ CiSetError(c, ERR_INVALID_VALUE);
+ return false;
+ }
+
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)
+ {
+ if (a->ClientAuth->ClientX == NULL ||
+ a->ClientAuth->ClientX->is_compatible_bit == false ||
+ a->ClientAuth->ClientK == NULL)
+ {
+ // The client certificate is invalid
+ UnlockList(c->AccountList);
+ CiSetError(c, ERR_NOT_RSA_1024);
+ return false;
+ }
+ }
+
+ if (a->ServerCert != NULL && a->ServerCert->is_compatible_bit == false)
+ {
+ // The server certificate is invalid
+ UnlockList(c->AccountList);
+ CiSetError(c, ERR_NOT_RSA_1024);
+ return false;
+ }
+
+ // Add a new account
+ new_account = ZeroMalloc(sizeof(ACCOUNT));
+ new_account->lock = NewLock();
+
+ // Copy the client authentication data
+ new_account->ClientAuth = CopyClientAuth(a->ClientAuth);
+
+ // Copy the client option
+ new_account->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(new_account->ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));
+
+ new_account->StartupAccount = a->StartupAccount;
+
+ new_account->CheckServerCert = a->CheckServerCert;
+ if (a->ServerCert != NULL)
+ {
+ new_account->ServerCert = CloneX(a->ServerCert);
+ }
+
+ // Shortcut Key
+ if (IsZero(a->ShortcutKey, SHA1_SIZE))
+ {
+ Rand(new_account->ShortcutKey, SHA1_SIZE);
+ }
+ else
+ {
+ Copy(new_account->ShortcutKey, a->ShortcutKey, SHA1_SIZE);
+ }
+
+ new_account->CreateDateTime = new_account->UpdateDateTime = SystemTime64();
+
+ // Insert into the list
+ Insert(c->AccountList, new_account);
+
+ CLog(c, "LC_NEW_ACCOUNT", a->ClientOption->AccountName);
+ }
+ UnlockList(c->AccountList);
+
+ CiNormalizeAccountVLan(c);
+
+ CiSaveConfigurationFile(c);
+
+ CiNotify(c);
+
+ return true;
+}
+
+// Release the account acquisition structure
+void CiFreeClientGetAccount(RPC_CLIENT_GET_ACCOUNT *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ // Release the account information
+ if (a->ServerCert != NULL)
+ {
+ FreeX(a->ServerCert);
+ }
+ CiFreeClientAuth(a->ClientAuth);
+ Free(a->ClientOption);
+}
+
+// Release the account creation structure
+void CiFreeClientCreateAccount(RPC_CLIENT_CREATE_ACCOUNT *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ // Release the account information
+ if (a->ServerCert != NULL)
+ {
+ FreeX(a->ServerCert);
+ }
+ CiFreeClientAuth(a->ClientAuth);
+ Free(a->ClientOption);
+}
+
+// Stop the virtual LAN card
+bool CtDisableVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *vlan)
+{
+ UINT i;
+ bool used;
+ // Validate arguments
+ if (c == NULL || vlan == NULL)
+ {
+ return false;
+ }
+
+#ifndef OS_WIN32
+
+ if (GetOsInfo()->OsType == OSTYPE_MACOS_X)
+ {
+ // Can not be added or removed the virtual LAN card in MacOS X
+ CiSetError(c, ERR_NOT_SUPPORTED);
+ return false;
+ }
+
+ // Check whether the virtual LAN card with the specified name is not
+ // being used by one or more accounts
+ used = false;
+ LockList(c->AccountList);
+ {
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+ if (StrCmpi(a->ClientOption->DeviceName, vlan->DeviceName) == 0)
+ {
+ Lock(a->lock);
+ {
+ if (a->ClientSession != NULL)
+ {
+ used = true;
+ }
+ }
+ Unlock(a->lock);
+ }
+ }
+ }
+ UnlockList(c->AccountList);
+
+ // Search for the virtual LAN card
+ LockList(c->UnixVLanList);
+ {
+ UNIX_VLAN *v, t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), vlan->DeviceName);
+
+ v = Search(c->UnixVLanList, &t);
+ if (v == NULL)
+ {
+ UnlockList(c->UnixVLanList);
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ return false;
+ }
+
+ // Stop
+ v->Enabled = false;
+ }
+ UnlockList(c->UnixVLanList);
+
+ CiSaveConfigurationFile(c);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ return true;
+
+#else // OS_WIN32
+
+ // Check whether the virtual LAN card with the specified name is not
+ // being used by one or more accounts
+ used = false;
+ LockList(c->AccountList);
+ {
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+ if (StrCmpi(a->ClientOption->DeviceName, vlan->DeviceName) == 0)
+ {
+ Lock(a->lock);
+ {
+ if (a->ClientSession != NULL)
+ {
+ used = true;
+ }
+ }
+ Unlock(a->lock);
+ }
+ }
+ }
+ UnlockList(c->AccountList);
+
+#if 0
+ if (used)
+ {
+ // In using
+ CiSetError(c, ERR_VLAN_IS_USED);
+ return false;
+ }
+#endif
+
+
+ // Check whether the virtual LAN card are present
+ if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, vlan->DeviceName) == false &&
+ MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, vlan->DeviceName) == false)
+ {
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+
+
+ if (MsIs64BitWindows() && Is32() && MsIsAdmin())
+ {
+ // Execute the driver_installer to process since this Windows is 64 bit
+ // but this code is 32 bit
+ char tmp[MAX_SIZE];
+
+ Format(tmp, sizeof(tmp), "disablevlan %s", vlan->DeviceName);
+
+ if (MsExecDriverInstaller(tmp) == false)
+ {
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+ }
+ else
+ {
+ // Stop the virtual LAN card
+ if (MsDisableVLan(vlan->DeviceName) == false)
+ {
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+ }
+
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ return true;
+
+#endif // OS_WIN32
+
+}
+
+// Start the virtual LAN card
+bool CtEnableVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *vlan)
+{
+ // Validate arguments
+ if (c == NULL || vlan == NULL)
+ {
+ return false;
+ }
+
+#ifndef OS_WIN32
+
+ if (GetOsInfo()->OsType == OSTYPE_MACOS_X)
+ {
+ // Can not be added or removed the virtual LAN card in MacOS X
+ CiSetError(c, ERR_NOT_SUPPORTED);
+ return false;
+ }
+
+ // Search the virtual LAN card
+ LockList(c->UnixVLanList);
+ {
+ UNIX_VLAN *v, t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), vlan->DeviceName);
+
+ v = Search(c->UnixVLanList, &t);
+ if (v == NULL)
+ {
+ UnlockList(c->UnixVLanList);
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ return false;
+ }
+
+ // Enable
+ v->Enabled = true;
+ }
+ UnlockList(c->UnixVLanList);
+
+ CiSaveConfigurationFile(c);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ return true;
+
+#else // OS_WIN32
+
+ // Check whether the virtual LAN card are present
+ if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, vlan->DeviceName) == false &&
+ MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, vlan->DeviceName) == false)
+ {
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+
+ if (MsIs64BitWindows() && Is32() && MsIsAdmin())
+ {
+ // Execute the driver_installer to process since this Windows is 64 bit
+ // but this code is 32 bit
+ char tmp[MAX_SIZE];
+
+ Format(tmp, sizeof(tmp), "enablevlan %s", vlan->DeviceName);
+
+ if (MsExecDriverInstaller(tmp) == false)
+ {
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+ }
+ else
+ {
+ // Start the virtual LAN card
+ if (MsEnableVLan(vlan->DeviceName) == false)
+ {
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+ }
+
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ return true;
+
+#endif // OS_WIN32
+
+}
+
+// Delete the virtual LAN card
+bool CtDeleteVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *d)
+{
+ UINT i;
+ bool used;
+ // Validate arguments
+ if (c == NULL || d == NULL)
+ {
+ return false;
+ }
+
+#ifndef OS_WIN32
+
+ if (GetOsInfo()->OsType == OSTYPE_MACOS_X)
+ {
+ // Can not be added or removed the virtual LAN card in MacOS X
+ CiSetError(c, ERR_NOT_SUPPORTED);
+ return false;
+ }
+
+ // Check whether the virtual LAN card with the specified name is not
+ // being used by one or more accounts
+ used = false;
+ LockList(c->AccountList);
+ {
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+ if (StrCmpi(a->ClientOption->DeviceName, d->DeviceName) == 0)
+ {
+ used = true;
+ }
+ }
+ }
+ UnlockList(c->AccountList);
+
+#if 0
+ if (used)
+ {
+ // In using
+ CiSetError(c, ERR_VLAN_IS_USED);
+ return false;
+ }
+#endif
+
+ // Search for the virtual LAN card
+ LockList(c->UnixVLanList);
+ {
+ UNIX_VLAN *v, t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), d->DeviceName);
+
+ v = Search(c->UnixVLanList, &t);
+ if (v == NULL)
+ {
+ UnlockList(c->UnixVLanList);
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ return false;
+ }
+
+ // Remove
+ if (Delete(c->UnixVLanList, v))
+ {
+ Free(v);
+ }
+
+ CLog(c, "LC_DELETE_VLAN", d->DeviceName);
+
+ UnixVLanDelete(d->DeviceName);
+ }
+ UnlockList(c->UnixVLanList);
+
+ CiNormalizeAccountVLan(c);
+
+ CiSaveConfigurationFile(c);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ return true;
+
+#else // OS_WIN32
+
+ if (MsIsNt() == false)
+ {
+ // Not available in Win9x
+ CiSetError(c, ERR_NOT_SUPPORTED);
+ return false;
+ }
+
+ // Check whether the virtual LAN card are present
+ if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, d->DeviceName) == false &&
+ MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, d->DeviceName) == false)
+ {
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ return false;
+ }
+
+ // Check whether the virtual LAN card with the specified name is not
+ // being used by one or more accounts
+ used = false;
+ LockList(c->AccountList);
+ {
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+ if (StrCmpi(a->ClientOption->DeviceName, d->DeviceName) == 0)
+ {
+ used = true;
+ }
+ }
+ }
+ UnlockList(c->AccountList);
+
+#if 0
+ if (used)
+ {
+ // In using
+ CiSetError(c, ERR_VLAN_IS_USED);
+ return false;
+ }
+#endif
+
+ if (MsIs64BitWindows() && Is32() && MsIsAdmin())
+ {
+ // Execute the driver_installer to process since this Windows is 64 bit
+ // but this code is 32 bit
+ char tmp[MAX_SIZE];
+
+ Format(tmp, sizeof(tmp), "uninstvlan %s", d->DeviceName);
+
+ if (MsExecDriverInstaller(tmp) == false)
+ {
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ return false;
+ }
+ }
+ else
+ {
+ // Delete the virtual LAN card directly
+ if (MsUninstallVLan(d->DeviceName) == false)
+ {
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+ }
+
+ CLog(c, "LC_DELETE_VLAN", d->DeviceName);
+
+ CiNormalizeAccountVLan(c);
+
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ return true;
+
+#endif // OS_WIN32
+
+}
+
+// Get the name of the first VLAN
+char *CiGetFirstVLan(CLIENT *c)
+{
+ char *ret = NULL;
+ RPC_CLIENT_ENUM_VLAN t;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&t, sizeof(t));
+ if (CtEnumVLan(c, &t) == false)
+ {
+ return NULL;
+ }
+
+ if (t.NumItem >= 1)
+ {
+ UINT i;
+ char *tmp = t.Items[0]->DeviceName;
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ if (t.Items[i]->Enabled)
+ {
+ tmp = t.Items[i]->DeviceName;
+ }
+ }
+
+ ret = CopyStr(tmp);
+ }
+
+ CiFreeClientEnumVLan(&t);
+
+ return ret;
+}
+
+// Enumerate virtual LAN cards
+bool CtEnumVLan(CLIENT *c, RPC_CLIENT_ENUM_VLAN *e)
+{
+ UINT i;
+ TOKEN_LIST *t;
+ // Validate arguments
+ if (c == NULL || e == NULL)
+ {
+ return false;
+ }
+
+#ifndef OS_WIN32
+
+ LockList(c->UnixVLanList);
+ {
+ e->NumItem = LIST_NUM(c->UnixVLanList);
+ e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM *) * e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_VLAN_ITEM *item;
+ UNIX_VLAN *v;
+
+ v = LIST_DATA(c->UnixVLanList, i);
+ e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM));
+ item = e->Items[i];
+
+ item->Enabled = v->Enabled;
+ BinToStr(item->MacAddress, sizeof(item->MacAddress), v->MacAddress, 6);
+ StrCpy(item->DeviceName, sizeof(item->DeviceName), v->Name);
+ StrCpy(item->Version, sizeof(item->Version), c->Cedar->VerString);
+ }
+ }
+ UnlockList(c->UnixVLanList);
+
+ return true;
+
+#else // OS_WIN32
+
+ // Enumeration
+ t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, VLAN_ADAPTER_NAME_OLD);
+ if (t == NULL)
+ {
+ // Enumeration failure
+ e->NumItem = 0;
+ e->Items = ZeroMalloc(0);
+ }
+ else
+ {
+ // Enumeration success
+ e->NumItem = t->NumTokens;
+ e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM *) * e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ char *tmp;
+ RPC_CLIENT_ENUM_VLAN_ITEM *item;
+ e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM));
+ item = e->Items[i];
+
+ StrCpy(item->DeviceName, sizeof(item->DeviceName), t->Token[i]);
+ item->Enabled = MsIsVLanEnabled(item->DeviceName);
+
+ tmp = MsGetMacAddress(VLAN_ADAPTER_NAME_TAG, item->DeviceName);
+ if (tmp == NULL)
+ {
+ tmp = MsGetMacAddress(VLAN_ADAPTER_NAME_TAG_OLD, item->DeviceName);
+ }
+
+ StrCpy(item->MacAddress, sizeof(item->MacAddress), tmp);
+ Free(tmp);
+
+ tmp = MsGetDriverVersion(VLAN_ADAPTER_NAME_TAG, item->DeviceName);
+ if (tmp == NULL)
+ {
+ tmp = MsGetDriverVersion(VLAN_ADAPTER_NAME_TAG_OLD, item->DeviceName);
+ }
+
+ StrCpy(item->Version, sizeof(item->Version), tmp);
+ Free(tmp);
+ }
+
+ FreeToken(t);
+ }
+
+ return true;
+
+#endif // OS_WIN32
+}
+
+// Release the virtual LAN card enumeration
+void CiFreeClientEnumVLan(RPC_CLIENT_ENUM_VLAN *e)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ Free(e->Items[i]);
+ }
+ Free(e->Items);
+}
+
+// Set the information about the virtual LAN card
+bool CtSetVLan(CLIENT *c, RPC_CLIENT_SET_VLAN *set)
+{
+ // Validate arguments
+ if (c == NULL || set == NULL)
+ {
+ return false;
+ }
+
+#ifndef OS_WIN32
+
+ LockList(c->UnixVLanList);
+ {
+ UNIX_VLAN t, *r;
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), set->DeviceName);
+
+ r = Search(c->UnixVLanList, &t);
+ if (r == NULL)
+ {
+ // Not exist
+ CiSetError(c, ERR_VLAN_ALREADY_EXISTS);
+ UnlockList(c->UnixVLanList);
+ return false;
+ }
+
+ StrToMac(r->MacAddress, set->MacAddress);
+ }
+ UnlockList(c->UnixVLanList);
+
+ CiSaveConfigurationFile(c);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ return true;
+
+#else // OS_WIN32
+
+ // Check whether the virtual LAN card with the specified name already exists
+ if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, set->DeviceName) == false &&
+ MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, set->DeviceName) == false)
+ {
+ // Not exist
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ return false;
+ }
+
+ // Configuring MAC address
+ MsSetMacAddress(VLAN_ADAPTER_NAME_TAG, set->DeviceName, set->MacAddress);
+ MsSetMacAddress(VLAN_ADAPTER_NAME_TAG_OLD, set->DeviceName, set->MacAddress);
+
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ return true;
+
+#endif // OS_WIN32
+}
+
+// Get the information about the virtual LAN card
+bool CtGetVLan(CLIENT *c, RPC_CLIENT_GET_VLAN *get)
+{
+ char *tmp;
+ // Validate arguments
+ if (c == NULL || get == NULL)
+ {
+ return false;
+ }
+
+#ifndef OS_WIN32
+
+ // Unsupported
+ CiSetError(c, ERR_NOT_SUPPORTED);
+ return false;
+
+#else // OS_WIN32
+
+ // Check whether the virtual LAN card with the specified name already exists
+ if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, get->DeviceName) == false &&
+ MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, get->DeviceName) == false)
+ {
+ // Not exist
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ return false;
+ }
+
+ // Activity
+ get->Enabled = MsIsVLanEnabled(get->DeviceName);
+
+ // MAC address
+ tmp = MsGetMacAddress(VLAN_ADAPTER_NAME_TAG, get->DeviceName);
+ if (tmp == NULL)
+ {
+ tmp = MsGetMacAddress(VLAN_ADAPTER_NAME_TAG_OLD, get->DeviceName);
+ }
+ StrCpy(get->MacAddress, sizeof(get->MacAddress), tmp);
+ Free(tmp);
+
+ // Version
+ tmp = MsGetDriverVersion(VLAN_ADAPTER_NAME_TAG, get->DeviceName);
+ if (tmp == NULL)
+ {
+ tmp = MsGetDriverVersion(VLAN_ADAPTER_NAME_TAG_OLD, get->DeviceName);
+ }
+ StrCpy(get->Version, sizeof(get->Version), tmp);
+ Free(tmp);
+
+ // File name
+ tmp = MsGetDriverFileName(VLAN_ADAPTER_NAME_TAG, get->DeviceName);
+ if (tmp == NULL)
+ {
+ tmp = MsGetDriverFileName(VLAN_ADAPTER_NAME_TAG_OLD, get->DeviceName);
+ }
+ StrCpy(get->FileName, sizeof(get->FileName), tmp);
+ Free(tmp);
+
+ // GUID
+ tmp = MsGetNetworkAdapterGuid(VLAN_ADAPTER_NAME_TAG, get->DeviceName);
+ if (tmp == NULL)
+ {
+ tmp = MsGetNetworkAdapterGuid(VLAN_ADAPTER_NAME_TAG_OLD, get->DeviceName);
+ }
+ StrCpy(get->Guid, sizeof(get->Guid), tmp);
+ Free(tmp);
+
+ return true;
+
+#endif // OS_WIN32
+}
+
+#ifdef OS_WIN32
+// Initialize the driver version information structure
+void CiInitDriverVerStruct(MS_DRIVER_VER *ver)
+{
+ UINT cedar_ver = CEDAR_VER;
+ // Validate arguments
+ if (ver == NULL)
+ {
+ return;
+ }
+
+ Zero(ver, sizeof(MS_DRIVER_VER));
+
+ ver->Year = BUILD_DATE_Y;
+ ver->Month = BUILD_DATE_M;
+ ver->Day = BUILD_DATE_D;
+ ver->Major = cedar_ver / 100;
+ ver->Minor = cedar_ver % 100;
+ ver->Build = CEDAR_BUILD;
+}
+#endif // OS_WIN32
+
+// Upgrade the virtual LAN card
+bool CtUpgradeVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *create)
+{
+ bool use_old_name = false;
+
+#ifdef OS_WIN32
+ KAKUSHI *k = NULL;
+ MS_DRIVER_VER ver;
+#endif // OS_WIN32
+
+ // Validate arguments
+ if (c == NULL || create == NULL)
+ {
+ return false;
+ }
+
+
+#ifndef OS_WIN32
+
+ // Always succeed
+ return true;
+
+#else // OS_WIN32
+
+ CiInitDriverVerStruct(&ver);
+
+ if (MsIsNt() == false)
+ {
+ // Not available in Win9x
+ CiSetError(c, ERR_NOT_SUPPORTED);
+ return false;
+ }
+
+ // Check whether the LAN card with the specified name already exists
+ if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, create->DeviceName) == false &&
+ MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, create->DeviceName) == false)
+ {
+ // Not exist
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+
+ if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, create->DeviceName))
+ {
+ use_old_name = true;
+ }
+
+ if (MsIsVista() == false)
+ {
+ k = InitKakushi();
+ }
+
+
+ if (MsIsVista() == false)
+ {
+ // Perform the installation (other than Windows Vista)
+ if (MsUpgradeVLan(use_old_name ? VLAN_ADAPTER_NAME_TAG_OLD : VLAN_ADAPTER_NAME_TAG,
+ use_old_name ? VLAN_CONNECTION_NAME_OLD : VLAN_CONNECTION_NAME,
+ create->DeviceName, &ver) == false)
+ {
+ // Installation Failed
+ FreeKakushi(k);
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+ }
+ else
+ {
+ // Perform the installation (Windows Vista)
+ char tmp[MAX_SIZE];
+
+ Format(tmp, sizeof(tmp), "upgradevlan %s", create->DeviceName);
+
+ if (CncExecDriverInstaller(tmp) == false)
+ {
+ // Installation Failed
+ FreeKakushi(k);
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+ }
+
+ FreeKakushi(k);
+
+ CLog(c, "LC_UPDATE_VLAN", create->DeviceName);
+
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ return true;
+
+#endif // OS_WIN32
+}
+
+// Create a virtual LAN card
+bool CtCreateVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *create)
+{
+ TOKEN_LIST *t;
+ UINT max_len;
+
+#ifdef OS_WIN32
+ KAKUSHI *k = NULL;
+#endif // OS_WIN32
+
+ // Validate arguments
+ if (c == NULL || create == NULL)
+ {
+ return false;
+ }
+
+ if (SearchStrEx(create->DeviceName, " ", 0, false) != INFINITE)
+ {
+ // Spaces in the name is not allowed
+ CiSetError(c, ERR_INVALID_PARAMETER);
+ return false;
+ }
+
+#ifndef OS_WIN32
+
+ // Non-Win32
+ if (GetOsInfo()->OsType == OSTYPE_MACOS_X)
+ {
+ // A virtual LAN card can not be added or removed in MacOS X
+ CiSetError(c, ERR_NOT_SUPPORTED);
+ return false;
+ }
+
+ // Check whether the specified name is valid or not
+ if (IsSafeStr(create->DeviceName) == false)
+ {
+ // Name is invalid
+ CiSetError(c, ERR_VLAN_INVALID_NAME);
+ return false;
+ }
+
+ // Check whether the LAN card of the specified name already exists
+ LockList(c->UnixVLanList);
+ {
+ UNIX_VLAN t, *r;
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), create->DeviceName);
+
+ r = Search(c->UnixVLanList, &t);
+ if (r != NULL)
+ {
+ // Already exist
+ CiSetError(c, ERR_VLAN_ALREADY_EXISTS);
+ UnlockList(c->UnixVLanList);
+ return false;
+ }
+
+ // Register
+ r = ZeroMalloc(sizeof(UNIX_VLAN));
+ r->Enabled = true;
+ GenMacAddress(r->MacAddress);
+ StrCpy(r->Name, sizeof(r->Name), create->DeviceName);
+
+ // Create a Tap
+ if (UnixVLanCreate(r->Name, r->MacAddress) == false)
+ {
+ // Failure
+ Free(r);
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ UnlockList(c->UnixVLanList);
+ return false;
+ }
+
+ CLog(c, "LC_CREATE_VLAN", create->DeviceName);
+
+ Add(c->UnixVLanList, r);
+ }
+ UnlockList(c->UnixVLanList);
+
+ CiNormalizeAccountVLan(c);
+
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ CiSaveConfigurationFile(c);
+
+ return true;
+
+#else // OS_WIN32
+
+ if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType))
+ {
+ // Only one LAN card is available in the Win9x
+ TOKEN_LIST *t;
+
+ t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, VLAN_ADAPTER_NAME_OLD);
+ if (t != NULL)
+ {
+ if (t->NumTokens >= 1)
+ {
+ FreeToken(t);
+ CiSetError(c, ERR_NOT_SUPPORTED);
+ return false;
+ }
+ FreeToken(t);
+ }
+ }
+
+ // Check whether the specified name is valid or not
+ if (IsSafeStr(create->DeviceName) == false)
+ {
+ // Name is invalid
+ CiSetError(c, ERR_VLAN_INVALID_NAME);
+ return false;
+ }
+
+ max_len = MsIsNt() ? MAX_DEVICE_NAME_LEN : MAX_DEVICE_NAME_LEN_9X;
+ if (StrLen(create->DeviceName) > max_len)
+ {
+ // Name is too long
+ CiSetError(c, ERR_VLAN_INVALID_NAME);
+ return false;
+ }
+
+ // Regulation in Windows 8
+ if (MsIsInfCatalogRequired())
+ {
+ if (CiIsValidVLanRegulatedName(create->DeviceName) == false)
+ {
+ // Name is invalid
+ CiSetError(c, ERR_VLAN_INVALID_NAME);
+ return false;
+ }
+ }
+
+ // Check whether the LAN card with the specified name already exists
+ if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, create->DeviceName) ||
+ MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, create->DeviceName))
+ {
+ // Already exist
+ CiSetError(c, ERR_VLAN_ALREADY_EXISTS);
+ return false;
+ }
+
+ if (MsIsNt())
+ {
+ if (MsIsVista() == false)
+ {
+ k = InitKakushi();
+ }
+ }
+
+ if (MsIsVista() == false)
+ {
+ MS_DRIVER_VER ver;
+
+ CiInitDriverVerStruct(&ver);
+
+ // Perform the installation (other than Windows Vista)
+ if (MsInstallVLan(VLAN_ADAPTER_NAME_TAG, VLAN_CONNECTION_NAME, create->DeviceName, &ver) == false)
+ {
+ // Installation Failed
+ FreeKakushi(k);
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+ }
+ else
+ {
+ // Perform the installation (Windows Vista)
+ char tmp[MAX_SIZE];
+
+ Format(tmp, sizeof(tmp), "instvlan %s", create->DeviceName);
+
+ if (CncExecDriverInstaller(tmp) == false)
+ {
+ // Installation Failed
+ FreeKakushi(k);
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+ }
+
+ FreeKakushi(k);
+
+ t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, VLAN_ADAPTER_NAME_OLD);
+ if (t->NumTokens == 1)
+ {
+ UINT i;
+ // If the result of the installation, virtual LAN card is only one,
+ // set virtual LAN card setting of all existing accounts to this virtual LAN card
+ LockList(c->AccountList);
+ {
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+ Lock(a->lock);
+ {
+ if (a->ClientOption != NULL)
+ {
+ StrCpy(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName), create->DeviceName);
+ }
+ }
+ Unlock(a->lock);
+ }
+ }
+ UnlockList(c->AccountList);
+ }
+ FreeToken(t);
+
+ CLog(c, "LC_CREATE_VLAN", create->DeviceName);
+
+ CiNormalizeAccountVLan(c);
+
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ CiSaveConfigurationFile(c);
+
+ if (MsIsNt() == false)
+ {
+ if (GetOsInfo()->OsType == OSTYPE_WINDOWS_ME)
+ {
+ // Show the warning in the case of Windows Me
+ MsgBox(NULL, 0x00000040L, _UU("CM_9X_VLAN_ME_MESSAGE"));
+ }
+
+ ReleaseThread(NewThread(Win9xRebootThread, NULL));
+ }
+
+ return true;
+
+#endif // OS_WIN32
+}
+
+// Enumerate objects in the secure device
+bool CtEnumObjectInSecure(CLIENT *c, RPC_ENUM_OBJECT_IN_SECURE *e)
+{
+ UINT i;
+ // Validate arguments
+ if (c == NULL || e == NULL)
+ {
+ return false;
+ }
+
+ e->NumItem = 5;
+ e->ItemName = ZeroMalloc(sizeof(char *) * e->NumItem);
+ e->ItemType = ZeroMalloc(sizeof(bool) * e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ char tmp[MAX_SIZE];
+ Format(tmp, sizeof(tmp), "Test Object %u", i);
+ e->ItemName[i] = CopyStr(tmp);
+ e->ItemType[i] = (i % 2 == 0) ? false : true;
+ }
+
+ return true;
+}
+
+// Get the secure device to be used
+bool CtGetUseSecure(CLIENT *c, RPC_USE_SECURE *sec)
+{
+ // Validate arguments
+ if (c == NULL || sec == NULL)
+ {
+ return false;
+ }
+
+ sec->DeviceId = c->UseSecureDeviceId;
+
+ return true;
+}
+
+// Specifying a secure device to be used
+bool CtUseSecure(CLIENT *c, RPC_USE_SECURE *sec)
+{
+ // Validate arguments
+ if (c == NULL || sec == NULL)
+ {
+ return false;
+ }
+
+// Do not check whether there is the specified device on the client manager
+/* if (CheckSecureDeviceId(sec->DeviceId))
+ {
+ c->UseSecureDeviceId = sec->DeviceId;
+ }
+ else
+ {
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ return false;
+ }
+*/
+ c->UseSecureDeviceId = sec->DeviceId;
+
+ CiSaveConfigurationFile(c);
+
+ return true;
+}
+
+// Enumeration of secure devices
+bool CtEnumSecure(CLIENT *c, RPC_CLIENT_ENUM_SECURE *e)
+{
+ LIST *o;
+ UINT i;
+ // Validate arguments
+ if (c == NULL || e == NULL)
+ {
+ return false;
+ }
+
+ o = GetSecureDeviceList();
+
+ e->NumItem = LIST_NUM(o);
+ e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM *) * e->NumItem);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ RPC_CLIENT_ENUM_SECURE_ITEM *item = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM));
+ SECURE_DEVICE *s = LIST_DATA(o, i);
+
+ item->DeviceId = s->Id;
+ StrCpy(item->DeviceName, sizeof(item->DeviceName), s->DeviceName);
+ StrCpy(item->Manufacturer, sizeof(item->Manufacturer), s->Manufacturer);
+ item->Type = s->Type;
+
+ e->Items[i] = item;
+ }
+
+ return true;
+}
+
+// Release the secure device enumeration
+void CiFreeClientEnumSecure(RPC_CLIENT_ENUM_SECURE *e)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ Free(e->Items[i]);
+ }
+ Free(e->Items);
+}
+
+// Release the RPC_GET_ISSUER
+void CiFreeGetIssuer(RPC_GET_ISSUER *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ if (a->issuer_x != NULL)
+ {
+ FreeX(a->issuer_x);
+ }
+ if (a->x != NULL)
+ {
+ FreeX(a->x);
+ }
+}
+
+// Get the common proxy settings
+bool CtGetCommonProxySetting(CLIENT *c, INTERNET_SETTING *a)
+{
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+ Copy(a, &c->CommonProxySetting, sizeof(INTERNET_SETTING));
+
+ return true;
+}
+
+// Set the common proxy settings
+bool CtSetCommonProxySetting(CLIENT *c, INTERNET_SETTING *a)
+{
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+ Copy(&c->CommonProxySetting, a, sizeof(INTERNET_SETTING));
+
+
+ CiSaveConfigurationFile(c);
+
+ return true;
+}
+
+// Get the issuer
+bool CtGetIssuer(CLIENT *c, RPC_GET_ISSUER *a)
+{
+ X *x;
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+ x = FindCaSignedX(c->Cedar->CaList, a->x);
+ if (x == NULL)
+ {
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);;
+ return false;
+ }
+ else
+ {
+ a->issuer_x = x;
+ if (a->x != NULL)
+ {
+ FreeX(a->x);
+ a->x = NULL;
+ }
+ return true;
+ }
+}
+
+// Get the CA certificate
+bool CtGetCa(CLIENT *c, RPC_GET_CA *get)
+{
+ bool ret = true;
+ X *cert = NULL;
+ // Validate arguments
+ if (c == NULL || get == NULL)
+ {
+ return false;
+ }
+
+ LockList(c->Cedar->CaList);
+ {
+ UINT i;
+
+ for (i = 0;i < LIST_NUM(c->Cedar->CaList);i++)
+ {
+ X *x = LIST_DATA(c->Cedar->CaList, i);
+
+ if (POINTER_TO_KEY(x) == get->Key)
+ {
+ cert = CloneX(x);
+ break;
+ }
+ }
+ }
+ UnlockList(c->Cedar->CaList);
+
+ if (cert == NULL)
+ {
+ // Certificate does not exist
+ ret = false;
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ }
+ else
+ {
+ ret = true;
+ get->x = cert;
+ }
+
+ return ret;
+}
+
+// Delete the CA certificate
+bool CtDeleteCa(CLIENT *c, RPC_CLIENT_DELETE_CA *p)
+{
+ bool ret;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return false;
+ }
+
+ ret = DeleteCa(c->Cedar, p->Key);
+
+ if (ret == false)
+ {
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ }
+
+ CiSaveConfigurationFile(c);
+
+ return ret;
+}
+
+// Add a CA certificate
+bool CtAddCa(CLIENT *c, RPC_CERT *cert)
+{
+ // Validate arguments
+ if (c == NULL || cert == NULL)
+ {
+ return false;
+ }
+
+ if (cert->x->is_compatible_bit == false)
+ {
+ CiSetError(c, ERR_NOT_RSA_1024);
+ return false;
+ }
+
+ AddCa(c->Cedar, cert->x);
+
+ CiSaveConfigurationFile(c);
+
+ return true;
+}
+
+// Enumerate the trusted CA
+bool CtEnumCa(CLIENT *c, RPC_CLIENT_ENUM_CA *e)
+{
+ // Validate arguments
+ if (c == NULL || e == NULL)
+ {
+ return false;
+ }
+
+ Zero(e, sizeof(RPC_CLIENT_ENUM_CA));
+
+ LockList(c->Cedar->CaList);
+ {
+ UINT i;
+ e->NumItem = LIST_NUM(c->Cedar->CaList);
+ e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM *) * e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ X *x = LIST_DATA(c->Cedar->CaList, i);
+ e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM));
+ GetAllNameFromNameEx(e->Items[i]->SubjectName, sizeof(e->Items[i]->SubjectName), x->subject_name);
+ GetAllNameFromNameEx(e->Items[i]->IssuerName, sizeof(e->Items[i]->IssuerName), x->issuer_name);
+ e->Items[i]->Expires = x->notAfter;
+ e->Items[i]->Key = POINTER_TO_KEY(x);
+ }
+ }
+ UnlockList(c->Cedar->CaList);
+
+ return true;
+}
+
+// Release the CA enumeration
+void CiFreeClientEnumCa(RPC_CLIENT_ENUM_CA *e)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_CA_ITEM *ca = e->Items[i];
+ Free(ca);
+ }
+ Free(e->Items);
+}
+
+// Get the password setting
+bool CtGetPasswordSetting(CLIENT *c, RPC_CLIENT_PASSWORD_SETTING *a)
+{
+ UCHAR hash[SHA1_SIZE];
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+ Hash(hash, "", 0, true);
+ if (Cmp(hash, c->EncryptedPassword, SHA1_SIZE) == 0)
+ {
+ a->IsPasswordPresented = false;
+ }
+ else
+ {
+ a->IsPasswordPresented = true;
+ }
+
+ a->PasswordRemoteOnly = c->PasswordRemoteOnly;
+
+ return true;
+}
+
+// Set the password
+bool CtSetPassword(CLIENT *c, RPC_CLIENT_PASSWORD *pass)
+{
+ char *str;
+ if (c == NULL)
+ {
+ return false;
+ }
+ if (pass->Password == NULL)
+ {
+ str = "";
+ }
+ else
+ {
+ str = pass->Password;
+ }
+
+ if (StrCmp(str, "********") != 0)
+ {
+ // Hash the password
+ Hash(c->EncryptedPassword, str, StrLen(str), true);
+ }
+
+ c->PasswordRemoteOnly = pass->PasswordRemoteOnly;
+
+ CLog(c, "LC_SET_PASSWORD");
+
+ CiSaveConfigurationFile(c);
+
+ return true;
+}
+
+void CiFreeIni(LIST *o)
+{
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ FreeIni(o);
+}
+
+// Read the custom.ini file
+LIST *CiLoadIni()
+{
+ BUF *b = ReadDump(CLIENT_CUSTOM_INI_FILENAME);
+ LIST *ini;
+ if (b == NULL)
+ {
+ return NULL;
+ }
+
+ ini = ReadIni(b);
+
+ FreeBuf(b);
+
+ return ini;
+
+}
+
+// Reflect the settings of the custom.ini
+void CiLoadIniSettings(CLIENT *c)
+{
+ LIST *o;
+ //char *log;
+ //char *config;
+
+ if (c == NULL)
+ {
+ return;
+ }
+
+ o = CiLoadIni();
+
+ if (o == NULL)
+ {
+ return;
+ }
+
+ /*log = IniStrValue(o, "NoSaveLog");
+ config = IniStrValue(o, "NoSaveConfig");
+
+ if(StrCmpi(log, "true") == 0)
+ {
+ c->NoSaveLog = true;
+ }
+ if(StrCmpi(config, "true") == 0)
+ {
+ c->NoSaveConfig = true;
+ }*/
+
+ c->NoSaveLog = ToBool(IniStrValue(o, "NoSaveLog"));
+ c->NoSaveConfig = ToBool(IniStrValue(o, "NoSaveConfig"));
+
+ CiFreeIni(o);
+
+}
+
+bool CiLoadConfigFilePathFromIni(char *path, UINT size)
+{
+ char *tmp;
+ LIST *o;
+ bool ret = false;
+
+ // Validate arguments
+ if (path == NULL)
+ {
+ return false;
+ }
+
+ o = CiLoadIni();
+
+ if (o == NULL)
+ {
+ return false;
+ }
+
+ StrCpy(path, size, "");
+
+ tmp = IniStrValue(o, "ConfigPath");
+ NormalizePath(path, size, tmp);
+
+ if (IsEmptyStr(path) == false)
+ {
+ ret = true;
+ }
+ else
+ {
+ ret = false;
+ }
+
+ CiFreeIni(o);
+
+ return ret;
+}
+
+// Set the client error code
+void CiSetError(CLIENT *c, UINT err)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->Err = err;
+}
+
+// UNIX virtual LAN card comparison function
+int CiCompareUnixVLan(void *p1, void *p2)
+{
+ UNIX_VLAN *v1, *v2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ v1 = *(UNIX_VLAN **)p1;
+ v2 = *(UNIX_VLAN **)p2;
+ if (v1 == NULL || v2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(v1->Name, v2->Name);
+}
+
+// Modify the account settings that an incorrect VLAN name is specified
+void CiNormalizeAccountVLan(CLIENT *c)
+{
+ bool b = false;
+ char *name;
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ name = CiGetFirstVLan(c);
+
+ if (name != NULL)
+ {
+ LockList(c->AccountList);
+ {
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+
+ Lock(a->lock);
+ {
+ if (a->ClientOption != NULL)
+ {
+ if (CiIsVLan(c, a->ClientOption->DeviceName) == false)
+ {
+ StrCpy(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName),
+ name);
+ b = true;
+ }
+ }
+ }
+ Unlock(a->lock);
+ }
+ }
+ UnlockList(c->AccountList);
+
+ Free(name);
+ }
+
+ if (b)
+ {
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ CiSaveConfigurationFile(c);
+ }
+}
+
+// Check whether a virtual LAN card of the specified name exists
+bool CiIsVLan(CLIENT *c, char *name)
+{
+ // Validate arguments
+ if (c == NULL || name == NULL)
+ {
+ return false;
+ }
+
+#ifdef OS_WIN32
+ {
+ TOKEN_LIST *t;
+ UINT i;
+
+ t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, VLAN_ADAPTER_NAME_OLD);
+ if (t == NULL)
+ {
+ return false;
+ }
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ if (StrCmpi(t->Token[i], name) == 0)
+ {
+ FreeToken(t);
+ return true;
+ }
+ }
+
+ FreeToken(t);
+
+ return false;
+ }
+#else // OS_WIN32
+ {
+ UNIX_VLAN *v;
+ UINT i;
+ bool ret = false;
+
+ LockList(c->UnixVLanList);
+ {
+ for (i = 0;i < LIST_NUM(c->UnixVLanList);i++)
+ {
+ v = (UNIX_VLAN *)LIST_DATA(c->UnixVLanList, i);
+ if (StrCmpi(v->Name, name) == 0)
+ {
+ ret = true;
+ }
+ }
+ }
+ UnlockList(c->UnixVLanList);
+
+ return ret;
+ }
+#endif // OS_WIN32
+}
+
+// If a non-existent virtual LAN card is specified in any Account, and only
+// one virtual LAN card is installed, set the virtual LAN card to the account
+void CiSetVLanToDefault(CLIENT *c)
+{
+ char device_name[MAX_SIZE];
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ {
+ TOKEN_LIST *t;
+
+ t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, VLAN_ADAPTER_NAME_OLD);
+ if (t == NULL)
+ {
+ return;
+ }
+ if (t->NumTokens != 1)
+ {
+ FreeToken(t);
+ return;
+ }
+ StrCpy(device_name, sizeof(device_name), t->Token[0]);
+ FreeToken(t);
+ }
+#else // OS_WIN32
+ {
+ UINT i;
+ UNIX_VLAN *v;
+
+ LockList(c->UnixVLanList);
+
+ if (LIST_NUM(c->UnixVLanList) != 1)
+ {
+ UnlockList(c->UnixVLanList);
+ return;
+ }
+ v = LIST_DATA(c->UnixVLanList, 0);
+ StrCpy(device_name, sizeof(device_name), v->Name);
+
+ UnlockList(c->UnixVLanList);
+ }
+#endif // OS_WIN32
+
+ {
+ UINT i;
+ LockList(c->AccountList);
+ {
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+
+ Lock(a->lock);
+ {
+ if (CiIsVLan(c, a->ClientOption->DeviceName) == false)
+ {
+ StrCpy(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName),
+ device_name);
+ }
+ }
+ Unlock(a->lock);
+ }
+ }
+ UnlockList(c->AccountList);
+ }
+}
+
+// Initialize the settings
+void CiInitConfiguration(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_UNIX
+ // Initialize the VLAN
+ UnixVLanInit();
+#endif // OS_UNIX
+
+ // Account list
+ c->AccountList = NewList(CiCompareAccount);
+
+ // Unix version VLAN list
+ if (OS_IS_UNIX(GetOsInfo()->OsType))
+ {
+ c->UnixVLanList = NewList(CiCompareUnixVLan);
+ }
+
+ // Read the configuration file
+ CLog(c, "LC_LOAD_CONFIG_1");
+ if (CiLoadConfigurationFile(c) == false)
+ {
+ CLog(c, "LC_LOAD_CONFIG_3");
+ // Do the initial setup because the configuration file does not exist
+ // Clear the password
+ Hash(c->EncryptedPassword, "", 0, true);
+ // Initialize the client configuration
+ if (OS_IS_WINDOWS(GetOsInfo()->OsType))
+ {
+ // Disable remote management in Windows
+ c->Config.AllowRemoteConfig = false;
+ }
+ else
+ {
+ // Disable the remote management also in case of UNIX
+ c->Config.AllowRemoteConfig = false;
+ }
+ StrCpy(c->Config.KeepConnectHost, sizeof(c->Config.KeepConnectHost), CLIENT_DEFAULT_KEEPALIVE_HOST);
+ c->Config.KeepConnectPort = CLIENT_DEFAULT_KEEPALIVE_PORT;
+ c->Config.KeepConnectProtocol = CONNECTION_UDP;
+ c->Config.KeepConnectInterval = CLIENT_DEFAULT_KEEPALIVE_INTERVAL;
+ c->Config.UseKeepConnect = false; // Don't use the connection maintenance function by default in the Client
+ // Eraser
+ c->Eraser = NewEraser(c->Logger, 0);
+ }
+ else
+ {
+ CLog(c, "LC_LOAD_CONFIG_2");
+ }
+
+ // Appropriate setting for virtual LAN card
+ CiSetVLanToDefault(c);
+}
+
+// Release the settings
+void CiFreeConfiguration(CLIENT *c)
+{
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Write to the configuration file
+ CiSaveConfigurationFile(c);
+
+ // Release the configuration file
+ FreeCfgRw(c->CfgRw);
+
+ // Release the account list
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+
+ CiFreeAccount(a);
+ }
+ ReleaseList(c->AccountList);
+
+ if (c->UnixVLanList != NULL)
+ {
+ // Release of UNIX version VLAN list
+ for (i = 0;i < LIST_NUM(c->UnixVLanList);i++)
+ {
+ UNIX_VLAN *v = LIST_DATA(c->UnixVLanList, i);
+ Free(v);
+ }
+ ReleaseList(c->UnixVLanList);
+ }
+ c->UnixVLanList = NULL;
+
+#ifdef OS_UNIX
+ // Release the VLAN
+ UnixVLanFree();
+#endif // OS_UNIX
+}
+
+// Release the certificate data acquisition
+void CiFreeGetCa(RPC_GET_CA *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ FreeX(a->x);
+}
+
+// Release the client authentication data
+void CiFreeClientAuth(CLIENT_AUTH *auth)
+{
+ // Validate arguments
+ if (auth == NULL)
+ {
+ return;
+ }
+
+ if (auth->ClientX != NULL)
+ {
+ FreeX(auth->ClientX);
+ }
+ if (auth->ClientK != NULL)
+ {
+ FreeK(auth->ClientK);
+ }
+
+ Free(auth);
+}
+
+// Release the account
+void CiFreeAccount(ACCOUNT *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ // Release the lock
+ DeleteLock(a->lock);
+
+ // Release the client option
+ Free(a->ClientOption);
+
+ // Release the client authentication data
+ CiFreeClientAuth(a->ClientAuth);
+
+ if (a->ServerCert != NULL)
+ {
+ FreeX(a->ServerCert);
+ }
+
+ Free(a);
+}
+
+// Sort accounts
+int CiCompareAccount(void *p1, void *p2)
+{
+ ACCOUNT *a1, *a2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ a1 = *(ACCOUNT **)p1;
+ a2 = *(ACCOUNT **)p2;
+ if (a1 == NULL || a2 == NULL)
+ {
+ return 0;
+ }
+
+ return UniStrCmpi(a1->ClientOption->AccountName, a2->ClientOption->AccountName);
+}
+
+// Read the client configuration
+void CiLoadClientConfig(CLIENT_CONFIG *c, FOLDER *f)
+{
+ // Validate arguments
+ if (c == NULL || f == NULL)
+ {
+ return;
+ }
+
+ c->UseKeepConnect = CfgGetBool(f, "UseKeepConnect");
+ CfgGetStr(f, "KeepConnectHost", c->KeepConnectHost, sizeof(c->KeepConnectHost));
+ c->KeepConnectPort = CfgGetInt(f, "KeepConnectPort");
+ c->KeepConnectProtocol = CfgGetInt(f, "KeepConnectProtocol");
+ c->AllowRemoteConfig = CfgGetBool(f, "AllowRemoteConfig");
+ c->KeepConnectInterval = MAKESURE(CfgGetInt(f, "KeepConnectInterval"), KEEP_INTERVAL_MIN, KEEP_INTERVAL_MAX);
+ c->NoChangeWcmNetworkSettingOnWindows8 = CfgGetBool(f, "NoChangeWcmNetworkSettingOnWindows8");
+}
+
+// Read the client authentication data
+CLIENT_AUTH *CiLoadClientAuth(FOLDER *f)
+{
+ CLIENT_AUTH *a;
+ char *s;
+ BUF *b;
+ // Validate arguments
+ if (f == NULL)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(CLIENT_AUTH));
+
+ a->AuthType = CfgGetInt(f, "AuthType");
+ CfgGetStr(f, "Username", a->Username, sizeof(a->Username));
+
+ switch (a->AuthType)
+ {
+ case CLIENT_AUTHTYPE_ANONYMOUS:
+ break;
+
+ case CLIENT_AUTHTYPE_PASSWORD:
+ CfgGetByte(f, "HashedPassword", a->HashedPassword, SHA1_SIZE);
+ break;
+
+ case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+ b = CfgGetBuf(f, "EncryptedPassword");
+ if (b != NULL)
+ {
+ s = DecryptPassword(b);
+ StrCpy(a->PlainPassword, sizeof(a->PlainPassword), s);
+ Free(s);
+ FreeBuf(b);
+ }
+ break;
+
+ case CLIENT_AUTHTYPE_CERT:
+ b = CfgGetBuf(f, "ClientCert");
+ if (b != NULL)
+ {
+ a->ClientX = BufToX(b, false);
+ }
+ FreeBuf(b);
+ b = CfgGetBuf(f, "ClientKey");
+ if (b != NULL)
+ {
+ a->ClientK = BufToK(b, true, false, NULL);
+ }
+ FreeBuf(b);
+ break;
+
+ case CLIENT_AUTHTYPE_SECURE:
+ CfgGetStr(f, "SecurePublicCertName", a->SecurePublicCertName, sizeof(a->SecurePublicCertName));
+ CfgGetStr(f, "SecurePrivateKeyName", a->SecurePrivateKeyName, sizeof(a->SecurePrivateKeyName));
+ break;
+ }
+
+ return a;
+}
+
+// Read the client option
+CLIENT_OPTION *CiLoadClientOption(FOLDER *f)
+{
+ CLIENT_OPTION *o;
+ char *s;
+ BUF *b;
+ // Validate arguments
+ if (f == NULL)
+ {
+ return NULL;
+ }
+
+ o = ZeroMalloc(sizeof(CLIENT_OPTION));
+
+ CfgGetUniStr(f, "AccountName", o->AccountName, sizeof(o->AccountName));
+ CfgGetStr(f, "Hostname", o->Hostname, sizeof(o->Hostname));
+ o->Port = CfgGetInt(f, "Port");
+ o->PortUDP = CfgGetInt(f, "PortUDP");
+ o->ProxyType = CfgGetInt(f, "ProxyType");
+ CfgGetStr(f, "ProxyName", o->ProxyName, sizeof(o->ProxyName));
+ o->ProxyPort = CfgGetInt(f, "ProxyPort");
+ CfgGetStr(f, "ProxyUsername", o->ProxyUsername, sizeof(o->ProxyUsername));
+ b = CfgGetBuf(f, "ProxyPassword");
+ s = DecryptPassword(b);
+ StrCpy(o->ProxyPassword, sizeof(o->ProxyPassword), s);
+ Free(s);
+ FreeBuf(b);
+ o->NumRetry = CfgGetInt(f, "NumRetry");
+ o->RetryInterval = CfgGetInt(f, "RetryInterval");
+ CfgGetStr(f, "HubName", o->HubName, sizeof(o->HubName));
+ o->MaxConnection = CfgGetInt(f, "MaxConnection");
+ o->UseEncrypt = CfgGetBool(f, "UseEncrypt");
+ o->UseCompress = CfgGetBool(f, "UseCompress");
+ o->HalfConnection = CfgGetBool(f, "HalfConnection");
+ o->NoRoutingTracking = CfgGetBool(f, "NoRoutingTracking");
+ CfgGetStr(f, "DeviceName", o->DeviceName, sizeof(o->DeviceName));
+ o->AdditionalConnectionInterval = CfgGetInt(f, "AdditionalConnectionInterval");
+ o->HideStatusWindow = CfgGetBool(f, "HideStatusWindow");
+ o->HideNicInfoWindow = CfgGetBool(f, "HideNicInfoWindow");
+ o->ConnectionDisconnectSpan = CfgGetInt(f, "ConnectionDisconnectSpan");
+ o->RequireMonitorMode = CfgGetBool(f, "RequireMonitorMode");
+ o->RequireBridgeRoutingMode = CfgGetBool(f, "RequireBridgeRoutingMode");
+ o->DisableQoS = CfgGetBool(f, "DisableQoS");
+ o->FromAdminPack = CfgGetBool(f, "FromAdminPack");
+ o->NoTls1 = CfgGetBool(f, "NoTls1");
+ o->NoUdpAcceleration = CfgGetBool(f, "NoUdpAcceleration");
+
+ b = CfgGetBuf(f, "HostUniqueKey");
+ if (b != NULL)
+ {
+ if (b->Size == SHA1_SIZE)
+ {
+ Copy(o->HostUniqueKey, b->Buf, SHA1_SIZE);
+ }
+
+ FreeBuf(b);
+ }
+
+ return o;
+}
+
+// Read the account data
+ACCOUNT *CiLoadClientAccount(FOLDER *f)
+{
+ ACCOUNT *a;
+ FOLDER *client_option_folder, *client_auth_folder;
+ BUF *b;
+ char tmp[64];
+ // Validate arguments
+ if (f == NULL)
+ {
+ return NULL;
+ }
+
+ client_option_folder = CfgGetFolder(f, "ClientOption");
+
+ if (client_option_folder != NULL)
+ {
+ // Compare whether it matches to the account name that is already registered
+ }
+
+ client_auth_folder = CfgGetFolder(f, "ClientAuth");
+
+ if (client_option_folder == NULL || client_auth_folder == NULL)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(ACCOUNT));
+ a->lock = NewLock();
+
+ a->ClientOption = CiLoadClientOption(client_option_folder);
+ a->ClientAuth = CiLoadClientAuth(client_auth_folder);
+
+ a->StartupAccount = CfgGetBool(f, "StartupAccount");
+ a->CheckServerCert = CfgGetBool(f, "CheckServerCert");
+ a->CreateDateTime = CfgGetInt64(f, "CreateDateTime");
+ a->UpdateDateTime = CfgGetInt64(f, "UpdateDateTime");
+ a->LastConnectDateTime = CfgGetInt64(f, "LastConnectDateTime");
+
+ b = CfgGetBuf(f, "ServerCert");
+ if (b != NULL)
+ {
+ a->ServerCert = BufToX(b, false);
+ FreeBuf(b);
+ }
+
+ if (CfgGetStr(f, "ShortcutKey", tmp, sizeof(tmp)))
+ {
+ BUF *b = StrToBin(tmp);
+ if (b->Size == SHA1_SIZE)
+ {
+ Copy(a->ShortcutKey, b->Buf, SHA1_SIZE);
+ }
+ FreeBuf(b);
+ }
+
+ if (IsZero(a->ShortcutKey, SHA1_SIZE))
+ {
+ Rand(a->ShortcutKey, SHA1_SIZE);
+ }
+
+ return a;
+}
+
+// Read the account database
+void CiLoadAccountDatabase(CLIENT *c, FOLDER *f)
+{
+ TOKEN_LIST *t;
+ UINT i;
+ // Validate arguments
+ if (c == NULL || f == NULL)
+ {
+ return;
+ }
+
+ t = CfgEnumFolderToTokenList(f);
+ if (t == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ FOLDER *ff = CfgGetFolder(f, t->Token[i]);
+
+ if (ff != NULL)
+ {
+ ACCOUNT *a = CiLoadClientAccount(ff);
+ if (a != NULL)
+ {
+ {
+ Add(c->AccountList, a);
+ }
+ }
+ }
+ }
+
+ Sort(c->AccountList);
+
+ FreeToken(t);
+}
+
+// Read the root CA certificate
+void CiLoadCACert(CLIENT *c, FOLDER *f)
+{
+ BUF *b;
+ X *x;
+ // Validate arguments
+ if (c == NULL || f == NULL)
+ {
+ return;
+ }
+
+ b = CfgGetBuf(f, "X509");
+ if (b == NULL)
+ {
+ return;
+ }
+
+ x = BufToX(b, false);
+
+ AddCa(c->Cedar, x);
+
+ FreeX(x);
+
+ FreeBuf(b);
+}
+
+// Read the root CA list
+void CiLoadCAList(CLIENT *c, FOLDER *f)
+{
+ CEDAR *cedar;
+ TOKEN_LIST *t;
+ // Validate arguments
+ if (c == NULL || f == NULL)
+ {
+ return;
+ }
+
+ t = CfgEnumFolderToTokenList(f);
+
+ cedar = c->Cedar;
+
+ LockList(cedar->CaList);
+ {
+ UINT i;
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ FOLDER *folder = CfgGetFolder(f, t->Token[i]);
+ CiLoadCACert(c, folder);
+ }
+ }
+ UnlockList(cedar->CaList);
+
+ FreeToken(t);
+}
+
+// Read a VLAN
+void CiLoadVLan(CLIENT *c, FOLDER *f)
+{
+ char tmp[MAX_SIZE];
+ UCHAR addr[6];
+ BUF *b;
+ UNIX_VLAN *v;
+ // Validate arguments
+ if (c == NULL || f == NULL)
+ {
+ return;
+ }
+
+ if (CfgGetStr(f, "MacAddress", tmp, sizeof(tmp)) == false)
+ {
+ return;
+ }
+
+ b = StrToBin(tmp);
+ if (b == NULL)
+ {
+ return;
+ }
+
+ if (b->Size != 6)
+ {
+ FreeBuf(b);
+ return;
+ }
+
+ Copy(addr, b->Buf, 6);
+
+ FreeBuf(b);
+
+ if (IsZero(addr, 6))
+ {
+ return;
+ }
+
+ v = ZeroMalloc(sizeof(UNIX_VLAN));
+ Copy(v->MacAddress, addr, 6);
+ StrCpy(v->Name, sizeof(v->Name), f->Name);
+ v->Enabled = CfgGetBool(f, "Enabled");
+
+ Add(c->UnixVLanList, v);
+
+#ifdef OS_UNIX
+ UnixVLanCreate(v->Name, v->MacAddress);
+#endif // OS_UNIX
+}
+
+// Read a VLAN list
+void CiLoadVLanList(CLIENT *c, FOLDER *f)
+{
+ TOKEN_LIST *t;
+ // Validate arguments
+ if (c == NULL || f == NULL)
+ {
+ return;
+ }
+
+ t = CfgEnumFolderToTokenList(f);
+
+ LockList(c->UnixVLanList);
+ {
+ UINT i;
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ FOLDER *folder = CfgGetFolder(f, t->Token[i]);
+ CiLoadVLan(c, folder);
+ }
+ }
+ UnlockList(c->UnixVLanList);
+
+ FreeToken(t);
+}
+
+// Read the configuration from the configuration file
+bool CiReadSettingFromCfg(CLIENT *c, FOLDER *root)
+{
+ FOLDER *config;
+ FOLDER *cert;
+ FOLDER *db;
+ FOLDER *vlan;
+ FOLDER *cmsetting;
+ FOLDER *proxy;
+ char user_agent[MAX_SIZE];
+ // Validate arguments
+ if (c == NULL || root == NULL)
+ {
+ return false;
+ }
+
+ // Initialize the setting if there isn't either of AccountDatabase and Config
+ config = CfgGetFolder(root, "Config");
+ if (config == NULL)
+ {
+ return false;
+ }
+
+ db = CfgGetFolder(root, "AccountDatabase");
+ if (db == NULL)
+ {
+ return false;
+ }
+
+ cmsetting = CfgGetFolder(root, "ClientManagerSetting");
+
+ CiLoadClientConfig(&c->Config, config);
+
+
+ proxy = CfgGetFolder(root, "CommonProxySetting");
+
+ if (proxy != NULL)
+ {
+ INTERNET_SETTING t;
+ BUF *pw;
+
+ // Proxy Setting
+ Zero(&t, sizeof(t));
+ t.ProxyType = CfgGetInt(proxy, "ProxyType");
+ CfgGetStr(proxy, "ProxyHostName", t.ProxyHostName, sizeof(t.ProxyHostName));
+ t.ProxyPort = CfgGetInt(proxy, "ProxyPort");
+ CfgGetStr(proxy, "ProxyUsername", t.ProxyUsername, sizeof(t.ProxyUsername));
+ pw = CfgGetBuf(proxy, "ProxyPassword");
+ if (pw != NULL)
+ {
+ char *pw_str = DecryptPassword(pw);
+ StrCpy(t.ProxyPassword, sizeof(t.ProxyPassword), pw_str);
+
+ Free(pw_str);
+ FreeBuf(pw);
+ }
+
+ Copy(&c->CommonProxySetting, &t, sizeof(INTERNET_SETTING));
+ }
+
+ // Eraser
+ c->Eraser = NewEraser(c->Logger, CfgGetInt64(config, "AutoDeleteCheckDiskFreeSpaceMin"));
+
+ if (OS_IS_UNIX(GetOsInfo()->OsType) && GetOsInfo()->OsType != OSTYPE_MACOS_X)
+ {
+ // Read the UNIX version virtual LAN card list (except MacOS)
+ vlan = CfgGetFolder(root, "UnixVLan");
+ if (vlan != NULL)
+ {
+ CiLoadVLanList(c, vlan);
+ }
+ }
+
+ if (GetOsInfo()->OsType == OSTYPE_MACOS_X)
+ {
+#ifdef OS_UNIX
+ UNIX_VLAN *uv;
+
+ // Create a Tap for MacOS X
+ if (UnixVLanCreate(CLIENT_MACOS_TAP_NAME, NULL) == false)
+ {
+ // Fail (abort)
+ CLog(c, "LC_TAP_NOT_FOUND");
+ Alert("tun/tap driver not found.", NULL);
+ exit(0);
+ }
+
+ uv = ZeroMalloc(sizeof(UNIX_VLAN));
+ uv->Enabled = true;
+ StrCpy(uv->Name, sizeof(uv->Name), CLIENT_MACOS_TAP_NAME);
+ Add(c->UnixVLanList, uv);
+#endif // OS_UNIX
+ }
+
+ CiLoadAccountDatabase(c, db);
+
+ if (CfgGetByte(root, "EncryptedPassword", c->EncryptedPassword, SHA1_SIZE) == false)
+ {
+ Hash(c->EncryptedPassword, "", 0, true);
+ }
+
+ c->PasswordRemoteOnly = CfgGetBool(root, "PasswordRemoteOnly");
+ c->UseSecureDeviceId = CfgGetInt(root, "UseSecureDeviceId");
+
+ if (CfgGetStr(root, "UserAgent", user_agent, sizeof(user_agent)))
+ {
+ if (IsEmptyStr(user_agent) == false)
+ {
+ Free(c->Cedar->HttpUserAgent);
+ c->Cedar->HttpUserAgent = CopyStr(user_agent);
+ }
+ }
+
+ cert = CfgGetFolder(root, "RootCA");
+ if (cert != NULL)
+ {
+ CiLoadCAList(c, cert);
+ }
+
+ c->DontSavePassword = CfgGetBool(root, "DontSavePassword");
+
+ if (cmsetting != NULL)
+ {
+ UINT ostype = GetOsInfo()->OsType;
+ // CM_SETTING
+ CM_SETTING *s = c->CmSetting;
+
+ if (OS_IS_UNIX(ostype) || OS_IS_WINDOWS_NT(ostype))
+ {
+ s->EasyMode = CfgGetBool(cmsetting, "EasyMode");
+ }
+
+ s->LockMode = CfgGetBool(cmsetting, "LockMode");
+ CfgGetByte(cmsetting, "HashedPassword", s->HashedPassword, sizeof(s->HashedPassword));
+ }
+
+ return true;
+}
+
+// Read the configuration file
+bool CiLoadConfigurationFile(CLIENT *c)
+{
+ bool ret;
+ FOLDER *root;
+ char path[MAX_SIZE];
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ // Read the configuration file
+ if (CiLoadConfigFilePathFromIni(path, sizeof(path)))
+ {
+ c->CfgRw = NewCfgRw(&root, path);
+ }
+ else
+ {
+ c->CfgRw = NewCfgRw(&root, CLIENT_CONFIG_FILE_NAME);
+ }
+
+ if (root == NULL)
+ {
+ return false;
+ }
+
+ ret = CiReadSettingFromCfg(c, root);
+
+ CfgDeleteFolder(root);
+
+ return ret;
+}
+
+// Write the CLIENT_CONFIG
+void CiWriteClientConfig(FOLDER *cc, CLIENT_CONFIG *config)
+{
+ // Validate arguments
+ if (cc == NULL || config == NULL)
+ {
+ return;
+ }
+
+ CfgAddBool(cc, "UseKeepConnect", config->UseKeepConnect);
+ CfgAddStr(cc, "KeepConnectHost", config->KeepConnectHost);
+ CfgAddInt(cc, "KeepConnectPort", config->KeepConnectPort);
+ CfgAddInt(cc, "KeepConnectProtocol", config->KeepConnectProtocol);
+ CfgAddBool(cc, "AllowRemoteConfig", config->AllowRemoteConfig);
+ CfgAddInt(cc, "KeepConnectInterval", config->KeepConnectInterval);
+ CfgAddBool(cc, "NoChangeWcmNetworkSettingOnWindows8", config->NoChangeWcmNetworkSettingOnWindows8);
+}
+
+// Write the client authentication data
+void CiWriteClientAuth(FOLDER *f, CLIENT_AUTH *a)
+{
+ BUF *b;
+ // Validate arguments
+ if (f == NULL || a == NULL)
+ {
+ return;
+ }
+
+ CfgAddInt(f, "AuthType", a->AuthType);
+ CfgAddStr(f, "Username", a->Username);
+
+ switch (a->AuthType)
+ {
+ case CLIENT_AUTHTYPE_ANONYMOUS:
+ break;
+
+ case CLIENT_AUTHTYPE_PASSWORD:
+ CfgAddByte(f, "HashedPassword", a->HashedPassword, SHA1_SIZE);
+ break;
+
+ case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+ b = EncryptPassword(a->PlainPassword);
+ CfgAddByte(f, "EncryptedPassword", b->Buf, b->Size);
+ FreeBuf(b);
+ break;
+
+ case CLIENT_AUTHTYPE_CERT:
+ if (a->ClientK != NULL && a->ClientX != NULL)
+ {
+ b = XToBuf(a->ClientX, false);
+ CfgAddByte(f, "ClientCert", b->Buf, b->Size);
+ FreeBuf(b);
+
+ b = KToBuf(a->ClientK, false, NULL);
+ CfgAddByte(f, "ClientKey", b->Buf, b->Size);
+ FreeBuf(b);
+ }
+ break;
+
+ case CLIENT_AUTHTYPE_SECURE:
+ CfgAddStr(f, "SecurePublicCertName", a->SecurePublicCertName);
+ CfgAddStr(f, "SecurePrivateKeyName", a->SecurePrivateKeyName);
+ break;
+ }
+}
+
+// Write the client option
+void CiWriteClientOption(FOLDER *f, CLIENT_OPTION *o)
+{
+ BUF *b;
+ // Validate arguments
+ if (f == NULL || o == NULL)
+ {
+ return;
+ }
+
+ CfgAddUniStr(f, "AccountName", o->AccountName);
+ CfgAddStr(f, "Hostname", o->Hostname);
+ CfgAddInt(f, "Port", o->Port);
+ CfgAddInt(f, "PortUDP", o->PortUDP);
+ CfgAddInt(f, "ProxyType", o->ProxyType);
+ CfgAddStr(f, "ProxyName", o->ProxyName);
+ CfgAddInt(f, "ProxyPort", o->ProxyPort);
+ CfgAddStr(f, "ProxyUsername", o->ProxyUsername);
+ b = EncryptPassword(o->ProxyPassword);
+ CfgAddByte(f, "ProxyPassword", b->Buf, b->Size);
+ FreeBuf(b);
+ CfgAddInt(f, "NumRetry", o->NumRetry);
+ CfgAddInt(f, "RetryInterval", o->RetryInterval);
+ CfgAddStr(f, "HubName", o->HubName);
+ CfgAddInt(f, "MaxConnection", o->MaxConnection);
+ CfgAddBool(f, "UseEncrypt", o->UseEncrypt);
+ CfgAddBool(f, "UseCompress", o->UseCompress);
+ CfgAddBool(f, "HalfConnection", o->HalfConnection);
+ CfgAddBool(f, "NoRoutingTracking", o->NoRoutingTracking);
+ CfgAddStr(f, "DeviceName", o->DeviceName);
+ CfgAddInt(f, "AdditionalConnectionInterval", o->AdditionalConnectionInterval);
+ CfgAddBool(f, "HideStatusWindow", o->HideStatusWindow);
+ CfgAddBool(f, "HideNicInfoWindow", o->HideNicInfoWindow);
+ CfgAddInt(f, "ConnectionDisconnectSpan", o->ConnectionDisconnectSpan);
+ CfgAddBool(f, "RequireMonitorMode", o->RequireMonitorMode);
+ CfgAddBool(f, "RequireBridgeRoutingMode", o->RequireBridgeRoutingMode);
+ CfgAddBool(f, "DisableQoS", o->DisableQoS);
+ CfgAddBool(f, "NoTls1", o->NoTls1);
+ CfgAddBool(f, "NoUdpAcceleration", o->NoUdpAcceleration);
+
+ if (o->FromAdminPack)
+ {
+ CfgAddBool(f, "FromAdminPack", o->FromAdminPack);
+ }
+
+ if (IsZero(o->HostUniqueKey, SHA1_SIZE) == false)
+ {
+ BUF *b = MemToBuf(o->HostUniqueKey, SHA1_SIZE);
+ CfgAddBuf(f, "HostUniqueKey", b);
+ FreeBuf(b);
+ }
+}
+
+// Decrypt the password
+char *DecryptPassword(BUF *b)
+{
+ char *str;
+ char *key = "EncryptPassword";
+ CRYPT *c;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return CopyStr("");
+ }
+
+ str = ZeroMalloc(b->Size + 1);
+ c = NewCrypt(key, sizeof(key));
+ Encrypt(c, str, b->Buf, b->Size);
+ FreeCrypt(c);
+
+ str[b->Size] = 0;
+
+ return str;
+}
+char *DecryptPassword2(BUF *b)
+{
+ char *str;
+ char *key = "EncryptPassword2";
+ CRYPT *c;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return CopyStr("");
+ }
+
+ str = ZeroMalloc(b->Size + 1);
+ c = NewCrypt(key, StrLen(key));
+ Encrypt(c, str, b->Buf, b->Size);
+ FreeCrypt(c);
+
+ str[b->Size] = 0;
+
+ return str;
+}
+
+// Encrypt the password
+BUF *EncryptPassword(char *password)
+{
+ UCHAR *tmp;
+ UINT size;
+ char *key = "EncryptPassword";
+ CRYPT *c;
+ BUF *b;
+ // Validate arguments
+ if (password == NULL)
+ {
+ password = "";
+ }
+
+ size = StrLen(password) + 1;
+ tmp = ZeroMalloc(size);
+
+ c = NewCrypt(key, sizeof(key));
+ Encrypt(c, tmp, password, size - 1);
+ FreeCrypt(c);
+
+ b = NewBuf();
+ WriteBuf(b, tmp, size - 1);
+ SeekBuf(b, 0, 0);
+ Free(tmp);
+
+ return b;
+}
+BUF *EncryptPassword2(char *password)
+{
+ UCHAR *tmp;
+ UINT size;
+ char *key = "EncryptPassword2";
+ CRYPT *c;
+ BUF *b;
+ // Validate arguments
+ if (password == NULL)
+ {
+ password = "";
+ }
+
+ size = StrLen(password) + 1;
+ tmp = ZeroMalloc(size);
+
+ c = NewCrypt(key, StrLen(key));
+ Encrypt(c, tmp, password, size - 1);
+ FreeCrypt(c);
+
+ b = NewBuf();
+ WriteBuf(b, tmp, size - 1);
+ SeekBuf(b, 0, 0);
+ Free(tmp);
+
+ return b;
+}
+
+// Write the account data
+void CiWriteAccountData(FOLDER *f, ACCOUNT *a)
+{
+ // Validate arguments
+ if (f == NULL || a == NULL)
+ {
+ return;
+ }
+
+ // Client Option
+ CiWriteClientOption(CfgCreateFolder(f, "ClientOption"), a->ClientOption);
+
+ // Client authentication data
+ CiWriteClientAuth(CfgCreateFolder(f, "ClientAuth"), a->ClientAuth);
+
+ // Startup account
+ CfgAddBool(f, "StartupAccount", a->StartupAccount);
+
+ // Server certificate check flag
+ CfgAddBool(f, "CheckServerCert", a->CheckServerCert);
+
+ // Date and time
+ CfgAddInt64(f, "CreateDateTime", a->CreateDateTime);
+ CfgAddInt64(f, "UpdateDateTime", a->UpdateDateTime);
+ CfgAddInt64(f, "LastConnectDateTime", a->LastConnectDateTime);
+
+ // Server certificate body
+ if (a->ServerCert != NULL)
+ {
+ BUF *b = XToBuf(a->ServerCert, false);
+ if (b != NULL)
+ {
+ CfgAddBuf(f, "ServerCert", b);
+ FreeBuf(b);
+ }
+ }
+
+ // Shortcut Key
+ if (IsZero(a->ShortcutKey, SHA1_SIZE) == false)
+ {
+ char tmp[64];
+ BinToStr(tmp, sizeof(tmp), a->ShortcutKey, SHA1_SIZE);
+ CfgAddStr(f, "ShortcutKey", tmp);
+ }
+}
+
+// Write the account database
+void CiWriteAccountDatabase(CLIENT *c, FOLDER *f)
+{
+ char name[MAX_SIZE];
+ // Validate arguments
+ if (c == NULL || f == NULL)
+ {
+ return;
+ }
+
+ LockList(c->AccountList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+
+ {
+ Format(name, sizeof(name), "Account%u", i);
+ Lock(a->lock);
+ {
+ CiWriteAccountData(CfgCreateFolder(f, name), a);
+ }
+ Unlock(a->lock);
+ }
+ }
+ }
+ UnlockList(c->AccountList);
+}
+
+// Write the CA certificate
+void CiWriteCACert(CLIENT *c, FOLDER *f, X *x)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || f == NULL || x == NULL)
+ {
+ return;
+ }
+
+ b = XToBuf(x, false);
+ CfgAddBuf(f, "X509", b);
+ FreeBuf(b);
+}
+
+// Write a VLAN
+void CiWriteVLan(CLIENT *c, FOLDER *f, UNIX_VLAN *v)
+{
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (c == NULL || f == NULL || v == NULL)
+ {
+ return;
+ }
+
+ MacToStr(tmp, sizeof(tmp), v->MacAddress);
+ CfgAddStr(f, "MacAddress", tmp);
+ CfgAddBool(f, "Enabled", v->Enabled);
+}
+
+// Write a VLAN list
+void CiWriteVLanList(CLIENT *c, FOLDER *f)
+{
+ // Validate arguments
+ if (c == NULL || f == NULL)
+ {
+ return;
+ }
+
+ LockList(c->UnixVLanList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(c->UnixVLanList);i++)
+ {
+ UNIX_VLAN *v = LIST_DATA(c->UnixVLanList, i);
+ CiWriteVLan(c, CfgCreateFolder(f, v->Name), v);
+ }
+ }
+ UnlockList(c->UnixVLanList);
+}
+
+// Write the CA list
+void CiWriteCAList(CLIENT *c, FOLDER *f)
+{
+ CEDAR *cedar;
+ // Validate arguments
+ if (c == NULL || f == NULL)
+ {
+ return;
+ }
+
+ cedar = c->Cedar;
+
+ LockList(cedar->CaList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(cedar->CaList);i++)
+ {
+ char tmp[MAX_SIZE];
+ X *x = LIST_DATA(cedar->CaList, i);
+ Format(tmp, sizeof(tmp), "Certificate%u", i);
+ CiWriteCACert(c, CfgCreateFolder(f, tmp), x);
+ }
+ }
+ UnlockList(cedar->CaList);
+}
+
+// Write the current settings to ROOT
+void CiWriteSettingToCfg(CLIENT *c, FOLDER *root)
+{
+ FOLDER *cc;
+ FOLDER *account_database;
+ FOLDER *ca;
+ FOLDER *vlan;
+ FOLDER *cmsetting;
+ FOLDER *proxy;
+ // Validate arguments
+ if (c == NULL || root == NULL)
+ {
+ return;
+ }
+
+ cmsetting = CfgCreateFolder(root, "ClientManagerSetting");
+
+ // CLIENT_CONFIG
+ cc = CfgCreateFolder(root, "Config");
+ CiWriteClientConfig(cc, &c->Config);
+
+
+ // Eraser
+ CfgAddInt64(cc, "AutoDeleteCheckDiskFreeSpaceMin", c->Eraser->MinFreeSpace);
+
+ // Account Database
+ account_database = CfgCreateFolder(root, "AccountDatabase");
+ CiWriteAccountDatabase(c, account_database);
+
+ // Proxy
+ proxy = CfgCreateFolder(root, "CommonProxySetting");
+ if (proxy != NULL)
+ {
+ INTERNET_SETTING *t = &c->CommonProxySetting;
+ BUF *pw;
+
+ CfgAddInt(proxy, "ProxyType", t->ProxyType);
+ CfgAddStr(proxy, "ProxyHostName", t->ProxyHostName);
+ CfgAddInt(proxy, "ProxyPort", t->ProxyPort);
+ CfgAddStr(proxy, "ProxyUsername", t->ProxyUsername);
+
+ if (IsEmptyStr(t->ProxyPassword) == false)
+ {
+ pw = EncryptPassword(t->ProxyPassword);
+
+ CfgAddBuf(proxy, "ProxyPassword", pw);
+
+ FreeBuf(pw);
+ }
+ }
+
+ // CA
+ ca = CfgCreateFolder(root, "RootCA");
+ CiWriteCAList(c, ca);
+
+ // VLAN
+ if (OS_IS_UNIX(GetOsInfo()->OsType) && GetOsInfo()->OsType != OSTYPE_MACOS_X)
+ {
+ vlan = CfgCreateFolder(root, "UnixVLan");
+ CiWriteVLanList(c, vlan);
+ }
+
+ // Password
+ CfgAddByte(root, "EncryptedPassword", c->EncryptedPassword, SHA1_SIZE);
+ CfgAddBool(root, "PasswordRemoteOnly", c->PasswordRemoteOnly);
+
+ // UseSecureDeviceId
+ CfgAddInt(root, "UseSecureDeviceId", c->UseSecureDeviceId);
+
+ // DontSavePassword
+ CfgAddBool(root, "DontSavePassword", c->DontSavePassword);
+
+ // UserAgent
+ if (c->Cedar != NULL)
+ {
+ CfgAddStr(root, "UserAgent", c->Cedar->HttpUserAgent);
+ }
+
+ if (cmsetting != NULL)
+ {
+ CM_SETTING *s = c->CmSetting;
+
+ CfgAddBool(cmsetting, "EasyMode", s->EasyMode);
+ CfgAddBool(cmsetting, "LockMode", s->LockMode);
+
+ if (IsZero(s->HashedPassword, sizeof(s->HashedPassword)) == false)
+ {
+ CfgAddByte(cmsetting, "HashedPassword", s->HashedPassword, sizeof(s->HashedPassword));
+ }
+ }
+}
+
+// Create the inner VPN Server
+SERVER *CiNewInnerVPNServer(CLIENT *c)
+{
+ SERVER *s = NULL;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ SetNatTLowPriority();
+
+ s = SiNewServerEx(false, true);
+
+ return s;
+}
+
+// Stop the inner VPN Server
+void CiFreeInnerVPNServer(CLIENT *c, SERVER *s)
+{
+ // Validate arguments
+ if (c == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SiReleaseServer(s);
+}
+
+// Apply settings of Inner VPN Server
+void CiApplyInnerVPNServerConfig(CLIENT *c)
+{
+}
+
+// Write to the configuration file
+void CiSaveConfigurationFile(CLIENT *c)
+{
+ FOLDER *root;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Do not save the configuration file
+ if(c->NoSaveConfig)
+ {
+ return;
+ }
+
+ root = CfgCreateFolder(NULL, TAG_ROOT);
+ CiWriteSettingToCfg(c, root);
+
+ SaveCfgRw(c->CfgRw, root);
+
+ CfgDeleteFolder(root);
+}
+
+// Set the CM_SETTING
+bool CtSetCmSetting(CLIENT *c, CM_SETTING *s)
+{
+ // Validate arguments
+ if (c == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ Copy(c->CmSetting, s, sizeof(CM_SETTING));
+
+ CiSaveConfigurationFile(c);
+
+ return true;
+}
+
+// Get the CM_SETTING
+bool CtGetCmSetting(CLIENT *c, CM_SETTING *s)
+{
+ // Validate arguments
+ if (c == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ Copy(s, c->CmSetting, sizeof(CM_SETTING));
+
+ return true;
+}
+
+// Get the client version
+bool CtGetClientVersion(CLIENT *c, RPC_CLIENT_VERSION *ver)
+{
+ // Validate arguments
+ if (ver == NULL)
+ {
+ return false;
+ }
+
+ Zero(ver, sizeof(RPC_CLIENT_VERSION));
+ StrCpy(ver->ClientProductName, sizeof(ver->ClientProductName), CEDAR_CLIENT_STR);
+ StrCpy(ver->ClientVersionString, sizeof(ver->ClientVersionString), c->Cedar->VerString);
+ StrCpy(ver->ClientBuildInfoString, sizeof(ver->ClientBuildInfoString), c->Cedar->BuildInfo);
+ ver->ClientVerInt = c->Cedar->Version;
+ ver->ClientBuildInt = c->Cedar->Build;
+
+
+#ifdef OS_WIN32
+ ver->ProcessId = MsGetProcessId();
+ ver->IsVLanNameRegulated = MsIsInfCatalogRequired();
+
+#endif // OS_WIN32
+
+ ver->OsType = GetOsInfo()->OsType;
+
+ return true;
+}
+
+// Creating a Client object
+CLIENT *CiNewClient()
+{
+ CLIENT *c = ZeroMalloc(sizeof(CLIENT));
+
+// StartCedarLog();
+
+ if (ci_active_sessions_lock == NULL)
+ {
+ ci_active_sessions_lock = NewLock();
+ ci_num_active_sessions = 0;
+ }
+
+
+ c->CmSetting = ZeroMalloc(sizeof(CM_SETTING));
+
+ c->SockList = NewSockList();
+
+ c->lock = NewLock();
+ c->lockForConnect = NewLock();
+ c->ref = NewRef();
+
+ c->Cedar = NewCedar(NULL, NULL);
+
+ c->Cedar->Client = c;
+
+ c->NotifyCancelList = NewList(NULL);
+
+ Hash(c->EncryptedPassword, "", 0, true);
+
+#ifdef OS_WIN32
+ c->GlobalPulse = MsOpenOrCreateGlobalPulse(CLIENT_GLOBAL_PULSE_NAME);
+#endif // OS_WIN32
+
+ if (c->GlobalPulse != NULL)
+ {
+ c->PulseRecvThread = NewThread(CiPulseRecvThread, c);
+ }
+
+ CiLoadIniSettings(c);
+
+ // Log Settings
+ if(c->NoSaveLog == false)
+ {
+ MakeDir(CLIENT_LOG_DIR_NAME);
+ c->Logger = NewLog(CLIENT_LOG_DIR_NAME, CLIENT_LOG_PREFIX, LOG_SWITCH_DAY);
+ }
+
+ CLog(c, "L_LINE");
+ CLog(c, "LC_START_2", CEDAR_CLIENT_STR, c->Cedar->VerString);
+ CLog(c, "LC_START_3", c->Cedar->BuildInfo);
+ CLog(c, "LC_START_1");
+
+#ifdef OS_WIN32
+ {
+ // Initialize the Win32 UI
+ wchar_t tmp[MAX_SIZE];
+ StrToUni(tmp, sizeof(tmp), CEDAR_CLIENT_STR);
+
+ InitWinUi(tmp, _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+ }
+#endif // OS_WIN32
+
+ // Initialize the settings
+ CiInitConfiguration(c);
+
+ // Raise the priority
+ OSSetHighPriority();
+
+
+
+#ifdef OS_WIN32
+ // For Win9x, release the DHCP address of all the virtual LAN card
+ if (MsIsNt() == false)
+ {
+ Win32ReleaseAllDhcp9x(true);
+ }
+#endif // OS_WIN32
+
+ CiChangeAllVLanMacAddressIfMachineChanged(c);
+
+ CiChangeAllVLanMacAddressIfCleared(c);
+
+ // Initialize the internal VPN server
+ CiApplyInnerVPNServerConfig(c);
+
+ return c;
+}
+
+// Examine whether two proxy server settings equal
+bool CompareInternetSetting(INTERNET_SETTING *s1, INTERNET_SETTING *s2)
+{
+ // Validate arguments
+ if (s1 == NULL || s2 == NULL)
+ {
+ return false;
+ }
+
+ if (s1->ProxyType != s2->ProxyType)
+ {
+ return false;
+ }
+
+ if (s1->ProxyType == PROXY_DIRECT)
+ {
+ return true;
+ }
+
+ if (s1->ProxyPort != s2->ProxyPort)
+ {
+ return false;
+ }
+
+ if (StrCmp(s1->ProxyHostName, s2->ProxyHostName) != 0)
+ {
+ return false;
+ }
+
+ if (StrCmp(s1->ProxyUsername, s2->ProxyUsername) != 0)
+ {
+ return false;
+ }
+
+ if (StrCmp(s1->ProxyPassword, s2->ProxyPassword) != 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Send a global pulse
+void CiSendGlobalPulse(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ MsSendGlobalPulse(c->GlobalPulse);
+#endif // OS_WIN32
+}
+
+// Pulse reception thread
+void CiPulseRecvThread(THREAD *thread, void *param)
+{
+#ifdef OS_WIN32
+ CLIENT *c = (CLIENT *)param;
+
+ if (c == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ if (c->HaltPulseThread)
+ {
+ break;
+ }
+
+ MsWaitForGlobalPulse(c->GlobalPulse, INFINITE);
+
+ if (c->HaltPulseThread)
+ {
+ break;
+ }
+
+ CiNotifyInternal(c);
+ }
+#endif // OS_WIN32
+}
+
+// Clean-up the client
+void CiCleanupClient(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+
+ // Release the settings
+ CiFreeConfiguration(c);
+
+#ifdef OS_WIN32
+ // Release the Win32 UI
+ FreeWinUi();
+#endif // OS_WIN32
+
+ CLog(c, "LC_END");
+ CLog(c, "L_LINE");
+ FreeEraser(c->Eraser);
+ FreeLog(c->Logger);
+ c->Logger = NULL;
+
+
+ ReleaseCedar(c->Cedar);
+
+ DeleteLock(c->lockForConnect);
+ DeleteLock(c->lock);
+
+ c->HaltPulseThread = true;
+
+ if (c->GlobalPulse != NULL)
+ {
+#ifdef OS_WIN32
+ MsSendGlobalPulse(c->GlobalPulse);
+#endif // OS_WIN32
+ }
+
+ if (c->PulseRecvThread != NULL)
+ {
+ WaitThread(c->PulseRecvThread, INFINITE);
+ ReleaseThread(c->PulseRecvThread);
+ }
+
+ if (c->GlobalPulse != NULL)
+ {
+#ifdef OS_WIN32
+ MsCloseGlobalPulse(c->GlobalPulse);
+#endif // OS_WIN32
+ }
+
+ ReleaseList(c->NotifyCancelList);
+
+ FreeSockList(c->SockList);
+
+ Free(c->CmSetting);
+
+
+ Free(c);
+
+#ifdef OS_WIN32
+ // For Win9x, release the DHCP address of all the virtual LAN card
+ if (MsIsNt() == false)
+ {
+ Win32ReleaseAllDhcp9x(true);
+ }
+#endif // OS_WIN32
+
+ StopCedarLog();
+
+ if (ci_active_sessions_lock != NULL)
+ {
+ DeleteLock(ci_active_sessions_lock);
+ ci_active_sessions_lock = NULL;
+
+ ci_num_active_sessions = 0;
+ }
+}
+
+// Increment of the number of active sessions
+void CiIncrementNumActiveSessions()
+{
+ Lock(ci_active_sessions_lock);
+ {
+ ci_num_active_sessions++;
+ }
+ Unlock(ci_active_sessions_lock);
+}
+
+// Decrement of the number of active sessions
+void CiDecrementNumActiveSessions()
+{
+ Lock(ci_active_sessions_lock);
+ {
+ if (ci_num_active_sessions >= 1)
+ {
+ ci_num_active_sessions--;
+ }
+ }
+ Unlock(ci_active_sessions_lock);
+}
+
+// Get the number of active sessions
+UINT CiGetNumActiveSessions()
+{
+ UINT ret;
+
+ Lock(ci_active_sessions_lock);
+ {
+ ret = ci_num_active_sessions;
+ }
+ Unlock(ci_active_sessions_lock);
+
+ return ret;
+}
+
+// Release the client
+void CtReleaseClient(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ if (Release(c->ref) == 0)
+ {
+ CiCleanupClient(c);
+ }
+}
+
+// Start the operation of the client program
+void CtStartClient()
+{
+ UINT i;
+ LIST *o;
+ if (client != NULL)
+ {
+ // It is already in running
+ return;
+ }
+
+ // OS check
+ CiCheckOs();
+
+#ifdef OS_WIN32
+ RegistWindowsFirewallAll();
+#endif
+
+ // Creating a client
+ client = CiNewClient();
+
+ // Start the Keep
+ CiInitKeep(client);
+
+ // Start the RPC server
+ CiStartRpcServer(client);
+
+ // Start the Saver
+ CiInitSaver(client);
+
+ // Start the startup connection
+ o = NewListFast(NULL);
+ LockList(client->AccountList);
+ {
+ for (i = 0;i < LIST_NUM(client->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(client->AccountList, i);
+ Lock(a->lock);
+ {
+ if (a->StartupAccount)
+ {
+ Add(o, CopyUniStr(a->ClientOption->AccountName));
+ }
+ }
+ Unlock(a->lock);
+ }
+ }
+ UnlockList(client->AccountList);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ wchar_t *s = LIST_DATA(o, i);
+ RPC_CLIENT_CONNECT c;
+ Zero(&c, sizeof(c));
+ UniStrCpy(c.AccountName, sizeof(c.AccountName), s);
+ CtConnect(client, &c);
+ Free(s);
+ }
+ ReleaseList(o);
+}
+
+// Stop the operation of the client program
+void CtStopClient()
+{
+ UINT i, num;
+ ACCOUNT **account_list;
+ if (client == NULL)
+ {
+ // It is not running yet
+ return;
+ }
+
+ // Halting flag
+ client->Halt = true;
+
+ // Disconnect all the RPC
+ CiStopRpcServer(client);
+
+ // Exit the client notification service
+ CncExit();
+
+ // Exit the Keep
+ CiFreeKeep(client);
+
+ // Disconnect all accounts connected
+ LockList(client->AccountList);
+ {
+ num = LIST_NUM(client->AccountList);
+ account_list = ToArray(client->AccountList);
+ }
+ UnlockList(client->AccountList);
+
+ for (i = 0;i < num;i++)
+ {
+ ACCOUNT *a = account_list[i];
+ SESSION *s = NULL;
+
+ Lock(a->lock);
+ {
+ if (a->ClientSession != NULL)
+ {
+ s = a->ClientSession;
+ AddRef(s->ref);
+ }
+ }
+ Unlock(a->lock);
+
+ if (s != NULL)
+ {
+ StopSession(s);
+ ReleaseSession(s);
+ Lock(a->lock);
+ {
+ if (a->ClientSession != NULL)
+ {
+ ReleaseSession(a->ClientSession);
+ a->ClientSession = NULL;
+ }
+ }
+ Unlock(a->lock);
+ }
+ }
+
+ Free(account_list);
+
+ // Stop the Saver
+ CiFreeSaver(client);
+
+ // Release the client
+ CtReleaseClient(client);
+ client = NULL;
+}
+
+// OS check
+void CiCheckOs()
+{
+ // Get the OS type
+ OS_INFO *info = GetOsInfo();
+
+ if (OS_IS_WINDOWS(info->OsType))
+ {
+ bool ok = IS_CLIENT_SUPPORTED_OS(info->OsType);
+
+ if (ok == false)
+ {
+ Alert(
+ CEDAR_PRODUCT_STR " VPN Client doesn't support this Windows Operating System.\n"
+ CEDAR_PRODUCT_STR " VPN Client requires Windows 98, Windows Me, Windows 2000, Windows XP, Windows Server 2003 or Greater.\n\n"
+ "Please contact your system administrator.", CEDAR_PRODUCT_STR " VPN Client");
+ exit(0);
+ }
+ }
+}
+
+// Get the client object
+CLIENT *CtGetClient()
+{
+ if (client == NULL)
+ {
+ return NULL;
+ }
+
+ AddRef(client->ref);
+
+ return client;
+}
+
+// Client status indicator
+void CiClientStatusPrinter(SESSION *s, wchar_t *status)
+{
+#ifdef OS_WIN32
+ ACCOUNT *a;
+ // Validate arguments
+ if (s == NULL || status == NULL)
+ {
+ return;
+ }
+
+ a = s->Account;
+ if (a == NULL)
+ {
+ return;
+ }
+
+ if (UniStrCmpi(status, L"init") == 0)
+ {
+ if (a->StatusWindow == NULL && s->Win32HideConnectWindow == false)
+ {
+ a->StatusWindow = CncStatusPrinterWindowStart(s);
+ }
+ }
+ else if (UniStrCmpi(status, L"free") == 0)
+ {
+ if (a->StatusWindow != NULL)
+ {
+ CncStatusPrinterWindowStop(a->StatusWindow);
+ a->StatusWindow = NULL;
+ }
+ }
+ else
+ {
+ if (a->StatusWindow != NULL)
+ {
+ CncStatusPrinterWindowPrint(a->StatusWindow, status);
+ }
+ }
+#else // OS_WIN32
+ UniPrint(L"Status: %s\n", status);
+#endif // OS_WIN32
+}
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Client.h b/src/Cedar/Client.h
new file mode 100644
index 00000000..345f8e76
--- /dev/null
+++ b/src/Cedar/Client.h
@@ -0,0 +1,849 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Client.h
+// Header of Client.c
+
+#ifndef CLIENT_H
+#define CLIENT_H
+
+#define CLIENT_CONFIG_PORT GC_CLIENT_CONFIG_PORT // Client port number
+#define CLIENT_NOTIFY_PORT GC_CLIENT_NOTIFY_PORT // Client notification port number
+#define CLIENT_WAIT_CN_READY_TIMEOUT (10 * 1000) // Standby time to start the client notification service
+
+
+// Check whether the client can run on the specified OS_TYPE
+#define IS_CLIENT_SUPPORTED_OS(t) \
+ ((OS_IS_WINDOWS_NT(t) && GET_KETA(t, 100) >= 2) || (OS_IS_WINDOWS_9X(t)))
+
+
+// Constants
+#define CLIENT_CONFIG_FILE_NAME "@vpn_client.config"
+#define CLIENT_DEFAULT_KEEPALIVE_HOST "keepalive.softether.org"
+#define CLIENT_DEFAULT_KEEPALIVE_PORT 80
+#define CLIENT_DEFAULT_KEEPALIVE_INTERVAL KEEP_INTERVAL_DEFAULT
+
+#define CLIENT_RPC_MODE_NOTIFY 0
+#define CLIENT_RPC_MODE_MANAGEMENT 1
+#define CLIENT_RPC_MODE_SHORTCUT 2
+#define CLIENT_RPC_MODE_SHORTCUT_DISCONNECT 3
+
+#define CLIENT_MACOS_TAP_NAME "tap0"
+
+#define CLIENT_SAVER_INTERVAL (30 * 1000)
+
+#define CLIENT_NOTIFY_SERVICE_INSTANCENAME GC_SW_SOFTETHER_PREFIX "vpnclient_uihelper"
+
+#define CLIENT_WIN32_EXE_FILENAME "vpnclient.exe"
+#define CLIENT_WIN32_EXE_FILENAME_X64 "vpnclient_x64.exe"
+#define CLIENT_WIN32_EXE_FILENAME_IA64 "vpnclient_ia64.exe"
+
+#define CLIENT_CUSTOM_INI_FILENAME "@custom.ini"
+
+#define CLIENT_GLOBAL_PULSE_NAME "clientglobalpulse"
+
+
+// List of virtual LAN cards in UNIX
+struct UNIX_VLAN
+{
+ bool Enabled; // Enable flag
+ char Name[MAX_SIZE]; // Name
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2];
+};
+
+// Account
+struct ACCOUNT
+{
+ // Static data
+ CLIENT_OPTION *ClientOption; // Client Option
+ CLIENT_AUTH *ClientAuth; // Client authentication data
+ bool CheckServerCert; // Check the server certificate
+ X *ServerCert; // Server certificate
+ bool StartupAccount; // Start-up account
+ UCHAR ShortcutKey[SHA1_SIZE]; // Key
+ UINT64 CreateDateTime; // Creation date and time
+ UINT64 UpdateDateTime; // Updating date
+ UINT64 LastConnectDateTime; // Last connection date and time
+
+ // Dynamic data
+ LOCK *lock; // Lock
+ SESSION *ClientSession; // Client session
+ CLIENT_STATUS_PRINTER *StatusPrinter; // Status indicator
+
+ SOCK *StatusWindow; // Status window
+};
+
+// Client Settings
+struct CLIENT_CONFIG
+{
+ bool AllowRemoteConfig; // Allow the remote configuration
+ bool UseKeepConnect; // Keep connected to the Internet
+ char KeepConnectHost[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT KeepConnectPort; // Port number
+ UINT KeepConnectProtocol; // Protocol
+ UINT KeepConnectInterval; // Interval
+ bool NoChangeWcmNetworkSettingOnWindows8; // Don't change the WCM network settings on Windows 8
+};
+
+// Version acquisition
+struct RPC_CLIENT_VERSION
+{
+ char ClientProductName[128]; // Client product name
+ char ClientVersionString[128]; // Client version string
+ char ClientBuildInfoString[128]; // Build client information string
+ UINT ClientVerInt; // Client version integer value
+ UINT ClientBuildInt; // Client build number integer value
+ UINT ProcessId; // Process ID
+ UINT OsType; // OS type
+ bool IsVLanNameRegulated; // Whether a virtual LAN card name must be "VLAN" + number
+ bool IsVgcSupported; // Whether the VPN Gate Client is supported
+ bool ShowVgcLink; // Display a VPN Gate Client link
+ char ClientId[128]; // Client OD
+};
+
+// Password Setting
+struct RPC_CLIENT_PASSWORD
+{
+ char Password[MAX_PASSWORD_LEN + 1]; // Password
+ bool PasswordRemoteOnly; // The password is required only remote access
+};
+
+// Get the password setting
+struct RPC_CLIENT_PASSWORD_SETTING
+{
+ bool IsPasswordPresented; // Password exists
+ bool PasswordRemoteOnly; // The password is required only remote access
+};
+
+// Certificate enumeration item
+struct RPC_CLIENT_ENUM_CA_ITEM
+{
+ UINT Key; // Certificate key
+ wchar_t SubjectName[MAX_SIZE]; // Issued to
+ wchar_t IssuerName[MAX_SIZE]; // Issuer
+ UINT64 Expires; // Expiration date
+};
+
+// Certificate enumeration
+struct RPC_CLIENT_ENUM_CA
+{
+ UINT NumItem; // Number of items
+ RPC_CLIENT_ENUM_CA_ITEM **Items; // Item
+};
+
+// Certificate item
+struct RPC_CERT
+{
+ X *x; // Certificate
+};
+
+// Delete the certificate
+struct RPC_CLIENT_DELETE_CA
+{
+ UINT Key; // Certificate key
+};
+
+// Get the certificate
+struct RPC_GET_CA
+{
+ UINT Key; // Certificate key
+ X *x; // Certificate
+};
+
+// Get the issuer
+struct RPC_GET_ISSUER
+{
+ X *x; // Certificate
+ X *issuer_x; // Issuer
+};
+
+// Secure device enumeration item
+struct RPC_CLIENT_ENUM_SECURE_ITEM
+{
+ UINT DeviceId; // Device ID
+ UINT Type; // Type
+ char DeviceName[MAX_SIZE]; // Device name
+ char Manufacturer[MAX_SIZE]; // Manufacturer
+};
+
+// Enumeration of secure devices
+struct RPC_CLIENT_ENUM_SECURE
+{
+ UINT NumItem; // Number of items
+ RPC_CLIENT_ENUM_SECURE_ITEM **Items; // Item
+};
+
+// Specify a secure device
+struct RPC_USE_SECURE
+{
+ UINT DeviceId; // Device ID
+};
+
+// Enumerate objects in the secure device
+struct RPC_ENUM_OBJECT_IN_SECURE
+{
+ UINT hWnd; // Window handle
+ UINT NumItem; // Number of items
+ char **ItemName; // Item name
+ bool *ItemType; // Type (true = secret key, false = public key)
+};
+
+// Create a virtual LAN
+struct RPC_CLIENT_CREATE_VLAN
+{
+ char DeviceName[MAX_SIZE]; // Device name
+};
+
+// Get a Virtual LAN information
+struct RPC_CLIENT_GET_VLAN
+{
+ char DeviceName[MAX_SIZE]; // Device name
+ bool Enabled; // Flag of whether it works or not
+ char MacAddress[MAX_SIZE]; // MAC address
+ char Version[MAX_SIZE]; // Version
+ char FileName[MAX_SIZE]; // Driver file name
+ char Guid[MAX_SIZE]; // GUID
+};
+
+// Set the virtual LAN information
+struct RPC_CLIENT_SET_VLAN
+{
+ char DeviceName[MAX_SIZE]; // Device name
+ char MacAddress[MAX_SIZE]; // MAC address
+};
+
+// Virtual LAN enumeration item
+struct RPC_CLIENT_ENUM_VLAN_ITEM
+{
+ char DeviceName[MAX_SIZE]; // Device name
+ bool Enabled; // Operation flag
+ char MacAddress[MAX_SIZE]; // MAC address
+ char Version[MAX_SIZE]; // Version
+};
+
+// Enumerate the virtual LANs
+struct RPC_CLIENT_ENUM_VLAN
+{
+ UINT NumItem; // Item count
+ RPC_CLIENT_ENUM_VLAN_ITEM **Items; // Item
+};
+
+// Create an account
+struct RPC_CLIENT_CREATE_ACCOUNT
+{
+ CLIENT_OPTION *ClientOption; // Client Option
+ CLIENT_AUTH *ClientAuth; // Client authentication data
+ bool StartupAccount; // Startup account
+ bool CheckServerCert; // Checking of the server certificate
+ X *ServerCert; // Server certificate
+ UCHAR ShortcutKey[SHA1_SIZE]; // Shortcut Key
+};
+
+// Enumeration item of account
+struct RPC_CLIENT_ENUM_ACCOUNT_ITEM
+{
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+ char UserName[MAX_USERNAME_LEN + 1]; // User name
+ char ServerName[MAX_HOST_NAME_LEN + 1]; // Server name
+ char DeviceName[MAX_DEVICE_NAME_LEN + 1]; // Device name
+ UINT ProxyType; // Type of proxy connection
+ char ProxyName[MAX_HOST_NAME_LEN + 1]; // Host name
+ bool Active; // Operation flag
+ bool Connected; // Connection completion flag
+ bool StartupAccount; // Startup account
+ UINT Port; // Port number (Ver 3.0 or later)
+ char HubName[MAX_HUBNAME_LEN + 1]; // Virtual HUB name (Ver 3.0 or later)
+ UINT64 CreateDateTime; // Creation date and time (Ver 3.0 or later)
+ UINT64 UpdateDateTime; // Modified date (Ver 3.0 or later)
+ UINT64 LastConnectDateTime; // Last connection date and time (Ver 3.0 or later)
+ UINT tmp1; // Temporary data
+};
+
+// Enumeration of accounts
+struct RPC_CLIENT_ENUM_ACCOUNT
+{
+ UINT NumItem; // Item count
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM **Items; // Items
+};
+
+// Delete the Account
+struct RPC_CLIENT_DELETE_ACCOUNT
+{
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+};
+
+// Change the account name
+struct RPC_RENAME_ACCOUNT
+{
+ wchar_t OldName[MAX_ACCOUNT_NAME_LEN + 1]; // Old name
+ wchar_t NewName[MAX_ACCOUNT_NAME_LEN + 1]; // New Name
+};
+
+// Get the account
+struct RPC_CLIENT_GET_ACCOUNT
+{
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+ CLIENT_OPTION *ClientOption; // Client Option
+ CLIENT_AUTH *ClientAuth; // Client authentication data
+ bool StartupAccount; // Startup account
+ bool CheckServerCert; // Check the server certificate
+ X *ServerCert; // Server certificate
+ UCHAR ShortcutKey[SHA1_SIZE]; // Shortcut Key
+ UINT64 CreateDateTime; // Creation date and time (Ver 3.0 or later)
+ UINT64 UpdateDateTime; // Modified date (Ver 3.0 or later)
+ UINT64 LastConnectDateTime; // Last connection date and time (Ver 3.0 or later)
+};
+
+// Connection
+struct RPC_CLIENT_CONNECT
+{
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+};
+
+// Get the Connection status
+struct RPC_CLIENT_GET_CONNECTION_STATUS
+{
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+ bool Active; // Operation flag
+ bool Connected; // Connected flag
+ UINT SessionStatus; // Session status
+ char ServerName[MAX_HOST_NAME_LEN + 1]; // Server name
+ UINT ServerPort; // Port number of the server
+ char ServerProductName[MAX_SIZE]; // Server product name
+ UINT ServerProductVer; // Server product version
+ UINT ServerProductBuild; // Server product build number
+ X *ServerX; // Server certificate
+ X *ClientX; // Client certificate
+ UINT64 StartTime; // Connection start time
+ UINT64 FirstConnectionEstablisiedTime; // Connection completion time of the first connection
+ UINT64 CurrentConnectionEstablishTime; // Connection completion time of this connection
+ UINT NumConnectionsEatablished; // Number of connections have been established so far
+ bool HalfConnection; // Half-connection
+ bool QoS; // VoIP / QoS
+ UINT MaxTcpConnections; // Maximum number of the TCP connections
+ UINT NumTcpConnections; // Number of current TCP connections
+ UINT NumTcpConnectionsUpload; // Number of inbound connections
+ UINT NumTcpConnectionsDownload; // Number of outbound connections
+ bool UseEncrypt; // Use of encryption
+ char CipherName[32]; // Cipher algorithm name
+ char ProtocolName[64]; // Protocol name
+ bool UseCompress; // Use of compression
+ bool IsRUDPSession; // R-UDP session
+ char UnderlayProtocol[64]; // Physical communication protocol
+ bool IsUdpAccelerationEnabled; // The UDP acceleration is enabled
+ bool IsUsingUdpAcceleration; // Using the UDP acceleration function
+ char SessionName[MAX_SESSION_NAME_LEN + 1]; // Session name
+ char ConnectionName[MAX_CONNECTION_NAME_LEN + 1]; // Connection name
+ UCHAR SessionKey[SHA1_SIZE]; // Session key
+ POLICY Policy; // Policy
+ UINT64 TotalSendSize; // Total transmitted data size
+ UINT64 TotalRecvSize; // Total received data size
+ UINT64 TotalSendSizeReal; // Total transmitted data size (no compression)
+ UINT64 TotalRecvSizeReal; // Total received data size (no compression)
+ TRAFFIC Traffic; // Traffic data
+ bool IsBridgeMode; // Bridge Mode
+ bool IsMonitorMode; // Monitor mode
+ UINT VLanId; // VLAN ID
+};
+
+
+// RPC connection
+struct CLIENT_RPC_CONNECTION
+{
+ struct CLIENT *Client; // Client
+ bool RpcMode; // True: RPC mode, false: notification mode
+ THREAD *Thread; // Processing thread
+ SOCK *Sock; // Socket
+};
+
+// Client object
+struct CLIENT
+{
+ LOCK *lock; // Lock
+ LOCK *lockForConnect; // Lock to be used in the CtConnect
+ REF *ref; // Reference counter
+ CEDAR *Cedar; // Cedar
+ volatile bool Halt; // Halting flag
+ UINT Err; // Error code
+ CFG_RW *CfgRw; // Configuration file R/W
+ LIST *AccountList; // Account list
+ UCHAR EncryptedPassword[SHA1_SIZE]; // Password
+ bool PasswordRemoteOnly; // Password is required only remote access
+ UINT UseSecureDeviceId; // Secure device ID to be used
+ CLIENT_CONFIG Config; // Client Settings
+ LIST *RpcConnectionList; // RPC connection list
+ SOCK *RpcListener; // RPC listener
+ THREAD *RpcThread; // RPC thread
+ LOCK *HelperLock; // Auxiliary lock
+ THREAD *SaverThread; // Saver thread
+ EVENT *SaverHalter; // The event to stop the Saver thread
+ LIST *NotifyCancelList; // Notification event list
+ KEEP *Keep; // Keep Connection
+ LIST *UnixVLanList; // List of virtual LAN cards in UNIX
+ LOG *Logger; // Logger
+ bool DontSavePassword; // Flag for not to save the password
+ ERASER *Eraser; // Eraser
+ SOCKLIST *SockList; // Socket list
+ CM_SETTING *CmSetting; // CM configuration
+ void *GlobalPulse; // Global pulse
+ THREAD *PulseRecvThread; // Pulse reception thread
+ volatile bool HaltPulseThread; // Stop flag for the pulse reception thread
+ bool NoSaveLog; // Do not save the log
+ bool NoSaveConfig; // Do not save the settings
+ INTERNET_SETTING CommonProxySetting; // Common proxy settings
+
+};
+
+// Notification to the remote client
+struct RPC_CLIENT_NOTIFY
+{
+ UINT NotifyCode; // Code
+};
+
+// Type of notification
+#define CLIENT_NOTIFY_ACCOUNT_CHANGED 1 // Account change notification
+#define CLIENT_NOTIFY_VLAN_CHANGED 2 // Virtual LAN card change notification
+
+// Remote client
+struct REMOTE_CLIENT
+{
+ RPC *Rpc;
+ UINT OsType;
+ bool Unix;
+ bool Win9x;
+ UINT ProcessId;
+ UINT ClientBuildInt;
+ bool IsVgcSupported;
+ bool ShowVgcLink;
+ char ClientId[128];
+};
+
+// Notification client
+struct NOTIFY_CLIENT
+{
+ SOCK *Sock;
+};
+
+// CM configuration
+struct CM_SETTING
+{
+ bool EasyMode; // Simple mode
+ bool LockMode; // Setting lock mode
+ UCHAR HashedPassword[SHA1_SIZE]; // Password
+};
+
+
+
+
+// Function prototype
+REMOTE_CLIENT *CcConnectRpc(char *server_name, char *password, bool *bad_pass, bool *no_remote, UINT wait_retry);
+REMOTE_CLIENT *CcConnectRpcEx(char *server_name, char *password, bool *bad_pass, bool *no_remote, UCHAR *key, UINT *key_error_code, bool shortcut_disconnect, UINT wait_retry);
+UINT CcShortcut(UCHAR *key);
+UINT CcShortcutDisconnect(UCHAR *key);
+void CcDisconnectRpc(REMOTE_CLIENT *rc);
+NOTIFY_CLIENT *CcConnectNotify(REMOTE_CLIENT *rc);
+void CcDisconnectNotify(NOTIFY_CLIENT *n);
+void CcStopNotify(NOTIFY_CLIENT *n);
+bool CcWaitNotify(NOTIFY_CLIENT *n);
+UINT CcGetClientVersion(REMOTE_CLIENT *r, RPC_CLIENT_VERSION *a);
+UINT CcSetCmSetting(REMOTE_CLIENT *r, CM_SETTING *a);
+UINT CcGetCmSetting(REMOTE_CLIENT *r, CM_SETTING *a);
+UINT CcSetPassword(REMOTE_CLIENT *r, RPC_CLIENT_PASSWORD *pass);
+UINT CcGetPasswordSetting(REMOTE_CLIENT *r, RPC_CLIENT_PASSWORD_SETTING *a);
+UINT CcEnumCa(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_CA *e);
+UINT CcAddCa(REMOTE_CLIENT *r, RPC_CERT *cert);
+UINT CcDeleteCa(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_CA *p);
+UINT CcGetCa(REMOTE_CLIENT *r, RPC_GET_CA *get);
+UINT CcEnumSecure(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_SECURE *e);
+UINT CcUseSecure(REMOTE_CLIENT *r, RPC_USE_SECURE *sec);
+UINT CcGetUseSecure(REMOTE_CLIENT *r, RPC_USE_SECURE *sec);
+UINT CcEnumObjectInSecure(REMOTE_CLIENT *r, RPC_ENUM_OBJECT_IN_SECURE *e);
+UINT CcCreateVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *create);
+UINT CcUpgradeVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *create);
+UINT CcGetVLan(REMOTE_CLIENT *r, RPC_CLIENT_GET_VLAN *get);
+UINT CcSetVLan(REMOTE_CLIENT *r, RPC_CLIENT_SET_VLAN *set);
+UINT CcEnumVLan(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_VLAN *e);
+UINT CcDeleteVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *d);
+UINT CcEnableVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *vlan);
+UINT CcDisableVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *vlan);
+UINT CcCreateAccount(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_ACCOUNT *a);
+UINT CcEnumAccount(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_ACCOUNT *e);
+UINT CcDeleteAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a);
+UINT CcSetAccount(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_ACCOUNT *a);
+UINT CcGetAccount(REMOTE_CLIENT *r, RPC_CLIENT_GET_ACCOUNT *a);
+UINT CcRenameAccount(REMOTE_CLIENT *r, RPC_RENAME_ACCOUNT *rename);
+UINT CcSetClientConfig(REMOTE_CLIENT *r, CLIENT_CONFIG *o);
+UINT CcGetClientConfig(REMOTE_CLIENT *r, CLIENT_CONFIG *o);
+UINT CcConnect(REMOTE_CLIENT *r, RPC_CLIENT_CONNECT *connect);
+UINT CcDisconnect(REMOTE_CLIENT *r, RPC_CLIENT_CONNECT *connect);
+UINT CcGetAccountStatus(REMOTE_CLIENT *r, RPC_CLIENT_GET_CONNECTION_STATUS *st);
+UINT CcSetStartupAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a);
+UINT CcRemoveStartupAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a);
+UINT CcGetIssuer(REMOTE_CLIENT *r, RPC_GET_ISSUER *a);
+UINT CcGetCommonProxySetting(REMOTE_CLIENT *r, INTERNET_SETTING *a);
+UINT CcSetCommonProxySetting(REMOTE_CLIENT *r, INTERNET_SETTING *a);
+
+
+void CcSetServiceToForegroundProcess(REMOTE_CLIENT *r);
+char *CiGetFirstVLan(CLIENT *c);
+void CiNormalizeAccountVLan(CLIENT *c);
+
+bool CompareInternetSetting(INTERNET_SETTING *s1, INTERNET_SETTING *s2);
+
+
+void CnStart();
+void CnListenerProc(THREAD *thread, void *param);
+
+void CnReleaseSocket(SOCK *s, PACK *p);
+
+void CnStatusPrinter(SOCK *s, PACK *p);
+void Win32CnStatusPrinter(SOCK *s, PACK *p);
+
+void CnConnectErrorDlg(SOCK *s, PACK *p);
+void Win32CnConnectErrorDlg(SOCK *s, PACK *p);
+void Win32CnConnectErrorDlgThreadProc(THREAD *thread, void *param);
+
+void CnPasswordDlg(SOCK *s, PACK *p);
+void Win32CnPasswordDlg(SOCK *s, PACK *p);
+void Win32CnPasswordDlgThreadProc(THREAD *thread, void *param);
+
+void CnMsgDlg(SOCK *s, PACK *p);
+void Win32CnMsgDlg(SOCK *s, PACK *p);
+void Win32CnMsgDlgThreadProc(THREAD *thread, void *param);
+
+void CnNicInfo(SOCK *s, PACK *p);
+void Win32CnNicInfo(SOCK *s, PACK *p);
+void Win32CnNicInfoThreadProc(THREAD *thread, void *param);
+
+void CnCheckCert(SOCK *s, PACK *p);
+void Win32CnCheckCert(SOCK *s, PACK *p);
+void Win32CnCheckCertThreadProc(THREAD *thread, void *param);
+
+void CnExecDriverInstaller(SOCK *s, PACK *p);
+void Win32CnExecDriverInstaller(SOCK *s, PACK *p);
+
+bool CnCheckAlreadyExists(bool lock);
+bool CnIsCnServiceReady();
+void CnWaitForCnServiceReady();
+
+void CnSecureSign(SOCK *s, PACK *p);
+
+SOCK *CncConnect();
+SOCK *CncConnectEx(UINT timeout);
+void CncReleaseSocket();
+void CncExit();
+UINT CncGetSessionId();
+bool CncExecDriverInstaller(char *arg);
+SOCK *CncStatusPrinterWindowStart(SESSION *s);
+void CncStatusPrinterWindowPrint(SOCK *s, wchar_t *str);
+void CncStatusPrinterWindowStop(SOCK *s);
+void CncStatusPrinterWindowThreadProc(THREAD *thread, void *param);
+bool CncConnectErrorDlg(SESSION *session, UI_CONNECTERROR_DLG *dlg);
+void CncConnectErrorDlgHaltThread(THREAD *thread, void *param);
+bool CncPasswordDlg(SESSION *session, UI_PASSWORD_DLG *dlg);
+void CncPasswordDlgHaltThread(THREAD *thread, void *param);
+void CncCheckCert(SESSION *session, UI_CHECKCERT *dlg);
+void CncCheckCertHaltThread(THREAD *thread, void *param);
+bool CncSecureSignDlg(SECURE_SIGN *sign);
+SOCK *CncMsgDlg(UI_MSG_DLG *dlg);
+void CndMsgDlgFree(SOCK *s);
+SOCK *CncNicInfo(UI_NICINFO *info);
+void CncNicInfoFree(SOCK *s);
+
+void CtStartClient();
+void CtStopClient();
+CLIENT *CtGetClient();
+void CtReleaseClient(CLIENT *c);
+bool CtGetClientVersion(CLIENT *c, RPC_CLIENT_VERSION *ver);
+bool CtGetCmSetting(CLIENT *c, CM_SETTING *s);
+bool CtSetCmSetting(CLIENT *c, CM_SETTING *s);
+bool CtSetPassword(CLIENT *c, RPC_CLIENT_PASSWORD *pass);
+bool CtGetPasswordSetting(CLIENT *c, RPC_CLIENT_PASSWORD_SETTING *a);
+bool CtEnumCa(CLIENT *c, RPC_CLIENT_ENUM_CA *e);
+bool CtAddCa(CLIENT *c, RPC_CERT *cert);
+bool CtDeleteCa(CLIENT *c, RPC_CLIENT_DELETE_CA *p);
+bool CtGetCa(CLIENT *c, RPC_GET_CA *get);
+bool CtEnumSecure(CLIENT *c, RPC_CLIENT_ENUM_SECURE *e);
+bool CtUseSecure(CLIENT *c, RPC_USE_SECURE *sec);
+bool CtGetUseSecure(CLIENT *c, RPC_USE_SECURE *sec);
+bool CtEnumObjectInSecure(CLIENT *c, RPC_ENUM_OBJECT_IN_SECURE *e);
+bool CtCreateVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *create);
+bool CtUpgradeVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *create);
+bool CtGetVLan(CLIENT *c, RPC_CLIENT_GET_VLAN *get);
+bool CtSetVLan(CLIENT *c, RPC_CLIENT_SET_VLAN *set);
+bool CtEnumVLan(CLIENT *c, RPC_CLIENT_ENUM_VLAN *e);
+bool CtDeleteVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *d);
+bool CtEnableVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *vlan);
+bool CtDisableVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *vlan);
+bool CtCreateAccount(CLIENT *c, RPC_CLIENT_CREATE_ACCOUNT *a, bool inner);
+bool CtEnumAccount(CLIENT *c, RPC_CLIENT_ENUM_ACCOUNT *e);
+bool CtDeleteAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a, bool inner);
+bool CtSetAccount(CLIENT *c, RPC_CLIENT_CREATE_ACCOUNT *a, bool inner);
+bool CtGetAccount(CLIENT *c, RPC_CLIENT_GET_ACCOUNT *a);
+bool CtRenameAccount(CLIENT *c, RPC_RENAME_ACCOUNT *rename, bool inner);
+bool CtSetClientConfig(CLIENT *c, CLIENT_CONFIG *o);
+bool CtGetClientConfig(CLIENT *c, CLIENT_CONFIG *o);
+bool CtConnect(CLIENT *c, RPC_CLIENT_CONNECT *connect);
+bool CtDisconnect(CLIENT *c, RPC_CLIENT_CONNECT *connect, bool inner);
+bool CtGetAccountStatus(CLIENT *c, RPC_CLIENT_GET_CONNECTION_STATUS *st);
+bool CtSetStartupAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a, bool inner);
+bool CtRemoveStartupAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a);
+bool CtGetIssuer(CLIENT *c, RPC_GET_ISSUER *a);
+bool CtGetCommonProxySetting(CLIENT *c, INTERNET_SETTING *a);
+bool CtSetCommonProxySetting(CLIENT *c, INTERNET_SETTING *a);
+
+
+// Internal function prototype
+void CiSendGlobalPulse(CLIENT *c);
+void CiPulseRecvThread(THREAD *thread, void *param);
+char *CiGetVpnClientExeFileName();
+void CiServerThread(THREAD *t, void *param);
+void CiInitSaver(CLIENT *c);
+void CiFreeSaver(CLIENT *c);
+void CiGetSessionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *st, SESSION *s);
+PACK *CiRpcDispatch(RPC *rpc, char *name, PACK *p);
+void CiRpcAccepted(CLIENT *c, SOCK *s);
+void CiNotifyMain(CLIENT *c, SOCK *s);
+void CiRpcAcceptThread(THREAD *thread, void *param);
+void CiRpcServerThread(THREAD *thread, void *param);
+void CiStartRpcServer(CLIENT *c);
+void CiStopRpcServer(CLIENT *c);
+CLIENT_OPTION *CiLoadClientOption(FOLDER *f);
+CLIENT_AUTH *CiLoadClientAuth(FOLDER *f);
+ACCOUNT *CiLoadClientAccount(FOLDER *f);
+void CiLoadClientConfig(CLIENT_CONFIG *c, FOLDER *f);
+void CiLoadAccountDatabase(CLIENT *c, FOLDER *f);
+void CiLoadCAList(CLIENT *c, FOLDER *f);
+void CiLoadCACert(CLIENT *c, FOLDER *f);
+void CiLoadVLanList(CLIENT *c, FOLDER *f);
+void CiLoadVLan(CLIENT *c, FOLDER *f);
+bool CiReadSettingFromCfg(CLIENT *c, FOLDER *root);
+void CiWriteAccountDatabase(CLIENT *c, FOLDER *f);
+void CiWriteAccountData(FOLDER *f, ACCOUNT *a);
+void CiWriteClientOption(FOLDER *f, CLIENT_OPTION *o);
+void CiWriteClientAuth(FOLDER *f, CLIENT_AUTH *a);
+void CiWriteClientConfig(FOLDER *cc, CLIENT_CONFIG *config);
+void CiWriteSettingToCfg(CLIENT *c, FOLDER *root);
+void CiWriteCAList(CLIENT *c, FOLDER *f);
+void CiWriteCACert(CLIENT *c, FOLDER *f, X *x);
+void CiWriteVLanList(CLIENT *c, FOLDER *f);
+void CiWriteVLan(CLIENT *c, FOLDER *f, UNIX_VLAN *v);
+void CiFreeClientGetConnectionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *st);
+bool CiCheckCertProc(SESSION *s, CONNECTION *c, X *server_x, bool *expired);
+bool CiSecureSignProc(SESSION *s, CONNECTION *c, SECURE_SIGN *sign);
+bool Win32CiSecureSign(SECURE_SIGN *sign);
+void CiFreeClientAuth(CLIENT_AUTH *auth);
+void CiFreeClientCreateAccount(RPC_CLIENT_CREATE_ACCOUNT *a);
+void CiFreeClientGetAccount(RPC_CLIENT_GET_ACCOUNT *a);
+void CiFreeClientEnumVLan(RPC_CLIENT_ENUM_VLAN *e);
+void CiFreeClientEnumSecure(RPC_CLIENT_ENUM_SECURE *e);
+void CiFreeClientEnumCa(RPC_CLIENT_ENUM_CA *e);
+void CiFreeEnumObjectInSecure(RPC_ENUM_OBJECT_IN_SECURE *a);
+void CiFreeGetCa(RPC_GET_CA *a);
+void CiFreeGetIssuer(RPC_GET_ISSUER *a);
+void CiFreeClientEnumAccount(RPC_CLIENT_ENUM_ACCOUNT *a);
+void CiSetError(CLIENT *c, UINT err);
+void CiCheckOs();
+CLIENT *CiNewClient();
+void CiCleanupClient(CLIENT *c);
+bool CiLoadConfigurationFile(CLIENT *c);
+void CiSaveConfigurationFile(CLIENT *c);
+void CiInitConfiguration(CLIENT *c);
+void CiSetVLanToDefault(CLIENT *c);
+bool CiIsVLan(CLIENT *c, char *name);
+void CiFreeConfiguration(CLIENT *c);
+int CiCompareAccount(void *p1, void *p2);
+void CiFreeAccount(ACCOUNT *a);
+void CiNotify(CLIENT *c);
+void CiNotifyInternal(CLIENT *c);
+void CiClientStatusPrinter(SESSION *s, wchar_t *status);
+void CiInitKeep(CLIENT *c);
+void CiFreeKeep(CLIENT *c);
+int CiCompareUnixVLan(void *p1, void *p2);
+BUF *CiAccountToCfg(RPC_CLIENT_CREATE_ACCOUNT *t);
+RPC_CLIENT_CREATE_ACCOUNT *CiCfgToAccount(BUF *b);
+void CiChangeAllVLanMacAddressIfCleared(CLIENT *c);
+void CiChangeAllVLanMacAddress(CLIENT *c);
+void CiChangeAllVLanMacAddressIfMachineChanged(CLIENT *c);
+bool CiReadLastMachineHash(void *data);
+bool CiWriteLastMachineHash(void *data);
+void CiGetCurrentMachineHash(void *data);
+void CiGetCurrentMachineHashOld(void *data);
+void CiGetCurrentMachineHashNew(void *data);
+LIST *CiLoadIni();
+void CiFreeIni(LIST *o);
+void CiLoadIniSettings(CLIENT *c);
+bool CiLoadConfigFilePathFromIni(char *path, UINT size);
+int CiCompareClientAccountEnumItemByLastConnectDateTime(void *p1, void *p2);
+bool CiIsValidVLanRegulatedName(char *name);
+void CiGenerateVLanRegulatedName(char *name, UINT size, UINT i);
+bool CiGetNextRecommendedVLanName(REMOTE_CLIENT *r, char *name, UINT size);
+void CiDisableWcmNetworkMinimize(CLIENT *c);
+bool CiTryToParseAccount(BUF *b);
+bool CiTryToParseAccountFile(wchar_t *name);
+bool CiEraseSensitiveInAccount(BUF *b);
+bool CiHasAccountSensitiveInformation(BUF *b);
+bool CiHasAccountSensitiveInformationFile(wchar_t *name);
+void CiApplyInnerVPNServerConfig(CLIENT *c);
+SERVER *CiNewInnerVPNServer(CLIENT *c);
+void CiFreeInnerVPNServer(CLIENT *c, SERVER *s);
+void CiIncrementNumActiveSessions();
+void CiDecrementNumActiveSessions();
+UINT CiGetNumActiveSessions();
+
+BUF *EncryptPassword(char *password);
+BUF *EncryptPassword2(char *password);
+char *DecryptPassword(BUF *b);
+char *DecryptPassword2(BUF *b);
+
+void InRpcGetIssuer(RPC_GET_ISSUER *c, PACK *p);
+void OutRpcGetIssuer(PACK *p, RPC_GET_ISSUER *c);
+void InRpcClientVersion(RPC_CLIENT_VERSION *ver, PACK *p);
+void OutRpcClientVersion(PACK *p, RPC_CLIENT_VERSION *ver);
+void InRpcClientPassword(RPC_CLIENT_PASSWORD *pw, PACK *p);
+void OutRpcClientPassword(PACK *p, RPC_CLIENT_PASSWORD *pw);
+void InRpcClientEnumCa(RPC_CLIENT_ENUM_CA *e, PACK *p);
+void OutRpcClientEnumCa(PACK *p, RPC_CLIENT_ENUM_CA *e);
+void InRpcCert(RPC_CERT *c, PACK *p);
+void OutRpcCert(PACK *p, RPC_CERT *c);
+void InRpcClientDeleteCa(RPC_CLIENT_DELETE_CA *c, PACK *p);
+void OutRpcClientDeleteCa(PACK *p, RPC_CLIENT_DELETE_CA *c);
+void InRpcGetCa(RPC_GET_CA *c, PACK *p);
+void OutRpcGetCa(PACK *p, RPC_GET_CA *c);
+void InRpcClientEnumSecure(RPC_CLIENT_ENUM_SECURE *e, PACK *p);
+void OutRpcClientEnumSecure(PACK *p, RPC_CLIENT_ENUM_SECURE *e);
+void InRpcUseSecure(RPC_USE_SECURE *u, PACK *p);
+void OutRpcUseSecure(PACK *p, RPC_USE_SECURE *u);
+void InRpcEnumObjectInSecure(RPC_ENUM_OBJECT_IN_SECURE *e, PACK *p);
+void OutRpcEnumObjectInSecure(PACK *p, RPC_ENUM_OBJECT_IN_SECURE *e);
+void InRpcCreateVLan(RPC_CLIENT_CREATE_VLAN *v, PACK *p);
+void OutRpcCreateVLan(PACK *p, RPC_CLIENT_CREATE_VLAN *v);
+void InRpcClientGetVLan(RPC_CLIENT_GET_VLAN *v, PACK *p);
+void OutRpcClientGetVLan(PACK *p, RPC_CLIENT_GET_VLAN *v);
+void InRpcClientSetVLan(RPC_CLIENT_SET_VLAN *v, PACK *p);
+void OutRpcClientSetVLan(PACK *p, RPC_CLIENT_SET_VLAN *v);
+void InRpcClientEnumVLan(RPC_CLIENT_ENUM_VLAN *v, PACK *p);
+void OutRpcClientEnumVLan(PACK *p, RPC_CLIENT_ENUM_VLAN *v);
+void InRpcClientOption(CLIENT_OPTION *c, PACK *p);
+void OutRpcClientOption(PACK *p, CLIENT_OPTION *c);
+void InRpcClientAuth(CLIENT_AUTH *c, PACK *p);
+void OutRpcClientAuth(PACK *p, CLIENT_AUTH *c);
+void InRpcClientCreateAccount(RPC_CLIENT_CREATE_ACCOUNT *c, PACK *p);
+void OutRpcClientCreateAccount(PACK *p, RPC_CLIENT_CREATE_ACCOUNT *c);
+void InRpcClientEnumAccount(RPC_CLIENT_ENUM_ACCOUNT *e, PACK *p);
+void OutRpcClientEnumAccount(PACK *p, RPC_CLIENT_ENUM_ACCOUNT *e);
+void InRpcClientDeleteAccount(RPC_CLIENT_DELETE_ACCOUNT *a, PACK *p);
+void OutRpcClientDeleteAccount(PACK *p, RPC_CLIENT_DELETE_ACCOUNT *a);
+void InRpcRenameAccount(RPC_RENAME_ACCOUNT *a, PACK *p);
+void OutRpcRenameAccount(PACK *p, RPC_RENAME_ACCOUNT *a);
+void InRpcClientGetAccount(RPC_CLIENT_GET_ACCOUNT *c, PACK *p);
+void OutRpcClientGetAccount(PACK *p, RPC_CLIENT_GET_ACCOUNT *c);
+void InRpcClientConnect(RPC_CLIENT_CONNECT *c, PACK *p);
+void OutRpcClientConnect(PACK *p, RPC_CLIENT_CONNECT *c);
+void InRpcPolicy(POLICY *o, PACK *p);
+void OutRpcPolicy(PACK *p, POLICY *o);
+void InRpcClientGetConnectionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *s, PACK *p);
+void OutRpcClientGetConnectionStatus(PACK *p, RPC_CLIENT_GET_CONNECTION_STATUS *c);
+void InRpcClientNotify(RPC_CLIENT_NOTIFY *n, PACK *p);
+void OutRpcClientNotify(PACK *p, RPC_CLIENT_NOTIFY *n);
+void InRpcClientConfig(CLIENT_CONFIG *c, PACK *p);
+void OutRpcClientConfig(PACK *p, CLIENT_CONFIG *c);
+void InRpcClientPasswordSetting(RPC_CLIENT_PASSWORD_SETTING *a, PACK *p);
+void OutRpcClientPasswordSetting(PACK *p, RPC_CLIENT_PASSWORD_SETTING *a);
+void InRpcTraffic(TRAFFIC *t, PACK *p);
+void OutRpcTraffic(PACK *p, TRAFFIC *t);
+void InRpcTrafficEx(TRAFFIC *t, PACK *p, UINT i);
+void OutRpcTrafficEx(TRAFFIC *t, PACK *p, UINT i, UINT num);
+void OutRpcCmSetting(PACK *p, CM_SETTING *c);
+void InRpcCmSetting(CM_SETTING *c, PACK *p);
+
+
+#ifdef OS_WIN32
+void CiInitDriverVerStruct(MS_DRIVER_VER *ver);
+#endif // OS_EIN32
+
+#endif // CLIENT_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Command.c b/src/Cedar/Command.c
new file mode 100644
index 00000000..1d762b45
--- /dev/null
+++ b/src/Cedar/Command.c
@@ -0,0 +1,23538 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Command.c
+// vpncmd Command Line Management Utility
+
+#include "CedarPch.h"
+
+// System checker definition
+typedef bool (CHECKER_PROC_DEF)();
+typedef struct CHECKER_PROC
+{
+ char *Title;
+ CHECKER_PROC_DEF *Proc;
+} CHECKER_PROC;
+
+static CHECKER_PROC checker_procs[] =
+{
+ {"CHECK_PROC_KERNEL", CheckKernel},
+ {"CHECK_PROC_MEMORY", CheckMemory},
+ {"CHECK_PROC_STRINGS", CheckStrings},
+ {"CHECK_PROC_FILESYSTEM", CheckFileSystem},
+ {"CHECK_PROC_THREAD", CheckThread},
+ {"CHECK_PROC_NETWORK", CheckNetwork},
+};
+
+typedef struct CHECK_NETWORK_1
+{
+ SOCK *ListenSocket;
+} CHECK_NETWORK_1;
+
+typedef struct CHECK_NETWORK_2
+{
+ SOCK *s;
+ X *x;
+ K *k;
+} CHECK_NETWORK_2;
+
+
+// Convert the TT_RESULT to RPC
+void OutRpcTtResult(PACK *p, TT_RESULT *t)
+{
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "Raw", t->Raw);
+ PackAddBool(p, "Double", t->Double);
+ PackAddInt64(p, "NumBytesUpload", t->NumBytesUpload);
+ PackAddInt64(p, "NumBytesDownload", t->NumBytesDownload);
+ PackAddInt64(p, "NumBytesTotal", t->NumBytesTotal);
+ PackAddInt64(p, "Span", t->Span);
+ PackAddInt64(p, "BpsUpload", t->BpsUpload);
+ PackAddInt64(p, "BpsDownload", t->BpsDownload);
+ PackAddInt64(p, "BpsTotal", t->BpsTotal);
+}
+
+// Convert an RPC to a TT_RESULT
+void InRpcTtResult(PACK *p, TT_RESULT *t)
+{
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(TT_RESULT));
+
+ t->Raw = PackGetBool(p, "Raw");
+ t->Double = PackGetBool(p, "Double");
+ t->NumBytesUpload = PackGetInt64(p, "NumBytesUpload");
+ t->NumBytesDownload = PackGetInt64(p, "NumBytesDownload");
+ t->NumBytesTotal = PackGetInt64(p, "NumBytesTotal");
+ t->Span = PackGetInt64(p, "Span");
+ t->BpsUpload = PackGetInt64(p, "BpsUpload");
+ t->BpsDownload = PackGetInt64(p, "BpsDownload");
+ t->BpsTotal = PackGetInt64(p, "BpsTotal");
+}
+
+// Accept thread
+void CheckNetworkAcceptThread(THREAD *thread, void *param)
+{
+ CHECK_NETWORK_2 *c = (CHECK_NETWORK_2 *)param;
+ SOCK *s = c->s;
+ UINT i = 0;
+
+ if (StartSSL(s, c->x, c->k))
+ {
+ while (true)
+ {
+ i++;
+ if (Send(s, &i, sizeof(UINT), true) == 0)
+ {
+ break;
+ }
+ }
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+}
+
+
+// Listen thread
+void CheckNetworkListenThread(THREAD *thread, void *param)
+{
+ CHECK_NETWORK_1 *c = (CHECK_NETWORK_1 *)param;
+ SOCK *s;
+ UINT i;
+ K *pub, *pri;
+ X *x;
+ LIST *o = NewList(NULL);
+ NAME *name = NewName(L"Test", L"Test", L"Test", L"JP", L"Ibaraki", L"Tsukuba");
+
+ RsaGen(&pri, &pub, 1024);
+ x = NewRootX(pub, pri, name, 1000, NULL);
+
+ FreeName(name);
+
+ for (i = 1025;;i++)
+ {
+ s = Listen(i);
+ if (s != NULL)
+ {
+ break;
+ }
+ }
+
+ c->ListenSocket = s;
+ AddRef(s->ref);
+
+ NoticeThreadInit(thread);
+
+ while (true)
+ {
+ SOCK *new_sock = Accept(s);
+
+ if (new_sock == NULL)
+ {
+ break;
+ }
+ else
+ {
+ CHECK_NETWORK_2 c;
+ THREAD *t;
+
+ Zero(&c, sizeof(c));
+ c.s = new_sock;
+ c.k = pri;
+ c.x = x;
+
+ t = NewThread(CheckNetworkAcceptThread, &c);
+ Insert(o, t);
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ THREAD *t = LIST_DATA(o, i);
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+ }
+
+ FreeK(pri);
+ FreeK(pub);
+
+ FreeX(x);
+
+ ReleaseSock(s);
+ ReleaseList(o);
+}
+
+// Network function check
+bool CheckNetwork()
+{
+ CHECK_NETWORK_1 c;
+ THREAD *t;
+ SOCK *listen_socket;
+ UINT port;
+ UINT i, num;
+ bool ok = true;
+ SOCK **socks;
+ SOCK_EVENT *se = NewSockEvent();
+
+ Zero(&c, sizeof(c));
+ t = NewThread(CheckNetworkListenThread, &c);
+ WaitThreadInit(t);
+
+ listen_socket = c.ListenSocket;
+
+ port = listen_socket->LocalPort;
+
+ num = 8;
+ socks = ZeroMalloc(sizeof(SOCK *) * num);
+ for (i = 0;i < num;i++)
+ {
+ socks[i] = Connect("localhost", port);
+ if (socks[i] == NULL)
+ {
+ Print("Connect Failed. (%u)\n", i);
+ ok = false;
+ num = i;
+ break;
+ }
+ if (StartSSL(socks[i], NULL, NULL) == false)
+ {
+ ReleaseSock(socks[i]);
+ Print("Connect Failed. (%u)\n", i);
+ ok = false;
+ num = i;
+ break;
+ }
+
+ JoinSockToSockEvent(socks[i], se);
+ }
+
+ if (ok)
+ {
+ while (true)
+ {
+ UINT i;
+ bool end = false;
+ bool all_blocked = true;
+
+ for (i = 0;i < num;i++)
+ {
+ UINT n;
+ UINT ret;
+
+ n = 0;
+ ret = Recv(socks[i], &n, sizeof(UINT), true);
+ if (ret == 0)
+ {
+ Print("Recv Failed (Disconnected).\n", ret);
+ end = true;
+ ok = false;
+ }
+ if (ret != SOCK_LATER)
+ {
+ all_blocked = false;
+ }
+
+ if (n >= 128)
+ {
+ end = true;
+ }
+ }
+
+ if (end)
+ {
+ break;
+ }
+
+ if (all_blocked)
+ {
+ WaitSockEvent(se, INFINITE);
+ }
+ }
+ }
+
+ for (i = 0;i < num;i++)
+ {
+ Disconnect(socks[i]);
+ ReleaseSock(socks[i]);
+ }
+ Free(socks);
+
+ Disconnect(listen_socket);
+
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+
+ ReleaseSock(listen_socket);
+
+ ReleaseSockEvent(se);
+
+ return ok;
+}
+
+typedef struct CHECK_THREAD_1
+{
+ UINT num;
+ LOCK *lock;
+ THREAD *wait_thread;
+} CHECK_THREAD_1;
+
+static UINT check_thread_global_1 = 0;
+
+#define CHECK_THREAD_INCREMENT_COUNT 32
+
+// Test thread 1
+void CheckThread1(THREAD *thread, void *param)
+{
+ CHECK_THREAD_1 *ct1 = (CHECK_THREAD_1 *)param;
+ UINT i;
+ UINT num = CHECK_THREAD_INCREMENT_COUNT;
+
+ WaitThread(ct1->wait_thread, INFINITE);
+
+ for (i = 0;i < num;i++)
+ {
+ Lock(ct1->lock);
+ check_thread_global_1 = ct1->num;
+ InputToNull((void *)check_thread_global_1);
+ check_thread_global_1 = check_thread_global_1 + 1 + RetZero();
+ ct1->num = check_thread_global_1;
+ Unlock(ct1->lock);
+ }
+}
+
+// Test thread 2
+void CheckThread2(THREAD *thread, void *param)
+{
+ EVENT *e = (EVENT *)param;
+ Wait(e, INFINITE);
+}
+
+typedef struct CHECK_THREAD_3
+{
+ UINT num, a;
+} CHECK_THREAD_3;
+
+// Test thread 3
+void CheckThread3(THREAD *thread, void *param)
+{
+ CHECK_THREAD_3 *c = (CHECK_THREAD_3 *)param;
+ THREAD *t;
+
+ if (c->num == 0)
+ {
+ return;
+ }
+ c->num--;
+ c->a++;
+
+ t = NewThread(CheckThread3, c);
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+}
+
+// Thread check
+bool CheckThread()
+{
+ bool ok = true;
+ CHECK_THREAD_1 ct1;
+ UINT num = 32;
+ UINT i;
+ THREAD **threads;
+ EVENT *e;
+ THREAD *t2;
+ THREAD *t;
+ CHECK_THREAD_3 c;
+
+ e = NewEvent();
+
+ Zero(&ct1, sizeof(ct1));
+ ct1.lock = NewLock();
+
+ t2 = NewThread(CheckThread2, e);
+ ct1.wait_thread = t2;
+
+ threads = ZeroMalloc(sizeof(THREAD *) * num);
+ for (i = 0;i < num;i++)
+ {
+ threads[i] = NewThread(CheckThread1, &ct1);
+ if (threads[i] == NULL)
+ {
+ Print("Thread %u Create Failed.\n", i);
+ ok = false;
+ }
+ }
+
+ Set(e);
+
+ for (i = 0;i < num;i++)
+ {
+ WaitThread(threads[i], INFINITE);
+ ReleaseThread(threads[i]);
+ }
+
+ Free(threads);
+
+ if (ct1.num != (num * CHECK_THREAD_INCREMENT_COUNT))
+ {
+ Print("Threading: %u != %u\n", ct1.num, num * CHECK_THREAD_INCREMENT_COUNT);
+ ok = false;
+ }
+
+ DeleteLock(ct1.lock);
+
+ WaitThread(t2, INFINITE);
+ ReleaseThread(t2);
+
+ ReleaseEvent(e);
+
+ num = 32;
+
+ Zero(&c, sizeof(c));
+ c.num = num;
+ t = NewThread(CheckThread3, &c);
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+
+ if (c.a != num)
+ {
+ Print("Threading: %u != %u\n", c.a, num);
+ ok = false;
+ }
+
+ return ok;
+}
+
+// File system check
+bool CheckFileSystem()
+{
+ bool ok = true;
+ char exe[MAX_PATH];
+ char exe_dir[MAX_PATH];
+ DIRLIST *dirs;
+ UINT i;
+
+ GetExeName(exe, sizeof(exe));
+ GetExeDir(exe_dir, sizeof(exe_dir));
+
+ ok = false;
+ dirs = EnumDir(exe_dir);
+ for (i = 0;i < dirs->NumFiles;i++)
+ {
+ if (EndWith(exe, dirs->File[i]->FileName))
+ {
+ ok = true;
+ break;
+ }
+ }
+ FreeDir(dirs);
+
+ if (ok == false)
+ {
+ Print("EnumDir Failed.\n");
+ return false;
+ }
+ else
+ {
+ UINT size = 1234567;
+ UCHAR *buf;
+ IO *io;
+#ifndef OS_WIN32
+ wchar_t *filename = L"/tmp/vpn_checker_tmp";
+#else // OS_WIN32
+ wchar_t filename[MAX_PATH];
+ CombinePathW(filename, sizeof(filename), MsGetMyTempDirW(), L"vpn_checker_tmp");
+#endif // OS_WIN32
+
+ buf = Malloc(size);
+ for (i = 0;i < size;i++)
+ {
+ buf[i] = i % 256;
+ }
+
+ io = FileCreateW(filename);
+ if (io == NULL)
+ {
+ Print("FileCreate Failed.\n");
+ Free(buf);
+ return false;
+ }
+ else
+ {
+ FileWrite(io, buf, size);
+ Free(buf);
+ FileClose(io);
+
+ io = FileOpenW(filename, false);
+ if (FileSize(io) != 1234567)
+ {
+ Print("FileSize Failed.\n");
+ FileClose(io);
+ return false;
+ }
+ else
+ {
+ BUF *b;
+
+ FileClose(io);
+ b = ReadDumpW(filename);
+
+ for (i = 0;i < b->Size;i++)
+ {
+ UCHAR c = ((UCHAR *)b->Buf)[i];
+
+ if (c != (i % 256))
+ {
+ Print("FileToBuf Failed.\n");
+ FreeBuf(b);
+ return false;
+ }
+ }
+
+ FreeBuf(b);
+ }
+ }
+
+ FileDeleteW(filename);
+ }
+
+ return ok;
+}
+
+// String check
+bool CheckStrings()
+{
+ wchar_t *numstr = _UU("CHECK_TEST_123456789");
+ char tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ UINT i;
+ UINT sum, sum2;
+ UNI_TOKEN_LIST *t;
+
+ UniStrCpy(tmp2, sizeof(tmp2), L"");
+
+ sum2 = 0;
+ for (i = 0;i < 64;i++)
+ {
+ sum2 += i;
+ UniFormat(tmp2, sizeof(tmp2), L"%s,%u", tmp2, i);
+ }
+
+ t = UniParseToken(tmp2, L",");
+
+ sum = 0;
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ wchar_t *s = t->Token[i];
+ UINT n = UniToInt(s);
+
+ sum += n;
+ }
+
+ UniFreeToken(t);
+
+ if (sum != sum2)
+ {
+ Print("UniParseToken Failed.\n");
+ return false;
+ }
+
+ if (UniToInt(numstr) != 123456789)
+ {
+ Print("UniToInt Failed.\n");
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), numstr);
+ if (ToInt(tmp) != 123456789)
+ {
+ Print("UniToStr Failed.\n");
+ return false;
+ }
+
+ return true;
+}
+
+// Memory check
+bool CheckMemory()
+{
+ UINT i, num, size, j;
+ void **pp;
+ bool ok = true;
+ UINT old_size;
+
+ num = 2000;
+ size = 1000;
+ pp = ZeroMalloc(sizeof(void *) * num);
+ for (i = 0;i < num;i++)
+ {
+ pp[i] = ZeroMalloc(size);
+ InputToNull(pp[i]);
+ for (j = 0;j < size;j++)
+ {
+ ((UCHAR *)pp[i])[j] = j % 256;
+ }
+ }
+ old_size = size;
+ size = size * 3;
+ for (i = 0;i < num;i++)
+ {
+ pp[i] = ReAlloc(pp[i], size);
+ for (j = old_size;j < size;j++)
+ {
+ InputToNull((void *)(UINT)(((UCHAR *)pp[i])[j] = j % 256));
+ }
+ }
+ for (i = 0;i < num;i++)
+ {
+ for (j = 0;j < size;j++)
+ {
+ if (((UCHAR *)pp[i])[j] != (j % 256))
+ {
+ ok = false;
+ }
+ }
+ Free(pp[i]);
+ }
+ Free(pp);
+
+ return ok;
+}
+
+// Function that do not do anything
+void InputToNull(void *p)
+{
+ if (RetZero() == 1)
+ {
+ UCHAR *c = (UCHAR *)p;
+ c[0] = 0x32;
+ }
+}
+
+// Function that returns 0
+UINT RetZero()
+{
+ if (g_debug == 0x123455)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+// Kernel check
+bool CheckKernel()
+{
+ UINT num = 10, i;
+ UINT64 s = Tick64();
+ UINT64 t = Tick64();
+
+ for (i = 0;i < num;i++)
+ {
+ UINT64 q = Tick64();
+ if (t > q)
+ {
+ Print("Tick64 #1 Failed.\n");
+ return false;
+ }
+
+ t = q;
+
+ SleepThread(100);
+ }
+
+ t = (Tick64() - s);
+ if (t <= 500 || t >= 2000)
+ {
+ Print("Tick64 #2 Failed.\n");
+ return false;
+ }
+ else if (false)
+ {
+ UINT64 tick1 = Tick64();
+ UINT64 time1;
+ UINT64 tick2, time2;
+
+ SleepThread(1000);
+
+ tick2 = Tick64();
+ time2 = LocalTime64();
+ time1 = SystemToLocal64(TickToTime(tick1));
+
+ if (time2 > time1)
+ {
+ s = time2 - time1;
+ }
+ else
+ {
+ s = time1 - time2;
+ }
+
+ if (s <= 500 || s >= 2000)
+ {
+ Print("TickToTime Failed.\n");
+ return false;
+ }
+ }
+
+#ifdef OS_UNIX
+ {
+ // Test of child process
+ UINT pid;
+ char exe[MAX_SIZE];
+
+ GetExeName(exe, sizeof(exe));
+
+ pid = fork();
+
+ if (pid == -1)
+ {
+ Print("fork Failed.\n");
+ return false;
+ }
+
+ if (pid == 0)
+ {
+ char *param = UNIX_ARG_EXIT;
+ char **args;
+
+ args = ZeroMalloc(sizeof(char *) * 3);
+ args[0] = exe;
+ args[1] = param;
+ args[2] = NULL;
+
+ setsid();
+
+ // Close the standard I/O
+ UnixCloseIO();
+
+ // Stop unwanted signals
+ signal(SIGHUP, SIG_IGN);
+
+ execvp(exe, args);
+ AbortExit();
+ }
+ else
+ {
+ int status = 0, ret;
+
+ // Wait for the termination of the child process
+ ret = waitpid(pid, &status, 0);
+
+ if (WIFEXITED(status) == 0)
+ {
+ // Aborted
+ Print("waitpid Failed: 0x%x\n", ret);
+ return false;
+ }
+ }
+ }
+#endif // OS_UNIX
+
+ return true;
+}
+
+// System checker
+bool SystemCheck()
+{
+ UINT i;
+ bool ng = false;
+
+ UniPrint(_UU("CHECK_TITLE"));
+ UniPrint(_UU("CHECK_NOTE"));
+ for (i = 0;i < sizeof(checker_procs) / sizeof(checker_procs[0]);i++)
+ {
+ wchar_t *title;
+ bool ret = false;
+ CHECKER_PROC *p = &checker_procs[i];
+
+ title = _UU(p->Title);
+
+ UniPrint(_UU("CHECK_EXEC_TAG"), title);
+
+ ret = p->Proc();
+
+ if (ret == false)
+ {
+ ng = true;
+ }
+
+ UniPrint(L" %s\n", ret ? _UU("CHECK_PASS") : _UU("CHECK_FAIL"));
+ }
+
+ UniPrint(L"\n");
+ if (ng == false)
+ {
+ UniPrint(L"%s\n\n", _UU("CHECK_RESULT_1"));
+ }
+ else
+ {
+ UniPrint(L"%s\n\n", _UU("CHECK_RESULT_2"));
+ }
+
+ return true;
+}
+
+
+// Behavior checker
+UINT PtCheck(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ UINT ret = ERR_NO_ERROR;
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (SystemCheck() == false)
+ {
+ ret = ERR_INTERNAL_ERROR;
+ }
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// VPN Tools main function
+void PtMain(PT *pt)
+{
+ char prompt[MAX_SIZE];
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (pt == NULL)
+ {
+ return;
+ }
+
+ // Display a message that start-up is complete
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_VPNCMD_TOOLS_CONNECTED"));
+ pt->Console->Write(pt->Console, tmp);
+ pt->Console->Write(pt->Console, L"");
+
+ while (true)
+ {
+ // Definition of command
+ CMD cmd[] =
+ {
+ {"About", PsAbout},
+ {"MakeCert", PtMakeCert},
+ {"TrafficClient", PtTrafficClient},
+ {"TrafficServer", PtTrafficServer},
+ {"Check", PtCheck},
+ };
+
+ // Generate a prompt
+ StrCpy(prompt, sizeof(prompt), "VPN Tools>");
+
+ if (DispatchNextCmdEx(pt->Console, pt->CmdLine, prompt, cmd, sizeof(cmd) / sizeof(cmd[0]), pt) == false)
+ {
+ break;
+ }
+ pt->LastError = pt->Console->RetCode;
+
+ if (pt->LastError == ERR_NO_ERROR && pt->Console->ConsoleType != CONSOLE_CSV)
+ {
+ pt->Console->Write(pt->Console, _UU("CMD_MSG_OK"));
+ pt->Console->Write(pt->Console, L"");
+ }
+
+ if (pt->CmdLine != NULL)
+ {
+ break;
+ }
+ }
+}
+
+// Create a VPN Tools context
+PT *NewPt(CONSOLE *c, wchar_t *cmdline)
+{
+ PT *pt;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ if (UniIsEmptyStr(cmdline))
+ {
+ cmdline = NULL;
+ }
+
+ pt = ZeroMalloc(sizeof(PT));
+ pt->Console = c;
+ pt->CmdLine = CopyUniStr(cmdline);
+
+ return pt;
+}
+
+// Release the VPN Tools context
+void FreePt(PT *pt)
+{
+ // Validate arguments
+ if (pt == NULL)
+ {
+ return;
+ }
+
+ Free(pt->CmdLine);
+ Free(pt);
+}
+
+// Start VPN Tools
+UINT PtConnect(CONSOLE *c, wchar_t *cmdline)
+{
+ PT *pt;
+ UINT ret = 0;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ pt = NewPt(c, cmdline);
+
+ PtMain(pt);
+
+ ret = pt->LastError;
+
+ FreePt(pt);
+
+ return ret;
+}
+
+// Initialize the execution path information of vpncmd command
+void VpnCmdInitBootPath()
+{
+#ifdef OS_WIN32
+ char exe_path[MAX_PATH];
+ char tmp[MAX_PATH];
+ GetExeName(exe_path, sizeof(exe_path));
+
+ if (SearchStrEx(exe_path, "ham.exe", 0, false) != INFINITE || SearchStrEx(exe_path, "ham_x64.exe", 0, false) != INFINITE || SearchStrEx(exe_path, "ham_ia64.exe", 0, false) != INFINITE)
+ {
+ return;
+ }
+
+ if (MsIsAdmin())
+ {
+ UINT current_ver;
+
+ // Get the version of vpncmd that is currently installed
+ current_ver = MsRegReadInt(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_VER);
+
+ if ((CEDAR_BUILD >= current_ver) ||
+ MsRegIsValue(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH) == false)
+ {
+ char *src_filename;
+ bool b = false;
+ // Copy the vpncmdsys.exe to system32
+ if (MsIsNt())
+ {
+ Format(tmp, sizeof(tmp), "%s\\vpncmd.exe", MsGetSystem32Dir());
+ }
+ else
+ {
+ Format(tmp, sizeof(tmp), "%s\\vpncmd.exe", MsGetWindowsDir());
+ }
+
+ src_filename = VPNCMD_BOOTSTRAP_FILENAME;
+
+ if (IsX64())
+ {
+ src_filename = VPNCMD_BOOTSTRAP_FILENAME_X64;
+ }
+
+ if (IsIA64())
+ {
+ src_filename = VPNCMD_BOOTSTRAP_FILENAME_IA64;
+ }
+
+ b = true;
+
+ if (MsIs64BitWindows() == false || Is64())
+ {
+ if (IsFile(tmp) == false || (CEDAR_BUILD > current_ver) || MsRegIsValue(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH) == false)
+ {
+ b = FileCopy(src_filename, tmp);
+ }
+ }
+ else
+ {
+ void *wow;
+
+ wow = MsDisableWow64FileSystemRedirection();
+
+ if (true)
+ {
+ if (IsFile(tmp) == false || (CEDAR_BUILD > current_ver) || MsRegIsValue(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH) == false)
+ {
+ b = FileCopy(src_filename, tmp);
+ }
+ }
+
+ MsRestoreWow64FileSystemRedirection(wow);
+
+ if (true)
+ {
+ if (IsFile(tmp) == false || (CEDAR_BUILD > current_ver) || MsRegIsValue(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH) == false)
+ {
+ b = FileCopy(src_filename, tmp);
+ }
+ }
+ }
+
+ // Because the currently running prompt is newer version, overwrite the registry
+ if (MsIs64BitWindows() == false)
+ {
+ MsRegWriteStr(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH, exe_path);
+ MsRegWriteInt(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_VER, CEDAR_BUILD);
+ }
+ else
+ {
+ MsRegWriteStrEx2(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH, exe_path, true, false);
+ MsRegWriteIntEx2(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_VER, CEDAR_BUILD, true, false);
+
+ MsRegWriteStrEx2(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH, exe_path, false, true);
+ MsRegWriteIntEx2(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_VER, CEDAR_BUILD, false, true);
+ }
+ }
+ }
+#endif // OS_WIN32
+}
+
+// Show the string
+void TtPrint(void *param, TT_PRINT_PROC *print_proc, wchar_t *str)
+{
+ // Validate arguments
+ if (print_proc == NULL || str == NULL)
+ {
+ return;
+ }
+
+ print_proc(param, str);
+}
+
+// Generate new random data
+void TtGenerateRandomData(UCHAR **buf, UINT *size)
+{
+ UCHAR *tmp;
+ UINT sz;
+ UINT i;
+ // Validate arguments
+ if (buf == NULL || size == NULL)
+ {
+ return;
+ }
+
+ sz = TRAFFIC_BUF_SIZE;
+ tmp = Malloc(sz);
+ for (i = 0;i < sz;i++)
+ {
+ tmp[i] = rand() % 256;
+
+ if (tmp[i] == '!')
+ {
+ tmp[i] = '_';
+ }
+ }
+
+ *buf = tmp;
+ *size = sz;
+}
+
+// Communication throughput measurement server worker thread
+void TtsWorkerThread(THREAD *thread, void *param)
+{
+ TTS *tts;
+ UINT buf_size;
+ UCHAR *send_buf_data, *recv_buf_data;
+ bool all_sockets_blocked = false;
+ UINT64 tmp64;
+ LIST *o;
+ UINT i;
+ wchar_t tmp[MAX_SIZE];
+ bool dont_block_next_time = false;
+ char *ver_str = TRAFFIC_VER_STR;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Allocate the data area
+ TtGenerateRandomData(&send_buf_data, &buf_size);
+ TtGenerateRandomData(&recv_buf_data, &buf_size);
+
+ tts = (TTS *)param;
+
+ // Preparation of socket events
+ tts->SockEvent = NewSockEvent();
+ AddRef(tts->SockEvent->ref);
+
+ // Preparing the Server socket list
+ tts->TtsSockList = NewList(NULL);
+
+ // Notify completion of preparation to parent thread
+ NoticeThreadInit(thread);
+
+ o = NewList(NULL);
+
+ while (tts->Halt == false)
+ {
+ UINT64 now = Tick64();
+
+ // Wait for all sockets
+ if (dont_block_next_time == false)
+ {
+ WaitSockEvent(tts->SockEvent, 50);
+ }
+ dont_block_next_time = false;
+
+ // Process for sockets that are currently registered
+ LockList(tts->TtsSockList);
+ {
+ UINT i;
+
+ all_sockets_blocked = false;
+
+ // Continue to send and receive data
+ // until all sockets become block state
+ while (all_sockets_blocked == false)
+ {
+ all_sockets_blocked = true;
+
+ for (i = 0;i < LIST_NUM(tts->TtsSockList);i++)
+ {
+ UINT ret = SOCK_LATER;
+ UCHAR *send_data = NULL, *recv_data = NULL;
+ UINT send_size = 0, recv_size = 0;
+ TTS_SOCK *ts = LIST_DATA(tts->TtsSockList, i);
+ bool blocked_for_this_socket = false;
+
+ if (ts->SockJoined == false)
+ {
+ JoinSockToSockEvent(ts->Sock, tts->SockEvent);
+ ts->SockJoined = true;
+ }
+
+ switch (ts->State)
+ {
+ case 0:
+ // Return the version string
+ ret = Send(ts->Sock, ver_str, TRAFFIC_VER_STR_SIZE, false);
+ if (ret != 0 && ret != SOCK_LATER)
+ {
+ ts->State = 5;
+ }
+ break;
+
+ case 5:
+ // Receive the direction from the client
+ ret = Recv(ts->Sock, recv_buf_data, buf_size, false);
+ if (ret != 0 && ret != SOCK_LATER)
+ {
+ UCHAR c;
+
+ // Direction of the data is in the first byte that is received
+ c = recv_buf_data[0];
+
+ if (c == 0)
+ {
+ // In the case of 0, Client -> Server
+ ts->State = 1;
+ }
+ else
+ {
+ // Otherwise Server -> Client
+ ts->State = 2;
+ }
+
+ if (ret >= (sizeof(UINT64) + sizeof(UINT64) + 1))
+ {
+ // Session ID
+ ts->SessionId = READ_UINT64(recv_buf_data + 1);
+
+ // Span
+ ts->Span = READ_UINT64(recv_buf_data + sizeof(UINT64) + 1);
+ }
+ }
+ break;
+
+ case 1:
+ // Client -> Server
+ ret = Recv(ts->Sock, recv_buf_data, buf_size, false);
+
+ if (ret != 0 && ret != SOCK_LATER)
+ {
+ // Checking the first byte of received
+ UCHAR c = recv_buf_data[0];
+
+ if (ts->FirstRecvTick == 0)
+ {
+ // Record the time at which the data has been received for the first
+ ts->FirstRecvTick = now;
+ }
+ else
+ {
+ // Check whether the span didn't finish yet
+ if (ts->FirstRecvTick <= now)
+ {
+ if (ts->Span != 0)
+ {
+ UINT64 giveup_tick = ts->FirstRecvTick + ts->Span;
+
+ if (now > giveup_tick)
+ {
+ // Span has expired
+ c = '!';
+ }
+ }
+ }
+ }
+
+ if (c == '!')
+ {
+ // Notice the size information from the server to the client
+ ts->State = 3;
+ Debug("!");
+ }
+ }
+ break;
+
+ case 2:
+ // Server -> Client
+ if (ts->NoMoreSendData == false)
+ {
+ ret = Send(ts->Sock, send_buf_data, buf_size, false);
+ }
+ else
+ {
+ ret = Recv(ts->Sock, recv_buf_data, buf_size, false);
+ }
+ break;
+
+ case 3:
+ // Notice the size information from the server to the client
+ tmp64 = Endian64(ts->NumBytes);
+
+ Recv(ts->Sock, recv_buf_data, buf_size, false);
+
+ if (ts->LastWaitTick == 0 || ts->LastWaitTick <= Tick64())
+ {
+ ret = Send(ts->Sock, &tmp64, sizeof(tmp64), false);
+
+ if (ret != SOCK_LATER)
+ {
+ UINT j;
+
+ ts->LastWaitTick = Tick64() + 100;
+
+ if (ts->SessionId != 0)
+ {
+ // Not to send more data to the socket of the
+ // transmission direction in the same session ID
+ for (j = 0;j < LIST_NUM(tts->TtsSockList);j++)
+ {
+ TTS_SOCK *ts2 = LIST_DATA(tts->TtsSockList, j);
+
+ if (ts2->SessionId == ts->SessionId &&
+ ts2 != ts)
+ {
+ ts2->NoMoreSendData = true;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ if (ret == 0)
+ {
+ // Mark as deleting the socket because it is disconnected
+ Insert(o, ts);
+ }
+ else if (ret == SOCK_LATER)
+ {
+ // Delay has occurred
+ blocked_for_this_socket = true;
+ dont_block_next_time = false;
+ }
+ else
+ {
+ if (ts->State == 1)
+ {
+ ts->NumBytes += (UINT64)ret;
+ }
+ }
+
+ if (blocked_for_this_socket == false)
+ {
+ all_sockets_blocked = false;
+ }
+ }
+
+ if (LIST_NUM(o) != 0)
+ {
+ UINT i;
+ // One or more sockets is disconnected
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ TTS_SOCK *ts = LIST_DATA(o, i);
+
+ UniFormat(tmp, sizeof(tmp), _UU("TTS_DISCONNECTED"), ts->Id, ts->Sock->RemoteHostname);
+ TtPrint(tts->Param, tts->Print, tmp);
+
+ Disconnect(ts->Sock);
+ ReleaseSock(ts->Sock);
+
+ Delete(tts->TtsSockList, ts);
+
+ Free(ts);
+ }
+
+ DeleteAll(o);
+ }
+
+ if (tts->NewSocketArrived || tts->Halt)
+ {
+ tts->NewSocketArrived = false;
+ all_sockets_blocked = true;
+ dont_block_next_time = true;
+ }
+ }
+ }
+ UnlockList(tts->TtsSockList);
+ }
+
+ LockList(tts->TtsSockList);
+ {
+ // Release the sockets of all remaining
+ for (i = 0;i < LIST_NUM(tts->TtsSockList);i++)
+ {
+ TTS_SOCK *ts = LIST_DATA(tts->TtsSockList, i);
+
+ UniFormat(tmp, sizeof(tmp), _UU("TTS_DISCONNECT"), ts->Id, ts->Sock->RemoteHostname);
+ TtPrint(tts->Param, tts->Print, tmp);
+
+ Disconnect(ts->Sock);
+ ReleaseSock(ts->Sock);
+
+ Free(ts);
+ }
+ }
+ UnlockList(tts->TtsSockList);
+
+ // Cleanup
+ ReleaseList(o);
+ ReleaseList(tts->TtsSockList);
+ ReleaseSockEvent(tts->SockEvent);
+ Free(send_buf_data);
+ Free(recv_buf_data);
+}
+
+// Accept thread for IPv6
+void TtsIPv6AcceptThread(THREAD *thread, void *param)
+{
+ TTS *tts = (TTS *)param;
+ // Validate arguments
+ if (tts == NULL || param == NULL)
+ {
+ return;
+ }
+
+ TtsAcceptProc(tts, tts->ListenSocketV6);
+}
+
+// Accept procedure
+void TtsAcceptProc(TTS *tts, SOCK *listen_socket)
+{
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (tts == NULL || listen_socket == NULL)
+ {
+ return;
+ }
+
+ while (tts->Halt == false)
+ {
+ SOCK *s;
+ // Accept
+ s = Accept(listen_socket);
+
+ if (s == NULL)
+ {
+ if (tts->Halt == false)
+ {
+ SleepThread(10);
+ }
+ continue;
+ }
+ else
+ {
+ // Connected from the client
+ AcceptInit(s);
+ tts->NewSocketArrived = true;
+ LockList(tts->TtsSockList);
+ {
+ TTS_SOCK *ts = ZeroMalloc(sizeof(TTS_SOCK));
+
+ ts->Id = (++tts->IdSeed);
+ ts->Sock = s;
+
+ UniFormat(tmp, sizeof(tmp), _UU("TTS_ACCEPTED"), ts->Id,
+ s->RemoteHostname, s->RemotePort);
+ TtPrint(tts->Param, tts->Print, tmp);
+
+ Insert(tts->TtsSockList, ts);
+ tts->NewSocketArrived = true;
+ }
+ UnlockList(tts->TtsSockList);
+
+ SetSockEvent(tts->SockEvent);
+ }
+ }
+}
+
+// Communication throughput measurement server wait thread
+void TtsListenThread(THREAD *thread, void *param)
+{
+ TTS *tts;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ tts = (TTS *)param;
+
+ tts->ListenSocket = NULL;
+ tts->ListenSocket = ListenEx(tts->Port, false);
+ tts->ListenSocketV6 = ListenEx6(tts->Port, false);
+
+ if (tts->ListenSocket == NULL && tts->ListenSocketV6 == NULL)
+ {
+ // Failed to Listen
+ UniFormat(tmp, sizeof(tmp), _UU("TT_LISTEN_FAILED"), tts->Port);
+ TtPrint(tts->Param, tts->Print, tmp);
+
+ // Notify completion of preparation to parent thread
+ NoticeThreadInit(thread);
+
+ tts->ErrorCode = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("TTS_LISTEN_STARTED"), tts->Port);
+ TtPrint(tts->Param, tts->Print, tmp);
+
+ if (tts->ListenSocketV6 != NULL)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("TTS_LISTEN_STARTED_V6"), tts->Port);
+ TtPrint(tts->Param, tts->Print, tmp);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("TTS_LISTEN_FAILED_V6"), tts->Port);
+ TtPrint(tts->Param, tts->Print, tmp);
+ }
+
+ if (tts->ListenSocket != NULL)
+ {
+ AddRef(tts->ListenSocket->ref);
+ }
+ if (tts->ListenSocketV6 != NULL)
+ {
+ AddRef(tts->ListenSocketV6->ref);
+ }
+
+ // Start the worker thread
+ tts->WorkThread = NewThread(TtsWorkerThread, tts);
+ WaitThreadInit(tts->WorkThread);
+
+ // Notify completion of preparation to parent thread
+ NoticeThreadInit(thread);
+
+ // Prepare for IPv6 Accept thread
+ tts->IPv6AcceptThread = NULL;
+ if (tts->ListenSocketV6 != NULL)
+ {
+ tts->IPv6AcceptThread = NewThread(TtsIPv6AcceptThread, tts);
+ }
+
+ TtsAcceptProc(tts, tts->ListenSocket);
+
+ if (tts->IPv6AcceptThread != NULL)
+ {
+ WaitThread(tts->IPv6AcceptThread, INFINITE);
+ ReleaseThread(tts->IPv6AcceptThread);
+ }
+
+ TtPrint(tts->Param, tts->Print, _UU("TTS_LISTEN_STOP"));
+
+ ReleaseSock(tts->ListenSocket);
+ ReleaseSock(tts->ListenSocketV6);
+ SetSockEvent(tts->SockEvent);
+
+ // Wait for stopping the worker thread
+ WaitThread(tts->WorkThread, INFINITE);
+ ReleaseThread(tts->WorkThread);
+ ReleaseSockEvent(tts->SockEvent);
+ }
+}
+
+// String of the direction in which data flows
+wchar_t *GetTtcTypeStr(UINT type)
+{
+ switch (type)
+ {
+ case TRAFFIC_TYPE_DOWNLOAD:
+ return _UU("TTC_TYPE_DOWNLOAD");
+
+ case TRAFFIC_TYPE_UPLOAD:
+ return _UU("TTC_TYPE_UPLOAD");
+
+ default:
+ return _UU("TTC_TYPE_FULL");
+ }
+}
+
+// Show a Summary
+void TtcPrintSummary(TTC *ttc)
+{
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t *tag = L"%-35s %s";
+ // Validate arguments
+ if (ttc == NULL)
+ {
+ return;
+ }
+
+ TtPrint(ttc->Param, ttc->Print, L"");
+ TtPrint(ttc->Param, ttc->Print, _UU("TTC_SUMMARY_BAR"));
+ TtPrint(ttc->Param, ttc->Print, _UU("TTC_SUMMARY_TITLE"));
+ TtPrint(ttc->Param, ttc->Print, L"");
+
+ // Destination host name
+ StrToUni(tmp2, sizeof(tmp2), ttc->Host);
+ UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_HOST"), tmp2);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ // Destination TCP port number
+ UniToStru(tmp2, ttc->Port);
+ UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_PORT"), tmp2);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ // Number of TCP connections to establish
+ UniToStru(tmp2, ttc->NumTcp);
+ UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_NUMTCP"), tmp2);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ // Data transmission direction
+ UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_TYPE"), GetTtcTypeStr(ttc->Type));
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ // Data transmission span
+ UniFormat(tmp2, sizeof(tmp2), _UU("TTC_SPAN_STR"), (double)(ttc->Span) / 1000.0);
+ UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_SPAN"), tmp2);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ // Correct the data for Ethernet frame
+ UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_ETHER"), ttc->Raw ? _UU("SEC_NO") : _UU("SEC_YES"));
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ // Measure the total amount of input and output throughput of relay equipment
+ UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_DOUBLE"), ttc->Double ? _UU("SEC_YES") : _UU("SEC_NO"));
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ TtPrint(ttc->Param, ttc->Print, _UU("TTC_SUMMARY_BAR"));
+ TtPrint(ttc->Param, ttc->Print, L"");
+}
+
+// Stop the communication throughput measurement client
+void StopTtc(TTC *ttc)
+{
+ // Validate arguments
+ if (ttc == NULL)
+ {
+ return;
+ }
+
+ TtPrint(ttc->Param, ttc->Print, _UU("TTC_STOPPING"));
+
+ ttc->Halt = true;
+ SetSockEvent(ttc->SockEvent);
+}
+
+// Generate a result
+void TtcGenerateResult(TTC *ttc)
+{
+ TT_RESULT *res;
+ UINT i;
+ // Validate arguments
+ if (ttc == NULL)
+ {
+ return;
+ }
+
+ res = &ttc->Result;
+
+ Zero(res, sizeof(TT_RESULT));
+
+ res->Raw = ttc->Raw;
+ res->Double = ttc->Double;
+ res->Span = ttc->RealSpan;
+
+ for (i = 0;i < LIST_NUM(ttc->ItcSockList);i++)
+ {
+ TTC_SOCK *ts = LIST_DATA(ttc->ItcSockList, i);
+
+ if (ts->Download == false)
+ {
+ // Upload
+ res->NumBytesUpload += ts->NumBytes;
+ }
+ else
+ {
+ // Download
+ res->NumBytesDownload += ts->NumBytes;
+ }
+ }
+
+ if (res->Raw == false)
+ {
+ // Correct to match the Ethernet
+ res->NumBytesDownload = (UINT64)((double)res->NumBytesDownload * 1514.0 / 1460.0);
+ res->NumBytesUpload = (UINT64)((double)res->NumBytesUpload * 1514.0 / 1460.0);
+ }
+
+ res->NumBytesTotal = res->NumBytesDownload + res->NumBytesUpload;
+
+ // Measure the throughput
+ if (res->Span != 0)
+ {
+ res->BpsUpload = (UINT64)((double)res->NumBytesUpload * 8.0 / ((double)res->Span / 1000.0));
+ res->BpsDownload = (UINT64)((double)res->NumBytesDownload * 8.0 / ((double)res->Span / 1000.0));
+ }
+
+ if (res->Double)
+ {
+ res->BpsUpload *= 2ULL;
+ res->BpsDownload *= 2ULL;
+ }
+
+ res->BpsTotal = res->BpsUpload + res->BpsDownload;
+}
+
+// Client thread
+void TtcThread(THREAD *thread, void *param)
+{
+ TTC *ttc;
+ UINT i;
+ wchar_t tmp[MAX_SIZE];
+ bool ok = false;
+ UINT buf_size;
+ UCHAR *send_buf_data, *recv_buf_data;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Allocate the data area
+ TtGenerateRandomData(&send_buf_data, &buf_size);
+ TtGenerateRandomData(&recv_buf_data, &buf_size);
+
+ ttc = (TTC *)param;
+
+ ttc->SockEvent = NewSockEvent();
+ AddRef(ttc->SockEvent->ref);
+
+ // Ready
+ NoticeThreadInit(thread);
+
+ TtcPrintSummary(ttc);
+
+ UniFormat(tmp, sizeof(tmp), _UU("TTC_CONNECT_START"),
+ ttc->Host, ttc->Port, ttc->NumTcp);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ // Establish all connections to the client
+ ttc->ItcSockList = NewList(NULL);
+
+ ok = true;
+
+ for (i = 0;i < ttc->NumTcp;i++)
+ {
+ SOCK *s;
+ TTC_SOCK *ts = ZeroMalloc(sizeof(TTC_SOCK));
+
+ ts->Id = i + 1;
+
+ if (ttc->Type == TRAFFIC_TYPE_DOWNLOAD)
+ {
+ ts->Download = true;
+ }
+ else if (ttc->Type == TRAFFIC_TYPE_UPLOAD)
+ {
+ ts->Download = false;
+ }
+ else
+ {
+ ts->Download = ((i % 2) == 0) ? true : false;
+ }
+
+ s = ConnectEx2(ttc->Host, ttc->Port, 0, ttc->Cancel);
+
+ if (s == NULL)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("TTC_CONNECT_FAILED"), i + 1);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+ ok = false;
+ Free(ts);
+ break;
+ }
+ else
+ {
+ char buffer[TRAFFIC_VER_STR_SIZE];
+
+ SetTimeout(s, 5000);
+
+ Zero(buffer, sizeof(buffer));
+ if (Recv(s, buffer, sizeof(buffer), false) != sizeof(buffer) || Cmp(buffer, TRAFFIC_VER_STR, TRAFFIC_VER_STR_SIZE) != 0)
+ {
+ TtPrint(ttc->Param, ttc->Print, _UU("TTC_CONNECT_NOT_SERVER"));
+ ok = false;
+ ReleaseSock(s);
+ Free(ts);
+ break;
+ }
+
+ UniFormat(tmp, sizeof(tmp), _UU("TTC_CONNECT_OK"), i + 1);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("TTC_CONNECT_OK_2"), GetTtcTypeStr(ts->Download ? TRAFFIC_TYPE_DOWNLOAD : TRAFFIC_TYPE_UPLOAD));
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ ts->Sock = s;
+
+ SetTimeout(s, TIMEOUT_INFINITE);
+
+ JoinSockToSockEvent(s, ttc->SockEvent);
+ }
+
+ Insert(ttc->ItcSockList, ts);
+ }
+
+ Set(ttc->InitedEvent);
+
+ if (ttc->StartEvent != NULL)
+ {
+ Wait(ttc->StartEvent, INFINITE);
+ SleepThread(500);
+ }
+
+ if (ok)
+ {
+ bool all_sockets_blocked;
+ bool dont_block_next_time = false;
+ bool halt_flag = false;
+ UINT64 start_tick, end_tick;
+ UINT64 halt_timeout = 0;
+ wchar_t tmp1[MAX_SIZE], tmp2[MAX_SIZE];
+ UINT check_clock_seed = 0;
+ bool halting = false;
+ UINT64 tmp64;
+ UINT64 session_id = Rand64();
+
+ // Record the current time
+ start_tick = Tick64();
+ end_tick = start_tick + ttc->Span;
+
+ // Show start message
+ GetDateTimeStrEx64(tmp1, sizeof(tmp1), SystemToLocal64(TickToTime(start_tick)), NULL);
+ GetDateTimeStrEx64(tmp2, sizeof(tmp2), SystemToLocal64(TickToTime(end_tick)), NULL);
+ UniFormat(tmp, sizeof(tmp), _UU("TTC_COMM_START"), tmp1, tmp2);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ // Main loop
+ while (true)
+ {
+ UINT i;
+
+ if (dont_block_next_time == false)
+ {
+ WaitSockEvent(ttc->SockEvent, 50);
+ }
+
+ dont_block_next_time = false;
+
+ if (ttc->AbnormalTerminated)
+ {
+ // Abnormal termination occured
+ break;
+ }
+
+ if (ttc->Halt || end_tick <= Tick64() || (ttc->Cancel != NULL && (*ttc->Cancel)))
+ {
+ // End measurement
+ if (halting == false)
+ {
+ if (ttc->Halt || (ttc->Cancel != NULL && (*ttc->Cancel)))
+ {
+ // User cancel
+ TtPrint(ttc->Param, ttc->Print, _UU("TTC_COMM_USER_CANCEL"));
+ }
+ else
+ {
+ // Time elapsed
+ UniFormat(tmp, sizeof(tmp), _UU("TTC_COMM_END"),
+ (double)ttc->Span / 1000.0);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+ }
+
+ ttc->RealSpan = Tick64() - start_tick;
+
+ halting = true;
+
+ // Wait for reporting data from the server
+ halt_timeout = Tick64() + 60000ULL;
+ }
+ }
+
+ if (halt_timeout != 0)
+ {
+ bool ok = true;
+
+ // Wait that all TCP connections to finish processing
+ for (i = 0;i < LIST_NUM(ttc->ItcSockList);i++)
+ {
+ TTC_SOCK *ts = LIST_DATA(ttc->ItcSockList, i);
+
+ if (ts->Download == false)
+ {
+ if (ts->ServerUploadReportReceived == false)
+ {
+ ok = false;
+ }
+ }
+ }
+
+ if (ok)
+ {
+ // Measurement completed
+ // Show the result
+ TtcGenerateResult(ttc);
+ break;
+ }
+ else
+ {
+ if (halt_timeout <= Tick64())
+ {
+ // An error occured
+ ttc->AbnormalTerminated = true;
+ ttc->ErrorCode = ERR_PROTOCOL_ERROR;
+ break;
+ }
+ }
+ }
+
+ all_sockets_blocked = false;
+
+ // Continue to send and receive data
+ // until all sockets become block state
+ while (all_sockets_blocked == false)
+ {
+ all_sockets_blocked = true;
+
+ for (i = 0;i < LIST_NUM(ttc->ItcSockList);i++)
+ {
+ UINT ret = SOCK_LATER;
+ TTC_SOCK *ts = LIST_DATA(ttc->ItcSockList, i);
+ bool blocked_for_this_socket = false;
+ UCHAR c = 0;
+ UCHAR c_and_session_id[1 + sizeof(UINT64) + sizeof(UINT64)];
+
+ if (halt_timeout != 0)
+ {
+ if (ts->State != 3 && ts->State != 4)
+ {
+ if (ts->Download == false)
+ {
+ if (ts->State != 0)
+ {
+ ts->State = 3;
+ }
+ else
+ {
+ ts->ServerUploadReportReceived = true;
+ ts->State = 4;
+ }
+ }
+ else
+ {
+ ts->State = 4;
+ }
+ }
+ }
+
+ switch (ts->State)
+ {
+ case 0:
+ // Initial state: Specify the direction of
+ // the data flow between client-server
+ if (ts->Download)
+ {
+ c = 1;
+ }
+ else
+ {
+ c = 0;
+ }
+
+ c_and_session_id[0] = c;
+ WRITE_UINT64(c_and_session_id + 1, session_id);
+ WRITE_UINT64(c_and_session_id + sizeof(UINT64) + 1, ttc->Span);
+
+ ret = Send(ts->Sock, c_and_session_id, 1 + sizeof(UINT64) + sizeof(UINT64), false);
+
+ if (ret != 0 && ret != SOCK_LATER)
+ {
+ if (ts->Download)
+ {
+ ts->State = 1;
+ }
+ else
+ {
+ ts->State = 2;
+ }
+ }
+ break;
+
+ case 1:
+ // Server -> Client (download)
+ ret = Recv(ts->Sock, recv_buf_data, buf_size, false);
+ break;
+
+ case 2:
+ // Client -> Server (upload)
+ ret = Send(ts->Sock, send_buf_data, buf_size, false);
+ break;
+
+ case 3:
+ // Transmission completion client -> server (upload)
+ // Request the data size
+ if (ts->NextSendRequestReportTick == 0 ||
+ (Tick64() >= ts->NextSendRequestReportTick))
+ {
+ UCHAR suprise[MAX_SIZE];
+ UINT i;
+
+ ts->NextSendRequestReportTick = Tick64() + 200ULL;
+
+ for (i = 0;i < sizeof(suprise);i++)
+ {
+ suprise[i] = '!';
+ }
+
+ ret = Send(ts->Sock, suprise, sizeof(suprise), false);
+ }
+
+ ret = Recv(ts->Sock, &tmp64, sizeof(tmp64), false);
+ if (ret != 0 && ret != SOCK_LATER && ret == sizeof(tmp64))
+ {
+ ts->NumBytes = Endian64(tmp64);
+
+ ts->ServerUploadReportReceived = true;
+
+ ts->State = 4;
+ }
+ break;
+
+ case 4:
+ // Do Nothing
+ if (Recv(ts->Sock, recv_buf_data, buf_size, false) == SOCK_LATER)
+ {
+ ret = SOCK_LATER;
+ }
+ break;
+ }
+
+ if (ret == 0)
+ {
+ // The socket is disconnected
+ ttc->AbnormalTerminated = true;
+ ttc->ErrorCode = ERR_PROTOCOL_ERROR;
+ blocked_for_this_socket = true;
+ dont_block_next_time = false;
+
+ if (ts->HideErrMsg == false)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("TTC_COMM_DISCONNECTED"), ts->Id);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+ ts->HideErrMsg = true;
+ }
+ }
+ else if (ret == SOCK_LATER)
+ {
+ // Delay has occurred
+ blocked_for_this_socket = true;
+ dont_block_next_time = false;
+ }
+ else
+ {
+ if (ts->Download)
+ {
+ ts->NumBytes += (UINT64)ret;
+ }
+ }
+
+ if (blocked_for_this_socket == false)
+ {
+ all_sockets_blocked = false;
+ }
+ }
+
+ if (ttc->Halt || (ttc->Cancel != NULL && (*ttc->Cancel)))
+ {
+ all_sockets_blocked = true;
+ dont_block_next_time = true;
+ }
+
+ if (end_tick <= Tick64())
+ {
+ all_sockets_blocked = true;
+ dont_block_next_time = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Abort
+ TtPrint(ttc->Param, ttc->Print, _UU("TTC_ERROR_ABORTED"));
+ ttc->ErrorCode = ERR_CONNECT_FAILED;
+ }
+
+ // Cleanup
+ for (i = 0;i < LIST_NUM(ttc->ItcSockList);i++)
+ {
+ TTC_SOCK *ts = LIST_DATA(ttc->ItcSockList, i);
+
+ Disconnect(ts->Sock);
+ ReleaseSock(ts->Sock);
+ Free(ts);
+ }
+
+ ReleaseSockEvent(ttc->SockEvent);
+ ReleaseList(ttc->ItcSockList);
+ Free(send_buf_data);
+ Free(recv_buf_data);
+}
+
+// Start the communication throughput measurement client
+TTC *NewTtc(char *host, UINT port, UINT numtcp, UINT type, UINT64 span, bool dbl, bool raw, TT_PRINT_PROC *print_proc, void *param)
+{
+ return NewTtcEx(host, port, numtcp, type, span, dbl, raw, print_proc, param, NULL, NULL);
+}
+TTC *NewTtcEx(char *host, UINT port, UINT numtcp, UINT type, UINT64 span, bool dbl, bool raw, TT_PRINT_PROC *print_proc, void *param, EVENT *start_event, bool *cancel)
+{
+ TTC *ttc;
+
+ ttc = ZeroMalloc(sizeof(TTC));
+ ttc->InitedEvent = NewEvent();
+ ttc->Port = port;
+ StrCpy(ttc->Host, sizeof(ttc->Host), host);
+ ttc->NumTcp = numtcp;
+ ttc->Type = type;
+ ttc->Span = span;
+ ttc->Double = dbl;
+ ttc->Raw = raw;
+ ttc->StartEvent = start_event;
+ ttc->Cancel = cancel;
+
+ if (ttc->Type == TRAFFIC_TYPE_FULL && ttc->NumTcp < 2)
+ {
+ ttc->NumTcp = 2;
+ }
+
+ ttc->Print = print_proc;
+ ttc->Param = param;
+ ttc->ErrorCode = ERR_NO_ERROR;
+
+ TtPrint(ttc->Param, ttc->Print, _UU("TTC_INIT"));
+
+ ttc->Thread = NewThread(TtcThread, ttc);
+ WaitThreadInit(ttc->Thread);
+
+ return ttc;
+}
+
+// Wait for stopping the communication throughput measurement client
+UINT FreeTtc(TTC *ttc, TT_RESULT *result)
+{
+ UINT ret;
+ // Validate arguments
+ if (ttc == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ WaitThread(ttc->Thread, INFINITE);
+ ReleaseThread(ttc->Thread);
+
+ TtPrint(ttc->Param, ttc->Print, _UU("TTC_FREE"));
+
+ ret = ttc->ErrorCode;
+
+ if (ret == ERR_NO_ERROR)
+ {
+ if (result != NULL)
+ {
+ Copy(result, &ttc->Result, sizeof(TT_RESULT));
+ }
+ }
+
+ ReleaseSockEvent(ttc->SockEvent);
+ ReleaseEvent(ttc->InitedEvent);
+
+ Free(ttc);
+
+ return ret;
+}
+
+// Start the communication throughput measurement server
+TTS *NewTts(UINT port, void *param, TT_PRINT_PROC *print_proc)
+{
+ TTS *tts;
+ THREAD *t;
+
+ tts = ZeroMalloc(sizeof(TTS));
+ tts->Port = port;
+ tts->Param = param;
+ tts->Print = print_proc;
+
+ TtPrint(param, print_proc, _UU("TTS_INIT"));
+
+ // Creating a thread
+ t = NewThread(TtsListenThread, tts);
+ WaitThreadInit(t);
+
+ tts->Thread = t;
+
+ return tts;
+}
+
+// Wait for stopping the communication throughput measurement server
+UINT FreeTts(TTS *tts)
+{
+ UINT ret;
+ // Validate arguments
+ if (tts == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ TtPrint(tts->Param, tts->Print, _UU("TTS_STOP_INIT"));
+
+ tts->Halt = true;
+ Disconnect(tts->ListenSocket);
+ ReleaseSock(tts->ListenSocket);
+ Disconnect(tts->ListenSocketV6);
+ ReleaseSock(tts->ListenSocketV6);
+
+ // Wait for the termination of the thread
+ WaitThread(tts->Thread, INFINITE);
+
+ ReleaseThread(tts->Thread);
+
+ TtPrint(tts->Param, tts->Print, _UU("TTS_STOP_FINISHED"));
+
+ ret = tts->ErrorCode;
+
+ Free(tts);
+
+ return ret;
+}
+
+// Show the measurement tools prompt
+void PtTrafficPrintProc(void *param, wchar_t *str)
+{
+ CONSOLE *c;
+ // Validate arguments
+ if (param == NULL || str == NULL)
+ {
+ return;
+ }
+
+ c = (CONSOLE *)param;
+
+ if (c->ConsoleType == CONSOLE_LOCAL)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ // Display only if the local console
+ // (Can not be displayed because threads aren't synchronized otherwise?)
+ UniStrCpy(tmp, sizeof(tmp), str);
+ if (UniEndWith(str, L"\n") == false)
+ {
+ UniStrCat(tmp, sizeof(tmp), L"\n");
+ }
+ UniPrint(L"%s", tmp);
+ }
+}
+
+// Display the communication throughput results
+void TtcPrintResult(CONSOLE *c, TT_RESULT *res)
+{
+ CT *ct;
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ char str[MAX_SIZE];
+ // Validate arguments
+ if (c == NULL || res == NULL)
+ {
+ return;
+ }
+
+ c->Write(c, _UU("TTC_RES_TITLE"));
+
+ ct = CtNew();
+ CtInsertColumn(ct, _UU("TTC_RES_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("TTC_RES_COLUMN_2"), true);
+ CtInsertColumn(ct, _UU("TTC_RES_COLUMN_3"), true);
+
+ // Time that was used to measure
+ GetSpanStrMilli(str, sizeof(str), res->Span);
+ StrToUni(tmp, sizeof(tmp), str);
+ CtInsert(ct, _UU("TTC_RES_SPAN"), tmp, L"");
+
+ // Correct the data for Ethernet frame
+ CtInsert(ct, _UU("TTC_RES_ETHER"), res->Raw ? _UU("SEC_NO") : _UU("SEC_YES"), L"");
+
+ // Amount of communication data of download direction
+ ToStr3(str, sizeof(str), res->NumBytesDownload);
+ UniFormat(tmp1, sizeof(tmp1), L"%S Bytes", str);
+ ToStrByte1000(str, sizeof(str), res->NumBytesDownload);
+ StrToUni(tmp2, sizeof(tmp2), str);
+ CtInsert(ct, _UU("TTC_RES_BYTES_DOWNLOAD"), tmp1, tmp2);
+
+ // Amount of communication data of upload direction
+ ToStr3(str, sizeof(str), res->NumBytesUpload);
+ UniFormat(tmp1, sizeof(tmp1), L"%S Bytes", str);
+ ToStrByte1000(str, sizeof(str), res->NumBytesUpload);
+ StrToUni(tmp2, sizeof(tmp2), str);
+ CtInsert(ct, _UU("TTC_RES_BYTES_UPLOAD"), tmp1, tmp2);
+
+ // Total amount of communication data
+ ToStr3(str, sizeof(str), res->NumBytesTotal);
+ UniFormat(tmp1, sizeof(tmp1), L"%S Bytes", str);
+ ToStrByte1000(str, sizeof(str), res->NumBytesTotal);
+ StrToUni(tmp2, sizeof(tmp2), str);
+ CtInsert(ct, _UU("TTC_RES_BYTES_TOTAL"), tmp1, tmp2);
+
+ // Calculate the total throughput of input and output of the relay equipment
+ CtInsert(ct, _UU("TTC_RES_DOUBLE"), (res->Double == false) ? _UU("SEC_NO") : _UU("SEC_YES"), L"");
+
+ // Average throughput of download direction
+ ToStr3(str, sizeof(str), res->BpsDownload);
+ UniFormat(tmp1, sizeof(tmp1), L"%S bps", str);
+ ToStrByte1000(str, sizeof(str), res->BpsDownload);
+ ReplaceStr(str, sizeof(str), str, "Bytes", "bps");
+ StrToUni(tmp2, sizeof(tmp2), str);
+ CtInsert(ct, _UU("TTC_RES_BPS_DOWNLOAD"), tmp1, tmp2);
+
+ // Average throughput of upload direction
+ ToStr3(str, sizeof(str), res->BpsUpload);
+ UniFormat(tmp1, sizeof(tmp1), L"%S bps", str);
+ ToStrByte1000(str, sizeof(str), res->BpsUpload);
+ ReplaceStr(str, sizeof(str), str, "Bytes", "bps");
+ StrToUni(tmp2, sizeof(tmp2), str);
+ CtInsert(ct, _UU("TTC_RES_BPS_UPLOAD"), tmp1, tmp2);
+
+ // Total average throughput
+ ToStr3(str, sizeof(str), res->BpsTotal);
+ UniFormat(tmp1, sizeof(tmp1), L"%S bps", str);
+ ToStrByte1000(str, sizeof(str), res->BpsTotal);
+ ReplaceStr(str, sizeof(str), str, "Bytes", "bps");
+ StrToUni(tmp2, sizeof(tmp2), str);
+ CtInsert(ct, _UU("TTC_RES_BPS_TOTAL"), tmp1, tmp2);
+
+ CtFree(ct, c);
+}
+
+// Execute the communication throughput measurement tool server
+UINT PtTrafficServer(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ UINT ret = ERR_NO_ERROR;
+ UINT port;
+ TTS *tts;
+ PARAM args[] =
+ {
+ {"[port]", NULL, NULL, NULL, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ port = GetParamInt(o, "[port]");
+ if (port == 0)
+ {
+ port = TRAFFIC_DEFAULT_PORT;
+ }
+
+ tts = NewTts(port, c, PtTrafficPrintProc);
+
+ c->Write(c, _UU("TTS_ENTER_TO_EXIT"));
+
+ Free(c->ReadLine(c, L"", true));
+
+ ret = tts->ErrorCode;
+
+ FreeTts(tts);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Execute the communication throughput measurement tool client
+UINT PtTrafficClient(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ TTC *ttc;
+ LIST *o;
+ UINT ret = ERR_NO_ERROR;
+ char *host = NULL;
+ UINT port;
+ UINT num, type;
+ bool dbl = false, raw = false;
+ UINT64 span;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX minmax =
+ {
+ "CMD_TrafficClient_EVAL_NUMTCP",
+ 0, TRAFFIC_NUMTCP_MAX,
+ };
+ PARAM args[] =
+ {
+ {"[host:port]", CmdPrompt, _UU("CMD_TrafficClient_PROMPT_HOST"), CmdEvalNotEmpty, NULL},
+ {"NUMTCP", NULL, NULL, CmdEvalMinMax, &minmax},
+ {"TYPE", NULL, NULL, NULL, NULL},
+ {"SPAN", NULL, NULL, NULL, NULL},
+ {"DOUBLE", NULL, NULL, NULL, NULL},
+ {"RAW", NULL, NULL, NULL, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (ParseHostPort(GetParamStr(o, "[host:port]"), &host, &port, TRAFFIC_DEFAULT_PORT) == false)
+ {
+ c->Write(c, _UU("CMD_TrafficClient_ERROR_HOSTPORT"));
+ ret = ERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ char *s;
+ UINT i;
+
+ Trim(host);
+
+ num = GetParamInt(o, "NUMTCP");
+ if (num == 0)
+ {
+ num = TRAFFIC_NUMTCP_DEFAULT;
+ }
+ s = GetParamStr(o, "TYPE");
+
+ if (StartWith("download", s))
+ {
+ type = TRAFFIC_TYPE_DOWNLOAD;
+ }
+ else if (StartWith("upload", s))
+ {
+ type = TRAFFIC_TYPE_UPLOAD;
+ }
+ else
+ {
+ type = TRAFFIC_TYPE_FULL;
+ }
+
+ i = GetParamInt(o, "SPAN");
+
+ if (i == 0)
+ {
+ i = TRAFFIC_SPAN_DEFAULT;
+ }
+
+ span = (UINT64)i * 1000ULL;
+
+ dbl = GetParamYes(o, "DOUBLE");
+ raw = GetParamYes(o, "RAW");
+
+ if (type == TRAFFIC_TYPE_FULL)
+ {
+ if ((num % 2) != 0)
+ {
+ ret = ERR_INVALID_PARAMETER;
+ c->Write(c, _UU("CMD_TrafficClient_ERROR_NUMTCP"));
+ }
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ TT_RESULT result;
+ ttc = NewTtc(host, port, num, type, span, dbl, raw, PtTrafficPrintProc, c);
+
+ if (c->ConsoleType == CONSOLE_LOCAL)
+ {
+ if (c->Param != NULL && (((LOCAL_CONSOLE_PARAM *)c->Param)->InBuf == NULL))
+ {
+// c->Write(c, _UU("TTC_ENTER_TO_EXIT"));
+// GetLine(NULL, 0);
+// StopTtc(ttc);
+ }
+ }
+
+
+ Zero(&result, sizeof(result));
+ ret = FreeTtc(ttc, &result);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ TtcPrintResult(c, &result);
+ }
+ }
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ Free(host);
+
+ return ret;
+}
+
+// Certificate easy creation tool
+UINT PtMakeCert(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ UINT ret = ERR_NO_ERROR;
+ X *x = NULL;
+ K *pub = NULL;
+ K *pri = NULL;
+ NAME *n;
+ X_SERIAL *x_serial = NULL;
+ BUF *buf;
+ UINT days;
+ X *root_x = NULL;
+ K *root_k = NULL;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX minmax =
+ {
+ "CMD_MakeCert_EVAL_EXPIRES",
+ 0,
+ 10950,
+ };
+ PARAM args[] =
+ {
+ {"CN", CmdPrompt, _UU("CMD_MakeCert_PROMPT_CN"), NULL, NULL},
+ {"O", CmdPrompt, _UU("CMD_MakeCert_PROMPT_O"), NULL, NULL},
+ {"OU", CmdPrompt, _UU("CMD_MakeCert_PROMPT_OU"), NULL, NULL},
+ {"C", CmdPrompt, _UU("CMD_MakeCert_PROMPT_C"), NULL, NULL},
+ {"ST", CmdPrompt, _UU("CMD_MakeCert_PROMPT_ST"), NULL, NULL},
+ {"L", CmdPrompt, _UU("CMD_MakeCert_PROMPT_L"), NULL, NULL},
+ {"SERIAL", CmdPrompt, _UU("CMD_MakeCert_PROMPT_SERIAL"), NULL, NULL},
+ {"EXPIRES", CmdPrompt, _UU("CMD_MakeCert_PROMPT_EXPIRES"), CmdEvalMinMax, &minmax},
+ {"SIGNCERT", NULL, NULL, CmdEvalIsFile, NULL},
+ {"SIGNKEY", NULL, NULL, CmdEvalIsFile, NULL},
+ {"SAVECERT", CmdPrompt, _UU("CMD_MakeCert_PROMPT_SAVECERT"), CmdEvalNotEmpty, NULL},
+ {"SAVEKEY", CmdPrompt, _UU("CMD_MakeCert_PROMPT_SAVEKEY"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "SIGNCERT")) == false && IsEmptyStr(GetParamStr(o, "SIGNKEY")) == false)
+ {
+ root_x = FileToXW(GetParamUniStr(o, "SIGNCERT"));
+ root_k = FileToKW(GetParamUniStr(o, "SIGNKEY"), true, NULL);
+
+ if (root_x == NULL || root_k == NULL || CheckXandK(root_x, root_k) == false)
+ {
+ ret = ERR_INTERNAL_ERROR;
+
+ c->Write(c, _UU("CMD_MakeCert_ERROR_SIGNKEY"));
+ }
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ buf = StrToBin(GetParamStr(o, "SERIAL"));
+ if (buf != NULL && buf->Size >= 1)
+ {
+ x_serial = NewXSerial(buf->Buf, buf->Size);
+ }
+ FreeBuf(buf);
+
+ n = NewName(GetParamUniStr(o, "CN"), GetParamUniStr(o, "O"), GetParamUniStr(o, "OU"),
+ GetParamUniStr(o, "C"), GetParamUniStr(o, "ST"), GetParamUniStr(o, "L"));
+
+ days = GetParamInt(o, "EXPIRES");
+ if (days == 0)
+ {
+ days = 3650;
+ }
+
+ RsaGen(&pri, &pub, 1024);
+
+ if (root_x == NULL)
+ {
+ x = NewRootX(pub, pri, n, days, x_serial);
+ }
+ else
+ {
+ x = NewX(pub, root_k, root_x, n, days, x_serial);
+ }
+
+ FreeXSerial(x_serial);
+ FreeName(n);
+
+ if (x == NULL)
+ {
+ ret = ERR_INTERNAL_ERROR;
+ c->Write(c, _UU("CMD_MakeCert_ERROR_GEN_FAILED"));
+ }
+ else
+ {
+ if (XToFileW(x, GetParamUniStr(o, "SAVECERT"), true) == false)
+ {
+ c->Write(c, _UU("CMD_SAVECERT_FAILED"));
+ }
+ else if (KToFileW(pri, GetParamUniStr(o, "SAVEKEY"), true, NULL) == false)
+ {
+ c->Write(c, _UU("CMD_SAVEKEY_FAILED"));
+ }
+ }
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ FreeX(root_x);
+ FreeK(root_k);
+
+ FreeX(x);
+ FreeK(pri);
+ FreeK(pub);
+
+ return ret;
+}
+
+
+// Client management tool main
+void PcMain(PC *pc)
+{
+ char prompt[MAX_SIZE];
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (pc == NULL)
+ {
+ return;
+ }
+
+ // Display a message that the connection has been made
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_VPNCMD_CLIENT_CONNECTED"),
+ pc->ServerName);
+ pc->Console->Write(pc->Console, tmp);
+ pc->Console->Write(pc->Console, L"");
+
+ while (true)
+ {
+ // Definition of command
+ CMD cmd[] =
+ {
+ {"About", PsAbout},
+ {"Check", PtCheck},
+ {"VersionGet", PcVersionGet},
+ {"PasswordSet", PcPasswordSet},
+ {"PasswordGet", PcPasswordGet},
+ {"CertList", PcCertList},
+ {"CertAdd", PcCertAdd},
+ {"CertDelete", PcCertDelete},
+ {"CertGet", PcCertGet},
+ {"SecureList", PcSecureList},
+ {"SecureSelect", PcSecureSelect},
+ {"SecureGet", PcSecureGet},
+ {"NicCreate", PcNicCreate},
+ {"NicDelete", PcNicDelete},
+ {"NicUpgrade", PcNicUpgrade},
+ {"NicGetSetting", PcNicGetSetting},
+ {"NicSetSetting", PcNicSetSetting},
+ {"NicEnable", PcNicEnable},
+ {"NicDisable", PcNicDisable},
+ {"NicList", PcNicList},
+ {"AccountList", PcAccountList},
+ {"AccountCreate", PcAccountCreate},
+ {"AccountSet", PcAccountSet},
+ {"AccountGet", PcAccountGet},
+ {"AccountDelete", PcAccountDelete},
+ {"AccountUsernameSet", PcAccountUsernameSet},
+ {"AccountAnonymousSet", PcAccountAnonymousSet},
+ {"AccountPasswordSet", PcAccountPasswordSet},
+ {"AccountCertSet", PcAccountCertSet},
+ {"AccountCertGet", PcAccountCertGet},
+ {"AccountEncryptDisable", PcAccountEncryptDisable},
+ {"AccountEncryptEnable", PcAccountEncryptEnable},
+ {"AccountCompressEnable", PcAccountCompressEnable},
+ {"AccountCompressDisable", PcAccountCompressDisable},
+ {"AccountProxyNone", PcAccountProxyNone},
+ {"AccountProxyHttp", PcAccountProxyHttp},
+ {"AccountProxySocks", PcAccountProxySocks},
+ {"AccountServerCertEnable", PcAccountServerCertEnable},
+ {"AccountServerCertDisable", PcAccountServerCertDisable},
+ {"AccountServerCertSet", PcAccountServerCertSet},
+ {"AccountServerCertDelete", PcAccountServerCertDelete},
+ {"AccountServerCertGet", PcAccountServerCertGet},
+ {"AccountDetailSet", PcAccountDetailSet},
+ {"AccountRename", PcAccountRename},
+ {"AccountConnect", PcAccountConnect},
+ {"AccountDisconnect", PcAccountDisconnect},
+ {"AccountStatusGet", PcAccountStatusGet},
+ {"AccountNicSet", PcAccountNicSet},
+ {"AccountStatusShow", PcAccountStatusShow},
+ {"AccountStatusHide", PcAccountStatusHide},
+ {"AccountSecureCertSet", PcAccountSecureCertSet},
+ {"AccountRetrySet", PcAccountRetrySet},
+ {"AccountStartupSet", PcAccountStartupSet},
+ {"AccountStartupRemove", PcAccountStartupRemove},
+ {"AccountExport", PcAccountExport},
+ {"AccountImport", PcAccountImport},
+ {"RemoteEnable", PcRemoteEnable},
+ {"RemoteDisable", PcRemoteDisable},
+ {"KeepEnable", PcKeepEnable},
+ {"KeepDisable", PcKeepDisable},
+ {"KeepSet", PcKeepSet},
+ {"KeepGet", PcKeepGet},
+ {"MakeCert", PtMakeCert},
+ {"TrafficClient", PtTrafficClient},
+ {"TrafficServer", PtTrafficServer},
+ };
+
+ // Generate a prompt
+ StrCpy(prompt, sizeof(prompt), "VPN Client>");
+
+ if (DispatchNextCmdEx(pc->Console, pc->CmdLine, prompt, cmd, sizeof(cmd) / sizeof(cmd[0]), pc) == false)
+ {
+ break;
+ }
+ pc->LastError = pc->Console->RetCode;
+
+ if (pc->LastError == ERR_NO_ERROR && pc->Console->ConsoleType != CONSOLE_CSV)
+ {
+ pc->Console->Write(pc->Console, _UU("CMD_MSG_OK"));
+ pc->Console->Write(pc->Console, L"");
+ }
+
+ if (pc->CmdLine != NULL)
+ {
+ break;
+ }
+ }
+}
+
+// Retrieve the version information of VPN Client service
+UINT PcVersionGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_VERSION t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcGetClientVersion(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ wchar_t tmp[MAX_SIZE];
+ CT *ct;
+
+ // Success
+ ct = CtNewStandard();
+
+ StrToUni(tmp, sizeof(tmp), t.ClientProductName);
+ CtInsert(ct, _UU("CMD_VersionGet_1"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.ClientVersionString);
+ CtInsert(ct, _UU("CMD_VersionGet_2"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.ClientBuildInfoString);
+ CtInsert(ct, _UU("CMD_VersionGet_3"), tmp);
+
+ UniToStru(tmp, t.ProcessId);
+ CtInsert(ct, _UU("CMD_VersionGet_4"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), OsTypeToStr(t.OsType));
+ CtInsert(ct, _UU("CMD_VersionGet_5"), tmp);
+
+ CtFree(ct, c);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set a password to connect to the VPN Client Service
+UINT PcPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_PASSWORD t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[password]", CmdPromptChoosePassword, NULL, NULL, NULL},
+ {"REMOTEONLY", NULL, NULL, NULL, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ StrCpy(t.Password, sizeof(t.Password), GetParamStr(o, "[password]"));
+ t.PasswordRemoteOnly = GetParamYes(o, "REMOTEONLY");
+
+ ret = CcSetPassword(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the settings of the password to connect to the VPN Client service
+UINT PcPasswordGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_PASSWORD_SETTING t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcGetPasswordSetting(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ CT *ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_PasswordGet_1"),
+ t.IsPasswordPresented ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ CtInsert(ct, _UU("CMD_PasswordGet_2"),
+ t.PasswordRemoteOnly ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ CtFree(ct, c);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the list of certificates of the trusted certification authority
+UINT PcCertList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_ENUM_CA t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcEnumCa(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ UINT i;
+ CT *ct = CtNewStandard();
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[64];
+ RPC_CLIENT_ENUM_CA_ITEM *e = t.Items[i];
+
+ GetDateStrEx64(tmp, sizeof(tmp), SystemToLocal64(e->Expires), NULL);
+
+ UniToStru(tmp2, e->Key);
+
+ CtInsert(ct, _UU("CMD_CAList_COLUMN_ID"), tmp2);
+ CtInsert(ct, _UU("CM_CERT_COLUMN_1"), e->SubjectName);
+ CtInsert(ct, _UU("CM_CERT_COLUMN_2"), e->IssuerName);
+ CtInsert(ct, _UU("CM_CERT_COLUMN_3"), tmp);
+
+ if (i != (t.NumItem - 1))
+ {
+ CtInsert(ct, L"---", L"---");
+ }
+ }
+
+ CtFree(ct, c);
+
+ CiFreeClientEnumCa(&t);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Add a certificate of the trusted certification authority
+UINT PcCertAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CERT t;
+ X *x;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[path]", CmdPrompt, _UU("CMD_CAAdd_PROMPT_PATH"), CmdEvalIsFile, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+
+ x = FileToXW(GetParamUniStr(o, "[path]"));
+
+ if (x == NULL)
+ {
+ FreeParamValueList(o);
+ c->Write(c, _UU("CMD_MSG_LOAD_CERT_FAILED"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ t.x = x;
+
+ ret = CcAddCa(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ FreeX(x);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Delete the certificate of the trusted certification authority
+UINT PcCertDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_DELETE_CA t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[id]", CmdPrompt, _UU("CMD_CADelete_PROMPT_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ t.Key = GetParamInt(o, "[id]");
+
+ ret = CcDeleteCa(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the certificate of the trusted certification authority
+UINT PcCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_GET_CA t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[id]", CmdPrompt, _UU("CMD_CAGet_PROMPT_ID"), CmdEvalNotEmpty, NULL},
+ {"SAVECERT", CmdPrompt, _UU("CMD_CAGet_PROMPT_SAVECERT"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ t.Key = GetParamInt(o, "[id]");
+
+ ret = CcGetCa(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ if (XToFileW(t.x, GetParamUniStr(o, "SAVECERT"), true))
+ {
+ // Success
+ }
+ else
+ {
+ // Failure
+ ret = ERR_INTERNAL_ERROR;
+ c->Write(c, _UU("CMD_MSG_SAVE_CERT_FAILED"));
+ }
+
+ CiFreeGetCa(&t);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the list of the type of smart card that can be used
+UINT PcSecureList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_ENUM_SECURE t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcEnumSecure(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ CT *ct;
+ UINT i;
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t *tmp3;
+
+ // Success
+ ct = CtNew();
+ CtInsertColumn(ct, _UU("SEC_COLUMN1"), false);
+ CtInsertColumn(ct, _UU("SEC_COLUMN2"), false);
+ CtInsertColumn(ct, _UU("SEC_COLUMN3"), false);
+ CtInsertColumn(ct, _UU("SEC_COLUMN4"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_SECURE_ITEM *e = t.Items[i];
+
+ // ID
+ UniToStru(tmp1, e->DeviceId);
+
+ // Device name
+ StrToUni(tmp2, sizeof(tmp2), e->DeviceName);
+
+ // Type
+ tmp3 = (e->Type == SECURE_IC_CARD) ? _UU("SEC_SMART_CARD") : _UU("SEC_USB_TOKEN");
+
+ // Manufacturer
+ StrToUni(tmp4, sizeof(tmp4), e->Manufacturer);
+
+ CtInsert(ct, tmp1, tmp2, tmp3, tmp4);
+ }
+
+ CtFreeEx(ct, c, true);
+
+ CiFreeClientEnumSecure(&t);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Select the type of smart card to be used
+UINT PcSecureSelect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_USE_SECURE t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[id]", CmdPrompt, _UU("CMD_SecureSelect_PROMPT_ID"), NULL, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ t.DeviceId = GetParamInt(o, "[id]");
+
+ ret = CcUseSecure(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the type ID of smart card to be used
+UINT PcSecureGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_USE_SECURE t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcGetUseSecure(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ wchar_t tmp[MAX_SIZE];
+
+ if (t.DeviceId != 0)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_SecureGet_Print"), t.DeviceId);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CMD_SecureGet_NoPrint"));
+ }
+ c->Write(c, tmp);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Create a new virtual LAN card
+UINT PcNicCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_CREATE_VLAN t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+
+ ret = CcCreateVLan(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Delete the virtual LAN card
+UINT PcNicDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_CREATE_VLAN t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+
+ ret = CcDeleteVLan(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Upgrading the device driver of the virtual LAN card
+UINT PcNicUpgrade(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_CREATE_VLAN t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+
+ ret = CcUpgradeVLan(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the settings of the virtual LAN card
+UINT PcNicGetSetting(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_VLAN t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+
+ ret = CcGetVLan(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ CT *ct = CtNewStandard();
+ wchar_t tmp[MAX_SIZE];
+
+ StrToUni(tmp, sizeof(tmp), t.DeviceName);
+ CtInsert(ct, _UU("CMD_NicGetSetting_1"), tmp);
+
+ CtInsert(ct, _UU("CMD_NicGetSetting_2"), t.Enabled ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ StrToUni(tmp, sizeof(tmp), t.MacAddress);
+ CtInsert(ct, _UU("CMD_NicGetSetting_3"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.Version);
+ CtInsert(ct, _UU("CMD_NicGetSetting_4"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.FileName);
+ CtInsert(ct, _UU("CMD_NicGetSetting_5"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.Guid);
+ CtInsert(ct, _UU("CMD_NicGetSetting_6"), tmp);
+
+ CtFree(ct, c);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Change the settings for the virtual LAN card
+UINT PcNicSetSetting(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_SET_VLAN t;
+ UCHAR mac_address[6];
+ BUF *b;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ {"MAC", CmdPrompt, _UU("CMD_NicSetSetting_PROMPT_MAC"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Inspect the MAC address
+ Zero(mac_address, sizeof(mac_address));
+ b = StrToBin(GetParamStr(o, "MAC"));
+ if (b != NULL && b->Size == 6)
+ {
+ Copy(mac_address, b->Buf, 6);
+ }
+ FreeBuf(b);
+
+ if (IsZero(mac_address, 6))
+ {
+ // MAC address is invalid
+ FreeParamValueList(o);
+
+ CmdPrintError(c, ERR_INVALID_PARAMETER);
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+ NormalizeMacAddress(t.MacAddress, sizeof(t.MacAddress), GetParamStr(o, "MAC"));
+
+ ret = CcSetVLan(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Enable the virtual LAN card
+UINT PcNicEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_CREATE_VLAN t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+
+ ret = CcEnableVLan(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Disable the virtual LAN card
+UINT PcNicDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_CREATE_VLAN t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+
+ ret = CcDisableVLan(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the Virtual LAN card list
+UINT PcNicList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_ENUM_VLAN t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcEnumVLan(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ CT *ct;
+ UINT i;
+
+ // Success
+ ct = CtNew();
+ CtInsertColumn(ct, _UU("CM_VLAN_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("CM_VLAN_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("CM_VLAN_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("CM_VLAN_COLUMN_4"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ wchar_t name[MAX_SIZE];
+ wchar_t mac[MAX_SIZE];
+ wchar_t ver[MAX_SIZE];
+ wchar_t *status;
+ RPC_CLIENT_ENUM_VLAN_ITEM *v = t.Items[i];
+
+ // Device name
+ StrToUni(name, sizeof(name), v->DeviceName);
+
+ // State
+ status = v->Enabled ? _UU("CM_VLAN_ENABLED") : _UU("CM_VLAN_DISABLED");
+
+ // MAC address
+ StrToUni(mac, sizeof(mac), v->MacAddress);
+
+ // Version
+ StrToUni(ver, sizeof(ver), v->Version);
+
+ CtInsert(ct,
+ name, status, mac, ver);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientEnumVLan(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the protocol name string from ID
+wchar_t *GetProtocolName(UINT n)
+{
+ switch (n)
+ {
+ case PROXY_DIRECT:
+ return _UU("PROTO_DIRECT_TCP");
+ case PROXY_HTTP:
+ return _UU("PROTO_HTTP_PROXY");
+ case PROXY_SOCKS:
+ return _UU("PROTO_SOCKS_PROXY");
+ }
+
+ return _UU("PROTO_UNKNOWN");
+}
+
+// Get the connection settings list
+UINT PcAccountList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_ENUM_ACCOUNT t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcEnumAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ UINT i;
+ CT *ct;
+
+ // Success
+ ct = CtNew();
+ CtInsertColumn(ct, _UU("CM_ACCOUNT_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("CM_ACCOUNT_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("CM_ACCOUNT_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("CM_ACCOUNT_COLUMN_3_2"), false);
+ CtInsertColumn(ct, _UU("CM_ACCOUNT_COLUMN_4"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *e = t.Items[i];
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ IP ip;
+ char ip_str[MAX_SIZE];
+
+ // Special treatment for IPv6 addresses
+ if (StrToIP6(&ip, e->ServerName) && StartWith(e->ServerName, "[") == false)
+ {
+ Format(ip_str, sizeof(ip_str),
+ "[%s]", e->ServerName);
+ }
+ else
+ {
+ StrCpy(ip_str, sizeof(ip_str), e->ServerName);
+ }
+
+ if (e->Port == 0)
+ {
+ // Port number unknown
+ UniFormat(tmp2, sizeof(tmp2), L"%S (%s)", ip_str, GetProtocolName(e->ProxyType));
+ }
+ else
+ {
+ // Port number are also shown
+ UniFormat(tmp2, sizeof(tmp2), L"%S:%u (%s)", ip_str, e->Port, GetProtocolName(e->ProxyType));
+ }
+
+ // Virtual HUB name
+ StrToUni(tmp4, sizeof(tmp4), e->HubName);
+
+ // Add
+ StrToUni(tmp, sizeof(tmp), e->DeviceName);
+
+ CtInsert(ct,
+ e->AccountName,
+ e->Active == false ? _UU("CM_ACCOUNT_OFFLINE") :
+ (e->Connected ? _UU("CM_ACCOUNT_ONLINE") : _UU("CM_ACCOUNT_CONNECTING")),
+ tmp2, tmp4,
+ tmp);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ CiFreeClientEnumAccount(&t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Create new connection settings
+UINT PcAccountCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_CREATE_ACCOUNT t;
+ UINT port = 443;
+ char *host = NULL;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SERVER", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Server"), CmdEvalHostAndPort, NULL},
+ {"HUB", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Hub"), CmdEvalSafe, NULL},
+ {"USERNAME", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Username"), CmdEvalNotEmpty, NULL},
+ {"NICNAME", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Nicname"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 443);
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+ t.ClientOption->Port = port;
+ StrCpy(t.ClientOption->Hostname, sizeof(t.ClientOption->Hostname), host);
+ StrCpy(t.ClientOption->HubName, sizeof(t.ClientOption->HubName), GetParamStr(o, "HUB"));
+ t.ClientOption->NumRetry = INFINITE;
+ t.ClientOption->RetryInterval = 15;
+ t.ClientOption->MaxConnection = 1;
+ t.ClientOption->UseEncrypt = true;
+ t.ClientOption->AdditionalConnectionInterval = 1;
+ StrCpy(t.ClientOption->DeviceName, sizeof(t.ClientOption->DeviceName), GetParamStr(o, "NICNAME"));
+
+ t.ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_ANONYMOUS;
+ StrCpy(t.ClientAuth->Username, sizeof(t.ClientAuth->Username), GetParamStr(o, "USERNAME"));
+
+ Free(host);
+
+ ret = CcCreateAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ CiFreeClientCreateAccount(&t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the destination of the connection settings
+UINT PcAccountSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ char *host = NULL;
+ UINT port = 443;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SERVER", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Server"), CmdEvalHostAndPort, NULL},
+ {"HUB", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Hub"), CmdEvalSafe, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 443);
+
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT c;
+ // Success
+ t.ClientOption->Port = port;
+ StrCpy(t.ClientOption->Hostname, sizeof(t.ClientOption->Hostname), host);
+ StrCpy(t.ClientOption->HubName, sizeof(t.ClientOption->HubName), GetParamStr(o, "HUB"));
+
+ Zero(&c, sizeof(c));
+
+ c.ClientAuth = t.ClientAuth;
+ c.ClientOption = t.ClientOption;
+ c.CheckServerCert = t.CheckServerCert;
+ c.ServerCert = t.ServerCert;
+ c.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &c);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ Free(host);
+
+ return ret;
+}
+
+// Get the configuration of the connection settings
+UINT PcAccountGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Show the contents of the connection settings
+ wchar_t tmp[MAX_SIZE];
+
+ CT *ct = CtNewStandard();
+
+ // Connection settings name
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_NAME"), t.ClientOption->AccountName);
+
+ // Host name of the destination VPN Server
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->Hostname);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_HOSTNAME"), tmp);
+
+ // The port number to connect to VPN Server
+ UniToStru(tmp, t.ClientOption->Port);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PORT"), tmp);
+
+ // Virtual HUB name of the destination VPN Server
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->HubName);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_HUBNAME"), tmp);
+
+ // Type of proxy server to go through
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_TYPE"), GetProxyTypeStr(t.ClientOption->ProxyType));
+
+ if (t.ClientOption->ProxyType != PROXY_DIRECT)
+ {
+ // Host name of the proxy server
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->ProxyName);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_HOSTNAME"), tmp);
+
+ // Port number of the proxy server
+ UniToStru(tmp, t.ClientOption->ProxyPort);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_PORT"), tmp);
+
+ // User name of the proxy server
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->ProxyUsername);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_USERNAME"), tmp);
+ }
+
+ // Verify the server certificate
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_SERVER_CERT_USE"),
+ t.CheckServerCert ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Registered specific certificate
+ if (t.ServerCert != NULL)
+ {
+ GetAllNameFromX(tmp, sizeof(tmp), t.ServerCert);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_SERVER_CERT_NAME"), tmp);
+ }
+
+ // Device name to be used for the connection
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->DeviceName);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_DEVICE_NAME"), tmp);
+
+ // Authentication type
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_AUTH_TYPE"), GetClientAuthTypeStr(t.ClientAuth->AuthType));
+
+ // User name
+ StrToUni(tmp, sizeof(tmp), t.ClientAuth->Username);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_AUTH_USERNAME"), tmp);
+
+ if (t.ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)
+ {
+ if (t.ClientAuth->ClientX != NULL)
+ {
+ // Client certificate name
+ GetAllNameFromX(tmp, sizeof(tmp), t.ClientAuth->ClientX);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_AUTH_CERT_NAME"), tmp);
+ }
+ }
+
+ // Number of TCP connections to be used for VPN communication
+ UniToStru(tmp, t.ClientOption->MaxConnection);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_NUMTCP"), tmp);
+
+ // Establishment interval of each TCP connection
+ UniToStru(tmp, t.ClientOption->AdditionalConnectionInterval);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_TCP_INTERVAL"), tmp);
+
+ // Life span of each TCP connection
+ if (t.ClientOption->ConnectionDisconnectSpan != 0)
+ {
+ UniToStru(tmp, t.ClientOption->ConnectionDisconnectSpan);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CMD_MSG_INFINITE"));
+ }
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_TCP_TTL"), tmp);
+
+ // Use of half-duplex mode
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_TCP_HALF"),
+ t.ClientOption->HalfConnection ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Encryption by SSL
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_ENCRYPT"),
+ t.ClientOption->UseEncrypt ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Data compression
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_COMPRESS"),
+ t.ClientOption->UseCompress ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Connect in bridge / router mode
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_BRIDGE_ROUTER"),
+ t.ClientOption->RequireBridgeRoutingMode ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Connect in monitoring mode
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_MONITOR"),
+ t.ClientOption->RequireMonitorMode ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Not to rewrite the routing table
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_NO_TRACKING"),
+ t.ClientOption->NoRoutingTracking ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Disable the QoS control
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_QOS_DISABLE"),
+ t.ClientOption->DisableQoS ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ CtFree(ct, c);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Delete the connection settings
+UINT PcAccountDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_DELETE_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcDeleteAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the user name used to connect with connection settings
+UINT PcAccountUsernameSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"USERNAME", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Username"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ StrCpy(t.ClientAuth->Username, sizeof(t.ClientAuth->Username), GetParamStr(o, "USERNAME"));
+
+ if (t.ClientAuth->AuthType == CLIENT_AUTHTYPE_PASSWORD)
+ {
+ c->Write(c, _UU("CMD_AccountUsername_Notice"));
+ }
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the type of user authentication of connection settings to anonymous authentication
+UINT PcAccountAnonymousSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_ANONYMOUS;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the type of user authentication of connection settings to the password authentication
+UINT PcAccountPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+ {"TYPE", CmdPrompt, _UU("CMD_CascadePasswordSet_Prompt_Type"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ char *typestr = GetParamStr(o, "TYPE");
+ RPC_CLIENT_CREATE_ACCOUNT z;
+
+ // Change the settings
+ if (StartWith("standard", typestr))
+ {
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_PASSWORD;
+ HashPassword(t.ClientAuth->HashedPassword, t.ClientAuth->Username,
+ GetParamStr(o, "PASSWORD"));
+ }
+ else if (StartWith("radius", typestr) || StartWith("ntdomain", typestr))
+ {
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_PLAIN_PASSWORD;
+
+ StrCpy(t.ClientAuth->PlainPassword, sizeof(t.ClientAuth->PlainPassword),
+ GetParamStr(o, "PASSWORD"));
+ }
+ else
+ {
+ // Error has occured
+ c->Write(c, _UU("CMD_CascadePasswordSet_Type_Invalid"));
+ ret = ERR_INVALID_PARAMETER;
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the type of user authentication of connection settings to the client certificate authentication
+UINT PcAccountCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ X *x;
+ K *k;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL},
+ {"LOADKEY", CmdPrompt, _UU("CMD_LOADKEYPATH"), CmdEvalIsFile, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (CmdLoadCertAndKey(c, &x, &k, GetParamUniStr(o, "LOADCERT"), GetParamUniStr(o, "LOADKEY")) == false)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_CERT;
+ if (t.ClientAuth->ClientX != NULL)
+ {
+ FreeX(t.ClientAuth->ClientX);
+ }
+ if (t.ClientAuth->ClientK != NULL)
+ {
+ FreeK(t.ClientAuth->ClientK);
+ }
+
+ t.ClientAuth->ClientX = CloneX(x);
+ t.ClientAuth->ClientK = CloneK(k);
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ FreeX(x);
+ FreeK(k);
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the client certificate to be used for the connection settings
+UINT PcAccountCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SAVECERT", CmdPrompt, _UU("CMD_SAVECERTPATH"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ if (t.ClientAuth->AuthType != CLIENT_AUTHTYPE_CERT)
+ {
+ c->Write(c, _UU("CMD_CascadeCertSet_Not_Auth_Cert"));
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else if (t.ClientAuth->ClientX == NULL)
+ {
+ c->Write(c, _UU("CMD_CascadeCertSet_Cert_Not_Exists"));
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ XToFileW(t.ClientAuth->ClientX, GetParamUniStr(o, "SAVECERT"), true);
+ }
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Disable communication encryption with the connection settings
+UINT PcAccountEncryptDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.ClientOption->UseEncrypt = false;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Enable communication encryption with the connection settings
+UINT PcAccountEncryptEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.ClientOption->UseEncrypt = true;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Enable communication data compression with the connection settings
+UINT PcAccountCompressEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.ClientOption->UseCompress = true;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Disable communication data compression with the connection settings
+UINT PcAccountCompressDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.ClientOption->UseCompress = false;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the connection method of the connection settings to the direct TCP/IP connection
+UINT PcAccountProxyNone(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.ClientOption->ProxyType = PROXY_DIRECT;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the connection method of the connection settings to the HTTP proxy server connection
+UINT PcAccountProxyHttp(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SERVER", CmdPrompt, _UU("CMD_AccountProxyHttp_Prompt_Server"), CmdEvalHostAndPort, NULL},
+ {"USERNAME", NULL, NULL, NULL, NULL},
+ {"PASSWORD", NULL, NULL, NULL, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ char *host;
+ UINT port;
+
+ // Data change
+ if (ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 8080))
+ {
+ t.ClientOption->ProxyType = PROXY_HTTP;
+ StrCpy(t.ClientOption->ProxyName, sizeof(t.ClientOption->ProxyName), host);
+ t.ClientOption->ProxyPort = port;
+ StrCpy(t.ClientOption->ProxyUsername, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "USERNAME"));
+ StrCpy(t.ClientOption->ProxyPassword, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "PASSWORD"));
+ Free(host);
+ }
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the connection method of the connection settings to the SOCKS proxy server connection
+UINT PcAccountProxySocks(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SERVER", CmdPrompt, _UU("CMD_AccountProxyHttp_Prompt_Server"), CmdEvalHostAndPort, NULL},
+ {"USERNAME", NULL, NULL, NULL, NULL},
+ {"PASSWORD", NULL, NULL, NULL, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ char *host;
+ UINT port;
+
+ // Data change
+ if (ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 8080))
+ {
+ t.ClientOption->ProxyType = PROXY_SOCKS;
+ StrCpy(t.ClientOption->ProxyName, sizeof(t.ClientOption->ProxyName), host);
+ t.ClientOption->ProxyPort = port;
+ StrCpy(t.ClientOption->ProxyUsername, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "USERNAME"));
+ StrCpy(t.ClientOption->ProxyPassword, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "PASSWORD"));
+ Free(host);
+ }
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Enable validation option for server certificate of connection settings
+UINT PcAccountServerCertEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.CheckServerCert = true;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Disable validation option of the server certificate of connection settings
+UINT PcAccountServerCertDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.CheckServerCert = false;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the server-specific certificate of connection settings
+UINT PcAccountServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ X *x;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ x = FileToXW(GetParamUniStr(o, "LOADCERT"));
+ if (x == NULL)
+ {
+ FreeParamValueList(o);
+ c->Write(c, _UU("CMD_LOADCERT_FAILED"));
+ return ERR_INTERNAL_ERROR;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ if (t.ServerCert != NULL)
+ {
+ FreeX(t.ServerCert);
+ }
+ t.ServerCert = CloneX(x);
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ FreeX(x);
+
+ return ret;
+}
+
+// Delete a server-specific certificate of connection settings
+UINT PcAccountServerCertDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ if (t.ServerCert != NULL)
+ {
+ FreeX(t.ServerCert);
+ }
+ t.ServerCert = NULL;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get a server-specific certificate of connection settings
+UINT PcAccountServerCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SAVECERT", CmdPrompt, _UU("CMD_SAVECERTPATH"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ if (t.ServerCert != NULL)
+ {
+ FreeX(t.ServerCert);
+ }
+ t.ServerCert = NULL;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the advanced settings of connection settings
+UINT PcAccountDetailSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ CMD_EVAL_MIN_MAX mm_maxtcp =
+ {
+ "CMD_CascadeDetailSet_Eval_MaxTcp", 1, 32
+ };
+ CMD_EVAL_MIN_MAX mm_interval =
+ {
+ "CMD_CascadeDetailSet_Eval_Interval", 1, 4294967295UL
+ };
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"MAXTCP", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_MaxTcp"), CmdEvalMinMax, &mm_maxtcp},
+ {"INTERVAL", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_Interval"), CmdEvalMinMax, &mm_interval},
+ {"TTL", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_TTL"), NULL, NULL},
+ {"HALF", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_HALF"), NULL, NULL},
+ {"BRIDGE", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_BRIDGE"), NULL, NULL},
+ {"MONITOR", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_MONITOR"), NULL, NULL},
+ {"NOTRACK", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_NOTRACK"), NULL, NULL},
+ {"NOQOS", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_NOQOS"), NULL, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Data change
+ t.ClientOption->MaxConnection = GetParamInt(o, "MAXTCP");
+ t.ClientOption->AdditionalConnectionInterval = GetParamInt(o, "INTERVAL");
+ t.ClientOption->ConnectionDisconnectSpan = GetParamInt(o, "TTL");
+ t.ClientOption->HalfConnection = GetParamYes(o, "HALF");
+ t.ClientOption->RequireBridgeRoutingMode = GetParamYes(o, "BRIDGE");
+ t.ClientOption->RequireMonitorMode = GetParamYes(o, "MONITOR");
+ t.ClientOption->NoRoutingTracking = GetParamYes(o, "NOTRACK");
+ t.ClientOption->DisableQoS = GetParamYes(o, "NOQOS");
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Change the name of the connection settings
+UINT PcAccountRename(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_RENAME_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountRename_PROMPT_OLD"), CmdEvalNotEmpty, NULL},
+ {"NEW", CmdPrompt, _UU("CMD_AccountRename_PROMPT_NEW"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.NewName, sizeof(t.NewName), GetParamUniStr(o, "NEW"));
+ UniStrCpy(t.OldName, sizeof(t.OldName), GetParamUniStr(o, "[name]"));
+
+ ret = CcRenameAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Start to connect to the VPN Server using the connection settings
+UINT PcAccountConnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_CONNECT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcConnect(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Disconnect the connection settings of connected
+UINT PcAccountDisconnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_CONNECT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcDisconnect(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the current state of the connection settings
+UINT PcAccountStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_CONNECTION_STATUS t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccountStatus(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ if (t.Active == false)
+ {
+ // Has been disconnected
+ ret = ERR_ACCOUNT_INACTIVE;
+ }
+ else
+ {
+ CT *ct = CtNewStandard();
+
+ CmdPrintStatusToListView(ct, &t);
+
+ CtFree(ct, c);
+ }
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetConnectionStatus(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set a virtual LAN card to be used in the connection settings
+UINT PcAccountNicSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"NICNAME", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Nicname"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT c;
+ // Success
+ StrCpy(t.ClientOption->DeviceName, sizeof(t.ClientOption->DeviceName),
+ GetParamStr(o, "NICNAME"));
+
+ Zero(&c, sizeof(c));
+
+ c.ClientAuth = t.ClientAuth;
+ c.ClientOption = t.ClientOption;
+ c.CheckServerCert = t.CheckServerCert;
+ c.ServerCert = t.ServerCert;
+ c.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &c);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set to display error screens and connection status while connecting to the VPN Server
+UINT PcAccountStatusShow(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.ClientOption->HideStatusWindow = false;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Configure not to display error screens and connection status while connecting to the VPN Server
+UINT PcAccountStatusHide(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.ClientOption->HideStatusWindow = true;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the type of user authentication of connection settings to the smart card authentication
+UINT PcAccountSecureCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"CERTNAME", CmdPrompt, _UU("CMD_AccountSecureCertSet_PROMPT_CERTNAME"), CmdEvalNotEmpty, NULL},
+ {"KEYNAME", CmdPrompt, _UU("CMD_AccountSecureCertSet_PROMPT_KEYNAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_SECURE;
+ StrCpy(t.ClientAuth->SecurePublicCertName, sizeof(t.ClientAuth->SecurePublicCertName),
+ GetParamStr(o, "CERTNAME"));
+ StrCpy(t.ClientAuth->SecurePrivateKeyName, sizeof(t.ClientAuth->SecurePrivateKeyName),
+ GetParamStr(o, "KEYNAME"));
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the retry interval and number of retries when disconnect or connection failure of connection settings
+UINT PcAccountRetrySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX minmax =
+ {
+ "CMD_AccountRetrySet_EVAL_INTERVAL",
+ 5,
+ 4294967295UL,
+ };
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"NUM", CmdPrompt, _UU("CMD_AccountRetrySet_PROMPT_NUM"), CmdEvalNotEmpty, NULL},
+ {"INTERVAL", CmdPrompt, _UU("CMD_AccountRetrySet_PROMPY_INTERVAL"), CmdEvalMinMax, &minmax},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ UINT num = GetParamInt(o, "NUM");
+ UINT interval = GetParamInt(o, "INTERVAL");
+
+ t.ClientOption->NumRetry = (num == 999) ? INFINITE : num;
+ t.ClientOption->RetryInterval = interval;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+
+// Set to start-up connection the connection settings
+UINT PcAccountStartupSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.StartupAccount = true;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Unset the start-up connection of the connection settings
+UINT PcAccountStartupRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.StartupAccount = false;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Export the connection settings
+UINT PcAccountExport(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SAVEPATH", CmdPrompt, _UU("CMD_AccountExport_PROMPT_SAVEPATH"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ BUF *b;
+ BUF *b2;
+ char tmp[MAX_SIZE];
+ UCHAR *buf;
+ UINT buf_size;
+ UCHAR bom[] = {0xef, 0xbb, 0xbf, };
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ b = CiAccountToCfg(&z);
+
+ StrCpy(tmp, sizeof(tmp), GetParamStr(o, "SAVEPATH"));
+ b2 = NewBuf();
+
+ WriteBuf(b2, bom, sizeof(bom));
+
+ // Add the header part
+ buf_size = CalcUniToUtf8(_UU("CM_ACCOUNT_FILE_BANNER"));
+ buf = ZeroMalloc(buf_size + 32);
+ UniToUtf8(buf, buf_size, _UU("CM_ACCOUNT_FILE_BANNER"));
+
+ WriteBuf(b2, buf, StrLen((char *)buf));
+ WriteBuf(b2, b->Buf, b->Size);
+ SeekBuf(b2, 0, 0);
+
+ FreeBuf(b);
+
+ if (DumpBuf(b2, tmp) == false)
+ {
+ c->Write(c, _UU("CMD_SAVEFILE_FAILED"));
+ ret = ERR_INTERNAL_ERROR;
+ }
+
+ FreeBuf(b2);
+ Free(buf);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Check whether the specified account name exists
+bool CmdIsAccountName(REMOTE_CLIENT *r, wchar_t *name)
+{
+ UINT i;
+ RPC_CLIENT_ENUM_ACCOUNT t;
+ wchar_t tmp[MAX_SIZE];
+ bool b = false;
+ // Validate arguments
+ if (r == NULL || name == NULL)
+ {
+ return false;
+ }
+
+ if (CcEnumAccount(r, &t) != ERR_NO_ERROR)
+ {
+ return false;
+ }
+
+ UniStrCpy(tmp, sizeof(tmp), name);
+ UniTrim(tmp);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ if (UniStrCmpi(t.Items[i]->AccountName, tmp) == 0)
+ {
+ b = true;
+ break;
+ }
+ }
+
+ CiFreeClientEnumAccount(&t);
+
+ return b;
+}
+
+// Generate an import name
+void CmdGenerateImportName(REMOTE_CLIENT *r, wchar_t *name, UINT size, wchar_t *old_name)
+{
+ UINT i;
+ // Validate arguments
+ if (r == NULL || name == NULL || old_name == NULL)
+ {
+ return;
+ }
+
+ for (i = 1;;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ if (i == 1)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_IMPORT_NAME_1"), old_name);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_IMPORT_NAME_2"), old_name, i);
+ }
+
+ if (CmdIsAccountName(r, tmp) == false)
+ {
+ UniStrCpy(name, size, tmp);
+ return;
+ }
+ }
+}
+
+// Import a connection setting
+UINT PcAccountImport(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ BUF *b;
+ wchar_t name[MAX_SIZE];
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[path]", CmdPrompt, _UU("CMD_AccountImport_PROMPT_PATH"), CmdEvalIsFile, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Read the file
+ b = ReadDumpW(GetParamUniStr(o, "[path]"));
+
+ if (b == NULL)
+ {
+ // Read failure
+ c->Write(c, _UU("CMD_LOADFILE_FAILED"));
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ RPC_CLIENT_CREATE_ACCOUNT *t;
+
+ t = CiCfgToAccount(b);
+
+ if (t == NULL)
+ {
+ // Failed to parse
+ c->Write(c, _UU("CMD_AccountImport_FAILED_PARSE"));
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ CmdGenerateImportName(pc->RemoteClient, name, sizeof(name), t->ClientOption->AccountName);
+ UniStrCpy(t->ClientOption->AccountName, sizeof(t->ClientOption->AccountName), name);
+
+ ret = CcCreateAccount(pc->RemoteClient, t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_AccountImport_OK"), name);
+ c->Write(c, tmp);
+ }
+
+ CiFreeClientCreateAccount(t);
+ Free(t);
+ }
+
+ FreeBuf(b);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Allow remote management of the VPN Client Service
+UINT PcRemoteEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ CLIENT_CONFIG t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcGetClientConfig(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ t.AllowRemoteConfig = true;
+ ret = CcSetClientConfig(pc->RemoteClient, &t);
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Prohibit remote management of the VPN Client Service
+UINT PcRemoteDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ CLIENT_CONFIG t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcGetClientConfig(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ t.AllowRemoteConfig = false;
+ ret = CcSetClientConfig(pc->RemoteClient, &t);
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Enable the maintenance function of the Internet connection
+UINT PcKeepEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ CLIENT_CONFIG t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcGetClientConfig(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Change the settings
+ t.UseKeepConnect = true;
+ ret = CcSetClientConfig(pc->RemoteClient, &t);
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Disable the maintenance function of the Internet connection
+UINT PcKeepDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ CLIENT_CONFIG t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcGetClientConfig(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Change the settings
+ t.UseKeepConnect = false;
+ ret = CcSetClientConfig(pc->RemoteClient, &t);
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the maintenance function of the Internet connection
+UINT PcKeepSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ CLIENT_CONFIG t;
+ char *host;
+ UINT port;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"HOST", CmdPrompt, _UU("CMD_KeepSet_PROMPT_HOST"), CmdEvalHostAndPort, NULL},
+ {"PROTOCOL", CmdPrompt, _UU("CMD_KeepSet_PROMPT_PROTOCOL"), CmdEvalTcpOrUdp, NULL},
+ {"INTERVAL", CmdPrompt, _UU("CMD_KeepSet_PROMPT_INTERVAL"), NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcGetClientConfig(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ if (ParseHostPort(GetParamStr(o, "HOST"), &host, &port, 0))
+ {
+ StrCpy(t.KeepConnectHost, sizeof(t.KeepConnectHost), host);
+ t.KeepConnectPort = port;
+ t.KeepConnectInterval = GetParamInt(o, "INTERVAL");
+ t.KeepConnectProtocol = (StrCmpi(GetParamStr(o, "PROTOCOL"), "tcp") == 0) ? 0 : 1;
+ Free(host);
+
+ ret = CcSetClientConfig(pc->RemoteClient, &t);
+ }
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the maintenance function of the Internet connection
+UINT PcKeepGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ CLIENT_CONFIG t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcGetClientConfig(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ wchar_t tmp[MAX_SIZE];
+ CT *ct = CtNewStandard();
+
+ StrToUni(tmp, sizeof(tmp), t.KeepConnectHost);
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_1"), tmp);
+
+ UniToStru(tmp, t.KeepConnectPort);
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_2"), tmp);
+
+ UniToStru(tmp, t.KeepConnectInterval);
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_3"), tmp);
+
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_4"),
+ t.KeepConnectProtocol == 0 ? L"TCP/IP" : L"UDP/IP");
+
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_5"),
+ t.UseKeepConnect ? _UU("SM_ACCESS_ENABLE") : _UU("SM_ACCESS_DISABLE"));
+
+ CtFree(ct, c);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+
+// Creat a new client management tool context
+PC *NewPc(CONSOLE *c, REMOTE_CLIENT *remote_client, char *servername, wchar_t *cmdline)
+{
+ PC *pc;
+ // Validate arguments
+ if (c == NULL || remote_client == NULL || servername == NULL)
+ {
+ return NULL;
+ }
+ if (UniIsEmptyStr(cmdline))
+ {
+ cmdline = NULL;
+ }
+
+ pc = ZeroMalloc(sizeof(PC));
+ pc->ConsoleForServer = false;
+ pc->ServerName = CopyStr(servername);
+ pc->Console = c;
+ pc->LastError = 0;
+ pc->RemoteClient = remote_client;
+ pc->CmdLine = CopyUniStr(cmdline);
+
+ return pc;
+}
+
+// Release the client management tools context
+void FreePc(PC *pc)
+{
+ // Validate arguments
+ if (pc == NULL)
+ {
+ return;
+ }
+
+ Free(pc->ServerName);
+ Free(pc->CmdLine);
+ Free(pc);
+}
+
+// Client management tool
+UINT PcConnect(CONSOLE *c, char *target, wchar_t *cmdline, char *password)
+{
+ CEDAR *cedar;
+ REMOTE_CLIENT *client;
+ bool bad_pass;
+ bool no_remote;
+ char pass[MAX_SIZE];
+ UINT ret = 0;
+ // Validate arguments
+ if (c == NULL || target == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ StrCpy(pass, sizeof(pass), password);
+
+ cedar = NewCedar(NULL, NULL);
+
+RETRY:
+ client = CcConnectRpc(target, pass, &bad_pass, &no_remote, 0);
+
+ if (client == NULL)
+ {
+ if (no_remote)
+ {
+ // Remote connection refusal
+ c->Write(c, _UU("CMD_VPNCMD_CLIENT_NO_REMODE"));
+ ReleaseCedar(cedar);
+ return ERR_INTERNAL_ERROR;
+ }
+ else if (bad_pass)
+ {
+ char *tmp;
+ // Password is different
+ c->Write(c, _UU("CMD_VPNCMD_PASSWORD_1"));
+ tmp = c->ReadPassword(c, _UU("CMD_VPNCMD_PASSWORD_2"));
+ c->Write(c, L"");
+
+ if (tmp == NULL)
+ {
+ // Cancel
+ ReleaseCedar(cedar);
+ return ERR_ACCESS_DENIED;
+ }
+ else
+ {
+ StrCpy(pass, sizeof(pass), tmp);
+ Free(tmp);
+ }
+
+ goto RETRY;
+ }
+ else
+ {
+ // Connection failure
+ CmdPrintError(c, ERR_CONNECT_FAILED);
+ ReleaseCedar(cedar);
+ return ERR_CONNECT_FAILED;
+ }
+ }
+ else
+ {
+ // Connection complete
+ PC *pc = NewPc(c, client, target, cmdline);
+ PcMain(pc);
+ ret = pc->LastError;
+ FreePc(pc);
+ }
+
+ CcDisconnectRpc(client);
+
+ ReleaseCedar(cedar);
+
+ return ret;
+}
+
+
+// Server Administration Tool Processor Main
+void PsMain(PS *ps)
+{
+ char prompt[MAX_SIZE];
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (ps == NULL)
+ {
+ return;
+ }
+
+ // If it's not in CSV mode, to display a message that the connection has been made
+ if(ps->Console->ConsoleType != CONSOLE_CSV)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_VPNCMD_SERVER_CONNECTED"),
+ ps->ServerName, ps->ServerPort);
+ ps->Console->Write(ps->Console, tmp);
+ ps->Console->Write(ps->Console, L"");
+
+ if (ps->HubName == NULL)
+ {
+ // Server management mode
+ ps->Console->Write(ps->Console, _UU("CMD_VPNCMD_SERVER_CONNECTED_1"));
+ }
+ else
+ {
+ // Virtual HUB management mode
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_VPNCMD_SERVER_CONNECTED_2"),
+ ps->HubName);
+ ps->Console->Write(ps->Console, tmp);
+ }
+ ps->Console->Write(ps->Console, L"");
+ }
+
+ // Get the Caps
+ ps->CapsList = ScGetCapsEx(ps->Rpc);
+
+ if (ps->AdminHub != NULL)
+ {
+ RPC_HUB_STATUS t;
+ UINT ret;
+ wchar_t tmp[MAX_SIZE];
+
+ // Choose the Virtual HUB that is specified in the ADMINHUB
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->AdminHub);
+
+ ret = ScGetHubStatus(ps->Rpc, &t);
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_Hub_Selected"), t.HubName);
+
+ if (ps->HubName != NULL)
+ {
+ Free(ps->HubName);
+ }
+ ps->HubName = CopyStr(t.HubName);
+
+ if( ps->Console->ConsoleType != CONSOLE_CSV)
+ {
+ ps->Console->Write(ps->Console, tmp);
+ }
+ }
+ else
+ {
+ // Failure
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_Hub_Select_Failed"), ps->AdminHub);
+
+ ps->Console->Write(ps->Console, tmp);
+ CmdPrintError(ps->Console, ret);
+ }
+ }
+
+ while (true)
+ {
+ // Definition of command
+ CMD cmd[] =
+ {
+ {"About", PsAbout},
+ {"Check", PtCheck},
+ {"Crash", PsCrash},
+ {"Flush", PsFlush},
+ {"Debug", PsDebug},
+ {"ServerInfoGet", PsServerInfoGet},
+ {"ServerStatusGet", PsServerStatusGet},
+ {"ListenerCreate", PsListenerCreate},
+ {"ListenerDelete", PsListenerDelete},
+ {"ListenerList", PsListenerList},
+ {"ListenerEnable", PsListenerEnable},
+ {"ListenerDisable", PsListenerDisable},
+ {"ServerPasswordSet", PsServerPasswordSet},
+ {"ClusterSettingGet", PsClusterSettingGet},
+ {"ClusterSettingStandalone", PsClusterSettingStandalone},
+ {"ClusterSettingController", PsClusterSettingController},
+ {"ClusterSettingMember", PsClusterSettingMember},
+ {"ClusterMemberList", PsClusterMemberList},
+ {"ClusterMemberInfoGet", PsClusterMemberInfoGet},
+ {"ClusterMemberCertGet", PsClusterMemberCertGet},
+ {"ClusterConnectionStatusGet", PsClusterConnectionStatusGet},
+ {"ServerCertGet", PsServerCertGet},
+ {"ServerKeyGet", PsServerKeyGet},
+ {"ServerCertSet", PsServerCertSet},
+ {"ServerCipherGet", PsServerCipherGet},
+ {"ServerCipherSet", PsServerCipherSet},
+ {"KeepEnable", PsKeepEnable},
+ {"KeepDisable", PsKeepDisable},
+ {"KeepSet", PsKeepSet},
+ {"KeepGet", PsKeepGet},
+ {"SyslogGet", PsSyslogGet},
+ {"SyslogDisable", PsSyslogDisable},
+ {"SyslogEnable", PsSyslogEnable},
+ {"ConnectionList", PsConnectionList},
+ {"ConnectionGet", PsConnectionGet},
+ {"ConnectionDisconnect", PsConnectionDisconnect},
+ {"BridgeDeviceList", PsBridgeDeviceList},
+ {"BridgeList", PsBridgeList},
+ {"BridgeCreate", PsBridgeCreate},
+ {"BridgeDelete", PsBridgeDelete},
+ {"Caps", PsCaps},
+ {"Reboot", PsReboot},
+ {"ConfigGet", PsConfigGet},
+ {"ConfigSet", PsConfigSet},
+ {"RouterList", PsRouterList},
+ {"RouterAdd", PsRouterAdd},
+ {"RouterDelete", PsRouterDelete},
+ {"RouterStart", PsRouterStart},
+ {"RouterStop", PsRouterStop},
+ {"RouterIfList", PsRouterIfList},
+ {"RouterIfAdd", PsRouterIfAdd},
+ {"RouterIfDel", PsRouterIfDel},
+ {"RouterTableList", PsRouterTableList},
+ {"RouterTableAdd", PsRouterTableAdd},
+ {"RouterTableDel", PsRouterTableDel},
+ {"LogFileList", PsLogFileList},
+ {"LogFileGet", PsLogFileGet},
+ {"HubCreate", PsHubCreate},
+ {"HubCreateDynamic", PsHubCreateDynamic},
+ {"HubCreateStatic", PsHubCreateStatic},
+ {"HubDelete", PsHubDelete},
+ {"HubSetStatic", PsHubSetStatic},
+ {"HubSetDynamic", PsHubSetDynamic},
+ {"HubList", PsHubList},
+ {"Hub", PsHub},
+ {"Online", PsOnline},
+ {"Offline", PsOffline},
+ {"SetMaxSession", PsSetMaxSession},
+ {"SetHubPassword", PsSetHubPassword},
+ {"SetEnumAllow", PsSetEnumAllow},
+ {"SetEnumDeny", PsSetEnumDeny},
+ {"OptionsGet", PsOptionsGet},
+ {"RadiusServerSet", PsRadiusServerSet},
+ {"RadiusServerDelete", PsRadiusServerDelete},
+ {"RadiusServerGet", PsRadiusServerGet},
+ {"StatusGet", PsStatusGet},
+ {"LogGet", PsLogGet},
+ {"LogEnable", PsLogEnable},
+ {"LogDisable", PsLogDisable},
+ {"LogSwitchSet", PsLogSwitchSet},
+ {"LogPacketSaveType", PsLogPacketSaveType},
+ {"CAList", PsCAList},
+ {"CAAdd", PsCAAdd},
+ {"CADelete", PsCADelete},
+ {"CAGet", PsCAGet},
+ {"CascadeList", PsCascadeList},
+ {"CascadeCreate", PsCascadeCreate},
+ {"CascadeSet", PsCascadeSet},
+ {"CascadeGet", PsCascadeGet},
+ {"CascadeDelete", PsCascadeDelete},
+ {"CascadeUsernameSet", PsCascadeUsernameSet},
+ {"CascadeAnonymousSet", PsCascadeAnonymousSet},
+ {"CascadePasswordSet", PsCascadePasswordSet},
+ {"CascadeCertSet", PsCascadeCertSet},
+ {"CascadeCertGet", PsCascadeCertGet},
+ {"CascadeEncryptEnable", PsCascadeEncryptEnable},
+ {"CascadeEncryptDisable", PsCascadeEncryptDisable},
+ {"CascadeCompressEnable", PsCascadeCompressEnable},
+ {"CascadeCompressDisable", PsCascadeCompressDisable},
+ {"CascadeProxyNone", PsCascadeProxyNone},
+ {"CascadeProxyHttp", PsCascadeProxyHttp},
+ {"CascadeProxySocks", PsCascadeProxySocks},
+ {"CascadeServerCertEnable", PsCascadeServerCertEnable},
+ {"CascadeServerCertDisable", PsCascadeServerCertDisable},
+ {"CascadeServerCertSet", PsCascadeServerCertSet},
+ {"CascadeServerCertDelete", PsCascadeServerCertDelete},
+ {"CascadeServerCertGet", PsCascadeServerCertGet},
+ {"CascadeDetailSet", PsCascadeDetailSet},
+ {"CascadePolicySet", PsCascadePolicySet},
+ {"PolicyList", PsPolicyList},
+ {"CascadeStatusGet", PsCascadeStatusGet},
+ {"CascadeRename", PsCascadeRename},
+ {"CascadeOnline", PsCascadeOnline},
+ {"CascadeOffline", PsCascadeOffline},
+ {"AccessAdd", PsAccessAdd},
+ {"AccessAddEx", PsAccessAddEx},
+ {"AccessAdd6", PsAccessAdd6},
+ {"AccessAddEx6", PsAccessAddEx6},
+ {"AccessList", PsAccessList},
+ {"AccessDelete", PsAccessDelete},
+ {"AccessEnable", PsAccessEnable},
+ {"AccessDisable", PsAccessDisable},
+ {"UserList", PsUserList},
+ {"UserCreate", PsUserCreate},
+ {"UserSet", PsUserSet},
+ {"UserDelete", PsUserDelete},
+ {"UserGet", PsUserGet},
+ {"UserAnonymousSet", PsUserAnonymousSet},
+ {"UserPasswordSet", PsUserPasswordSet},
+ {"UserCertSet", PsUserCertSet},
+ {"UserCertGet", PsUserCertGet},
+ {"UserSignedSet", PsUserSignedSet},
+ {"UserRadiusSet", PsUserRadiusSet},
+ {"UserNTLMSet", PsUserNTLMSet},
+ {"UserPolicyRemove", PsUserPolicyRemove},
+ {"UserPolicySet", PsUserPolicySet},
+ {"UserExpiresSet", PsUserExpiresSet},
+ {"GroupList", PsGroupList},
+ {"GroupCreate", PsGroupCreate},
+ {"GroupSet", PsGroupSet},
+ {"GroupDelete", PsGroupDelete},
+ {"GroupGet", PsGroupGet},
+ {"GroupJoin", PsGroupJoin},
+ {"GroupUnjoin", PsGroupUnjoin},
+ {"GroupPolicyRemove", PsGroupPolicyRemove},
+ {"GroupPolicySet", PsGroupPolicySet},
+ {"SessionList", PsSessionList},
+ {"SessionGet", PsSessionGet},
+ {"SessionDisconnect", PsSessionDisconnect},
+ {"MacTable", PsMacTable},
+ {"MacDelete", PsMacDelete},
+ {"IpTable", PsIpTable},
+ {"IpDelete", PsIpDelete},
+ {"SecureNatEnable", PsSecureNatEnable},
+ {"SecureNatDisable", PsSecureNatDisable},
+ {"SecureNatStatusGet", PsSecureNatStatusGet},
+ {"SecureNatHostGet", PsSecureNatHostGet},
+ {"SecureNatHostSet", PsSecureNatHostSet},
+ {"NatGet", PsNatGet},
+ {"NatEnable", PsNatEnable},
+ {"NatDisable", PsNatDisable},
+ {"NatSet", PsNatSet},
+ {"NatTable", PsNatTable},
+ {"DhcpGet", PsDhcpGet},
+ {"DhcpEnable", PsDhcpEnable},
+ {"DhcpDisable", PsDhcpDisable},
+ {"DhcpSet", PsDhcpSet},
+ {"DhcpTable", PsDhcpTable},
+ {"AdminOptionList", PsAdminOptionList},
+ {"AdminOptionSet", PsAdminOptionSet},
+ {"ExtOptionList", PsExtOptionList},
+ {"ExtOptionSet", PsExtOptionSet},
+ {"CrlList", PsCrlList},
+ {"CrlAdd", PsCrlAdd},
+ {"CrlDel", PsCrlDel},
+ {"CrlGet", PsCrlGet},
+ {"AcList", PsAcList},
+ {"AcAdd", PsAcAdd},
+ {"AcAdd6", PsAcAdd6},
+ {"AcDel", PsAcDel},
+ {"MakeCert", PtMakeCert},
+ {"TrafficClient", PtTrafficClient},
+ {"TrafficServer", PtTrafficServer},
+ {"LicenseAdd", PsLicenseAdd},
+ {"LicenseDel", PsLicenseDel},
+ {"LicenseList", PsLicenseList},
+ {"LicenseStatus", PsLicenseStatus},
+ {"IPsecEnable", PsIPsecEnable},
+ {"IPsecGet", PsIPsecGet},
+ {"EtherIpClientAdd", PsEtherIpClientAdd},
+ {"EtherIpClientDelete", PsEtherIpClientDelete},
+ {"EtherIpClientList", PsEtherIpClientList},
+ {"OpenVpnEnable", PsOpenVpnEnable},
+ {"OpenVpnGet", PsOpenVpnGet},
+ {"OpenVpnMakeConfig", PsOpenVpnMakeConfig},
+ {"SstpEnable", PsSstpEnable},
+ {"SstpGet", PsSstpGet},
+ {"ServerCertRegenerate", PsServerCertRegenerate},
+ {"VpnOverIcmpDnsEnable", PsVpnOverIcmpDnsEnable},
+ {"VpnOverIcmpDnsGet", PsVpnOverIcmpDnsGet},
+ {"DynamicDnsGetStatus", PsDynamicDnsGetStatus},
+ {"DynamicDnsSetHostname", PsDynamicDnsSetHostname},
+ {"VpnAzureGetStatus", PsVpnAzureGetStatus},
+ {"VpnAzureSetEnable", PsVpnAzureSetEnable},
+ };
+
+ // Generate a prompt
+ if (ps->HubName == NULL)
+ {
+ Format(prompt, sizeof(prompt), "VPN Server>");
+ }
+ else
+ {
+ Format(prompt, sizeof(prompt), "VPN Server/%s>", ps->HubName);
+ }
+
+ if (DispatchNextCmdEx(ps->Console, ps->CmdLine, prompt, cmd, sizeof(cmd) / sizeof(cmd[0]), ps) == false)
+ {
+ break;
+ }
+ ps->LastError = ps->Console->RetCode;
+
+ if (ps->LastError == ERR_NO_ERROR && ps->Console->ConsoleType != CONSOLE_CSV)
+ {
+ ps->Console->Write(ps->Console, _UU("CMD_MSG_OK"));
+ ps->Console->Write(ps->Console, L"");
+ }
+
+ if (ps->CmdLine != NULL)
+ {
+ break;
+ }
+ }
+
+ // Release the Caps
+ FreeCapsList(ps->CapsList);
+ ps->CapsList = NULL;
+}
+
+// A template for a new command function
+UINT PsXxx(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_LISTENER t;
+ PARAM args[] =
+ {
+ {"[port]", CmdPromptPort, _UU("CMD_ListenerCreate_PortPrompt"), CmdEvalPort, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.Enable = true;
+ t.Port = ToInt(GetParamStr(o, "[port]"));
+
+ ret = ScCreateListener(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set to the stand-alone mode
+UINT PsClusterSettingStandalone(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_FARM t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.ServerType = SERVER_TYPE_STANDALONE;
+
+ // RPC call
+ ret = ScSetFarmSetting(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set to the cluster controller mode
+UINT PsClusterSettingController(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_FARM t;
+ UINT weight;
+ PARAM args[] =
+ {
+ {"WEIGHT", NULL, NULL, NULL, NULL},
+ {"ONLY", NULL, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ weight = GetParamInt(o, "WEIGHT");
+ if (weight == 0)
+ {
+ weight = FARM_DEFAULT_WEIGHT;
+ }
+
+ Zero(&t, sizeof(t));
+ t.ServerType = SERVER_TYPE_FARM_CONTROLLER;
+ t.Weight = weight;
+ t.ControllerOnly = GetParamYes(o, "ONLY");
+
+ // RPC call
+ ret = ScSetFarmSetting(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Evaluate the IP address
+bool CmdEvalIp(CONSOLE *c, wchar_t *str, void *param)
+{
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ if (UniIsEmptyStr(str))
+ {
+ return true;
+ }
+
+ if (UniStrToIP32(str) == 0 && UniStrCmpi(str, L"0.0.0.0") != 0)
+ {
+ wchar_t *msg = (param == NULL) ? _UU("CMD_IP_EVAL_FAILED") : (wchar_t *)param;
+ c->Write(c, msg);
+ return false;
+ }
+
+ return true;
+}
+
+// Convert a string to port list
+LIST *StrToPortList(char *str)
+{
+ LIST *o;
+ TOKEN_LIST *t;
+ UINT i;
+ if (str == NULL)
+ {
+ return NULL;
+ }
+
+ // Convert to token
+ t = ParseToken(str, ", ");
+ if (t == NULL)
+ {
+ return NULL;
+ }
+ if (t->NumTokens == 0)
+ {
+ FreeToken(t);
+ return NULL;
+ }
+
+ o = NewListFast(NULL);
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ char *s = t->Token[i];
+ UINT n;
+ if (IsNum(s) == false)
+ {
+ ReleaseList(o);
+ FreeToken(t);
+ return NULL;
+ }
+ n = ToInt(s);
+ if (n == 0 || n >= 65536)
+ {
+ ReleaseList(o);
+ FreeToken(t);
+ return NULL;
+ }
+ if (IsInList(o, (void *)n))
+ {
+ ReleaseList(o);
+ FreeToken(t);
+ return NULL;
+ }
+ Add(o, (void *)n);
+ }
+
+ FreeToken(t);
+
+ if (LIST_NUM(o) > MAX_PUBLIC_PORT_NUM)
+ {
+ ReleaseList(o);
+ return NULL;
+ }
+
+ return o;
+}
+
+// Set to the cluster member mode
+UINT PsClusterSettingMember(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_FARM t;
+ char *host_and_port;
+ char *host;
+ UINT port;
+ UINT weight;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[server:port]", CmdPrompt, _UU("CMD_ClusterSettingMember_Prompt_HOST_1"), CmdEvalHostAndPort, NULL},
+ {"IP", PsClusterSettingMemberPromptIp, NULL, CmdEvalIp, NULL},
+ {"PORTS", PsClusterSettingMemberPromptPorts, NULL, CmdEvalPortList, NULL},
+ {"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+ {"WEIGHT", NULL, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ weight = GetParamInt(o, "WEIGHT");
+
+ if (weight == 0)
+ {
+ weight = FARM_DEFAULT_WEIGHT;
+ }
+
+ Zero(&t, sizeof(t));
+ host_and_port = GetParamStr(o, "[server:port]");
+ if (ParseHostPort(host_and_port, &host, &port, 0))
+ {
+ char *pw;
+ char *ports_str;
+ LIST *ports;
+ UINT i;
+
+ StrCpy(t.ControllerName, sizeof(t.ControllerName), host);
+ t.ControllerPort = port;
+ Free(host);
+
+ pw = GetParamStr(o, "PASSWORD");
+
+ Hash(t.MemberPassword, pw, StrLen(pw), true);
+ t.PublicIp = StrToIP32(GetParamStr(o, "IP"));
+ t.ServerType = SERVER_TYPE_FARM_MEMBER;
+
+ ports_str = GetParamStr(o, "PORTS");
+
+ ports = StrToPortList(ports_str);
+
+ t.NumPort = LIST_NUM(ports);
+ t.Ports = ZeroMalloc(sizeof(UINT) * t.NumPort);
+
+ for (i = 0;i < t.NumPort;i++)
+ {
+ t.Ports[i] = (UINT)LIST_DATA(ports, i);
+ }
+
+ t.Weight = weight;
+
+ ReleaseList(ports);
+
+ // RPC call
+ ret = ScSetFarmSetting(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcFarm(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Evaluate the port list
+bool CmdEvalPortList(CONSOLE *c, wchar_t *str, void *param)
+{
+ char *s;
+ bool ret = false;
+ LIST *o;
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ s = CopyUniToStr(str);
+
+ o = StrToPortList(s);
+
+ if (o != NULL)
+ {
+ ret = true;
+ }
+
+ ReleaseList(o);
+
+ Free(s);
+
+ if (ret == false)
+ {
+ c->Write(c, _UU("CMD_PORTLIST_EVAL_FAILED"));
+ }
+
+ return ret;
+}
+
+// Check the string of the form of the host name and port number
+bool CmdEvalHostAndPort(CONSOLE *c, wchar_t *str, void *param)
+{
+ char *tmp;
+ bool ret = false;
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ tmp = CopyUniToStr(str);
+
+ ret = ParseHostPort(tmp, NULL, NULL, (UINT)param);
+
+ if (ret == false)
+ {
+ c->Write(c, param == NULL ? _UU("CMD_HOSTPORT_EVAL_FAILED") : (wchar_t *)param);
+ }
+
+ Free(tmp);
+
+ return ret;
+}
+
+// Input the public port number
+wchar_t *PsClusterSettingMemberPromptPorts(CONSOLE *c, void *param)
+{
+ wchar_t *ret;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ c->Write(c, _UU("CMD_ClusterSettingMember_Prompt_PORT_1"));
+ c->Write(c, L"");
+
+ ret = c->ReadLine(c, _UU("CMD_ClusterSettingMember_Prompt_PORT_2"), true);
+
+ return ret;
+}
+
+// Input the public IP address
+wchar_t *PsClusterSettingMemberPromptIp(CONSOLE *c, void *param)
+{
+ wchar_t *ret;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ c->Write(c, _UU("CMD_ClusterSettingMember_Prompt_IP_1"));
+ c->Write(c, L"");
+
+ ret = c->ReadLine(c, _UU("CMD_ClusterSettingMember_Prompt_IP_2"), true);
+
+ return ret;
+}
+
+// Show the cluster members list
+UINT PsClusterMemberList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_FARM t;
+ CT *ct;
+ UINT i;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScEnumFarmMember(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNew();
+
+ CtInsertColumn(ct, _UU("CMD_ID"), true);
+ CtInsertColumn(ct, _UU("SM_FM_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_FM_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_FM_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_FM_COLUMN_4"), true);
+ CtInsertColumn(ct, _UU("SM_FM_COLUMN_5"), true);
+ CtInsertColumn(ct, _UU("SM_FM_COLUMN_6"), true);
+ CtInsertColumn(ct, _UU("SM_FM_COLUMN_7"), true);
+ CtInsertColumn(ct, _UU("SM_FM_COLUMN_8"), true);
+ CtInsertColumn(ct, _UU("SM_FM_COLUMN_9"), true);
+
+ for (i = 0;i < t.NumFarm;i++)
+ {
+ RPC_ENUM_FARM_ITEM *e = &t.Farms[i];
+ wchar_t tmp0[64];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[64];
+ wchar_t tmp4[64];
+ wchar_t tmp5[64];
+ wchar_t tmp6[64];
+ wchar_t tmp7[64];
+ wchar_t tmp8[64];
+
+ GetDateTimeStrEx64(tmp1, sizeof(tmp1), SystemToLocal64(e->ConnectedTime), NULL);
+ StrToUni(tmp2, sizeof(tmp2), e->Hostname);
+ UniToStru(tmp3, e->Point);
+ UniToStru(tmp4, e->NumSessions);
+ UniToStru(tmp5, e->NumTcpConnections);
+ UniToStru(tmp6, e->NumHubs);
+ UniToStru(tmp7, e->AssignedClientLicense);
+ UniToStru(tmp8, e->AssignedBridgeLicense);
+
+ UniToStru(tmp0, e->Id);
+
+ CtInsert(ct, tmp0,
+ e->Controller ? _UU("SM_FM_CONTROLLER") : _UU("SM_FM_MEMBER"),
+ tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8);
+ }
+
+ CtFree(ct, c);
+
+ FreeRpcEnumFarm(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get information of cluster members
+UINT PsClusterMemberInfoGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_FARM_INFO t;
+ CT *ct;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_ClusterMemberInfoGet_PROMPT_ID"), NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.Id = UniToInt(GetParamUniStr(o, "[id]"));
+
+ // RPC call
+ ret = ScGetFarmInfo(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNewStandard();
+
+ {
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+ UINT i;
+
+ CtInsert(ct, _UU("SM_FMINFO_TYPE"),
+ t.Controller ? _UU("SM_FARM_CONTROLLER") : _UU("SM_FARM_MEMBER"));
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.ConnectedTime), NULL);
+ CtInsert(ct, _UU("SM_FMINFO_CONNECT_TIME"), tmp);
+
+ IPToStr32(str, sizeof(str), t.Ip);
+ StrToUni(tmp, sizeof(tmp), str);
+ CtInsert(ct, _UU("SM_FMINFO_IP"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.Hostname);
+ CtInsert(ct, _UU("SM_FMINFO_HOSTNAME"), tmp);
+
+ UniToStru(tmp, t.Point);
+ CtInsert(ct, _UU("SM_FMINFO_POINT"), tmp);
+
+ UniToStru(tmp, t.Weight);
+ CtInsert(ct, _UU("SM_FMINFO_WEIGHT"), tmp);
+
+ UniToStru(tmp, t.NumPort);
+ CtInsert(ct, _UU("SM_FMINFO_NUM_PORT"), tmp);
+
+ for (i = 0;i < t.NumPort;i++)
+ {
+ wchar_t tmp2[MAX_SIZE];
+ UniFormat(tmp, sizeof(tmp), _UU("SM_FMINFO_PORT"), i + 1);
+ UniToStru(tmp2, t.Ports[i]);
+ CtInsert(ct, tmp, tmp2);
+ }
+
+ UniToStru(tmp, t.NumFarmHub);
+ CtInsert(ct, _UU("SM_FMINFO_NUM_HUB"), tmp);
+
+ for (i = 0;i < t.NumFarmHub;i++)
+ {
+ wchar_t tmp2[MAX_SIZE];
+ UniFormat(tmp, sizeof(tmp), _UU("SM_FMINFO_HUB"), i + 1);
+ UniFormat(tmp2, sizeof(tmp2),
+ t.FarmHubs[i].DynamicHub ? _UU("SM_FMINFO_HUB_TAG_2") : _UU("SM_FMINFO_HUB_TAG_1"),
+ t.FarmHubs[i].HubName);
+ CtInsert(ct, tmp, tmp2);
+ }
+
+ UniToStru(tmp, t.NumSessions);
+ CtInsert(ct, _UU("SM_FMINFO_NUM_SESSION"), tmp);
+
+ UniToStru(tmp, t.NumTcpConnections);
+ CtInsert(ct, _UU("SM_FMINFO_NUN_CONNECTION"), tmp);
+ }
+
+ CtFree(ct, c);
+
+ FreeRpcFarmInfo(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get certificates of cluster members
+UINT PsClusterMemberCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_FARM_INFO t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_ClusterMemberCertGet_PROMPT_ID"), NULL, NULL},
+ {"SAVECERT", CmdPrompt, _UU("CMD_SAVECERTPATH"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ t.Id = UniToInt(GetParamUniStr(o, "[id]"));
+
+ // RPC call
+ ret = ScGetFarmInfo(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ X *x = t.ServerCert;
+ wchar_t *filename = GetParamUniStr(o, "SAVECERT");
+
+ if (XToFileW(x, filename, true) == false)
+ {
+ c->Write(c, _UU("CMD_SAVECERT_FAILED"));
+
+ ret = ERR_INTERNAL_ERROR;
+ }
+ }
+
+ FreeRpcFarmInfo(&t);
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the status of the connection to the cluster controller
+UINT PsClusterConnectionStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_FARM_CONNECTION_STATUS t;
+ wchar_t tmp[MAX_SIZE];
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetFarmConnectionStatus(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNewStandard();
+ char str[MAX_SIZE];
+
+ if (t.Online == false)
+ {
+ CtInsert(ct, _UU("SM_FC_IP"), _UU("SM_FC_NOT_CONNECTED"));
+
+ CtInsert(ct, _UU("SM_FC_PORT"), _UU("SM_FC_NOT_CONNECTED"));
+ }
+ else
+ {
+ IPToStr32(str, sizeof(str), t.Ip);
+ StrToUni(tmp, sizeof(tmp), str);
+ CtInsert(ct, _UU("SM_FC_IP"), tmp);
+
+ UniToStru(tmp, t.Port);
+ CtInsert(ct, _UU("SM_FC_PORT"), tmp);
+ }
+
+ CtInsert(ct,
+ _UU("SM_FC_STATUS"),
+ t.Online ? _UU("SM_FC_ONLINE") : _UU("SM_FC_OFFLINE"));
+
+ if (t.Online == false)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SM_FC_ERROR_TAG"), _E(t.LastError), t.LastError);
+ CtInsert(ct,
+ _UU("SM_FC_LAST_ERROR"), tmp);
+ }
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.StartedTime), NULL);
+ CtInsert(ct, _UU("SM_FC_START_TIME"), tmp);
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.FirstConnectedTime), NULL);
+ CtInsert(ct, _UU("SM_FC_FIRST_TIME"), tmp);
+
+ //if (t.Online == false)
+ {
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.CurrentConnectedTime), NULL);
+ CtInsert(ct, _UU("SM_FC_CURRENT_TIME"), tmp);
+ }
+
+ UniToStru(tmp, t.NumTry);
+ CtInsert(ct, _UU("SM_FC_NUM_TRY"), tmp);
+
+ UniToStru(tmp, t.NumConnected);
+ CtInsert(ct, _UU("SM_FC_NUM_CONNECTED"), tmp);
+
+ UniToStru(tmp, t.NumFailed);
+ CtInsert(ct, _UU("SM_FC_NUM_FAILED"), tmp);
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the SSL certificate of the VPN Server
+UINT PsServerCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_KEY_PAIR t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[cert]", CmdPrompt, _UU("CMD_SAVECERTPATH"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetServerCert(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ if (XToFileW(t.Cert, GetParamUniStr(o, "[cert]"), true) == false)
+ {
+ c->Write(c, _UU("CMD_SAVECERT_FAILED"));
+ }
+
+ FreeRpcKeyPair(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the private key of the SSL certificate of the VPN Server
+UINT PsServerKeyGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_KEY_PAIR t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[key]", CmdPrompt, _UU("CMD_SAVEKEYPATH"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetServerCert(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ if (t.Key != NULL)
+ {
+ if (KToFileW(t.Key, GetParamUniStr(o, "[key]"), true, NULL) == false)
+ {
+ c->Write(c, _UU("CMD_SAVEKEY_FAILED"));
+ }
+ }
+ else
+ {
+ ret = ERR_NOT_ENOUGH_RIGHT;
+ CmdPrintError(c, ret);
+ }
+
+ FreeRpcKeyPair(&t);
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Read the certificate and the private key
+bool CmdLoadCertAndKey(CONSOLE *c, X **xx, K **kk, wchar_t *cert_filename, wchar_t *key_filename)
+{
+ X *x;
+ K *k;
+ // Validate arguments
+ if (c == NULL || cert_filename == NULL || key_filename == NULL || xx == NULL || kk == NULL)
+ {
+ return false;
+ }
+
+ x = FileToXW(cert_filename);
+ if (x == NULL)
+ {
+ c->Write(c, _UU("CMD_LOADCERT_FAILED"));
+ return false;
+ }
+
+ k = CmdLoadKey(c, key_filename);
+ if (k == NULL)
+ {
+ c->Write(c, _UU("CMD_LOADKEY_FAILED"));
+ FreeX(x);
+ return false;
+ }
+
+ if (CheckXandK(x, k) == false)
+ {
+ c->Write(c, _UU("CMD_KEYPAIR_FAILED"));
+ FreeX(x);
+ FreeK(k);
+
+ return false;
+ }
+
+ *xx = x;
+ *kk = k;
+
+ return true;
+}
+
+// Read the secret key
+K *CmdLoadKey(CONSOLE *c, wchar_t *filename)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || filename == NULL)
+ {
+ return NULL;
+ }
+
+ b = ReadDumpW(filename);
+ if (b == NULL)
+ {
+ c->Write(c, _UU("CMD_LOADCERT_FAILED"));
+ return NULL;
+ }
+ else
+ {
+ K *key;
+ if (IsEncryptedK(b, true) == false)
+ {
+ key = BufToK(b, true, IsBase64(b), NULL);
+ }
+ else
+ {
+ c->Write(c, _UU("CMD_LOADKEY_ENCRYPTED_1"));
+
+ while (true)
+ {
+ char *pass = c->ReadPassword(c, _UU("CMD_LOADKEY_ENCRYPTED_2"));
+
+ if (pass == NULL)
+ {
+ FreeBuf(b);
+ return NULL;
+ }
+
+ key = BufToK(b, true, IsBase64(b), pass);
+ Free(pass);
+
+ if (key != NULL)
+ {
+ break;
+ }
+
+ c->Write(c, _UU("CMD_LOADKEY_ENCRYPTED_3"));
+ }
+ }
+
+ FreeBuf(b);
+
+ return key;
+ }
+}
+
+// Set the SSL certificate and the private key of the VPN Server
+UINT PsServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_KEY_PAIR t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL},
+ {"LOADKEY", CmdPrompt, _UU("CMD_LOADKEYPATH"), CmdEvalIsFile, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ if (CmdLoadCertAndKey(c, &t.Cert, &t.Key,
+ GetParamUniStr(o, "LOADCERT"),
+ GetParamUniStr(o, "LOADKEY")))
+ {
+ // RPC call
+ ret = ScSetServerCert(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcKeyPair(&t);
+ }
+ else
+ {
+ ret = ERR_INTERNAL_ERROR;
+ }
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the encryption algorithm used for the VPN communication
+UINT PsServerCipherGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_STR t;
+ TOKEN_LIST *ciphers;
+ UINT i;
+ wchar_t tmp[MAX_SIZE];
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetServerCipher(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ciphers = GetCipherList();
+
+ c->Write(c, _UU("CMD_ServerCipherGet_SERVER"));
+
+ UniFormat(tmp, sizeof(tmp), L" %S", t.String);
+ c->Write(c, tmp);
+
+ c->Write(c, L"");
+ c->Write(c, _UU("CMD_ServerCipherGet_CIPHERS"));
+
+ for (i = 0;i < ciphers->NumTokens;i++)
+ {
+ UniFormat(tmp, sizeof(tmp), L" %S", ciphers->Token[i]);
+ c->Write(c, tmp);
+ }
+
+ FreeRpcStr(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the encryption algorithm used for the VPN communication
+UINT PsServerCipherSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_STR t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_ServerCipherSet_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.String = CopyStr(GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScSetServerCipher(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcStr(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enabling the maintenance function of the Internet connection
+UINT PsKeepEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_KEEP t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetKeep(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ t.UseKeepConnect = true;
+
+ ret = ScSetKeep(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disabling the maintenance function of the Internet connection
+UINT PsKeepDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_KEEP t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetKeep(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ t.UseKeepConnect = false;
+
+ ret = ScSetKeep(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Evaluate the UDP or the TCP
+bool CmdEvalTcpOrUdp(CONSOLE *c, wchar_t *str, void *param)
+{
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ if (UniStrCmpi(str, L"tcp") == 0 || UniStrCmpi(str, L"udp") == 0)
+ {
+ return true;
+ }
+
+ c->Write(c, _UU("CMD_KeepSet_EVAL_TCP_UDP"));
+
+ return false;
+}
+
+// Enable the syslog configuration
+UINT PsSyslogEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ SYSLOG_SETTING t;
+ CMD_EVAL_MIN_MAX minmax = {"CMD_SyslogEnable_MINMAX", 1, 3};
+ char *host;
+ UINT port;
+
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[1|2|3]", CmdPrompt, _UU("CMD_SyslogEnable_Prompt_123"), CmdEvalMinMax, &minmax},
+ {"HOST", CmdPrompt, _UU("CMD_SyslogEnable_Prompt_HOST"), CmdEvalHostAndPort, (void *)SYSLOG_PORT},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ if (ParseHostPort(GetParamStr(o, "HOST"), &host, &port, SYSLOG_PORT))
+ {
+ StrCpy(t.Hostname, sizeof(t.Hostname), host);
+ t.Port = port;
+ t.SaveType = GetParamInt(o, "[1|2|3]");
+
+ Free(host);
+
+ // RPC call
+ ret = ScSetSysLog(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disable the syslog configuration
+UINT PsSyslogDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ SYSLOG_SETTING t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetSysLog(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ t.SaveType = SYSLOG_NONE;
+
+ // RPC call
+ ret = ScSetSysLog(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the syslog configuration
+UINT PsSyslogGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ SYSLOG_SETTING t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetSysLog(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ CT *ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_SyslogGet_COLUMN_1"), GetSyslogSettingName(t.SaveType));
+
+ if (t.SaveType != SYSLOG_NONE)
+ {
+ StrToUni(tmp, sizeof(tmp), t.Hostname);
+ CtInsert(ct, _UU("CMD_SyslogGet_COLUMN_2"), tmp);
+
+ UniToStru(tmp, t.Port);
+ CtInsert(ct, _UU("CMD_SyslogGet_COLUMN_3"), tmp);
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the syslog configuration name
+wchar_t *GetSyslogSettingName(UINT n)
+{
+ char tmp[MAX_PATH];
+
+ Format(tmp, sizeof(tmp), "SM_SYSLOG_%u", n);
+
+ return _UU(tmp);
+}
+
+// Setting of maintenance function of the Internet connection
+UINT PsKeepSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_KEEP t;
+ char *host;
+ UINT port;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"HOST", CmdPrompt, _UU("CMD_KeepSet_PROMPT_HOST"), CmdEvalHostAndPort, NULL},
+ {"PROTOCOL", CmdPrompt, _UU("CMD_KeepSet_PROMPT_PROTOCOL"), CmdEvalTcpOrUdp, NULL},
+ {"INTERVAL", CmdPrompt, _UU("CMD_KeepSet_PROMPT_INTERVAL"), NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetKeep(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ if (ParseHostPort(GetParamStr(o, "HOST"), &host, &port, 0))
+ {
+ StrCpy(t.KeepConnectHost, sizeof(t.KeepConnectHost), host);
+ t.KeepConnectPort = port;
+ t.KeepConnectInterval = GetParamInt(o, "INTERVAL");
+ t.KeepConnectProtocol = (StrCmpi(GetParamStr(o, "PROTOCOL"), "tcp") == 0) ? 0 : 1;
+ Free(host);
+
+ // RPC call
+ ret = ScSetKeep(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the maintenance function of the Internet connection
+UINT PsKeepGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_KEEP t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetKeep(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ CT *ct = CtNewStandard();
+
+ StrToUni(tmp, sizeof(tmp), t.KeepConnectHost);
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_1"), tmp);
+
+ UniToStru(tmp, t.KeepConnectPort);
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_2"), tmp);
+
+ UniToStru(tmp, t.KeepConnectInterval);
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_3"), tmp);
+
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_4"),
+ t.KeepConnectProtocol == 0 ? L"TCP/IP" : L"UDP/IP");
+
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_5"),
+ t.UseKeepConnect ? _UU("SM_ACCESS_ENABLE") : _UU("SM_ACCESS_DISABLE"));
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the connection type string
+wchar_t *GetConnectionTypeStr(UINT type)
+{
+ char tmp[MAX_SIZE];
+ Format(tmp, sizeof(tmp), "SM_CONNECTION_TYPE_%u", type);
+
+ return _UU(tmp);
+}
+
+// Get the list of TCP connections connected to VPN Server
+UINT PsConnectionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_CONNECTION t;
+ UINT i;
+ CT *ct;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScEnumConnection(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNew();
+ CtInsertColumn(ct, _UU("SM_CONN_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_CONN_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_CONN_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_CONN_COLUMN_4"), false);
+
+ for (i = 0;i < t.NumConnection;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ wchar_t name[MAX_SIZE];
+ wchar_t datetime[MAX_SIZE];
+ RPC_ENUM_CONNECTION_ITEM *e = &t.Connections[i];
+
+ StrToUni(name, sizeof(name), e->Name);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_HOSTNAME_AND_PORT"), e->Hostname, e->Port);
+ GetDateTimeStrEx64(datetime, sizeof(datetime), SystemToLocal64(e->ConnectedTime), NULL);
+
+ CtInsert(ct, name, tmp, datetime,
+ GetConnectionTypeStr(e->Type));
+ }
+
+ CtFree(ct, c);
+
+ FreeRpcEnumConnetion(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the TCP connection information currently connected to the VPN Server
+UINT PsConnectionGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CONNECTION_INFO t;
+ CT *ct;
+ wchar_t tmp[MAX_SIZE];
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_ConnectionGet_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetConnectionInfo(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ ct = CtNewStandard();
+
+ StrToUni(tmp, sizeof(tmp), t.Name);
+ CtInsert(ct, _UU("SM_CONNINFO_NAME"), tmp);
+
+ CtInsert(ct, _UU("SM_CONNINFO_TYPE"), GetConnectionTypeStr(t.Type));
+
+ StrToUni(tmp, sizeof(tmp), t.Hostname);
+ CtInsert(ct, _UU("SM_CONNINFO_HOSTNAME"), tmp);
+
+ UniToStru(tmp, t.Port);
+ CtInsert(ct, _UU("SM_CONNINFO_PORT"), tmp);
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.ConnectedTime), NULL);
+ CtInsert(ct, _UU("SM_CONNINFO_TIME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.ServerStr);
+ CtInsert(ct, _UU("SM_CONNINFO_SERVER_STR"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), L"%u.%02u", t.ServerVer / 100, t.ServerVer % 100);
+ CtInsert(ct, _UU("SM_CONNINFO_SERVER_VER"), tmp);
+
+ UniToStru(tmp, t.ServerBuild);
+ CtInsert(ct, _UU("SM_CONNINFO_SERVER_BUILD"), tmp);
+
+ if (StrLen(t.ClientStr) != 0)
+ {
+ StrToUni(tmp, sizeof(tmp), t.ClientStr);
+ CtInsert(ct, _UU("SM_CONNINFO_CLIENT_STR"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), L"%u.%02u", t.ClientVer / 100, t.ClientVer % 100);
+ CtInsert(ct, _UU("SM_CONNINFO_CLIENT_VER"), tmp);
+
+ UniToStru(tmp, t.ClientBuild);
+ CtInsert(ct, _UU("SM_CONNINFO_CLIENT_BUILD"), tmp);
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disconnect the TCP connection connected to the VPN Server
+UINT PsConnectionDisconnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_DISCONNECT_CONNECTION t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_ConnectionDisconnect_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScDisconnectConnection(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the LAN card list that can be used for local bridge
+UINT PsBridgeDeviceList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_ETH t;
+ UINT i;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScEnumEthernet(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_ETH_ITEM *item = &t.Items[i];
+ wchar_t tmp[MAX_SIZE * 2];
+
+ StrToUni(tmp, sizeof(tmp), item->DeviceName);
+ c->Write(c, tmp);
+ }
+
+ FreeRpcEnumEth(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the list of local bridge connection
+UINT PsBridgeList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_LOCALBRIDGE t;
+ UINT i;
+ CT *ct;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScEnumLocalBridge(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNew();
+
+ CtInsertColumn(ct, _UU("SM_BRIDGE_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_BRIDGE_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_BRIDGE_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_BRIDGE_COLUMN_4"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_LOCALBRIDGE *e = &t.Items[i];
+ wchar_t name[MAX_SIZE];
+ wchar_t nic[MAX_SIZE];
+ wchar_t hub[MAX_SIZE];
+ wchar_t *status = _UU("SM_BRIDGE_OFFLINE");
+
+ UniToStru(name, i + 1);
+ StrToUni(nic, sizeof(nic), e->DeviceName);
+ StrToUni(hub, sizeof(hub), e->HubName);
+
+ if (e->Online)
+ {
+ status = e->Active ? _UU("SM_BRIDGE_ONLINE") : _UU("SM_BRIDGE_ERROR");
+ }
+
+ CtInsert(ct, name, hub, nic, status);
+ }
+
+ CtFree(ct, c);
+
+ FreeRpcEnumLocalBridge(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Create a local bridge connection
+UINT PsBridgeCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_LOCALBRIDGE t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[hubname]", CmdPrompt, _UU("CMD_BridgeCreate_PROMPT_HUBNAME"), CmdEvalNotEmpty, NULL},
+ {"DEVICE", CmdPrompt, _UU("CMD_BridgeCreate_PROMPT_DEVICE"), CmdEvalNotEmpty, NULL},
+ {"TAP", NULL, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ t.Active = true;
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "DEVICE"));
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[hubname]"));
+ t.Online = true;
+ t.TapMode = GetParamYes(o, "TAP");
+
+ // RPC call
+ ret = ScAddLocalBridge(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ c->Write(c, _UU("SM_BRIDGE_INTEL"));
+ c->Write(c, L"");
+
+ if (GetCapsBool(ps->CapsList, "b_is_in_vm"))
+ {
+ // Message in the case of operating in a VM
+ c->Write(c, _UU("D_SM_VMBRIDGE@CAPTION"));
+ c->Write(c, _UU("D_SM_VMBRIDGE@S_1"));
+ c->Write(c, _UU("D_SM_VMBRIDGE@S_2"));
+ c->Write(c, L"");
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the local bridge connection
+UINT PsBridgeDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_LOCALBRIDGE t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[hubname]", CmdPrompt, _UU("CMD_BridgeDelete_PROMPT_HUBNAME"), CmdEvalNotEmpty, NULL},
+ {"DEVICE", CmdPrompt, _UU("CMD_BridgeDelete_PROMPT_DEVICE"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "DEVICE"));
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[hubname]"));
+
+ // RPC call
+ ret = ScDeleteLocalBridge(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the list of features and capabilities of the server
+UINT PsCaps(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ CAPSLIST *t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ t = ScGetCapsEx(ps->Rpc);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ CT *ct;
+
+ ct = CtNewStandard();
+
+ for (i = 0;i < LIST_NUM(t->CapsList);i++)
+ {
+ CAPS *c = LIST_DATA(t->CapsList, i);
+ wchar_t title[MAX_SIZE];
+ char name[256];
+
+ Format(name, sizeof(name), "CT_%s", c->Name);
+
+ UniStrCpy(title, sizeof(title), _UU(name));
+
+ if (UniIsEmptyStr(title))
+ {
+ UniFormat(title, sizeof(title), L"%S", (StrLen(c->Name) >= 2) ? c->Name + 2 : c->Name);
+ }
+
+ if (StartWith(c->Name, "b_"))
+ {
+ bool icon_pass = c->Value == 0 ? false : true;
+ if (StrCmpi(c->Name, "b_must_install_pcap") == 0)
+ {
+ // Reverse only item of WinPcap
+ icon_pass = !icon_pass;
+ }
+ CtInsert(ct, title, c->Value == 0 ? _UU("CAPS_NO") : _UU("CAPS_YES"));
+ }
+ else
+ {
+ wchar_t str[64];
+ UniToStru(str, c->Value);
+ CtInsert(ct, title, str);
+ }
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeCapsList(t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Restart the VPN Server service
+UINT PsReboot(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_TEST t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"RESETCONFIG", NULL, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ t.IntValue = GetParamYes(o, "RESETCONFIG") ? 1 : 0;
+
+ // RPC call
+ ret = ScRebootServer(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcTest(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the current configuration of the VPN Server
+UINT PsConfigGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CONFIG t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[path]", NULL, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetConfig(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t *filename = GetParamUniStr(o, "[path]");
+
+ if (IsEmptyUniStr(filename))
+ {
+ // Display on the screen
+ wchar_t tmp[MAX_SIZE];
+ UINT buf_size;
+ wchar_t *buf;
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_ConfigGet_FILENAME"), t.FileName,
+ StrLen(t.FileData));
+ c->Write(c, tmp);
+ c->Write(c, L"");
+
+ buf_size = CalcUtf8ToUni((BYTE *)t.FileData, StrLen(t.FileData));
+ buf = ZeroMalloc(buf_size + 32);
+
+ Utf8ToUni(buf, buf_size, (BYTE *)t.FileData, StrLen(t.FileData));
+
+ c->Write(c, buf);
+ c->Write(c, L"");
+
+ Free(buf);
+ }
+ else
+ {
+ // Save to the file
+ IO *io = FileCreateW(filename);
+
+ if (io == NULL)
+ {
+ c->Write(c, _UU("CMD_ConfigGet_FILE_SAVE_FAILED"));
+
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ FileWrite(io, t.FileData, StrLen(t.FileData));
+ FileClose(io);
+ }
+ }
+ }
+
+ FreeRpcConfig(&t);
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Write the configuration to the VPN Server
+UINT PsConfigSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CONFIG t;
+ wchar_t *filename;
+ BUF *buf;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[path]", CmdPrompt, _UU("CMD_ConfigSet_PROMPT_PATH"), CmdEvalIsFile, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ filename = GetParamUniStr(o, "[path]");
+
+ buf = ReadDumpW(filename);
+ if (buf == NULL)
+ {
+ c->Write(c, _UU("CMD_ConfigSet_FILE_LOAD_FAILED"));
+ }
+ else
+ {
+ Zero(&t, sizeof(t));
+
+ t.FileData = ZeroMalloc(buf->Size + 1);
+ Copy(t.FileData, buf->Buf, buf->Size);
+ FreeBuf(buf);
+
+ // RPC call
+ ret = ScSetConfig(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcConfig(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the Virtual Layer 3 switch list
+UINT PsRouterList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_L3SW t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScEnumL3Switch(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNew();
+ UINT i;
+
+ CtInsertColumn(ct, _UU("SM_L3_SW_COLUMN1"), false);
+ CtInsertColumn(ct, _UU("SM_L3_SW_COLUMN2"), false);
+ CtInsertColumn(ct, _UU("SM_L3_SW_COLUMN3"), true);
+ CtInsertColumn(ct, _UU("SM_L3_SW_COLUMN4"), true);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_L3SW_ITEM *e = &t.Items[i];
+ wchar_t tmp1[MAX_SIZE], *tmp2, tmp3[64], tmp4[64];
+
+ StrToUni(tmp1, sizeof(tmp1), e->Name);
+ if (e->Active == false)
+ {
+ tmp2 = _UU("SM_L3_SW_ST_F_F");
+ }
+ else if (e->Online == false)
+ {
+ tmp2 = _UU("SM_L3_SW_ST_T_F");
+ }
+ else
+ {
+ tmp2 = _UU("SM_L3_SW_ST_T_T");
+ }
+ UniToStru(tmp3, e->NumInterfaces);
+ UniToStru(tmp4, e->NumTables);
+
+ CtInsert(ct,
+ tmp1, tmp2, tmp3, tmp4);
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeRpcEnumL3Sw(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Define a new virtual layer 3 switch
+UINT PsRouterAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_L3SW t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_RouterAdd_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScAddL3Switch(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the Virtual Layer 3 Switch
+UINT PsRouterDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_L3SW t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_RouterDelete_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScDelL3Switch(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Start the Virtual Layer 3 Switch
+UINT PsRouterStart(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_L3SW t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_RouterStart_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScStartL3Switch(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Stop the Virtual Layer 3 Switch
+UINT PsRouterStop(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_L3SW t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_RouterStop_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScStopL3Switch(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the interface list registered on Virtual Layer 3 Switch
+UINT PsRouterIfList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_L3IF t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_RouterIfList_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScEnumL3If(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ CT *ct = CtNew();
+
+ CtInsertColumn(ct, _UU("SM_L3_SW_IF_COLUMN1"), false);
+ CtInsertColumn(ct, _UU("SM_L3_SW_IF_COLUMN2"), false);
+ CtInsertColumn(ct, _UU("SM_L3_SW_IF_COLUMN3"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_L3IF *e = &t.Items[i];
+
+ IPToUniStr32(tmp1, sizeof(tmp1), e->IpAddress);
+ IPToUniStr32(tmp2, sizeof(tmp2), e->SubnetMask);
+ StrToUni(tmp3, sizeof(tmp3), e->HubName);
+
+ CtInsert(ct, tmp1, tmp2, tmp3);
+ }
+
+
+ CtFree(ct, c);
+ }
+
+ FreeRpcEnumL3If(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Evaluate the IP address and mask
+bool CmdEvalIpAndMask4(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[MAX_SIZE];
+ UINT ip, mask;
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+ if (ParseIpAndMask4(tmp, &ip, &mask) == false)
+ {
+ c->Write(c, _UU("CMD_PARSE_IP_MASK_ERROR_1"));
+ return false;
+ }
+
+ return true;
+}
+bool CmdEvalIpAndMask6(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[MAX_SIZE];
+ IP ip, mask;
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+ if (ParseIpAndMask6(tmp, &ip, &mask) == false)
+ {
+ c->Write(c, _UU("CMD_PARSE_IP_MASK_ERROR_1_6"));
+ return false;
+ }
+
+ return true;
+}
+bool CmdEvalIpAndMask46(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[MAX_SIZE];
+ TOKEN_LIST *t;
+ bool ret = false;
+
+ Zero(tmp, sizeof(tmp));
+ UniToStr(tmp, sizeof(tmp), str);
+
+ t = ParseToken(tmp, "/");
+ if (t == NULL)
+ {
+ return false;
+ }
+
+ if (t->NumTokens >= 1)
+ {
+ Trim(t->Token[0]);
+
+ if (IsIpStr4(t->Token[0]))
+ {
+ ret = CmdEvalIpAndMask4(c, str, param);
+ }
+ else
+ {
+ ret = CmdEvalIpAndMask6(c, str, param);
+ }
+ }
+
+ FreeToken(t);
+
+ return ret;
+}
+
+// Evaluate the network address and the subnet mask
+bool CmdEvalNetworkAndSubnetMask4(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[MAX_SIZE];
+ UINT ip, mask;
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+ if (ParseIpAndSubnetMask4(tmp, &ip, &mask) == false)
+ {
+ c->Write(c, _UU("CMD_PARSE_IP_SUBNET_ERROR_1"));
+ return false;
+ }
+
+ if (IsNetworkAddress32(ip, mask) == false)
+ {
+ c->Write(c, _UU("CMD_PARSE_IP_SUBNET_ERROR_2"));
+ return false;
+ }
+
+ return true;
+}
+bool CmdEvalNetworkAndSubnetMask6(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[MAX_SIZE];
+ IP ip, mask;
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+ if (ParseIpAndSubnetMask6(tmp, &ip, &mask) == false)
+ {
+ c->Write(c, _UU("CMD_PARSE_IP_SUBNET_ERROR_1_6"));
+ return false;
+ }
+
+ if (IsNetworkPrefixAddress6(&ip, &mask) == false)
+ {
+ c->Write(c, _UU("CMD_PARSE_IP_SUBNET_ERROR_3"));
+ return false;
+ }
+
+ return true;
+}
+bool CmdEvalNetworkAndSubnetMask46(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[MAX_SIZE];
+ TOKEN_LIST *t;
+ bool ret = false;
+
+ Zero(tmp, sizeof(tmp));
+ UniToStr(tmp, sizeof(tmp), str);
+
+ t = ParseToken(tmp, "/");
+ if (t == NULL)
+ {
+ return false;
+ }
+
+ if (t->NumTokens >= 1)
+ {
+ Trim(t->Token[0]);
+
+ if (IsIpStr4(t->Token[0]))
+ {
+ ret = CmdEvalNetworkAndSubnetMask4(c, str, param);
+ }
+ else
+ {
+ ret = CmdEvalNetworkAndSubnetMask6(c, str, param);
+ }
+ }
+
+ FreeToken(t);
+
+ return ret;
+}
+
+// Evaluate the IP address and subnet mask
+bool CmdEvalHostAndSubnetMask4(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+ if (ParseIpAndSubnetMask4(tmp, NULL, NULL) == false)
+ {
+ c->Write(c, _UU("CMD_PARSE_IP_SUBNET_ERROR_1"));
+ return false;
+ }
+
+ return true;
+}
+
+// Add a virtual interface to the virtual layer 3 switch
+UINT PsRouterIfAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_L3IF t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_RouterIfAdd_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ {"HUB", CmdPrompt, _UU("CMD_RouterIfAdd_PROMPT_HUB"), CmdEvalNotEmpty, NULL},
+ {"IP", CmdPrompt, _UU("CMD_RouterIfAdd_PROMPT_IP"), CmdEvalHostAndSubnetMask4, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+ ParseIpAndSubnetMask4(GetParamStr(o, "IP"), &t.IpAddress, &t.SubnetMask);
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "HUB"));
+
+ // RPC call
+ ret = ScAddL3If(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the virtual interface of the virtual layer 3 switch
+UINT PsRouterIfDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_L3IF t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_RouterIfAdd_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ {"HUB", CmdPrompt, _UU("CMD_RouterIfAdd_PROMPT_HUB"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "HUB"));
+
+ // RPC call
+ ret = ScDelL3If(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the routing table of the Virtual Layer 3 Switch
+UINT PsRouterTableList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_L3TABLE t;
+ CT *ct;
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_RouterTableList_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScEnumL3Table(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+
+ ct = CtNew();
+
+ CtInsertColumn(ct, _UU("SM_L3_SW_TABLE_COLUMN1"), false);
+ CtInsertColumn(ct, _UU("SM_L3_SW_TABLE_COLUMN2"), false);
+ CtInsertColumn(ct, _UU("SM_L3_SW_TABLE_COLUMN3"), false);
+ CtInsertColumn(ct, _UU("SM_L3_SW_TABLE_COLUMN4"), true);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_L3TABLE *e = &t.Items[i];
+
+ IPToUniStr32(tmp1, sizeof(tmp1), e->NetworkAddress);
+ IPToUniStr32(tmp2, sizeof(tmp2), e->SubnetMask);
+ IPToUniStr32(tmp3, sizeof(tmp3), e->GatewayAddress);
+ UniToStru(tmp4, e->Metric);
+
+ CtInsert(ct, tmp1, tmp2, tmp3, tmp4);
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeRpcEnumL3Table(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Add a routing table entry to the Virtual Layer 3 Switch
+UINT PsRouterTableAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_L3TABLE t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ {"NETWORK", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_NETWORK"), CmdEvalNetworkAndSubnetMask4, NULL},
+ {"GATEWAY", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_GATEWAY"), CmdEvalIp, NULL},
+ {"METRIC", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_METRIC"), CmdEvalInt1, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+ ParseIpAndSubnetMask4(GetParamStr(o, "NETWORK"), &t.NetworkAddress, &t.SubnetMask);
+ t.Metric = GetParamInt(o, "METRIC");
+ t.GatewayAddress = StrToIP32(GetParamStr(o, "GATEWAY"));
+
+ // RPC call
+ ret = ScAddL3Table(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the routing table entry of the Virtual Layer 3 Switch
+UINT PsRouterTableDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_L3TABLE t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ {"NETWORK", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_NETWORK"), CmdEvalNetworkAndSubnetMask4, NULL},
+ {"GATEWAY", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_GATEWAY"), CmdEvalIp, NULL},
+ {"METRIC", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_METRIC"), CmdEvalInt1, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+ ParseIpAndSubnetMask4(GetParamStr(o, "NETWORK"), &t.NetworkAddress, &t.SubnetMask);
+ t.Metric = GetParamInt(o, "METRIC");
+ t.GatewayAddress = StrToIP32(GetParamStr(o, "GATEWAY"));
+
+ // RPC call
+ ret = ScDelL3Table(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the log files list
+UINT PsLogFileList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_LOG_FILE t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ c->Write(c, _UU("CMD_LogFileList_START"));
+ c->Write(c, L"");
+
+ // RPC call
+ ret = ScEnumLogFile(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ wchar_t tmp[MAX_SIZE];
+ CT *ct;
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_LogFileList_NUM_LOGS"), t.NumItem);
+ c->Write(c, tmp);
+
+ ct = CtNew();
+
+ CtInsertColumn(ct, _UU("SM_LOG_FILE_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_LOG_FILE_COLUMN_2"), true);
+ CtInsertColumn(ct, _UU("SM_LOG_FILE_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_LOG_FILE_COLUMN_4"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_LOG_FILE_ITEM *e = &t.Items[i];
+ wchar_t tmp1[MAX_PATH], tmp2[128], tmp3[128], tmp4[MAX_HOST_NAME_LEN + 1];
+ char tmp[MAX_SIZE];
+
+ StrToUni(tmp1, sizeof(tmp1), e->FilePath);
+
+ ToStrByte(tmp, sizeof(tmp), e->FileSize);
+ StrToUni(tmp2, sizeof(tmp2), tmp);
+
+ GetDateTimeStr64Uni(tmp3, sizeof(tmp3), SystemToLocal64(e->UpdatedTime));
+
+ StrToUni(tmp4, sizeof(tmp4), e->ServerName);
+
+ CtInsert(ct, tmp1, tmp2, tmp3, tmp4);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumLogFile(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Download a log file
+UINT PsLogFileGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ BUF *buf;
+ char *filename = NULL;
+ char *server_name;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_LogFileGet_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ {"SERVER", NULL, NULL, NULL, NULL},
+ {"SAVEPATH", NULL, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ filename = GetParamStr(o, "SAVE");
+
+ c->Write(c, _UU("CMD_LogFileGet_START"));
+
+ server_name = GetParamStr(o, "SERVER");
+
+ buf = DownloadFileFromServer(ps->Rpc, server_name,
+ GetParamStr(o, "[name]"), 0, NULL, NULL);
+
+ if (buf == NULL)
+ {
+ c->Write(c, _UU("CMD_LogFileGet_FAILED"));
+
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ if (IsEmptyStr(filename) == false)
+ {
+ // Save to the file
+ if (DumpBuf(buf, filename) == false)
+ {
+ ret = ERR_INTERNAL_ERROR;
+ c->Write(c, _UU("CMD_LogFileGet_SAVE_FAILED"));
+ }
+ }
+ else
+ {
+ // Display on the screen
+ wchar_t tmp[MAX_SIZE];
+ UINT buf_size;
+ wchar_t *uni_buf;
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_LogFileGet_FILESIZE"),
+ buf->Size);
+ c->Write(c, tmp);
+ c->Write(c, L"");
+
+ buf_size = CalcUtf8ToUni((BYTE *)buf->Buf, buf->Size);
+ uni_buf = ZeroMalloc(buf_size + 32);
+
+ Utf8ToUni(uni_buf, buf_size, (BYTE *)buf->Buf, buf->Size);
+
+ c->Write(c, uni_buf);
+ c->Write(c, L"");
+
+ Free(uni_buf);
+ }
+
+ FreeBuf(buf);
+ }
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Create a New Virtual HUB
+UINT PsHubCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+ char *pass = "";
+ UINT hub_type = HUB_TYPE_STANDALONE;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_HubCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ {"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ RPC_SERVER_INFO t;
+ Zero(&t, sizeof(t));
+ if (ScGetServerInfo(ps->Rpc, &t) == ERR_NO_ERROR)
+ {
+ if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ hub_type = HUB_TYPE_FARM_DYNAMIC;
+ }
+ FreeRpcServerInfo(&t);
+ }
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+ t.HubType = hub_type;
+
+ if (IsEmptyStr(GetParamStr(o, "PASSWORD")) == false)
+ {
+ pass = GetParamStr(o, "PASSWORD");
+ }
+
+ Hash(t.HashedPassword, pass, StrLen(pass), true);
+ HashPassword(t.SecurePassword, ADMINISTRATOR_USERNAME, pass);
+ t.Online = true;
+
+ // RPC call
+ ret = ScCreateHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Create a New Virtual HUB (dynamic mode)
+UINT PsHubCreateDynamic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+ char *pass = "";
+ UINT hub_type = HUB_TYPE_FARM_DYNAMIC;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_HubCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ {"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+ t.HubType = hub_type;
+
+ if (IsEmptyStr(GetParamStr(o, "PASSWORD")) == false)
+ {
+ pass = GetParamStr(o, "PASSWORD");
+ }
+
+ Hash(t.HashedPassword, pass, StrLen(pass), true);
+ HashPassword(t.SecurePassword, ADMINISTRATOR_USERNAME, pass);
+ t.Online = true;
+
+ // RPC call
+ ret = ScCreateHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Create a New Virtual HUB (static mode)
+UINT PsHubCreateStatic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+ char *pass = "";
+ UINT hub_type = HUB_TYPE_FARM_STATIC;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_HubCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ {"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+ t.HubType = hub_type;
+
+ if (IsEmptyStr(GetParamStr(o, "PASSWORD")) == false)
+ {
+ pass = GetParamStr(o, "PASSWORD");
+ }
+
+ Hash(t.HashedPassword, pass, StrLen(pass), true);
+ HashPassword(t.SecurePassword, ADMINISTRATOR_USERNAME, pass);
+ t.Online = true;
+
+ // RPC call
+ ret = ScCreateHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete a Virtual HUB
+UINT PsHubDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_DELETE_HUB t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_HubDelete_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScDeleteHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the Virtual HUB to static
+UINT PsHubSetStatic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_HubChange_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+
+ // Retrieve the current setting first
+ ret = ScGetHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Change the settings
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+ t.HubType = HUB_TYPE_FARM_STATIC;
+
+ // Write
+ ret = ScSetHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Change the type of Virtual HUB to dynamic Virtual HUB
+UINT PsHubSetDynamic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_HubChange_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+
+ // Retrieve the current setting first
+ ret = ScGetHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Change the settings
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+ t.HubType = HUB_TYPE_FARM_DYNAMIC;
+
+ // Write
+ ret = ScSetHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the list of Virtual HUB
+UINT PsHubList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_HUB t;
+ UINT i;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScEnumHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNew();
+
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_4"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_5"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_6"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_7"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_8"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_9"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_10"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_11"), false);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_6"), false);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_7"), false);
+
+ for (i = 0;i < t.NumHub;i++)
+ {
+ RPC_ENUM_HUB_ITEM *e = &t.Hubs[i];
+ wchar_t name[MAX_HUBNAME_LEN + 1];
+ wchar_t s1[64], s2[64], s3[64], s4[64], s5[64];
+ wchar_t s6[64], s7[128], s8[128];
+ wchar_t s9[64], s10[64];
+
+ UniToStru(s1, e->NumUsers);
+ UniToStru(s2, e->NumGroups);
+ UniToStru(s3, e->NumSessions);
+ UniToStru(s4, e->NumMacTables);
+ UniToStru(s5, e->NumIpTables);
+
+ UniToStru(s6, e->NumLogin);
+
+ if (e->LastLoginTime != 0)
+ {
+ GetDateTimeStr64Uni(s7, sizeof(s7), SystemToLocal64(e->LastLoginTime));
+ }
+ else
+ {
+ UniStrCpy(s7, sizeof(s7), _UU("COMMON_UNKNOWN"));
+ }
+
+ if (e->LastCommTime != 0)
+ {
+ GetDateTimeStr64Uni(s8, sizeof(s8), SystemToLocal64(e->LastCommTime));
+ }
+ else
+ {
+ UniStrCpy(s8, sizeof(s8), _UU("COMMON_UNKNOWN"));
+ }
+
+ if (e->IsTrafficFilled == false)
+ {
+ UniStrCpy(s9, sizeof(s9), _UU("CM_ST_NONE"));
+ UniStrCpy(s10, sizeof(s10), _UU("CM_ST_NONE"));
+ }
+ else
+ {
+ UniToStr3(s9, sizeof(s9),
+ e->Traffic.Recv.BroadcastBytes + e->Traffic.Recv.UnicastBytes +
+ e->Traffic.Send.BroadcastBytes + e->Traffic.Send.UnicastBytes);
+
+ UniToStr3(s10, sizeof(s10),
+ e->Traffic.Recv.BroadcastCount + e->Traffic.Recv.UnicastCount +
+ e->Traffic.Send.BroadcastCount + e->Traffic.Send.UnicastCount);
+ }
+
+ StrToUni(name, sizeof(name), e->HubName);
+
+ CtInsert(ct,
+ name,
+ e->Online ? _UU("SM_HUB_ONLINE") : _UU("SM_HUB_OFFLINE"),
+ GetHubTypeStr(e->HubType),
+ s1, s2, s3, s4, s5, s6, s7, s8, s9, s10);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumHub(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Select a Virtual HUB to manage
+UINT PsHub(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_STATUS t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", NULL, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "[name]")) == false)
+ {
+ wchar_t tmp[MAX_SIZE];
+ Zero(&t, sizeof(t));
+
+ // Examine whether the specified Virtual HUB is accessible
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetHubStatus(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Change the selection
+ if (ps->HubName != NULL)
+ {
+ Free(ps->HubName);
+ }
+ ps->HubName = CopyStr(t.HubName);
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_Hub_Selected"), t.HubName);
+ c->Write(c, tmp);
+ }
+ else
+ {
+ // Deselect
+ if (ps->HubName != NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Unselected"));
+ Free(ps->HubName);
+ }
+ ps->HubName = NULL;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the Virtual HUB to online
+UINT PsOnline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_HUB_ONLINE t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Online = true;
+
+ // RPC call
+ ret = ScSetHubOnline(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the Virtual HUB to offline
+UINT PsOffline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_HUB_ONLINE t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Online = false;
+
+ // RPC call
+ ret = ScSetHubOnline(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the maximum number of concurrent connecting sessions of the Virtual HUB
+UINT PsSetMaxSession(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[max_session]", CmdPrompt, _UU("CMD_SetMaxSession_Prompt"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Get current settings of Virtual HUB
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScGetHub(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ t.HubOption.MaxSession = GetParamInt(o, "[max_session]");
+
+ // Write the configuration of Virtual HUB
+ ret = ScSetHub(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the administrative password of the Virtual HUB
+UINT PsSetHubPassword(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+ char *pw;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[password]", CmdPromptChoosePassword, NULL, NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Get current settings of Virtual HUB
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScGetHub(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Change the settings
+ pw = GetParamStr(o, "[password]");
+ HashPassword(t.SecurePassword, ADMINISTRATOR_USERNAME, pw);
+ Hash(t.HashedPassword, pw, StrLen(pw), true);
+
+ // Write the configuration of Virtual HUB
+ ret = ScSetHub(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the Virtual HUB to permit to be enumerated for anonymous users
+UINT PsSetEnumAllow(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Get current settings of Virtual HUB
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScGetHub(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ t.HubOption.NoEnum = false;
+
+ // Write the configuration of Virtual HUB
+ ret = ScSetHub(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the Virtual HUB to deny to be enumerated for anonymous users
+UINT PsSetEnumDeny(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Get current settings of Virtual HUB
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScGetHub(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ t.HubOption.NoEnum = true;
+
+ // Write the configuration of Virtual HUB
+ ret = ScSetHub(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the option settings for the virtual HUB
+UINT PsOptionsGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct;
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_OptionsGet_TITLE"), ps->HubName);
+ c->Write(c, tmp);
+
+ // Display settings
+ ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_OptionsGet_ENUM"),
+ t.HubOption.NoEnum ? _UU("CMD_MSG_DENY") : _UU("CMD_MSG_ALLOW"));
+
+ if (t.HubOption.MaxSession == 0)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CMD_MSG_INFINITE"));
+ }
+ else
+ {
+ UniToStru(tmp, t.HubOption.MaxSession);
+ }
+ CtInsert(ct, _UU("CMD_OptionsGet_MAXSESSIONS"), tmp);
+
+ CtInsert(ct, _UU("CMD_OptionsGet_STATUS"), t.Online ? _UU("SM_HUB_ONLINE") : _UU("SM_HUB_OFFLINE"));
+
+ CtInsert(ct, _UU("CMD_OptionsGet_TYPE"), GetHubTypeStr(t.HubType));
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Setting the Radius server to use for user authentication
+UINT PsRadiusServerSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_RADIUS t;
+ char *host;
+ UINT port;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX minmax =
+ {
+ "CMD_RadiusServerSet_EVAL_NUMINTERVAL", RADIUS_RETRY_INTERVAL, RADIUS_RETRY_TIMEOUT,
+ };
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[server_name:port]", CmdPrompt, _UU("CMD_RadiusServerSet_Prompt_Host"), CmdEvalNotEmpty, NULL},
+ {"SECRET", CmdPromptChoosePassword, _UU("CMD_RadiusServerSet_Prompt_Secret"), NULL, NULL},
+ {"RETRY_INTERVAL", CmdPrompt, _UU("CMD_RadiusServerSet_Prompt_RetryInterval"), CmdEvalMinMax, &minmax},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (ParseHostPort(GetParamStr(o, "[server_name:port]"), &host, &port, 1812))
+ {
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.RadiusPort = port;
+ StrCpy(t.RadiusServerName, sizeof(t.RadiusServerName), host);
+ StrCpy(t.RadiusSecret, sizeof(t.RadiusSecret), GetParamStr(o, "SECRET"));
+ t.RadiusRetryInterval = GetParamInt(o, "RETRY_INTERVAL");
+
+ Free(host);
+
+ // RPC call
+ ret = ScSetHubRadius(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the Radius server configuration to be used for user authentication
+UINT PsRadiusServerDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_RADIUS t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.RadiusPort = 1812;
+
+ // RPC call
+ ret = ScSetHubRadius(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the Radius server settings to use for user authentication
+UINT PsRadiusServerGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_RADIUS t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubRadius(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct;
+ wchar_t tmp[MAX_SIZE];
+
+ ct = CtNewStandard();
+
+ if (IsEmptyStr(t.RadiusServerName))
+ {
+ CtInsert(ct, _UU("CMD_RadiusServerGet_STATUS"), _UU("CMD_MSG_DISABLE"));
+ }
+ else
+ {
+ CtInsert(ct, _UU("CMD_RadiusServerGet_STATUS"), _UU("CMD_MSG_ENABLE"));
+
+ StrToUni(tmp, sizeof(tmp), t.RadiusServerName);
+ CtInsert(ct, _UU("CMD_RadiusServerGet_HOST"), tmp);
+
+ UniToStri(tmp, t.RadiusPort);
+ CtInsert(ct, _UU("CMD_RadiusServerGet_PORT"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.RadiusSecret);
+ CtInsert(ct, _UU("CMD_RadiusServerGet_SECRET"), tmp);
+
+ UniToStri(tmp, t.RadiusRetryInterval);
+ CtInsert(ct, _UU("CMD_RadiusServerGet_RetryInterval"), tmp);
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the current status of the Virtual HUB
+UINT PsStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_STATUS t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubStatus(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNewStandard();
+ wchar_t *s;
+ wchar_t tmp[MAX_SIZE];
+
+ // HUB name
+ s = CopyStrToUni(t.HubName);
+ CtInsert(ct, _UU("SM_HUB_STATUS_HUBNAME"), s);
+ Free(s);
+
+ // Online
+ CtInsert(ct, _UU("SM_HUB_STATUS_ONLINE"),
+ t.Online ? _UU("SM_HUB_ONLINE") : _UU("SM_HUB_OFFLINE"));
+
+ // Type of HUB
+ CtInsert(ct, _UU("SM_HUB_TYPE"),
+ GetHubTypeStr(t.HubType));
+
+ if (t.HubType == HUB_TYPE_STANDALONE)
+ {
+ // Enable / Disable the SecureNAT
+ CtInsert(ct, _UU("SM_HUB_SECURE_NAT"),
+ t.SecureNATEnabled ? _UU("SM_HUB_SECURE_NAT_YES") : _UU("SM_HUB_SECURE_NAT_NO"));
+ }
+
+ // Other values
+ UniToStru(tmp, t.NumSessions);
+ CtInsert(ct, _UU("SM_HUB_NUM_SESSIONS"), tmp);
+
+ if (t.NumSessionsClient != 0 || t.NumSessionsBridge != 0)
+ {
+ UniToStru(tmp, t.NumSessionsClient);
+ CtInsert(ct, _UU("SM_HUB_NUM_SESSIONS_CLIENT"), tmp);
+ UniToStru(tmp, t.NumSessionsBridge);
+ CtInsert(ct, _UU("SM_HUB_NUM_SESSIONS_BRIDGE"), tmp);
+ }
+
+ UniToStru(tmp, t.NumAccessLists);
+ CtInsert(ct, _UU("SM_HUB_NUM_ACCESSES"), tmp);
+
+ UniToStru(tmp, t.NumUsers);
+ CtInsert(ct, _UU("SM_HUB_NUM_USERS"), tmp);
+ UniToStru(tmp, t.NumGroups);
+ CtInsert(ct, _UU("SM_HUB_NUM_GROUPS"), tmp);
+
+ UniToStru(tmp, t.NumMacTables);
+ CtInsert(ct, _UU("SM_HUB_NUM_MAC_TABLES"), tmp);
+ UniToStru(tmp, t.NumIpTables);
+ CtInsert(ct, _UU("SM_HUB_NUM_IP_TABLES"), tmp);
+
+ // Usage status
+ UniToStru(tmp, t.NumLogin);
+ CtInsert(ct, _UU("SM_HUB_NUM_LOGIN"), tmp);
+
+ if (t.LastLoginTime != 0)
+ {
+ GetDateTimeStr64Uni(tmp, sizeof(tmp), SystemToLocal64(t.LastLoginTime));
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("COMMON_UNKNOWN"));
+ }
+ CtInsert(ct, _UU("SM_HUB_LAST_LOGIN_TIME"), tmp);
+
+ if (t.LastCommTime != 0)
+ {
+ GetDateTimeStr64Uni(tmp, sizeof(tmp), SystemToLocal64(t.LastCommTime));
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("COMMON_UNKNOWN"));
+ }
+ CtInsert(ct, _UU("SM_HUB_LAST_COMM_TIME"), tmp);
+
+ if (t.CreatedTime != 0)
+ {
+ GetDateTimeStr64Uni(tmp, sizeof(tmp), SystemToLocal64(t.CreatedTime));
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("COMMON_UNKNOWN"));
+ }
+ CtInsert(ct, _UU("SM_HUB_CREATED_TIME"), tmp);
+
+ // Traffic information
+ CmdInsertTrafficInfo(ct, &t.Traffic);
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the log switching string
+wchar_t *GetLogSwitchStr(UINT i)
+{
+ char tmp[64];
+
+ Format(tmp, sizeof(tmp), "SM_LOG_SWITCH_%u", i);
+
+ return _UU(tmp);
+}
+
+// Get the packet log name string
+wchar_t *GetPacketLogNameStr(UINT i)
+{
+ char tmp[64];
+
+ Format(tmp, sizeof(tmp), "CMD_Log_%u", i);
+
+ return _UU(tmp);
+}
+
+// Get the log storage settings for the virtual HUB
+UINT PsLogGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_LOG t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubLog(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_Log_SecurityLog"),
+ t.LogSetting.SaveSecurityLog ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+ if (t.LogSetting.SaveSecurityLog)
+ {
+ CtInsert(ct, _UU("CMD_Log_SwitchType"), GetLogSwitchStr(t.LogSetting.SecurityLogSwitchType));
+ }
+
+ CtInsert(ct, L"", L"");
+
+ CtInsert(ct, _UU("CMD_Log_PacketLog"),
+ t.LogSetting.SavePacketLog ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+ if (t.LogSetting.SavePacketLog)
+ {
+ UINT i;
+
+ CtInsert(ct, _UU("CMD_Log_SwitchType"), GetLogSwitchStr(t.LogSetting.PacketLogSwitchType));
+
+ for (i = 0;i <= 7;i++)
+ {
+ wchar_t *tmp = NULL;
+
+ switch (t.LogSetting.PacketLogConfig[i])
+ {
+ case PACKET_LOG_NONE:
+ tmp = _UU("D_SM_LOG@B_PACKET_0_0");
+ break;
+
+ case PACKET_LOG_HEADER:
+ tmp = _UU("D_SM_LOG@B_PACKET_0_1");
+ break;
+
+ case PACKET_LOG_ALL:
+ tmp = _UU("D_SM_LOG@B_PACKET_0_2");
+ break;
+ }
+
+ CtInsert(ct, GetPacketLogNameStr(i),
+ tmp);
+ }
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// LogEnable command
+UINT PsLogEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_LOG t;
+ bool packet_log = false;
+ char *tmp;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[security|packet]", CmdPrompt, _UU("CMD_LogEnable_Prompt"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ tmp = GetParamStr(o, "[security|packet]");
+
+ if (StartWith(tmp, "p"))
+ {
+ packet_log = true;
+ }
+ else if (StartWith(tmp, "s") == false)
+ {
+ c->Write(c, _UU("CMD_LogEnable_Prompt_Error"));
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubLog(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ if (packet_log == false)
+ {
+ t.LogSetting.SaveSecurityLog = true;
+ }
+ else
+ {
+ t.LogSetting.SavePacketLog = true;
+ }
+
+ // RPC call
+ ret = ScSetHubLog(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disable the packet log or the security log
+UINT PsLogDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_LOG t;
+ bool packet_log = false;
+ char *tmp;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[security|packet]", CmdPrompt, _UU("CMD_LogEnable_Prompt"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ tmp = GetParamStr(o, "[security|packet]");
+
+ if (StartWith(tmp, "p"))
+ {
+ packet_log = true;
+ }
+ else if (StartWith(tmp, "s") == false)
+ {
+ c->Write(c, _UU("CMD_LogEnable_Prompt_Error"));
+ FreeParamValueList(o);
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubLog(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ if (packet_log == false)
+ {
+ t.LogSetting.SaveSecurityLog = false;
+ }
+ else
+ {
+ t.LogSetting.SavePacketLog = false;
+ }
+
+ // RPC call
+ ret = ScSetHubLog(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Convert the string to log switching type
+UINT StrToLogSwitchType(char *str)
+{
+ UINT ret = INFINITE;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return INFINITE;
+ }
+
+ if (IsEmptyStr(str) || StartWith("none", str))
+ {
+ ret = LOG_SWITCH_NO;
+ }
+ else if (StartWith("second", str))
+ {
+ ret = LOG_SWITCH_SECOND;
+ }
+ else if (StartWith("minute", str))
+ {
+ ret = LOG_SWITCH_MINUTE;
+ }
+ else if (StartWith("hour", str))
+ {
+ ret = LOG_SWITCH_HOUR;
+ }
+ else if (StartWith("day", str))
+ {
+ ret = LOG_SWITCH_DAY;
+ }
+ else if (StartWith("month", str))
+ {
+ ret = LOG_SWITCH_MONTH;
+ }
+
+ return ret;
+}
+
+// Set the switching period of the log file
+UINT PsLogSwitchSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_LOG t;
+ bool packet_log = false;
+ char *tmp;
+ UINT new_switch_type = 0;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[security|packet]", CmdPrompt, _UU("CMD_LogEnable_Prompt"), CmdEvalNotEmpty, NULL},
+ {"SWITCH", CmdPrompt, _UU("CMD_LogSwitchSet_Prompt"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ tmp = GetParamStr(o, "[security|packet]");
+
+ if (StartWith(tmp, "p"))
+ {
+ packet_log = true;
+ }
+ else if (StartWith(tmp, "s") == false)
+ {
+ c->Write(c, _UU("CMD_LogEnable_Prompt_Error"));
+ FreeParamValueList(o);
+ return ERR_INVALID_PARAMETER;
+ }
+
+ new_switch_type = StrToLogSwitchType(GetParamStr(o, "SWITCH"));
+
+ if (new_switch_type == INFINITE)
+ {
+ c->Write(c, _UU("CMD_LogEnable_Prompt_Error"));
+ FreeParamValueList(o);
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubLog(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ if (packet_log == false)
+ {
+ t.LogSetting.SecurityLogSwitchType = new_switch_type;
+ }
+ else
+ {
+ t.LogSetting.PacketLogSwitchType = new_switch_type;
+ }
+
+ // RPC call
+ ret = ScSetHubLog(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Convert the type string of the packet log contents to an integer
+UINT StrToPacketLogSaveInfoType(char *str)
+{
+ UINT ret = INFINITE;
+ if (str == NULL)
+ {
+ return INFINITE;
+ }
+
+ if (StartWith("none", str) || IsEmptyStr(str))
+ {
+ ret = PACKET_LOG_NONE;
+ }
+ else if (StartWith("header", str))
+ {
+ ret = PACKET_LOG_HEADER;
+ }
+ else if (StartWith("full", str) || StartWith("all", str))
+ {
+ ret = PACKET_LOG_ALL;
+ }
+
+ return ret;
+}
+
+// Convert a packet type string of the packet log to an integer
+UINT StrToPacketLogType(char *str)
+{
+ UINT ret = INFINITE;
+ if (str == NULL || IsEmptyStr(str))
+ {
+ return INFINITE;
+ }
+
+ if (StartWith("tcpconn", str))
+ {
+ ret = PACKET_LOG_TCP_CONN;
+ }
+ else if (StartWith("tcpdata", str))
+ {
+ ret = PACKET_LOG_TCP;
+ }
+ else if (StartWith("dhcp", str))
+ {
+ ret = PACKET_LOG_DHCP;
+ }
+ else if (StartWith("udp", str))
+ {
+ ret = PACKET_LOG_UDP;
+ }
+ else if (StartWith("icmp", str))
+ {
+ ret = PACKET_LOG_ICMP;
+ }
+ else if (StartWith("ip", str))
+ {
+ ret = PACKET_LOG_IP;
+ }
+ else if (StartWith("arp", str))
+ {
+ ret = PACKET_LOG_ARP;
+ }
+ else if (StartWith("ethernet", str))
+ {
+ ret = PACKET_LOG_ETHERNET;
+ }
+
+ return ret;
+}
+
+// Set the detail level and type of packet to be stored in the packet log
+UINT PsLogPacketSaveType(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_LOG t;
+ bool packet_log = false;
+ UINT packet_type = INFINITE;
+ UINT packet_save_info_type = INFINITE;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"TYPE", CmdPrompt, _UU("CMD_LogPacketSaveType_Prompt_TYPE"), NULL, NULL},
+ {"SAVE", CmdPrompt, _UU("CMD_LogPacketSaveType_Prompt_SAVE"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ packet_type = StrToPacketLogType(GetParamStr(o, "TYPE"));
+ packet_save_info_type = StrToPacketLogSaveInfoType(GetParamStr(o, "SAVE"));
+
+ if (packet_type == INFINITE || packet_save_info_type == INFINITE)
+ {
+ c->Write(c, _UU("CMD_LogEnable_Prompt_Error"));
+ FreeParamValueList(o);
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubLog(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ t.LogSetting.PacketLogConfig[packet_type] = packet_save_info_type;
+
+ // RPC call
+ ret = ScSetHubLog(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the list of certificates of the trusted certification authority
+UINT PsCAList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_ENUM_CA t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumCa(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ CT *ct = CtNewStandard();
+
+ for (i = 0;i < t.NumCa;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[64];
+ RPC_HUB_ENUM_CA_ITEM *e = &t.Ca[i];
+
+ GetDateStrEx64(tmp, sizeof(tmp), SystemToLocal64(e->Expires), NULL);
+
+ UniToStru(tmp2, e->Key);
+
+ CtInsert(ct, _UU("CMD_CAList_COLUMN_ID"), tmp2);
+ CtInsert(ct, _UU("CM_CERT_COLUMN_1"), e->SubjectName);
+ CtInsert(ct, _UU("CM_CERT_COLUMN_2"), e->IssuerName);
+ CtInsert(ct, _UU("CM_CERT_COLUMN_3"), tmp);
+
+ if (i != (t.NumCa - 1))
+ {
+ CtInsert(ct, L"---", L"---");
+ }
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeRpcHubEnumCa(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Add a certificate to the trusted certification authority
+UINT PsCAAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_ADD_CA t;
+ X *x;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[path]", CmdPrompt, _UU("CMD_CAAdd_PROMPT_PATH"), CmdEvalIsFile, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ x = FileToXW(GetParamUniStr(o, "[path]"));
+
+ if (x == NULL)
+ {
+ FreeParamValueList(o);
+ c->Write(c, _UU("CMD_MSG_LOAD_CERT_FAILED"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Cert = x;
+
+ // RPC call
+ ret = ScAddCa(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcHubAddCa(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the certificate of the trusted certification authority
+UINT PsCADelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_DELETE_CA t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_CADelete_PROMPT_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Key = GetParamInt(o, "[id]");
+
+ // RPC call
+ ret = ScDeleteCa(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the certificate of the trusted certification authority
+UINT PsCAGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_GET_CA t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_CAGet_PROMPT_ID"), CmdEvalNotEmpty, NULL},
+ {"SAVECERT", CmdPrompt, _UU("CMD_CAGet_PROMPT_SAVECERT"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Key = GetParamInt(o, "[id]");
+
+ // RPC call
+ ret = ScGetCa(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ if (XToFileW(t.Cert, GetParamUniStr(o, "SAVECERT"), true))
+ {
+ // Success
+ }
+ else
+ {
+ ret = ERR_INTERNAL_ERROR;
+ c->Write(c, _UU("CMD_MSG_SAVE_CERT_FAILED"));
+ }
+ }
+
+ FreeRpcHubGetCa(&t);
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the cascade connection list
+UINT PsCascadeList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_LINK t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNew();
+ UINT i;
+
+ CtInsertColumn(ct, _UU("SM_LINK_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_LINK_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_LINK_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_LINK_COLUMN_4"), false);
+ CtInsertColumn(ct, _UU("SM_LINK_COLUMN_5"), false);
+
+ for (i = 0;i < t.NumLink;i++)
+ {
+ RPC_ENUM_LINK_ITEM *e = &t.Links[i];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+
+ GetDateTimeStrEx64(tmp1, sizeof(tmp1), SystemToLocal64(e->ConnectedTime), NULL);
+ StrToUni(tmp2, sizeof(tmp2), e->Hostname);
+ StrToUni(tmp3, sizeof(tmp3), e->HubName);
+
+ if (e->Online == false)
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_LINK_STATUS_OFFLINE"));
+ }
+ else
+ {
+ if (e->Connected)
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_LINK_STATUS_ONLINE"));
+ }
+ else
+ {
+ if (e->LastError != 0)
+ {
+ UniFormat(tmp4, sizeof(tmp4), _UU("SM_LINK_STATUS_ERROR"), e->LastError, _E(e->LastError));
+ }
+ else
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_LINK_CONNECTING"));
+ }
+ }
+ }
+
+ CtInsert(ct, e->AccountName, tmp4, tmp1, tmp2, tmp3);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumLink(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Creat a new cascade
+UINT PsCascadeCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ char *host = NULL;
+ UINT port = 443;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SERVER", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Server"), CmdEvalHostAndPort, NULL},
+ {"HUB", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Hub"), CmdEvalSafe, NULL},
+ {"USERNAME", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Username"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 443);
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ t.Online = false;
+
+ Copy(&t.Policy, GetDefaultPolicy(), sizeof(POLICY));
+
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+ t.ClientOption->Port = port;
+ StrCpy(t.ClientOption->Hostname, sizeof(t.ClientOption->Hostname), host);
+ StrCpy(t.ClientOption->HubName, sizeof(t.ClientOption->HubName), GetParamStr(o, "HUB"));
+ t.ClientOption->NumRetry = INFINITE;
+ t.ClientOption->RetryInterval = 15;
+ t.ClientOption->MaxConnection = 8;
+ t.ClientOption->UseEncrypt = true;
+ t.ClientOption->AdditionalConnectionInterval = 1;
+ t.ClientOption->RequireBridgeRoutingMode = true;
+
+ t.ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_ANONYMOUS;
+ StrCpy(t.ClientAuth->Username, sizeof(t.ClientAuth->Username), GetParamStr(o, "USERNAME"));
+
+ Free(host);
+
+ // RPC call
+ ret = ScCreateLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the user name and destination of the cascade connection
+UINT PsCascadeSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ char *host = NULL;
+ UINT port = 443;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SERVER", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Server"), CmdEvalHostAndPort, NULL},
+ {"HUB", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Hub"), CmdEvalSafe, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 443);
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = ScGetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ Free(host);
+ return ret;
+ }
+
+ t.ClientOption->Port = port;
+ StrCpy(t.ClientOption->Hostname, sizeof(t.ClientOption->Hostname), host);
+ StrCpy(t.ClientOption->HubName, sizeof(t.ClientOption->HubName), GetParamStr(o, "HUB"));
+
+ Free(host);
+
+ // RPC call
+ ret = ScSetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the type string of proxy
+wchar_t *GetProxyTypeStr(UINT i)
+{
+ switch (i)
+ {
+ case PROXY_DIRECT:
+
+ return _UU("PROTO_DIRECT_TCP");
+
+ case PROXY_HTTP:
+ return _UU("PROTO_HTTP_PROXY");
+
+ case PROXY_SOCKS:
+ return _UU("PROTO_SOCKS_PROXY");
+
+ default:
+ return _UU("PROTO_UNKNOWN");
+ }
+}
+
+// Get type string in user authentication for client
+wchar_t *GetClientAuthTypeStr(UINT i)
+{
+ char tmp[MAX_SIZE];
+
+ Format(tmp, sizeof(tmp), "PW_TYPE_%u", i);
+
+ return _UU(tmp);
+}
+
+// Get the setting of cascade connection
+UINT PsCascadeGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName),
+ GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Show the contents of the connection settings
+ wchar_t tmp[MAX_SIZE];
+
+ CT *ct = CtNewStandard();
+
+ // Connection settings name
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_NAME"), t.ClientOption->AccountName);
+
+ // Host name of the destination VPN Server
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->Hostname);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_HOSTNAME"), tmp);
+
+ // The port number to connect to VPN Server
+ UniToStru(tmp, t.ClientOption->Port);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PORT"), tmp);
+
+ // Virtual HUB name of the destination VPN Server
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->HubName);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_HUBNAME"), tmp);
+
+ // Type of proxy server to go through
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_TYPE"), GetProxyTypeStr(t.ClientOption->ProxyType));
+
+ if (t.ClientOption->ProxyType != PROXY_DIRECT)
+ {
+ // Host name of the proxy server
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->ProxyName);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_HOSTNAME"), tmp);
+
+ // Port number of the proxy server
+ UniToStru(tmp, t.ClientOption->ProxyPort);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_PORT"), tmp);
+
+ // User name of the proxy server
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->ProxyUsername);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_USERNAME"), tmp);
+ }
+
+ // To verify the server certificate
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_SERVER_CERT_USE"),
+ t.CheckServerCert ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Registered specific certificate
+ if (t.ServerCert != NULL)
+ {
+ GetAllNameFromX(tmp, sizeof(tmp), t.ServerCert);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_SERVER_CERT_NAME"), tmp);
+ }
+
+ // Device name to be used for the connection
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->DeviceName);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_DEVICE_NAME"), tmp);
+
+ // Authentication type
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_AUTH_TYPE"), GetClientAuthTypeStr(t.ClientAuth->AuthType));
+
+ // User name
+ StrToUni(tmp, sizeof(tmp), t.ClientAuth->Username);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_AUTH_USERNAME"), tmp);
+
+ if (t.ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)
+ {
+ if (t.ClientAuth->ClientX != NULL)
+ {
+ // Client certificate name
+ GetAllNameFromX(tmp, sizeof(tmp), t.ClientAuth->ClientX);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_AUTH_CERT_NAME"), tmp);
+ }
+ }
+
+ // Number of TCP connections to be used for VPN communication
+ UniToStru(tmp, t.ClientOption->MaxConnection);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_NUMTCP"), tmp);
+
+ // Establishment interval of each TCP connection
+ UniToStru(tmp, t.ClientOption->AdditionalConnectionInterval);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_TCP_INTERVAL"), tmp);
+
+ // Life span of each TCP connection
+ if (t.ClientOption->ConnectionDisconnectSpan != 0)
+ {
+ UniToStru(tmp, t.ClientOption->ConnectionDisconnectSpan);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CMD_MSG_INFINITE"));
+ }
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_TCP_TTL"), tmp);
+
+ // Use of half-duplex mode
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_TCP_HALF"),
+ t.ClientOption->HalfConnection ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Encryption by SSL
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_ENCRYPT"),
+ t.ClientOption->UseEncrypt ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Data compression
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_COMPRESS"),
+ t.ClientOption->UseCompress ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Connect in bridge / router mode
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_BRIDGE_ROUTER"),
+ t.ClientOption->RequireBridgeRoutingMode ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Connect in monitoring mode
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_MONITOR"),
+ t.ClientOption->RequireMonitorMode ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Not to rewrite the routing table
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_NO_TRACKING"),
+ t.ClientOption->NoRoutingTracking ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Disable the QoS control
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_QOS_DISABLE"),
+ t.ClientOption->DisableQoS ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ CtFree(ct, c);
+
+ // Security policy
+ c->Write(c, L"");
+ c->Write(c, _UU("CMD_CascadeGet_Policy"));
+ PrintPolicy(c, &t.Policy, true);
+ }
+
+ FreeRpcCreateLink(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the cascade connection
+UINT PsCascadeDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScDeleteLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the user name to use for the cascade connection
+UINT PsCascadeUsernameSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"USERNAME", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Username"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Change the settings for the cascade connection
+ StrCpy(t.ClientAuth->Username, sizeof(t.ClientAuth->Username),
+ GetParamStr(o, "USERNAME"));
+
+ if (t.ClientAuth->AuthType == CLIENT_AUTHTYPE_PASSWORD)
+ {
+ c->Write(c, _UU("CMD_CascadeUsername_Notice"));
+ }
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+//Set the type of user authentication of cascade connection to the anonymous authentication
+UINT PsCascadeAnonymousSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Change the settings for the cascade connection
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_ANONYMOUS;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the type of user authentication of cascade connection to the password authentication
+UINT PsCascadePasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+ {"TYPE", CmdPrompt, _UU("CMD_CascadePasswordSet_Prompt_Type"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Change the settings for the cascade connection
+ char *typestr = GetParamStr(o, "TYPE");
+
+ if (StartWith("standard", typestr))
+ {
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_PASSWORD;
+ HashPassword(t.ClientAuth->HashedPassword, t.ClientAuth->Username,
+ GetParamStr(o, "PASSWORD"));
+ }
+ else if (StartWith("radius", typestr) || StartWith("ntdomain", typestr))
+ {
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_PLAIN_PASSWORD;
+
+ StrCpy(t.ClientAuth->PlainPassword, sizeof(t.ClientAuth->PlainPassword),
+ GetParamStr(o, "PASSWORD"));
+ }
+ else
+ {
+ // An error has occured
+ c->Write(c, _UU("CMD_CascadePasswordSet_Type_Invalid"));
+ FreeRpcCreateLink(&t);
+ ret = ERR_INVALID_PARAMETER;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the type of user authentication of cascade connection to the client certificate authentication
+UINT PsCascadeCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ X *x;
+ K *k;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL},
+ {"LOADKEY", CmdPrompt, _UU("CMD_LOADKEYPATH"), CmdEvalIsFile, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (CmdLoadCertAndKey(c, &x, &k, GetParamUniStr(o, "LOADCERT"), GetParamUniStr(o, "LOADKEY")) == false)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ FreeX(x);
+ FreeK(k);
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Change authentication data
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_CERT;
+ if (t.ClientAuth->ClientX != NULL)
+ {
+ FreeX(t.ClientAuth->ClientX);
+ }
+ if (t.ClientAuth->ClientK != NULL)
+ {
+ FreeK(t.ClientAuth->ClientK);
+ }
+
+ t.ClientAuth->ClientX = x;
+ t.ClientAuth->ClientK = k;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the client certificate to be used in the cascade connection
+UINT PsCascadeCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SAVECERT", CmdPrompt, _UU("CMD_SAVECERTPATH"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ if (t.ClientAuth->AuthType != CLIENT_AUTHTYPE_CERT)
+ {
+ c->Write(c, _UU("CMD_CascadeCertSet_Not_Auth_Cert"));
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else if (t.ClientAuth->ClientX == NULL)
+ {
+ c->Write(c, _UU("CMD_CascadeCertSet_Cert_Not_Exists"));
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ XToFileW(t.ClientAuth->ClientX, GetParamUniStr(o, "SAVECERT"), true);
+ }
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Enable encryption of communication at the time of the cascade connection
+UINT PsCascadeEncryptEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ t.ClientOption->UseEncrypt = true;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disable encryption of communication at the time of the cascade connection
+UINT PsCascadeEncryptDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ t.ClientOption->UseEncrypt = false;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable data compression at the time of communication of the cascade connection
+UINT PsCascadeCompressEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ t.ClientOption->UseCompress = true;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disable data compression at the time of communication of the cascade connection
+UINT PsCascadeCompressDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ t.ClientOption->UseCompress = false;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the cascade connection method to the TCP/IP direct connection mode
+UINT PsCascadeProxyNone(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ t.ClientOption->ProxyType = PROXY_DIRECT;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the cascade connection method as the mode via HTTP proxy server
+UINT PsCascadeProxyHttp(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SERVER", CmdPrompt, _UU("CMD_CascadeProxyHttp_Prompt_Server"), CmdEvalHostAndPort, NULL},
+ {"USERNAME", NULL, NULL, NULL, NULL},
+ {"PASSWORD", NULL, NULL, NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ char *host;
+ UINT port;
+
+ // Data change
+ if (ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 8080))
+ {
+ t.ClientOption->ProxyType = PROXY_HTTP;
+ StrCpy(t.ClientOption->ProxyName, sizeof(t.ClientOption->ProxyName), host);
+ t.ClientOption->ProxyPort = port;
+ StrCpy(t.ClientOption->ProxyUsername, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "USERNAME"));
+ StrCpy(t.ClientOption->ProxyPassword, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "PASSWORD"));
+ Free(host);
+ }
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the cascade connection method as the mode via SOCKS proxy server
+UINT PsCascadeProxySocks(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SERVER", CmdPrompt, _UU("CMD_CascadeProxyHttp_Prompt_Server"), CmdEvalHostAndPort, NULL},
+ {"USERNAME", NULL, NULL, NULL, NULL},
+ {"PASSWORD", NULL, NULL, NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ char *host;
+ UINT port;
+
+ // Data change
+ if (ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 8080))
+ {
+ t.ClientOption->ProxyType = PROXY_SOCKS;
+ StrCpy(t.ClientOption->ProxyName, sizeof(t.ClientOption->ProxyName), host);
+ t.ClientOption->ProxyPort = port;
+ StrCpy(t.ClientOption->ProxyUsername, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "USERNAME"));
+ StrCpy(t.ClientOption->ProxyPassword, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "PASSWORD"));
+ Free(host);
+ }
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable the validation options for the server certificate of cascade connection
+UINT PsCascadeServerCertEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ t.CheckServerCert = true;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disable the validation options for the server certificate of cascade connection
+UINT PsCascadeServerCertDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ t.CheckServerCert = false;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Server-specific certificate settings of cascade connection
+UINT PsCascadeServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ X *x;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ x = FileToXW(GetParamUniStr(o, "LOADCERT"));
+ if (x == NULL)
+ {
+ FreeParamValueList(o);
+ c->Write(c, _UU("CMD_LOADCERT_FAILED"));
+ return ERR_INTERNAL_ERROR;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ FreeX(x);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ if (t.ServerCert != NULL)
+ {
+ FreeX(t.ServerCert);
+ }
+ t.ServerCert = x;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the server-specific certificate of cascade connection
+UINT PsCascadeServerCertDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ if (t.ServerCert != NULL)
+ {
+ FreeX(t.ServerCert);
+ }
+ t.ServerCert = NULL;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the server-specific certificate of cascade connection
+UINT PsCascadeServerCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SAVECERT", CmdPrompt, _UU("CMD_SAVECERTPATH"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Save the certificate
+ if (t.ServerCert == NULL)
+ {
+ c->Write(c, _UU("CMD_CERT_NOT_EXISTS"));
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ if (XToFileW(t.ServerCert, GetParamUniStr(o, "SAVECERT"), true) == false)
+ {
+ c->Write(c, _UU("CMD_SAVECERT_FAILED"));
+ ret = ERR_INTERNAL_ERROR;
+ }
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the advanced settings of the cascade connection
+UINT PsCascadeDetailSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ CMD_EVAL_MIN_MAX mm_maxtcp =
+ {
+ "CMD_CascadeDetailSet_Eval_MaxTcp", 1, 32
+ };
+ CMD_EVAL_MIN_MAX mm_interval =
+ {
+ "CMD_CascadeDetailSet_Eval_Interval", 1, 4294967295UL
+ };
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"MAXTCP", CmdPrompt, _UU("CMD_CascadeDetailSet_Prompt_MaxTcp"), CmdEvalMinMax, &mm_maxtcp},
+ {"INTERVAL", CmdPrompt, _UU("CMD_CascadeDetailSet_Prompt_Interval"), CmdEvalMinMax, &mm_interval},
+ {"TTL", CmdPrompt, _UU("CMD_CascadeDetailSet_Prompt_TTL"), NULL, NULL},
+ {"HALF", CmdPrompt, _UU("CMD_CascadeDetailSet_Prompt_HALF"), NULL, NULL},
+ {"NOQOS", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_NOQOS"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ t.ClientOption->MaxConnection = GetParamInt(o, "MAXTCP");
+ t.ClientOption->AdditionalConnectionInterval = GetParamInt(o, "INTERVAL");
+ t.ClientOption->ConnectionDisconnectSpan = GetParamInt(o, "TTL");
+ t.ClientOption->HalfConnection = GetParamYes(o, "HALF");
+ t.ClientOption->DisableQoS = GetParamYes(o, "NOQOS");
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Show a security policy
+void PrintPolicy(CONSOLE *c, POLICY *pol, bool cascade_mode)
+{
+ UINT i;
+ CT *ct;
+ PACK *p;
+ // Validate arguments
+ if (c == NULL || pol == NULL)
+ {
+ return;
+ }
+
+ ct = CtNew();
+ CtInsertColumn(ct, _UU("CMD_PolicyList_Column_1"), false);
+ CtInsertColumn(ct, _UU("CMD_PolicyList_Column_2"), false);
+ CtInsertColumn(ct, _UU("CMD_PolicyList_Column_3"), false);
+
+ p = NewPack();
+ OutRpcPolicy(p, pol);
+
+ // Show the list of all policies
+ for (i = 0; i < PolicyNum();i++)
+ {
+ char name[64];
+ wchar_t *tmp;
+
+ if (cascade_mode == false || PolicyIsSupportedForCascade(i))
+ {
+ wchar_t value_str[256];
+ UINT value;
+ char tmp2[256];
+
+ Format(tmp2, sizeof(tmp2), "policy:%s", PolicyIdToStr(i));
+ value = PackGetInt(p, tmp2);
+
+ tmp = CopyStrToUni(PolicyIdToStr(i));
+
+ FormatPolicyValue(value_str, sizeof(value_str),
+ i, value);
+
+ Format(name, sizeof(name), "POL_%u", i);
+ CtInsert(ct, tmp, _UU(name), value_str);
+
+ Free(tmp);
+ }
+ }
+
+ FreePack(p);
+
+ CtFree(ct, c);
+}
+
+// Show the security policy list
+void PrintPolicyList(CONSOLE *c, char *name)
+{
+ UINT id;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+ if (IsEmptyStr(name))
+ {
+ name = NULL;
+ }
+
+ if (name != NULL)
+ {
+ id = PolicyStrToId(name);
+ if (id == INFINITE)
+ {
+ // Invalid ID
+ c->Write(c, _UU("CMD_PolicyList_Invalid_Name"));
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ char name1[64], name2[64];
+ wchar_t *title, *descript;
+ wchar_t policy_name[MAX_SIZE];
+
+ Format(name1, sizeof(name1), "POL_%u", id);
+ Format(name2, sizeof(name2), "POL_EX_%u", id);
+
+ title = _UU(name1);
+ descript = _UU(name2);
+
+ StrToUni(policy_name, sizeof(policy_name), PolicyIdToStr(id));
+
+ // Policy name
+ c->Write(c, _UU("CMD_PolicyList_Help_1"));
+ UniFormat(tmp2, sizeof(tmp2), L" %s", policy_name);
+ c->Write(c, tmp2);
+ c->Write(c, L"");
+
+ // Simple description of the policy
+ c->Write(c, _UU("CMD_PolicyList_Help_2"));
+ UniFormat(tmp2, sizeof(tmp2), L" %s", title);
+ c->Write(c, tmp2);
+ c->Write(c, L"");
+
+ // Range of the value that can be set
+ GetPolicyValueRangeStr(tmp, sizeof(tmp), id);
+ c->Write(c, _UU("CMD_PolicyList_Help_3"));
+ UniFormat(tmp2, sizeof(tmp2), L" %s", tmp);
+ c->Write(c, tmp2);
+ c->Write(c, L"");
+
+ // Default value
+ FormatPolicyValue(tmp, sizeof(tmp), id, GetPolicyItem(id)->DefaultValue);
+ c->Write(c, _UU("CMD_PolicyList_Help_4"));
+ UniFormat(tmp2, sizeof(tmp2), L" %s", tmp);
+ c->Write(c, tmp2);
+ c->Write(c, L"");
+
+ // Detailed description of the policy
+ c->Write(c, _UU("CMD_PolicyList_Help_5"));
+ c->Write(c, descript);
+ c->Write(c, L"");
+ }
+ }
+ else
+ {
+ UINT i;
+ CT *ct = CtNew();
+ CtInsertColumn(ct, _UU("CMD_PolicyList_Column_1"), false);
+ CtInsertColumn(ct, _UU("CMD_PolicyList_Column_2"), false);
+
+ // Show the list of all policies
+ for (i = 0; i < PolicyNum();i++)
+ {
+ char name[64];
+ wchar_t *tmp;
+
+ tmp = CopyStrToUni(PolicyIdToStr(i));
+
+ Format(name, sizeof(name), "POL_%u", i);
+ CtInsert(ct, tmp, _UU(name));
+
+ Free(tmp);
+ }
+
+ CtFree(ct, c);
+ }
+}
+
+// Editing the contents of the policy
+bool EditPolicy(CONSOLE *c, POLICY *pol, char *name, char *value, bool cascade_mode)
+{
+ PACK *p;
+ ELEMENT *e;
+ POLICY_ITEM *item;
+ UINT id;
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ char pack_name[128];
+ // Validate arguments
+ if (c == NULL || pol == NULL || name == NULL || value == NULL)
+ {
+ return false;
+ }
+
+ p = NewPack();
+
+ OutRpcPolicy(p, pol);
+
+ Format(pack_name, sizeof(pack_name), "policy:%s", PolicyIdToStr(PolicyStrToId(name)));
+
+ if ((e = GetElement(p, pack_name, VALUE_INT)) == NULL || (id = PolicyStrToId(name)) == INFINITE)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_CascadePolicySet_Invalid_Name"), name);
+ c->Write(c, tmp);
+ FreePack(p);
+ return false;
+ }
+
+ if (cascade_mode && (PolicyIsSupportedForCascade(id) == false))
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_CascadePolicySet_Invalid_Name_For_Cadcade"), name);
+ c->Write(c, tmp);
+ FreePack(p);
+ return false;
+ }
+
+ item = GetPolicyItem(id);
+
+ if (item->TypeInt == false)
+ {
+ // bool type
+ e->values[0]->IntValue = (
+ StartWith(value, "y") || StartWith(value, "t") ||
+ ToInt(value) != 0) ? 1 : 0;
+ }
+ else
+ {
+ UINT n = ToInt(value);
+ bool b = true;
+
+ // int type
+ GetPolicyValueRangeStr(tmp, sizeof(tmp), id);
+
+ if (item->AllowZero == false)
+ {
+ if (n == 0)
+ {
+ b = false;
+ }
+ }
+
+ if (n != 0 && (n < item->MinValue || n > item->MaxValue))
+ {
+ b = false;
+ }
+
+ if (b == false)
+ {
+ UniFormat(tmp2, sizeof(tmp2), _UU("CMD_CascadePolicySet_Invalid_Range"), PolicyIdToStr(id), tmp);
+ c->Write(c, tmp2);
+ FreePack(p);
+ return false;
+ }
+
+ e->values[0]->IntValue = n;
+ }
+
+ Zero(pol, sizeof(POLICY));
+
+ InRpcPolicy(pol, p);
+
+ FreePack(p);
+
+ return true;
+}
+
+// Show the list of the type of security policy and possible values
+UINT PsPolicyList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", NULL, NULL, NULL, NULL}
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ PrintPolicyList(c, GetParamStr(o, "[name]"));
+
+ FreeParamValueList(o);
+
+ return ERR_NO_ERROR;
+}
+
+// Set the security policy of the cascade session
+UINT PsCascadePolicySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"NAME", CmdPrompt, _UU("CMD_CascadePolicySet_PROMPT_POLNAME"), CmdEvalNotEmpty, NULL},
+ {"VALUE", CmdPrompt, _UU("CMD_CascadePolicySet_PROMPT_POLVALUE"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ if (EditPolicy(c, &t.Policy, GetParamStr(o, "NAME"), GetParamStr(o, "VALUE"), true) == false)
+ {
+ // An error has occured
+ FreeRpcCreateLink(&t);
+ FreeParamValueList(o);
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Display the status information of the session
+void CmdPrintStatusToListView(CT *ct, RPC_CLIENT_GET_CONNECTION_STATUS *s)
+{
+ CmdPrintStatusToListViewEx(ct, s, false);
+}
+void CmdPrintStatusToListViewEx(CT *ct, RPC_CLIENT_GET_CONNECTION_STATUS *s, bool server_mode)
+{
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+ char vv[128];
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ if (server_mode == false)
+ {
+ CtInsert(ct, _UU("CM_ST_ACCOUNT_NAME"), s->AccountName);
+
+ if (s->Connected == false)
+ {
+ wchar_t *st = _UU("CM_ST_CONNECTED_FALSE");
+ switch (s->SessionStatus)
+ {
+ case CLIENT_STATUS_CONNECTING:
+ st = _UU("CM_ST_CONNECTING");
+ break;
+ case CLIENT_STATUS_NEGOTIATION:
+ st = _UU("CM_ST_NEGOTIATION");
+ break;
+ case CLIENT_STATUS_AUTH:
+ st = _UU("CM_ST_AUTH");
+ break;
+ case CLIENT_STATUS_ESTABLISHED:
+ st = _UU("CM_ST_ESTABLISHED");
+ break;
+ case CLIENT_STATUS_RETRY:
+ st = _UU("CM_ST_RETRY");
+ break;
+ case CLIENT_STATUS_IDLE:
+ st = _UU("CM_ST_IDLE");
+ break;
+ }
+ CtInsert(ct, _UU("CM_ST_CONNECTED"), st);
+ }
+ else
+ {
+ CtInsert(ct, _UU("CM_ST_CONNECTED"), _UU("CM_ST_CONNECTED_TRUE"));
+ }
+ }
+
+ if (s->Connected)
+ {
+ if (s->VLanId == 0)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_ST_NO_VLAN"));
+ }
+ else
+ {
+ UniToStru(tmp, s->VLanId);
+ }
+
+ CtInsert(ct, _UU("CM_ST_VLAN_ID"), tmp);
+
+ if (server_mode == false)
+ {
+ StrToUni(tmp, sizeof(tmp), s->ServerName);
+ CtInsert(ct, _UU("CM_ST_SERVER_NAME"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_PORT_TCP"), s->ServerPort);
+ CtInsert(ct, _UU("CM_ST_SERVER_PORT"), tmp);
+ }
+
+ StrToUni(tmp, sizeof(tmp), s->ServerProductName);
+ CtInsert(ct, _UU("CM_ST_SERVER_P_NAME"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), L"%u.%02u", s->ServerProductVer / 100, s->ServerProductVer % 100);
+ CtInsert(ct, _UU("CM_ST_SERVER_P_VER"), tmp);
+ UniFormat(tmp, sizeof(tmp), L"Build %u", s->ServerProductBuild);
+ CtInsert(ct, _UU("CM_ST_SERVER_P_BUILD"), tmp);
+ }
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->StartTime), NULL);
+ CtInsert(ct, _UU("CM_ST_START_TIME"), tmp);
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->FirstConnectionEstablisiedTime), NULL);
+ CtInsert(ct, _UU("CM_ST_FIRST_ESTAB_TIME"), s->FirstConnectionEstablisiedTime == 0 ? _UU("CM_ST_NONE") : tmp);
+
+ if (s->Connected)
+ {
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->CurrentConnectionEstablishTime), NULL);
+ CtInsert(ct, _UU("CM_ST_CURR_ESTAB_TIME"), tmp);
+ }
+
+ if (server_mode == false)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_STR"), s->NumConnectionsEatablished);
+ CtInsert(ct, _UU("CM_ST_NUM_ESTABLISHED"), tmp);
+ }
+
+ if (s->Connected)
+ {
+ CtInsert(ct, _UU("CM_ST_HALF_CONNECTION"), s->HalfConnection ? _UU("CM_ST_HALF_TRUE") : _UU("CM_ST_HALF_FALSE"));
+
+ CtInsert(ct, _UU("CM_ST_QOS"), s->QoS ? _UU("CM_ST_QOS_TRUE") : _UU("CM_ST_QOS_FALSE"));
+
+ UniFormat(tmp, sizeof(tmp), L"%u", s->NumTcpConnections);
+ CtInsert(ct, _UU("CM_ST_NUM_TCP"), tmp);
+
+ if (s->HalfConnection)
+ {
+ UniFormat(tmp, sizeof(tmp), L"%u", s->NumTcpConnectionsUpload);
+ CtInsert(ct, _UU("CM_ST_NUM_TCP_UPLOAD"), tmp);
+ UniFormat(tmp, sizeof(tmp), L"%u", s->NumTcpConnectionsDownload);
+ CtInsert(ct, _UU("CM_ST_NUM_TCP_DOWNLOAD"), tmp);
+ }
+
+ UniFormat(tmp, sizeof(tmp), L"%u", s->MaxTcpConnections);
+ CtInsert(ct, _UU("CM_ST_MAX_TCP"), tmp);
+
+ if (s->UseEncrypt == false)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_ST_USE_ENCRYPT_FALSE"));
+ }
+ else
+ {
+ if (StrLen(s->CipherName) != 0)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_USE_ENCRYPT_TRUE"), s->CipherName);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_USE_ENCRYPT_TRUE2"));
+ }
+ }
+ CtInsert(ct, _UU("CM_ST_USE_ENCRYPT"), tmp);
+
+ if (s->UseCompress)
+ {
+ UINT percent = 0;
+ if ((s->TotalRecvSize + s->TotalSendSize) > 0)
+ {
+ percent = (UINT)((UINT64)100 - (UINT64)(s->TotalRecvSizeReal + s->TotalSendSizeReal) * (UINT64)100 /
+ (s->TotalRecvSize + s->TotalSendSize));
+ percent = MAKESURE(percent, 0, 100);
+ }
+
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_COMPRESS_TRUE"), percent);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_ST_COMPRESS_FALSE"));
+ }
+ CtInsert(ct, _UU("CM_ST_USE_COMPRESS"), tmp);
+
+ if (IsEmptyStr(s->UnderlayProtocol) == false)
+ {
+ StrToUni(tmp, sizeof(tmp), s->UnderlayProtocol);
+ CtInsert(ct, _UU("CM_ST_UNDERLAY_PROTOCOL"), tmp);
+ }
+
+ CtInsert(ct, _UU("CM_ST_UDP_ACCEL_ENABLED"), (s->IsUdpAccelerationEnabled ? _UU("CM_ST_YES") : _UU("CM_ST_NO")));
+ CtInsert(ct, _UU("CM_ST_UDP_ACCEL_USING"), (s->IsUsingUdpAcceleration ? _UU("CM_ST_YES") : _UU("CM_ST_NO")));
+
+ StrToUni(tmp, sizeof(tmp), s->SessionName);
+ CtInsert(ct, _UU("CM_ST_SESSION_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), s->ConnectionName);
+ if (UniStrCmpi(tmp, L"INITING") != 0)
+ {
+ CtInsert(ct, _UU("CM_ST_CONNECTION_NAME"), tmp);
+ }
+
+ BinToStr(str, sizeof(str), s->SessionKey, sizeof(s->SessionKey));
+ StrToUni(tmp, sizeof(tmp), str);
+ CtInsert(ct, _UU("CM_ST_SESSION_KEY"), tmp);
+
+ CtInsert(ct, _UU("CM_ST_BRIDGE_MODE"), s->IsBridgeMode ? _UU("CM_ST_YES") : _UU("CM_ST_NO"));
+
+ CtInsert(ct, _UU("CM_ST_MONITOR_MODE"), s->IsMonitorMode ? _UU("CM_ST_YES") : _UU("CM_ST_NO"));
+
+ ToStr3(vv, sizeof(vv), s->TotalSendSize);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_SEND_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->TotalRecvSize);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_RECV_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Send.UnicastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_SEND_UCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Send.UnicastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_SEND_UCAST_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Send.BroadcastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_SEND_BCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Send.BroadcastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_SEND_BCAST_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Recv.UnicastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_RECV_UCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Recv.UnicastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_RECV_UCAST_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Recv.BroadcastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_RECV_BCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Recv.BroadcastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_RECV_BCAST_SIZE"), tmp);
+ }
+}
+
+// Get the current state of the cascade connection
+UINT PsCascadeStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_LINK_STATUS t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLinkStatus(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Get the cascade connection state
+ CT *ct = CtNewStandard();
+
+ CmdPrintStatusToListView(ct, &t.Status);
+
+ CtFree(ct, c);
+
+ FreeRpcLinkStatus(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Rename the cascade connection
+UINT PsCascadeRename(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_RENAME_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeRename_PROMPT_OLD"), CmdEvalNotEmpty, NULL},
+ {"NEW", CmdPrompt, _UU("CMD_CascadeRename_PROMPT_NEW"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ UniStrCpy(t.NewAccountName, sizeof(t.NewAccountName), GetParamUniStr(o, "NEW"));
+ UniStrCpy(t.OldAccountName, sizeof(t.OldAccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScRenameLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the cascade connection to on-line state
+UINT PsCascadeOnline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScSetLinkOnline(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the cascade connection to the off-line state
+UINT PsCascadeOffline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScSetLinkOffline(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Convert the string to pass / discard flag
+bool StrToPassOrDiscard(char *str)
+{
+ // Validate arguments
+ if (str == NULL)
+ {
+ return false;
+ }
+
+ if (ToInt(str) != 0)
+ {
+ return true;
+ }
+
+ if (StartWith(str, "p") || StartWith(str, "y") || StartWith(str, "t"))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Convert the string to the protocol
+UINT StrToProtocol(char *str)
+{
+ if (IsEmptyStr(str))
+ {
+ return 0;
+ }
+
+ if (StartWith("ip", str))
+ {
+ return 0;
+ }
+ else if (StartWith("tcp", str))
+ {
+ return IP_PROTO_TCP;
+ }
+ else if (StartWith("udp", str))
+ {
+ return IP_PROTO_UDP;
+ }
+ else if (StartWith("icmpv4", str))
+ {
+ return IP_PROTO_ICMPV4;
+ }
+ else if (StartWith("icmpv6", str))
+ {
+ return IP_PROTO_ICMPV6;
+ }
+
+ if (ToInt(str) == 0)
+ {
+ if (StrCmpi(str, "0") == 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return INFINITE;
+ }
+ }
+
+ if (ToInt(str) >= 256)
+ {
+ return INFINITE;
+ }
+
+ return ToInt(str);
+}
+
+// Check the protocol name
+bool CmdEvalProtocol(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[64];
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+ if (StrToProtocol(tmp) == INFINITE)
+ {
+ c->Write(c, _UU("CMD_PROTOCOL_EVAL_FAILED"));
+ return false;
+ }
+
+ return true;
+}
+
+// Parse the port range
+bool ParsePortRange(char *str, UINT *start, UINT *end)
+{
+ UINT a = 0, b = 0;
+ TOKEN_LIST *t;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return false;
+ }
+
+ if (IsEmptyStr(str) == false)
+ {
+
+ t = ParseToken(str, "\t -");
+
+ if (t->NumTokens == 1)
+ {
+ a = b = ToInt(t->Token[0]);
+ }
+ else if (t->NumTokens == 2)
+ {
+ a = ToInt(t->Token[0]);
+ b = ToInt(t->Token[1]);
+ }
+
+ FreeToken(t);
+
+ if (a > b)
+ {
+ return false;
+ }
+
+ if (a >= 65536 || b >= 65536)
+ {
+ return false;
+ }
+
+ if (a == 0 && b != 0)
+ {
+ return false;
+ }
+ }
+
+ if (start != NULL)
+ {
+ *start = a;
+ }
+ if (end != NULL)
+ {
+ *end = b;
+ }
+
+ return true;
+}
+
+// Check the port range
+bool CmdEvalPortRange(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[64];
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+ if (ParsePortRange(tmp, NULL, NULL) == false)
+ {
+ c->Write(c, _UU("CMD_PORT_RANGE_EVAL_FAILED"));
+ return false;
+ }
+
+ return true;
+}
+
+// Parse the MAC address and the mask
+bool ParseMacAddressAndMask(char *src, bool *check_mac, UCHAR *mac_bin, UCHAR *mask_bin)
+{
+ TOKEN_LIST *t;
+ char *macstr, *maskstr;
+ UCHAR mac[6], mask[6];
+ bool ok = false;
+
+ // Validate arguments
+ if (src == NULL)
+ {
+ return false;
+ }
+
+ //Zero(mac, sizeof(mac));
+ //Zero(mask, sizeof(mask));
+
+ if(check_mac != NULL && mac_bin != NULL && mask_bin != NULL)
+ {
+ ok = true;
+ }
+ if(IsEmptyStr(src) != false)
+ {
+ if(ok != false)
+ {
+ *check_mac = false;
+ Zero(mac_bin, 6);
+ Zero(mask_bin, 6);
+ }
+ return true;
+ }
+
+ t = ParseToken(src, "/");
+ if(t->NumTokens != 2)
+ {
+ FreeToken(t);
+ return false;
+ }
+
+ macstr = t->Token[0];
+ maskstr = t->Token[1];
+
+ Trim(macstr);
+ Trim(maskstr);
+
+ if(StrToMac(mac, macstr) == false || StrToMac(mask, maskstr) == false)
+ {
+ FreeToken(t);
+ return false;
+ }
+ else
+ {
+ if(ok != false)
+ {
+ Copy(mac_bin, mac, 6);
+ Copy(mask_bin, mask, 6);
+ *check_mac = true;
+ }
+ }
+ FreeToken(t);
+
+ return true;
+}
+
+// Check the MAC address and mask
+bool CmdEvalMacAddressAndMask(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[64];
+ // Validate arguments
+ if(c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+
+ if(ParseMacAddressAndMask(tmp, NULL, NULL, NULL) == false)
+ {
+ c->Write(c, _UU("CMD_MAC_ADDRESS_AND_MASK_EVAL_FAILED"));
+ return false;
+ }
+
+ return true;
+}
+// Parse the status of TCP connection
+bool ParseTcpState(char *src, bool *check_tcp_state, bool *established)
+{
+ bool ok = false;
+ // Validate arguments
+ if(src == NULL)
+ {
+ return false;
+ }
+
+ if(check_tcp_state != NULL && established != NULL)
+ {
+ ok = true;
+ }
+
+ if (IsEmptyStr(src) == false)
+ {
+ if (StartWith("Established", src) == 0)
+ {
+ if(ok != false)
+ {
+ *check_tcp_state = true;
+ *established = true;
+ }
+ }
+ else if (StartWith("Unestablished", src) == 0)
+ {
+ if(ok != false)
+ {
+ *check_tcp_state = true;
+ *established = false;
+ }
+ }
+ else
+ {
+ // Illegal string
+ return false;
+ }
+ }
+ else
+ {
+ if(ok != false)
+ {
+ *check_tcp_state = false;
+ *established = false;
+ }
+ }
+
+ return true;
+}
+// Check the status of the TCP connection
+bool CmdEvalTcpState(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[64];
+ // Validate arguments
+ if(c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+ if(ParseTcpState(tmp, NULL, NULL) == false)
+ {
+ c->Write(c, _UU("CMD_TCP_CONNECTION_STATE_EVAL_FAILED"));
+ return false;
+ }
+
+ return true;
+}
+
+// Adding a rule to the access list (Standard, IPv4)
+UINT PsAccessAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ADD_ACCESS t;
+ ACCESS *a;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX minmax =
+ {
+ "CMD_AccessAdd_Eval_PRIORITY", 1, 4294967295UL,
+ };
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[pass|discard]", CmdPrompt, _UU("CMD_AccessAdd_Prompt_TYPE"), CmdEvalNotEmpty, NULL},
+ {"MEMO", CmdPrompt, _UU("CMD_AccessAdd_Prompt_MEMO"), NULL, NULL},
+ {"PRIORITY", CmdPrompt, _UU("CMD_AccessAdd_Prompt_PRIORITY"), CmdEvalMinMax, &minmax},
+ {"SRCUSERNAME", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCUSERNAME"), NULL, NULL},
+ {"DESTUSERNAME", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTUSERNAME"), NULL, NULL},
+ {"SRCMAC", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCMAC"), CmdEvalMacAddressAndMask, NULL},
+ {"DESTMAC", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTMAC"), CmdEvalMacAddressAndMask, NULL},
+ {"SRCIP", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCIP"), CmdEvalIpAndMask4, NULL},
+ {"DESTIP", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTIP"), CmdEvalIpAndMask4, NULL},
+ {"PROTOCOL", CmdPrompt, _UU("CMD_AccessAdd_Prompt_PROTOCOL"), CmdEvalProtocol, NULL},
+ {"SRCPORT", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCPORT"), CmdEvalPortRange, NULL},
+ {"DESTPORT", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTPORT"), CmdEvalPortRange, NULL},
+ {"TCPSTATE", CmdPrompt, _UU("CMD_AccessAdd_Prompt_TCPSTATE"), CmdEvalTcpState, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ a = &t.Access;
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ UniStrCpy(a->Note, sizeof(a->Note), GetParamUniStr(o, "MEMO"));
+ a->Active = true;
+ a->Priority = GetParamInt(o, "PRIORITY");
+ a->Discard = StrToPassOrDiscard(GetParamStr(o, "[pass|discard]")) ? false : true;
+ StrCpy(a->SrcUsername, sizeof(a->SrcUsername), GetParamStr(o, "SRCUSERNAME"));
+ StrCpy(a->DestUsername, sizeof(a->DestUsername), GetParamStr(o, "DESTUSERNAME"));
+ ParseMacAddressAndMask(GetParamStr(o, "SRCMAC"), &a->CheckSrcMac, a->SrcMacAddress, a->SrcMacMask);
+ ParseMacAddressAndMask(GetParamStr(o, "DESTMAC"), &a->CheckDstMac, a->DstMacAddress, a->DstMacMask);
+ ParseIpAndMask4(GetParamStr(o, "SRCIP"), &a->SrcIpAddress, &a->SrcSubnetMask);
+ ParseIpAndMask4(GetParamStr(o, "DESTIP"), &a->DestIpAddress, &a->DestSubnetMask);
+ a->Protocol = StrToProtocol(GetParamStr(o, "PROTOCOL"));
+ ParsePortRange(GetParamStr(o, "SRCPORT"), &a->SrcPortStart, &a->SrcPortEnd);
+ ParsePortRange(GetParamStr(o, "DESTPORT"), &a->DestPortStart, &a->DestPortEnd);
+ ParseTcpState(GetParamStr(o, "TCPSTATE"), &a->CheckTcpState, &a->Established);
+
+ // RPC call
+ ret = ScAddAccess(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Adding a rule to the access list (Extended, IPv4)
+UINT PsAccessAddEx(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ADD_ACCESS t;
+ ACCESS *a;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX minmax =
+ {
+ "CMD_AccessAdd_Eval_PRIORITY", 1, 4294967295UL,
+ };
+ CMD_EVAL_MIN_MAX minmax_delay =
+ {
+ "CMD_AccessAddEx_Eval_DELAY", 0, HUB_ACCESSLIST_DELAY_MAX,
+ };
+ CMD_EVAL_MIN_MAX minmax_jitter =
+ {
+ "CMD_AccessAddEx_Eval_JITTER", 0, HUB_ACCESSLIST_JITTER_MAX,
+ };
+ CMD_EVAL_MIN_MAX minmax_loss =
+ {
+ "CMD_AccessAddEx_Eval_LOSS", 0, HUB_ACCESSLIST_LOSS_MAX,
+ };
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[pass|discard]", CmdPrompt, _UU("CMD_AccessAdd_Prompt_TYPE"), CmdEvalNotEmpty, NULL},
+ {"MEMO", CmdPrompt, _UU("CMD_AccessAdd_Prompt_MEMO"), NULL, NULL},
+ {"PRIORITY", CmdPrompt, _UU("CMD_AccessAdd_Prompt_PRIORITY"), CmdEvalMinMax, &minmax},
+ {"SRCUSERNAME", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCUSERNAME"), NULL, NULL},
+ {"DESTUSERNAME", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTUSERNAME"), NULL, NULL},
+ {"SRCMAC", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCMAC"), CmdEvalMacAddressAndMask, NULL},
+ {"DESTMAC", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTMAC"), CmdEvalMacAddressAndMask, NULL},
+ {"SRCIP", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCIP"), CmdEvalIpAndMask4, NULL},
+ {"DESTIP", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTIP"), CmdEvalIpAndMask4, NULL},
+ {"PROTOCOL", CmdPrompt, _UU("CMD_AccessAdd_Prompt_PROTOCOL"), CmdEvalProtocol, NULL},
+ {"SRCPORT", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCPORT"), CmdEvalPortRange, NULL},
+ {"DESTPORT", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTPORT"), CmdEvalPortRange, NULL},
+ {"TCPSTATE", CmdPrompt, _UU("CMD_AccessAdd_Prompt_TCPSTATE"), CmdEvalTcpState, NULL},
+ {"DELAY", CmdPrompt, _UU("CMD_AccessAddEx_Prompt_DELAY"), CmdEvalMinMax, &minmax_delay},
+ {"JITTER", CmdPrompt, _UU("CMD_AccessAddEx_Prompt_JITTER"), CmdEvalMinMax, &minmax_jitter},
+ {"LOSS", CmdPrompt, _UU("CMD_AccessAddEx_Prompt_LOSS"), CmdEvalMinMax, &minmax_loss},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Check whether it is supported
+ if (GetCapsBool(ps->CapsList, "b_support_ex_acl") == false)
+ {
+ c->Write(c, _E(ERR_NOT_SUPPORTED));
+ return ERR_NOT_SUPPORTED;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ a = &t.Access;
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ UniStrCpy(a->Note, sizeof(a->Note), GetParamUniStr(o, "MEMO"));
+ a->Active = true;
+ a->Priority = GetParamInt(o, "PRIORITY");
+ a->Discard = StrToPassOrDiscard(GetParamStr(o, "[pass|discard]")) ? false : true;
+ StrCpy(a->SrcUsername, sizeof(a->SrcUsername), GetParamStr(o, "SRCUSERNAME"));
+ StrCpy(a->DestUsername, sizeof(a->DestUsername), GetParamStr(o, "DESTUSERNAME"));
+ ParseMacAddressAndMask(GetParamStr(o, "SRCMAC"), &a->CheckSrcMac, a->SrcMacAddress, a->SrcMacMask);
+ ParseMacAddressAndMask(GetParamStr(o, "DESTMAC"), &a->CheckDstMac, a->DstMacAddress, a->DstMacMask);
+ ParseIpAndMask4(GetParamStr(o, "SRCIP"), &a->SrcIpAddress, &a->SrcSubnetMask);
+ ParseIpAndMask4(GetParamStr(o, "DESTIP"), &a->DestIpAddress, &a->DestSubnetMask);
+ a->Protocol = StrToProtocol(GetParamStr(o, "PROTOCOL"));
+ ParsePortRange(GetParamStr(o, "SRCPORT"), &a->SrcPortStart, &a->SrcPortEnd);
+ ParsePortRange(GetParamStr(o, "DESTPORT"), &a->DestPortStart, &a->DestPortEnd);
+ ParseTcpState(GetParamStr(o, "TCPSTATE"), &a->CheckTcpState, &a->Established);
+ a->Delay = GetParamInt(o, "DELAY");
+ a->Jitter = GetParamInt(o, "JITTER");
+ a->Loss = GetParamInt(o, "LOSS");
+
+ // RPC call
+ ret = ScAddAccess(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Adding a rule to the access list (Standard, IPv6)
+UINT PsAccessAdd6(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ADD_ACCESS t;
+ ACCESS *a;
+ IP ip, mask;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX minmax =
+ {
+ "CMD_AccessAdd6_Eval_PRIORITY", 1, 4294967295UL,
+ };
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[pass|discard]", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_TYPE"), CmdEvalNotEmpty, NULL},
+ {"MEMO", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_MEMO"), NULL, NULL},
+ {"PRIORITY", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_PRIORITY"), CmdEvalMinMax, &minmax},
+ {"SRCUSERNAME", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCUSERNAME"), NULL, NULL},
+ {"DESTUSERNAME", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTUSERNAME"), NULL, NULL},
+ {"SRCMAC", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCMAC"), CmdEvalMacAddressAndMask, NULL},
+ {"DESTMAC", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTMAC"), CmdEvalMacAddressAndMask, NULL},
+ {"SRCIP", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCIP"), CmdEvalIpAndMask6, NULL},
+ {"DESTIP", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTIP"), CmdEvalIpAndMask6, NULL},
+ {"PROTOCOL", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_PROTOCOL"), CmdEvalProtocol, NULL},
+ {"SRCPORT", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCPORT"), CmdEvalPortRange, NULL},
+ {"DESTPORT", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTPORT"), CmdEvalPortRange, NULL},
+ {"TCPSTATE", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_TCPSTATE"), CmdEvalTcpState, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Check whether it is supported
+ if (GetCapsBool(ps->CapsList, "b_support_ex_acl") == false)
+ {
+ c->Write(c, _E(ERR_NOT_SUPPORTED));
+ return ERR_NOT_SUPPORTED;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ a = &t.Access;
+
+ a->IsIPv6 = true;
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ UniStrCpy(a->Note, sizeof(a->Note), GetParamUniStr(o, "MEMO"));
+ a->Active = true;
+ a->Priority = GetParamInt(o, "PRIORITY");
+ a->Discard = StrToPassOrDiscard(GetParamStr(o, "[pass|discard]")) ? false : true;
+ StrCpy(a->SrcUsername, sizeof(a->SrcUsername), GetParamStr(o, "SRCUSERNAME"));
+ StrCpy(a->DestUsername, sizeof(a->DestUsername), GetParamStr(o, "DESTUSERNAME"));
+ ParseMacAddressAndMask(GetParamStr(o, "SRCMAC"), &a->CheckSrcMac, a->SrcMacAddress, a->SrcMacMask);
+ ParseMacAddressAndMask(GetParamStr(o, "DESTMAC"), &a->CheckDstMac, a->DstMacAddress, a->DstMacMask);
+
+ Zero(&ip, sizeof(ip));
+ Zero(&mask, sizeof(mask));
+
+ ParseIpAndMask6(GetParamStr(o, "SRCIP"), &ip, &mask);
+ IPToIPv6Addr(&a->SrcIpAddress6, &ip);
+ IPToIPv6Addr(&a->SrcSubnetMask6, &mask);
+
+ ParseIpAndMask6(GetParamStr(o, "DESTIP"), &ip, &mask);
+ IPToIPv6Addr(&a->DestIpAddress6, &ip);
+ IPToIPv6Addr(&a->DestSubnetMask6, &mask);
+
+ a->Protocol = StrToProtocol(GetParamStr(o, "PROTOCOL"));
+ ParsePortRange(GetParamStr(o, "SRCPORT"), &a->SrcPortStart, &a->SrcPortEnd);
+ ParsePortRange(GetParamStr(o, "DESTPORT"), &a->DestPortStart, &a->DestPortEnd);
+ ParseTcpState(GetParamStr(o, "TCPSTATE"), &a->CheckTcpState, &a->Established);
+
+ // RPC call
+ ret = ScAddAccess(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Adding a rule to the access list (Extended, IPv6)
+UINT PsAccessAddEx6(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ADD_ACCESS t;
+ ACCESS *a;
+ IP ip, mask;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX minmax =
+ {
+ "CMD_AccessAdd6_Eval_PRIORITY", 1, 4294967295UL,
+ };
+ CMD_EVAL_MIN_MAX minmax_delay =
+ {
+ "CMD_AccessAddEx6_Eval_DELAY", 0, HUB_ACCESSLIST_DELAY_MAX,
+ };
+ CMD_EVAL_MIN_MAX minmax_jitter =
+ {
+ "CMD_AccessAddEx6_Eval_JITTER", 0, HUB_ACCESSLIST_JITTER_MAX,
+ };
+ CMD_EVAL_MIN_MAX minmax_loss =
+ {
+ "CMD_AccessAddEx6_Eval_LOSS", 0, HUB_ACCESSLIST_LOSS_MAX,
+ };
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[pass|discard]", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_TYPE"), CmdEvalNotEmpty, NULL},
+ {"MEMO", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_MEMO"), NULL, NULL},
+ {"PRIORITY", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_PRIORITY"), CmdEvalMinMax, &minmax},
+ {"SRCUSERNAME", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCUSERNAME"), NULL, NULL},
+ {"DESTUSERNAME", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTUSERNAME"), NULL, NULL},
+ {"SRCMAC", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCMAC"), CmdEvalMacAddressAndMask, NULL},
+ {"DESTMAC", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTMAC"), CmdEvalMacAddressAndMask, NULL},
+ {"SRCIP", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCIP"), CmdEvalIpAndMask6, NULL},
+ {"DESTIP", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTIP"), CmdEvalIpAndMask6, NULL},
+ {"PROTOCOL", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_PROTOCOL"), CmdEvalProtocol, NULL},
+ {"SRCPORT", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCPORT"), CmdEvalPortRange, NULL},
+ {"DESTPORT", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTPORT"), CmdEvalPortRange, NULL},
+ {"TCPSTATE", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_TCPSTATE"), CmdEvalTcpState, NULL},
+ {"DELAY", CmdPrompt, _UU("CMD_AccessAddEx6_Prompt_DELAY"), CmdEvalMinMax, &minmax_delay},
+ {"JITTER", CmdPrompt, _UU("CMD_AccessAddEx6_Prompt_JITTER"), CmdEvalMinMax, &minmax_jitter},
+ {"LOSS", CmdPrompt, _UU("CMD_AccessAddEx6_Prompt_LOSS"), CmdEvalMinMax, &minmax_loss},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Check whether it is supported
+ if (GetCapsBool(ps->CapsList, "b_support_ex_acl") == false)
+ {
+ c->Write(c, _E(ERR_NOT_SUPPORTED));
+ return ERR_NOT_SUPPORTED;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ a = &t.Access;
+
+ a->IsIPv6 = true;
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ UniStrCpy(a->Note, sizeof(a->Note), GetParamUniStr(o, "MEMO"));
+ a->Active = true;
+ a->Priority = GetParamInt(o, "PRIORITY");
+ a->Discard = StrToPassOrDiscard(GetParamStr(o, "[pass|discard]")) ? false : true;
+ StrCpy(a->SrcUsername, sizeof(a->SrcUsername), GetParamStr(o, "SRCUSERNAME"));
+ StrCpy(a->DestUsername, sizeof(a->DestUsername), GetParamStr(o, "DESTUSERNAME"));
+ ParseMacAddressAndMask(GetParamStr(o, "SRCMAC"), &a->CheckSrcMac, a->SrcMacAddress, a->SrcMacMask);
+ ParseMacAddressAndMask(GetParamStr(o, "DESTMAC"), &a->CheckDstMac, a->DstMacAddress, a->DstMacMask);
+
+ Zero(&ip, sizeof(ip));
+ Zero(&mask, sizeof(mask));
+
+ ParseIpAndMask6(GetParamStr(o, "SRCIP"), &ip, &mask);
+ IPToIPv6Addr(&a->SrcIpAddress6, &ip);
+ IPToIPv6Addr(&a->SrcSubnetMask6, &mask);
+
+ ParseIpAndMask6(GetParamStr(o, "DESTIP"), &ip, &mask);
+ IPToIPv6Addr(&a->DestIpAddress6, &ip);
+ IPToIPv6Addr(&a->DestSubnetMask6, &mask);
+
+ a->Protocol = StrToProtocol(GetParamStr(o, "PROTOCOL"));
+ ParsePortRange(GetParamStr(o, "SRCPORT"), &a->SrcPortStart, &a->SrcPortEnd);
+ ParsePortRange(GetParamStr(o, "DESTPORT"), &a->DestPortStart, &a->DestPortEnd);
+ ParseTcpState(GetParamStr(o, "TCPSTATE"), &a->CheckTcpState, &a->Established);
+ a->Delay = GetParamInt(o, "DELAY");
+ a->Jitter = GetParamInt(o, "JITTER");
+ a->Loss = GetParamInt(o, "LOSS");
+
+ // RPC call
+ ret = ScAddAccess(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+
+// Get the list of rules in the access list
+UINT PsAccessList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_ACCESS_LIST t;
+ CT *ct;
+ UINT i;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumAccess(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNew();
+ CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_0"), true);
+ CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_1"), true);
+ CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_2"), true);
+ CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_3"), true);
+ CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_6"), true);
+ CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_5"), false);
+ CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_4"), false);
+
+ for (i = 0;i < t.NumAccess;i++)
+ {
+ ACCESS *a = &t.Accesses[i];
+ char tmp[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+
+ GetAccessListStr(tmp, sizeof(tmp), a);
+ UniToStru(tmp1, a->Priority);
+ StrToUni(tmp2, sizeof(tmp2), tmp);
+ UniToStru(tmp4, a->UniqueId);
+ if (a->UniqueId == 0)
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SEC_NONE"));
+ }
+
+ UniToStru(tmp3, a->Id);
+
+ CtInsert(ct,
+ tmp3,
+ a->Discard ? _UU("SM_ACCESS_DISCARD") : _UU("SM_ACCESS_PASS"),
+ a->Active ? _UU("SM_ACCESS_ENABLE") : _UU("SM_ACCESS_DISABLE"),
+ tmp1,
+ tmp4,
+ tmp2,
+ a->Note);
+ }
+
+ CtFreeEx(ct, c, true);
+
+ FreeRpcEnumAccessList(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Remove a rule from the access list
+UINT PsAccessDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_DELETE_ACCESS t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_Access_Prompt_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Id = GetParamInt(o, "[id]");
+
+ // RPC call
+ ret = ScDeleteAccess(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable the rule of access list
+UINT PsAccessEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_ACCESS_LIST t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_Access_Prompt_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumAccess(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ bool b = false;
+ for (i = 0;i < t.NumAccess;i++)
+ {
+ ACCESS *a = &t.Accesses[i];
+
+ if (a->Id == GetParamInt(o, "[id]"))
+ {
+ b = true;
+
+ a->Active = true;
+ }
+ }
+
+ if (b == false)
+ {
+ // The specified ID is not found
+ ret = ERR_OBJECT_NOT_FOUND;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ FreeRpcEnumAccessList(&t);
+ return ret;
+ }
+
+ ret = ScSetAccessList(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcEnumAccessList(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Disable the rule of access list
+UINT PsAccessDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_ACCESS_LIST t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_Access_Prompt_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumAccess(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ bool b = false;
+ for (i = 0;i < t.NumAccess;i++)
+ {
+ ACCESS *a = &t.Accesses[i];
+
+ if (a->Id == GetParamInt(o, "[id]"))
+ {
+ b = true;
+
+ a->Active = false;
+ }
+ }
+
+ if (b == false)
+ {
+ // The specified ID is not found
+ ret = ERR_OBJECT_NOT_FOUND;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ FreeRpcEnumAccessList(&t);
+ return ret;
+ }
+
+ ret = ScSetAccessList(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcEnumAccessList(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the user list
+UINT PsUserList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_USER t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ CT *ct = CtNew();
+
+ CtInsertColumn(ct, _UU("SM_USER_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_USER_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_USER_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_USER_COLUMN_4"), false);
+ CtInsertColumn(ct, _UU("SM_USER_COLUMN_5"), false);
+ CtInsertColumn(ct, _UU("SM_USER_COLUMN_6"), false);
+ CtInsertColumn(ct, _UU("SM_USER_COLUMN_7"), false);
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_5"), false);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_6"), false);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_7"), false);
+
+ for (i = 0;i < t.NumUser;i++)
+ {
+ RPC_ENUM_USER_ITEM *e = &t.Users[i];
+ wchar_t name[MAX_SIZE];
+ wchar_t group[MAX_SIZE];
+ wchar_t num[MAX_SIZE];
+ wchar_t time[MAX_SIZE];
+ wchar_t exp[MAX_SIZE];
+ wchar_t num1[64], num2[64];
+
+ StrToUni(name, sizeof(name), e->Name);
+
+ if (StrLen(e->GroupName) != 0)
+ {
+ StrToUni(group, sizeof(group), e->GroupName);
+ }
+ else
+ {
+ UniStrCpy(group, sizeof(group), _UU("SM_NO_GROUP"));
+ }
+
+ UniToStru(num, e->NumLogin);
+
+ GetDateTimeStrEx64(time, sizeof(time), SystemToLocal64(e->LastLoginTime), NULL);
+
+ if (e->IsExpiresFilled == false)
+ {
+ UniStrCpy(exp, sizeof(exp), _UU("CM_ST_NONE"));
+ }
+ else
+ {
+ if (e->Expires == 0)
+ {
+ UniStrCpy(exp, sizeof(exp), _UU("SM_LICENSE_NO_EXPIRES"));
+ }
+ else
+ {
+ GetDateTimeStrEx64(exp, sizeof(exp), SystemToLocal64(e->Expires), NULL);
+ }
+ }
+
+ if (e->IsTrafficFilled == false)
+ {
+ UniStrCpy(num1, sizeof(num1), _UU("CM_ST_NONE"));
+ UniStrCpy(num2, sizeof(num2), _UU("CM_ST_NONE"));
+ }
+ else
+ {
+ UniToStr3(num1, sizeof(num1),
+ e->Traffic.Recv.BroadcastBytes + e->Traffic.Recv.UnicastBytes +
+ e->Traffic.Send.BroadcastBytes + e->Traffic.Send.UnicastBytes);
+
+ UniToStr3(num2, sizeof(num2),
+ e->Traffic.Recv.BroadcastCount + e->Traffic.Recv.UnicastCount +
+ e->Traffic.Send.BroadcastBytes + e->Traffic.Send.UnicastCount);
+ }
+
+ CtInsert(ct,
+ name, e->Realname, group, e->Note, GetAuthTypeStr(e->AuthType),
+ num, time, exp, num1, num2);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get a string of user authentication method
+wchar_t *GetAuthTypeStr(UINT id)
+{
+ char tmp[MAX_SIZE];
+ Format(tmp, sizeof(tmp), "SM_AUTHTYPE_%u", id);
+
+ return _UU(tmp);
+}
+
+// Creating a user
+UINT PsUserCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"GROUP", CmdPrompt, _UU("CMD_UserCreate_Prompt_GROUP"), NULL, NULL},
+ {"REALNAME", CmdPrompt, _UU("CMD_UserCreate_Prompt_REALNAME"), NULL, NULL},
+ {"NOTE", CmdPrompt, _UU("CMD_UserCreate_Prompt_NOTE"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+ StrCpy(t.GroupName, sizeof(t.GroupName), GetParamStr(o, "GROUP"));
+ UniStrCpy(t.Realname, sizeof(t.Realname), GetParamUniStr(o, "REALNAME"));
+ UniStrCpy(t.Note, sizeof(t.Note), GetParamUniStr(o, "NOTE"));
+
+ Trim(t.Name);
+ if (StrCmpi(t.Name, "*") == 0)
+ {
+ t.AuthType = AUTHTYPE_RADIUS;
+ t.AuthData = NewRadiusAuthData(NULL);
+ }
+ else
+ {
+ UCHAR random_pass[SHA1_SIZE];
+ UCHAR random_pass2[MD5_SIZE];
+
+ Rand(random_pass, sizeof(random_pass));
+ Rand(random_pass2, sizeof(random_pass2));
+ t.AuthType = AUTHTYPE_PASSWORD;
+ t.AuthData = NewPasswordAuthDataRaw(random_pass, random_pass2);
+ }
+
+ // RPC call
+ ret = ScCreateUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Change the user information
+UINT PsUserSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"GROUP", CmdPrompt, _UU("CMD_UserCreate_Prompt_GROUP"), NULL, NULL},
+ {"REALNAME", CmdPrompt, _UU("CMD_UserCreate_Prompt_REALNAME"), NULL, NULL},
+ {"NOTE", CmdPrompt, _UU("CMD_UserCreate_Prompt_NOTE"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Update the information
+ StrCpy(t.GroupName, sizeof(t.GroupName), GetParamStr(o, "GROUP"));
+ UniStrCpy(t.Realname, sizeof(t.Realname), GetParamUniStr(o, "REALNAME"));
+ UniStrCpy(t.Note, sizeof(t.Note), GetParamUniStr(o, "NOTE"));
+
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the user
+UINT PsUserDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_DELETE_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScDeleteUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the user information
+UINT PsUserGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ CT *ct;
+
+ // Display the user's data
+ ct = CtNewStandard();
+
+ // User name
+ StrToUni(tmp, sizeof(tmp), t.Name);
+ CtInsert(ct, _UU("CMD_UserGet_Column_Name"), tmp);
+
+ // Real name
+ CtInsert(ct, _UU("CMD_UserGet_Column_RealName"), t.Realname);
+
+ // Description
+ CtInsert(ct, _UU("CMD_UserGet_Column_Note"), t.Note);
+
+ // Group name
+ if (IsEmptyStr(t.GroupName) == false)
+ {
+ StrToUni(tmp, sizeof(tmp), t.GroupName);
+ CtInsert(ct, _UU("CMD_UserGet_Column_Group"), tmp);
+ }
+
+ // Expiration date
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.ExpireTime), NULL);
+ CtInsert(ct, _UU("CMD_UserGet_Column_Expires"), tmp);
+
+ // Authentication method
+ CtInsert(ct, _UU("CMD_UserGet_Column_AuthType"), GetAuthTypeStr(t.AuthType));
+
+ switch (t.AuthType)
+ {
+ case AUTHTYPE_USERCERT:
+ if (t.AuthData != NULL)
+ {
+ AUTHUSERCERT *auc = (AUTHUSERCERT *)t.AuthData;
+
+ if (auc != NULL && auc->UserX != NULL)
+ {
+ // Registered user-specific certificate
+ GetAllNameFromX(tmp, sizeof(tmp), auc->UserX);
+ CtInsert(ct, _UU("CMD_UserGet_Column_UserCert"), tmp);
+ }
+ }
+ break;
+
+ case AUTHTYPE_ROOTCERT:
+ if (t.AuthData != NULL)
+ {
+ AUTHROOTCERT *arc = (AUTHROOTCERT *)t.AuthData;
+
+ if (IsEmptyUniStr(arc->CommonName) == false)
+ {
+ // Limitation the value of the certificate's CN
+ CtInsert(ct, _UU("CMD_UserGet_Column_RootCert_CN"), arc->CommonName);
+ }
+
+ if (arc->Serial != NULL && arc->Serial->size >= 1)
+ {
+ char tmp2[MAX_SIZE];
+
+ // Limitation the serial number of the certificate
+ BinToStrEx(tmp2, sizeof(tmp2), arc->Serial->data, arc->Serial->size);
+ StrToUni(tmp, sizeof(tmp), tmp2);
+ CtInsert(ct, _UU("CMD_UserGet_Column_RootCert_SERIAL"), tmp);
+ }
+ }
+ break;
+
+ case AUTHTYPE_RADIUS:
+ case AUTHTYPE_NT:
+ if (t.AuthData != NULL)
+ {
+ AUTHRADIUS *ar = (AUTHRADIUS *)t.AuthData;
+
+ // Authentication user name of the external authentication server
+ if (IsEmptyUniStr(ar->RadiusUsername) == false)
+ {
+ CtInsert(ct, _UU("CMD_UserGet_Column_RadiusAlias"), ar->RadiusUsername);
+ }
+ }
+ break;
+ }
+
+ CtInsert(ct, L"---", L"---");
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.CreatedTime), NULL);
+ CtInsert(ct, _UU("SM_USERINFO_CREATE"), tmp);
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.UpdatedTime), NULL);
+ CtInsert(ct, _UU("SM_USERINFO_UPDATE"), tmp);
+
+ CmdInsertTrafficInfo(ct, &t.Traffic);
+
+ UniToStru(tmp, t.NumLogin);
+ CtInsert(ct, _UU("SM_USERINFO_NUMLOGIN"), tmp);
+
+
+ CtFree(ct, c);
+
+ if (t.Policy != NULL)
+ {
+ c->Write(c, L"");
+ c->Write(c, _UU("CMD_UserGet_Policy"));
+ PrintPolicy(c, t.Policy, false);
+ }
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the authentication method for the user to the anonymous authentication
+UINT PsUserAnonymousSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Update the information
+ FreeAuthData(t.AuthType, t.AuthData);
+
+ // Set to anonymous authentication
+ t.AuthType = AUTHTYPE_ANONYMOUS;
+ t.AuthData = NULL;
+
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the authentication method for the user to the password authentication and set a password
+UINT PsUserPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Update the information
+ FreeAuthData(t.AuthType, t.AuthData);
+
+ {
+ AUTHPASSWORD *pw;
+
+ pw = NewPasswordAuthData(t.Name, GetParamStr(o, "PASSWORD"));
+
+ // Set to the password authentication
+ t.AuthType = AUTHTYPE_PASSWORD;
+ t.AuthData = pw;
+ }
+
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the authentication method for the user to the specific certificate authentication and set a certificate
+UINT PsUserCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ X *x;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Read the certificate
+ x = FileToXW(GetParamUniStr(o, "LOADCERT"));
+ if (x == NULL)
+ {
+ c->Write(c, _UU("CMD_LOADCERT_FAILED"));
+
+ FreeParamValueList(o);
+
+ return ERR_INTERNAL_ERROR;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ FreeX(x);
+ return ret;
+ }
+
+ // Update the information
+ FreeAuthData(t.AuthType, t.AuthData);
+
+ {
+ AUTHUSERCERT *c;
+
+ c = NewUserCertAuthData(x);
+
+ FreeX(x);
+
+ // Set to the password authentication
+ t.AuthType = AUTHTYPE_USERCERT;
+ t.AuthData = c;
+ }
+
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get certificates that are registered in the user which uses certificate authentication
+UINT PsUserCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ AUTHUSERCERT *a;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"SAVECERT", CmdPrompt, _UU("CMD_SAVECERTPATH"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ a = (AUTHUSERCERT *)t.AuthData;
+
+ if (t.AuthType != AUTHTYPE_USERCERT || a == NULL || a->UserX == NULL)
+ {
+ // The user is not using specific certificate authentication
+ ret = ERR_INVALID_PARAMETER;
+
+ c->Write(c, _UU("CMD_UserCertGet_Not_Cert"));
+ }
+ else
+ {
+ if (XToFileW(a->UserX, GetParamUniStr(o, "SAVECERT"), true) == false)
+ {
+ c->Write(c, _UU("CMD_SAVECERT_FAILED"));
+ }
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the authentication method for the user to the signed certificate authentication
+UINT PsUserSignedSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"CN", CmdPrompt, _UU("CMD_UserSignedSet_Prompt_CN"), NULL, NULL},
+ {"SERIAL", CmdPrompt, _UU("CMD_UserSignedSet_Prompt_SERIAL"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Update the information
+ FreeAuthData(t.AuthType, t.AuthData);
+
+ {
+ AUTHROOTCERT *c;
+ BUF *b;
+ X_SERIAL *serial = NULL;
+
+ b = StrToBin(GetParamStr(o, "SERIAL"));
+
+ if (b != NULL && b->Size >= 1)
+ {
+ serial = NewXSerial(b->Buf, b->Size);
+ }
+
+ FreeBuf(b);
+
+ c = NewRootCertAuthData(serial, GetParamUniStr(o, "CN"));
+
+ FreeXSerial(serial);
+
+ // Set to the signed certificate authentication
+ t.AuthType = AUTHTYPE_ROOTCERT;
+ t.AuthData = c;
+ }
+
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the authentication method for the user to the Radius authentication
+UINT PsUserRadiusSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"ALIAS", CmdPrompt, _UU("CMD_UserRadiusSet_Prompt_ALIAS"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Update the information
+ FreeAuthData(t.AuthType, t.AuthData);
+
+ {
+ AUTHRADIUS *a;
+
+ a = NewRadiusAuthData(GetParamUniStr(o, "ALIAS"));
+
+ // Set to Radius authentication
+ t.AuthType = AUTHTYPE_RADIUS;
+ t.AuthData = a;
+ }
+
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the authentication method for the user to the NT domain authentication
+UINT PsUserNTLMSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"ALIAS", CmdPrompt, _UU("CMD_UserRadiusSet_Prompt_ALIAS"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Update the information
+ FreeAuthData(t.AuthType, t.AuthData);
+
+ {
+ AUTHRADIUS *a;
+
+ a = NewRadiusAuthData(GetParamUniStr(o, "ALIAS"));
+
+ // Set to the NT domain authentication
+ t.AuthType = AUTHTYPE_NT;
+ t.AuthData = a;
+ }
+
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the security policy of the user
+UINT PsUserPolicyRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Update
+ if (t.Policy != NULL)
+ {
+ Free(t.Policy);
+ t.Policy = NULL;
+ }
+
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set a security policy of the user
+UINT PsUserPolicySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"NAME", CmdPrompt, _UU("CMD_CascadePolicySet_PROMPT_POLNAME"), CmdEvalNotEmpty, NULL},
+ {"VALUE", CmdPrompt, _UU("CMD_CascadePolicySet_PROMPT_POLVALUE"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Update
+ if (t.Policy == NULL)
+ {
+ t.Policy = ClonePolicy(GetDefaultPolicy());
+ }
+
+ // Edit
+ if (EditPolicy(c, t.Policy, GetParamStr(o, "NAME"), GetParamStr(o, "VALUE"), false) == false)
+ {
+ ret = ERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Convert the string to a date and time
+UINT64 StrToDateTime64(char *str)
+{
+ UINT64 ret = 0;
+ TOKEN_LIST *t;
+ UINT a, b, c, d, e, f;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return INFINITE;
+ }
+
+ if (IsEmptyStr(str) || StrCmpi(str, "none") == 0)
+ {
+ return 0;
+ }
+
+ t = ParseToken(str, ":/,. \"");
+ if (t->NumTokens != 6)
+ {
+ FreeToken(t);
+ return INFINITE;
+ }
+
+ a = ToInt(t->Token[0]);
+ b = ToInt(t->Token[1]);
+ c = ToInt(t->Token[2]);
+ d = ToInt(t->Token[3]);
+ e = ToInt(t->Token[4]);
+ f = ToInt(t->Token[5]);
+
+ ret = INFINITE;
+
+ if (a >= 1000 && a <= 9999 && b >= 1 && b <= 12 && c >= 1 && c <= 31 &&
+ d >= 0 && d <= 23 && e >= 0 && e <= 59 && f >= 0 && f <= 59)
+ {
+ SYSTEMTIME t;
+
+ Zero(&t, sizeof(t));
+ t.wYear = a;
+ t.wMonth = b;
+ t.wDay = c;
+ t.wHour = d;
+ t.wMinute = e;
+ t.wSecond = f;
+
+ ret = SystemToUINT64(&t);
+ }
+
+ FreeToken(t);
+
+ return ret;
+}
+
+// Evaluate the date and time string
+bool CmdEvalDateTime(CONSOLE *c, wchar_t *str, void *param)
+{
+ UINT64 ret;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+ ret = StrToDateTime64(tmp);
+
+ if (ret == INFINITE)
+ {
+ c->Write(c, _UU("CMD_EVAL_DATE_TIME_FAILED"));
+ return false;
+ }
+
+ return true;
+}
+
+// Set the expiration date of the user
+UINT PsUserExpiresSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ UINT64 expires;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"EXPIRES", CmdPrompt, _UU("CMD_UserExpiresSet_Prompt_EXPIRES"), CmdEvalDateTime, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Update the information
+ expires = StrToDateTime64(GetParamStr(o, "EXPIRES"));
+
+ if (expires != 0)
+ {
+ expires = LocalToSystem64(expires);
+ }
+
+ t.ExpireTime = expires;
+
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the group list
+UINT PsGroupList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_GROUP t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNew();
+ UINT i;
+
+ CtInsertColumn(ct, _UU("SM_GROUPLIST_NAME"), false);
+ CtInsertColumn(ct, _UU("SM_GROUPLIST_REALNAME"), false);
+ CtInsertColumn(ct, _UU("SM_GROUPLIST_NOTE"), false);
+ CtInsertColumn(ct, _UU("SM_GROUPLIST_NUMUSERS"), false);
+
+ for (i = 0;i < t.NumGroup;i++)
+ {
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ RPC_ENUM_GROUP_ITEM *e = &t.Groups[i];
+
+ StrToUni(tmp1, sizeof(tmp1), e->Name);
+ UniToStru(tmp2, e->NumUsers);
+
+ CtInsert(ct, tmp1, e->Realname, e->Note, tmp2);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumGroup(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Create a group
+UINT PsGroupCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_GROUP t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"REALNAME", CmdPrompt, _UU("CMD_GroupCreate_Prompt_REALNAME"), NULL, NULL},
+ {"NOTE", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NOTE"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+ UniStrCpy(t.Realname, sizeof(t.Realname), GetParamUniStr(o, "REALNAME"));
+ UniStrCpy(t.Note, sizeof(t.Note), GetParamUniStr(o, "NOTE"));
+
+ // RPC call
+ ret = ScCreateGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetGroup(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the group information
+UINT PsGroupSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_GROUP t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"REALNAME", CmdPrompt, _UU("CMD_GroupCreate_Prompt_REALNAME"), NULL, NULL},
+ {"NOTE", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NOTE"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Information update
+ UniStrCpy(t.Realname, sizeof(t.Realname), GetParamUniStr(o, "REALNAME"));
+ UniStrCpy(t.Note, sizeof(t.Note), GetParamUniStr(o, "NOTE"));
+
+ // RPC call
+ ret = ScSetGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetGroup(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete a group
+UINT PsGroupDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_DELETE_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScDeleteGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the group information and the list of users who belong to the group
+UINT PsGroupGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_GROUP t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ char groupname[MAX_USERNAME_LEN + 1];
+ CT *ct = CtNewStandard();
+
+ StrCpy(groupname, sizeof(groupname), t.Name);
+
+ StrToUni(tmp, sizeof(tmp), t.Name);
+ CtInsert(ct, _UU("CMD_GroupGet_Column_NAME"), tmp);
+ CtInsert(ct, _UU("CMD_GroupGet_Column_REALNAME"), t.Realname);
+ CtInsert(ct, _UU("CMD_GroupGet_Column_NOTE"), t.Note);
+
+ CtFree(ct, c);
+
+ if (t.Policy != NULL)
+ {
+ c->Write(c, L"");
+ c->Write(c, _UU("CMD_GroupGet_Column_POLICY"));
+
+ PrintPolicy(c, t.Policy, false);
+ }
+
+ {
+ RPC_ENUM_USER t;
+ bool b = false;
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ if (ScEnumUser(ps->Rpc, &t) == ERR_NO_ERROR)
+ {
+ UINT i;
+
+ for (i = 0;i < t.NumUser;i++)
+ {
+ RPC_ENUM_USER_ITEM *u = &t.Users[i];
+
+ if (StrCmpi(u->GroupName, groupname) == 0)
+ {
+ if (b == false)
+ {
+ b = true;
+ c->Write(c, L"");
+ c->Write(c, _UU("CMD_GroupGet_Column_MEMBERS"));
+ }
+
+ UniFormat(tmp, sizeof(tmp), L" %S", u->Name);
+ c->Write(c, tmp);
+ }
+ }
+ FreeRpcEnumUser(&t);
+
+ if (b)
+ {
+ c->Write(c, L"");
+ }
+ }
+ }
+
+ }
+
+ FreeRpcSetGroup(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Add an user to the group
+UINT PsGroupJoin(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"USERNAME", CmdPrompt, _UU("CMD_GroupJoin_Prompt_USERNAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "USERNAME"));
+
+ // RPC call
+ ret = ScGetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Update the Group
+ StrCpy(t.GroupName, sizeof(t.GroupName), GetParamStr(o, "[name]"));
+
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the user from a group
+UINT PsGroupUnjoin(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_GroupUnjoin_Prompt_name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Update the Group
+ StrCpy(t.GroupName, sizeof(t.GroupName), "");
+
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the security policy of the group
+UINT PsGroupPolicyRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_GROUP t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Update
+ if (t.Policy != NULL)
+ {
+ Free(t.Policy);
+ t.Policy = NULL;
+ }
+
+ ret = ScSetGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeRpcSetGroup(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set a security policy to a group
+UINT PsGroupPolicySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_GROUP t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"NAME", CmdPrompt, _UU("CMD_CascadePolicySet_PROMPT_POLNAME"), CmdEvalNotEmpty, NULL},
+ {"VALUE", CmdPrompt, _UU("CMD_CascadePolicySet_PROMPT_POLVALUE"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Update
+ if (t.Policy == NULL)
+ {
+ t.Policy = ClonePolicy(GetDefaultPolicy());
+ }
+
+ if (EditPolicy(c, t.Policy, GetParamStr(o, "NAME"), GetParamStr(o, "VALUE"), false) == false)
+ {
+ // An error has occured
+ FreeRpcSetGroup(&t);
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = ScSetGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeRpcSetGroup(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the connected session list
+UINT PsSessionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_SESSION t;
+ UINT server_type = 0;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ {
+ // Get the server type
+ RPC_SERVER_INFO t;
+
+ Zero(&t, sizeof(t));
+
+ if (ScGetServerInfo(ps->Rpc, &t) == ERR_NO_ERROR)
+ {
+ server_type = t.ServerType;
+
+ FreeRpcServerInfo(&t);
+ }
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumSession(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNew();
+ UINT i;
+
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_8"), false);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_4"), false);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_5"), true);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_6"), true);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_7"), true);
+
+ for (i = 0;i < t.NumSession;i++)
+ {
+ RPC_ENUM_SESSION_ITEM *e = &t.Sessions[i];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t *tmp2;
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t tmp5[MAX_SIZE];
+ wchar_t tmp6[MAX_SIZE];
+ wchar_t tmp7[MAX_SIZE];
+ wchar_t tmp8[MAX_SIZE];
+ bool free_tmp2 = false;
+
+ StrToUni(tmp1, sizeof(tmp1), e->Name);
+
+ tmp2 = _UU("SM_SESS_NORMAL");
+ if (server_type != SERVER_TYPE_STANDALONE)
+ {
+ if (e->RemoteSession)
+ {
+ tmp2 = ZeroMalloc(MAX_SIZE);
+ UniFormat(tmp2, MAX_SIZE, _UU("SM_SESS_REMOTE"), e->RemoteHostname);
+ free_tmp2 = true;
+ }
+ else
+ {
+ if (StrLen(e->RemoteHostname) == 0)
+ {
+ tmp2 = _UU("SM_SESS_LOCAL");
+ }
+ else
+ {
+ tmp2 = ZeroMalloc(MAX_SIZE);
+ UniFormat(tmp2, MAX_SIZE, _UU("SM_SESS_LOCAL_2"), e->RemoteHostname);
+ free_tmp2 = true;
+ }
+ }
+ }
+ if (e->LinkMode)
+ {
+ if (free_tmp2)
+ {
+ Free(tmp2);
+ free_tmp2 = false;
+ }
+ tmp2 = _UU("SM_SESS_LINK");
+ }
+ else if (e->SecureNATMode)
+ {
+ /*if (free_tmp2)
+ {
+ Free(tmp2);
+ free_tmp2 = false;
+ }*/
+ tmp2 = _UU("SM_SESS_SNAT");
+ }
+
+ StrToUni(tmp3, sizeof(tmp3), e->Username);
+
+ StrToUni(tmp4, sizeof(tmp4), e->Hostname);
+ if (e->LinkMode)
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_LINK_HOSTNAME"));
+ }
+ else if (e->SecureNATMode)
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_SNAT_HOSTNAME"));
+ }
+ else if (e->BridgeMode)
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_BRIDGE_HOSTNAME"));
+ }
+ else if (StartWith(e->Username, L3_USERNAME))
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_LAYER3_HOSTNAME"));
+ }
+
+ UniFormat(tmp5, sizeof(tmp5), L"%u / %u", e->CurrentNumTcp, e->MaxNumTcp);
+ if (e->LinkMode)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_SESS_LINK_TCP"));
+ }
+ else if (e->SecureNATMode)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_SESS_SNAT_TCP"));
+ }
+ else if (e->BridgeMode)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_SESS_BRIDGE_TCP"));
+ }
+
+ UniToStr3(tmp6, sizeof(tmp6), e->PacketSize);
+ UniToStr3(tmp7, sizeof(tmp7), e->PacketNum);
+
+ if (e->VLanId == 0)
+ {
+ UniStrCpy(tmp8, sizeof(tmp8), _UU("CM_ST_NO_VLAN"));
+ }
+ else
+ {
+ UniToStru(tmp8, e->VLanId);
+ }
+
+ CtInsert(ct, tmp1, tmp8, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7);
+
+ if (free_tmp2)
+ {
+ Free(tmp2);
+ }
+ }
+
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumSession(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Display the NODE_INFO
+void CmdPrintNodeInfo(CT *ct, NODE_INFO *info)
+{
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+ // Validate arguments
+ if (ct == NULL || info == NULL)
+ {
+ return;
+ }
+
+ StrToUni(tmp, sizeof(tmp), info->ClientProductName);
+ CtInsert(ct, _UU("SM_NODE_CLIENT_NAME"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), L"%u.%02u", Endian32(info->ClientProductVer) / 100, Endian32(info->ClientProductVer) % 100);
+ CtInsert(ct, _UU("SM_NODE_CLIENT_VER"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), L"Build %u", Endian32(info->ClientProductBuild));
+ CtInsert(ct, _UU("SM_NODE_CLIENT_BUILD"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), info->ClientOsName);
+ CtInsert(ct, _UU("SM_NODE_CLIENT_OS_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), info->ClientOsVer);
+ CtInsert(ct, _UU("SM_NODE_CLIENT_OS_VER"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), info->ClientOsProductId);
+ CtInsert(ct, _UU("SM_NODE_CLIENT_OS_PID"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), info->ClientHostname);
+ CtInsert(ct, _UU("SM_NODE_CLIENT_HOST"), tmp);
+
+ IPToStr4or6(str, sizeof(str), info->ClientIpAddress, info->ClientIpAddress6);
+ StrToUni(tmp, sizeof(tmp), str);
+ CtInsert(ct, _UU("SM_NODE_CLIENT_IP"), tmp);
+
+ UniToStru(tmp, Endian32(info->ClientPort));
+ CtInsert(ct, _UU("SM_NODE_CLIENT_PORT"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), info->ServerHostname);
+ CtInsert(ct, _UU("SM_NODE_SERVER_HOST"), tmp);
+
+ IPToStr4or6(str, sizeof(str), info->ServerIpAddress, info->ServerIpAddress6);
+ StrToUni(tmp, sizeof(tmp), str);
+ CtInsert(ct, _UU("SM_NODE_SERVER_IP"), tmp);
+
+ UniToStru(tmp, Endian32(info->ServerPort));
+ CtInsert(ct, _UU("SM_NODE_SERVER_PORT"), tmp);
+
+ if (StrLen(info->ProxyHostname) != 0)
+ {
+ StrToUni(tmp, sizeof(tmp), info->ProxyHostname);
+ CtInsert(ct, _UU("SM_NODE_PROXY_HOSTNAME"), tmp);
+
+ IPToStr4or6(str, sizeof(str), info->ProxyIpAddress, info->ProxyIpAddress6);
+ StrToUni(tmp, sizeof(tmp), str);
+ CtInsert(ct, _UU("SM_NODE_PROXY_IP"), tmp);
+
+ UniToStru(tmp, Endian32(info->ProxyPort));
+ CtInsert(ct, _UU("SM_NODE_PROXY_PORT"), tmp);
+ }
+}
+
+// Get the session information
+UINT PsSessionGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SESSION_STATUS t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_SessionGet_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetSessionStatus(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+ CT *ct = CtNewStandard();
+
+ if (t.ClientIp != 0)
+ {
+ IPToStr4or6(str, sizeof(str), t.ClientIp, t.ClientIp6);
+ StrToUni(tmp, sizeof(tmp), str);
+ CtInsert(ct, _UU("SM_CLIENT_IP"), tmp);
+ }
+
+ if (StrLen(t.ClientHostName) != 0)
+ {
+ StrToUni(tmp, sizeof(tmp), t.ClientHostName);
+ CtInsert(ct, _UU("SM_CLIENT_HOSTNAME"), tmp);
+ }
+
+ StrToUni(tmp, sizeof(tmp), t.Username);
+ CtInsert(ct, _UU("SM_SESS_STATUS_USERNAME"), tmp);
+
+ if (StrCmpi(t.Username, LINK_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, SNAT_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, BRIDGE_USER_NAME_PRINT) != 0)
+ {
+ StrToUni(tmp, sizeof(tmp), t.RealUsername);
+ CtInsert(ct, _UU("SM_SESS_STATUS_REALUSER"), tmp);
+ }
+
+ if (IsEmptyStr(t.GroupName) == false)
+ {
+ StrToUni(tmp, sizeof(tmp), t.GroupName);
+ CtInsert(ct, _UU("SM_SESS_STATUS_GROUPNAME"), tmp);
+ }
+
+
+ CmdPrintStatusToListViewEx(ct, &t.Status, true);
+
+ if (StrCmpi(t.Username, LINK_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, SNAT_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, BRIDGE_USER_NAME_PRINT) != 0 &&
+ StartWith(t.Username, L3_USERNAME) == false)
+ {
+ CmdPrintNodeInfo(ct, &t.NodeInfo);
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeRpcSessionStatus(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disconnect the session
+UINT PsSessionDisconnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_DELETE_SESSION t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_SessionGet_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScDeleteSession(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the MAC address table database
+UINT PsMacTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_MAC_TABLE t;
+ UINT i;
+
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[session_name]", NULL, NULL, NULL, NULL,}
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumMacTable(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNew();
+ char *session_name = GetParamStr(o, "[session_name]");
+
+ if (IsEmptyStr(session_name))
+ {
+ session_name = NULL;
+ }
+
+ CtInsertColumn(ct, _UU("CMD_ID"), false);
+ CtInsertColumn(ct, _UU("SM_MAC_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_MAC_COLUMN_1A"), false);
+ CtInsertColumn(ct, _UU("SM_MAC_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_MAC_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_MAC_COLUMN_4"), false);
+ CtInsertColumn(ct, _UU("SM_MAC_COLUMN_5"), false);
+
+ for (i = 0;i < t.NumMacTable;i++)
+ {
+ char str[MAX_SIZE];
+ wchar_t tmp0[128];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t tmp5[MAX_SIZE];
+ wchar_t tmp6[MAX_SIZE];
+
+ RPC_ENUM_MAC_TABLE_ITEM *e = &t.MacTables[i];
+
+ if (session_name == NULL || StrCmpi(e->SessionName, session_name) == 0)
+ {
+ UniToStru(tmp0, e->Key);
+
+ StrToUni(tmp1, sizeof(tmp1), e->SessionName);
+
+ MacToStr(str, sizeof(str), e->MacAddress);
+ StrToUni(tmp2, sizeof(tmp2), str);
+
+ GetDateTimeStr64Uni(tmp3, sizeof(tmp3), SystemToLocal64(e->CreatedTime));
+
+ GetDateTimeStr64Uni(tmp4, sizeof(tmp4), SystemToLocal64(e->UpdatedTime));
+
+ if (StrLen(e->RemoteHostname) == 0)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_MACIP_LOCAL"));
+ }
+ else
+ {
+ UniFormat(tmp5, sizeof(tmp5), _UU("SM_MACIP_SERVER"), e->RemoteHostname);
+ }
+
+ UniToStru(tmp6, e->VlanId);
+ if (e->VlanId == 0)
+ {
+ UniStrCpy(tmp6, sizeof(tmp6), _UU("CM_ST_NONE"));
+ }
+
+ CtInsert(ct,
+ tmp0, tmp1, tmp6, tmp2, tmp3, tmp4, tmp5);
+ }
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumMacTable(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete a MAC address table entry
+UINT PsMacDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_DELETE_TABLE t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_MacDelete_Prompt"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Key = GetParamInt(o, "[id]");
+
+ // RPC call
+ ret = ScDeleteMacTable(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the IP address table database
+UINT PsIpTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_IP_TABLE t;
+ UINT i;
+
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[session_name]", NULL, NULL, NULL, NULL,}
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumIpTable(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNew();
+ char *session_name = GetParamStr(o, "[session_name]");
+
+ if (IsEmptyStr(session_name))
+ {
+ session_name = NULL;
+ }
+
+ CtInsertColumn(ct, _UU("CMD_ID"), false);
+ CtInsertColumn(ct, _UU("SM_IP_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_IP_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_IP_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_IP_COLUMN_4"), false);
+ CtInsertColumn(ct, _UU("SM_IP_COLUMN_5"), false);
+
+ for (i = 0;i < t.NumIpTable;i++)
+ {
+ char str[MAX_SIZE];
+ wchar_t tmp0[128];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t tmp5[MAX_SIZE];
+ RPC_ENUM_IP_TABLE_ITEM *e = &t.IpTables[i];
+
+ if (session_name == NULL || StrCmpi(e->SessionName, session_name) == 0)
+ {
+ UniToStru(tmp0, e->Key);
+
+ StrToUni(tmp1, sizeof(tmp1), e->SessionName);
+
+ if (e->DhcpAllocated == false)
+ {
+ IPToStr(str, sizeof(str), &e->IpV6);
+ StrToUni(tmp2, sizeof(tmp2), str);
+ }
+ else
+ {
+ IPToStr(str, sizeof(str), &e->IpV6);
+ UniFormat(tmp2, sizeof(tmp2), _UU("SM_MAC_IP_DHCP"), str);
+ }
+
+ GetDateTimeStr64Uni(tmp3, sizeof(tmp3), SystemToLocal64(e->CreatedTime));
+
+ GetDateTimeStr64Uni(tmp4, sizeof(tmp4), SystemToLocal64(e->UpdatedTime));
+
+ if (StrLen(e->RemoteHostname) == 0)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_MACIP_LOCAL"));
+ }
+ else
+ {
+ UniFormat(tmp5, sizeof(tmp5), _UU("SM_MACIP_SERVER"), e->RemoteHostname);
+ }
+
+ CtInsert(ct,
+ tmp0, tmp1, tmp2, tmp3, tmp4, tmp5);
+ }
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumIpTable(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the IP address table entry
+UINT PsIpDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_DELETE_TABLE t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_MacDelete_Prompt"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Key = GetParamInt(o, "[id]");
+
+ // RPC call
+ ret = ScDeleteIpTable(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable the DHCP server function and the virtual NAT (SecureNAT function)
+UINT PsSecureNatEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnableSecureNAT(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disable the DHCP server function and the virtual NAT (SecureNAT function)
+UINT PsSecureNatDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScDisableSecureNAT(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the operating status of the DHCP server function and the virtual NAT (SecureNAT function)
+UINT PsSecureNatStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_NAT_STATUS t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATStatus(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ CT *ct = CtNewStandard();
+
+ StrToUni(tmp, sizeof(tmp), ps->HubName);
+ CtInsert(ct, _UU("SM_HUB_COLUMN_1"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumTcpSessions);
+ CtInsert(ct, _UU("NM_STATUS_TCP"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumUdpSessions);
+ CtInsert(ct, _UU("NM_STATUS_UDP"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumIcmpSessions);
+ CtInsert(ct, _UU("NM_STATUS_ICMP"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumDnsSessions);
+ CtInsert(ct, _UU("NM_STATUS_DNS"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_CLIENT"), t.NumDhcpClients);
+ CtInsert(ct, _UU("NM_STATUS_DHCP"), tmp);
+
+ CtInsert(ct, _UU("SM_SNAT_IS_KERNEL"), t.IsKernelMode ? _UU("SEC_YES") : _UU("SEC_NO"));
+
+ CtFree(ct, c);
+ }
+
+ FreeRpcNatStatus(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the network interface settings for a virtual host of SecureNAT function
+UINT PsSecureNatHostGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+ CT *ct = CtNewStandard();
+
+ // Flags
+ // MAC Address
+ MacToStr(str, sizeof(str), t.MacAddress);
+ StrToUni(tmp, sizeof(tmp), str);
+ CtInsert(ct, _UU("CMD_SecureNatHostGet_Column_MAC"), tmp);
+
+ // IP address
+ IPToUniStr(tmp, sizeof(tmp), &t.Ip);
+ CtInsert(ct, _UU("CMD_SecureNatHostGet_Column_IP"), tmp);
+
+ // Subnet mask
+ IPToUniStr(tmp, sizeof(tmp), &t.Mask);
+ CtInsert(ct, _UU("CMD_SecureNatHostGet_Column_MASK"), tmp);
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Change the network interface settings for a virtual host of SecureNAT function
+UINT PsSecureNatHostSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"MAC", CmdPrompt, _UU("CMD_SecureNatHostSet_Prompt_MAC"), NULL, NULL},
+ {"IP", CmdPrompt, _UU("CMD_SecureNatHostSet_Prompt_IP"), CmdEvalIp, NULL},
+ {"MASK", CmdPrompt, _UU("CMD_SecureNatHostSet_Prompt_MASK"), CmdEvalIp, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ char *mac, *ip, *mask;
+ bool ok = true;
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ mac = GetParamStr(o, "MAC");
+ ip = GetParamStr(o, "IP");
+ mask = GetParamStr(o, "MASK");
+
+ if (IsEmptyStr(mac) == false)
+ {
+ BUF *b = StrToBin(mac);
+
+ if (b == NULL || b->Size != 6)
+ {
+ ok = false;
+ }
+ else
+ {
+ Copy(t.MacAddress, b->Buf, 6);
+ }
+
+ FreeBuf(b);
+ }
+
+ if (IsEmptyStr(ip) == false)
+ {
+ if (IsIpStr4(ip) == false)
+ {
+ ok = false;
+ }
+ else
+ {
+ UINT u = StrToIP32(ip);
+
+ if (u == 0 || u == 0xffffffff)
+ {
+ ok = false;
+ }
+ else
+ {
+ UINTToIP(&t.Ip, u);
+ }
+ }
+ }
+
+ if (IsEmptyStr(mask) == false)
+ {
+ if (IsIpStr4(mask) == false)
+ {
+ ok = false;
+ }
+ else
+ {
+ StrToIP(&t.Mask, mask);
+ }
+ }
+
+ if (ok == false)
+ {
+ // Parameter is invalid
+ ret = ERR_INVALID_PARAMETER;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the settings for the virtual NAT function of the SecureNAT function
+UINT PsNatGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ CT *ct = CtNewStandard();
+
+ // Use the virtual NAT function
+ CtInsert(ct, _UU("CMD_NatGet_Column_USE"), t.UseNat ? _UU("SEC_YES") : _UU("SEC_NO"));
+
+ // MTU value
+ UniToStru(tmp, t.Mtu);
+ CtInsert(ct, _UU("CMD_NetGet_Column_MTU"), tmp);
+
+ // TCP session timeout (in seconds)
+ UniToStru(tmp, t.NatTcpTimeout);
+ CtInsert(ct, _UU("CMD_NatGet_Column_TCP"), tmp);
+
+ // UDP session timeout (in seconds)
+ UniToStru(tmp, t.NatUdpTimeout);
+ CtInsert(ct, _UU("CMD_NatGet_Column_UDP"), tmp);
+
+ // To save the log
+ CtInsert(ct, _UU("CMD_SecureNatHostGet_Column_LOG"), t.SaveLog ? _UU("SEC_YES") : _UU("SEC_NO"));
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable the virtual NAT function of the SecureNAT function
+UINT PsNatEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ bool ok = true;
+
+ t.UseNat = true;
+
+ if (ok == false)
+ {
+ // Parameter is invalid
+ ret = ERR_INVALID_PARAMETER;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disable the virtual NAT function of the SecureNAT function
+UINT PsNatDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ bool ok = true;
+
+ t.UseNat = false;
+
+ if (ok == false)
+ {
+ // Parameter is invalid
+ ret = ERR_INVALID_PARAMETER;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Change the settings for the virtual NAT function of the SecureNAT function
+UINT PsNatSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX mtu_mm =
+ {
+ "CMD_NatSet_Eval_MTU", TCP_HEADER_SIZE + IP_HEADER_SIZE + MAC_HEADER_SIZE + 8, MAX_L3_DATA_SIZE,
+ };
+ CMD_EVAL_MIN_MAX tcp_mm =
+ {
+ "CMD_NatSet_Eval_TCP", NAT_TCP_MIN_TIMEOUT / 1000, NAT_TCP_MAX_TIMEOUT / 1000,
+ };
+ CMD_EVAL_MIN_MAX udp_mm =
+ {
+ "CMD_NatSet_Eval_UDP", NAT_UDP_MIN_TIMEOUT / 1000, NAT_UDP_MAX_TIMEOUT / 1000,
+ };
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"MTU", CmdPrompt, _UU("CMD_NatSet_Prompt_MTU"), CmdEvalMinMax, &mtu_mm},
+ {"TCPTIMEOUT", CmdPrompt, _UU("CMD_NatSet_Prompt_TCPTIMEOUT"), CmdEvalMinMax, &tcp_mm},
+ {"UDPTIMEOUT", CmdPrompt, _UU("CMD_NatSet_Prompt_UDPTIMEOUT"), CmdEvalMinMax, &udp_mm},
+ {"LOG", CmdPrompt, _UU("CMD_NatSet_Prompt_LOG"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ bool ok = true;
+
+ t.Mtu = GetParamInt(o, "MTU");
+ t.NatTcpTimeout = GetParamInt(o, "TCPTIMEOUT");
+ t.NatUdpTimeout = GetParamInt(o, "UDPTIMEOUT");
+ t.SaveLog = GetParamYes(o, "LOG");
+
+ if (ok == false)
+ {
+ // Parameter is invalid
+ ret = ERR_INVALID_PARAMETER;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the session table of the virtual NAT function of the SecureNAT function
+UINT PsNatTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_NAT t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumNAT(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNew();
+ UINT i;
+
+ CtInsertColumn(ct, _UU("NM_NAT_ID"), false);
+ CtInsertColumn(ct, _UU("NM_NAT_PROTOCOL"), false);
+ CtInsertColumn(ct, _UU("NM_NAT_SRC_HOST"), false);
+ CtInsertColumn(ct, _UU("NM_NAT_SRC_PORT"), false);
+ CtInsertColumn(ct, _UU("NM_NAT_DST_HOST"), false);
+ CtInsertColumn(ct, _UU("NM_NAT_DST_PORT"), false);
+ CtInsertColumn(ct, _UU("NM_NAT_CREATED"), false);
+ CtInsertColumn(ct, _UU("NM_NAT_LAST_COMM"), false);
+ CtInsertColumn(ct, _UU("NM_NAT_SIZE"), false);
+ CtInsertColumn(ct, _UU("NM_NAT_TCP_STATUS"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_NAT_ITEM *e = &t.Items[i];
+ wchar_t tmp0[MAX_SIZE];
+ wchar_t *tmp1 = L"";
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t tmp5[MAX_SIZE];
+ wchar_t tmp6[MAX_SIZE];
+ wchar_t tmp7[MAX_SIZE];
+ wchar_t tmp8[MAX_SIZE];
+ wchar_t *tmp9 = L"";
+ char v1[128], v2[128];
+
+ // ID
+ UniToStru(tmp0, e->Id);
+
+ // Protocol
+ switch (e->Protocol)
+ {
+ case NAT_TCP:
+ tmp1 = _UU("NM_NAT_PROTO_TCP");
+ break;
+ case NAT_UDP:
+ tmp1 = _UU("NM_NAT_PROTO_UDP");
+ break;
+ case NAT_DNS:
+ tmp1 = _UU("NM_NAT_PROTO_DNS");
+ break;
+ case NAT_ICMP:
+ tmp1 = _UU("NM_NAT_PROTO_ICMP");
+ break;
+ }
+
+ // Source host
+ StrToUni(tmp2, sizeof(tmp2), e->SrcHost);
+
+ // Source port
+ UniToStru(tmp3, e->SrcPort);
+
+ // Destination host
+ StrToUni(tmp4, sizeof(tmp4), e->DestHost);
+
+ // Destination port
+ UniToStru(tmp5, e->DestPort);
+
+ // Creation date and time of the session
+ GetDateTimeStrEx64(tmp6, sizeof(tmp6), SystemToLocal64(e->CreatedTime), NULL);
+
+ // Last communication date and time
+ GetDateTimeStrEx64(tmp7, sizeof(tmp7), SystemToLocal64(e->LastCommTime), NULL);
+
+ // Communication amount
+ ToStr3(v1, sizeof(v1), e->RecvSize);
+ ToStr3(v2, sizeof(v2), e->SendSize);
+ UniFormat(tmp8, sizeof(tmp8), L"%S / %S", v1, v2);
+
+ // TCP state
+ if (e->Protocol == NAT_TCP)
+ {
+ switch (e->TcpStatus)
+ {
+ case NAT_TCP_CONNECTING:
+ tmp9 = _UU("NAT_TCP_CONNECTING");
+ break;
+ case NAT_TCP_SEND_RESET:
+ tmp9 = _UU("NAT_TCP_SEND_RESET");
+ break;
+ case NAT_TCP_CONNECTED:
+ tmp9 = _UU("NAT_TCP_CONNECTED");
+ break;
+ case NAT_TCP_ESTABLISHED:
+ tmp9 = _UU("NAT_TCP_ESTABLISHED");
+ break;
+ case NAT_TCP_WAIT_DISCONNECT:
+ tmp9 = _UU("NAT_TCP_WAIT_DISCONNECT");
+ break;
+ }
+ }
+
+ CtInsert(ct,
+ tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumNat(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the settings for a virtual DHCP server function of the SecureNAT function
+UINT PsDhcpGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ CT *ct = CtNewStandard();
+
+ // To use the virtual DHCP function
+ CtInsert(ct, _UU("CMD_DhcpGet_Column_USE"), t.UseDhcp ? _UU("SEC_YES") : _UU("SEC_NO"));
+
+ // Start address of the distributing address zone
+ IPToUniStr(tmp, sizeof(tmp), &t.DhcpLeaseIPStart);
+ CtInsert(ct, _UU("CMD_DhcpGet_Column_IP1"), tmp);
+
+ // End address of the distributing address zone
+ IPToUniStr(tmp, sizeof(tmp), &t.DhcpLeaseIPEnd);
+ CtInsert(ct, _UU("CMD_DhcpGet_Column_IP2"), tmp);
+
+ // Subnet mask
+ IPToUniStr(tmp, sizeof(tmp), &t.DhcpSubnetMask);
+ CtInsert(ct, _UU("CMD_DhcpGet_Column_MASK"), tmp);
+
+ // Lease time (in seconds)
+ UniToStru(tmp, t.DhcpExpireTimeSpan);
+ CtInsert(ct, _UU("CMD_DhcpGet_Column_LEASE"), tmp);
+
+ // Default gateway address
+ UniStrCpy(tmp, sizeof(tmp), _UU("SEC_NONE"));
+ if (IPToUINT(&t.DhcpGatewayAddress) != 0)
+ {
+ IPToUniStr(tmp, sizeof(tmp), &t.DhcpGatewayAddress);
+ }
+ CtInsert(ct, _UU("CMD_DhcpGet_Column_GW"), tmp);
+
+ // DNS server address 1
+ UniStrCpy(tmp, sizeof(tmp), _UU("SEC_NONE"));
+ if (IPToUINT(&t.DhcpDnsServerAddress) != 0)
+ {
+ IPToUniStr(tmp, sizeof(tmp), &t.DhcpDnsServerAddress);
+ }
+ CtInsert(ct, _UU("CMD_DhcpGet_Column_DNS"), tmp);
+
+ // DNS server address 2
+ UniStrCpy(tmp, sizeof(tmp), _UU("SEC_NONE"));
+ if (IPToUINT(&t.DhcpDnsServerAddress2) != 0)
+ {
+ IPToUniStr(tmp, sizeof(tmp), &t.DhcpDnsServerAddress2);
+ }
+ CtInsert(ct, _UU("CMD_DhcpGet_Column_DNS2"), tmp);
+
+ // Domain name
+ StrToUni(tmp, sizeof(tmp), t.DhcpDomainName);
+ CtInsert(ct, _UU("CMD_DhcpGet_Column_DOMAIN"), tmp);
+
+ // To save the log
+ CtInsert(ct, _UU("CMD_SecureNatHostGet_Column_LOG"), t.SaveLog ? _UU("SEC_YES") : _UU("SEC_NO"));
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable the Virtual DHCP server function of SecureNAT function
+UINT PsDhcpEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ bool ok = true;
+
+ t.UseDhcp = true;
+
+ if (ok == false)
+ {
+ // Parameter is invalid
+ ret = ERR_INVALID_PARAMETER;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disable the virtual DHCP server function of SecureNAT function
+UINT PsDhcpDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ bool ok = true;
+
+ t.UseDhcp = false;
+
+ if (ok == false)
+ {
+ // Parameter is invalid
+ ret = ERR_INVALID_PARAMETER;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Change the settings for a virtual DHCP server function of the SecureNAT function
+UINT PsDhcpSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX mm =
+ {
+ "CMD_NatSet_Eval_UDP", NAT_UDP_MIN_TIMEOUT / 1000, NAT_UDP_MAX_TIMEOUT / 1000,
+ };
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"START", CmdPrompt, _UU("CMD_DhcpSet_Prompt_START"), CmdEvalIp, NULL},
+ {"END", CmdPrompt, _UU("CMD_DhcpSet_Prompt_END"), CmdEvalIp, NULL},
+ {"MASK", CmdPrompt, _UU("CMD_DhcpSet_Prompt_MASK"), CmdEvalIp, NULL},
+ {"EXPIRE", CmdPrompt, _UU("CMD_DhcpSet_Prompt_EXPIRE"), CmdEvalMinMax, &mm},
+ {"GW", CmdPrompt, _UU("CMD_DhcpSet_Prompt_GW"), CmdEvalIp, NULL},
+ {"DNS", CmdPrompt, _UU("CMD_DhcpSet_Prompt_DNS"), CmdEvalIp, NULL},
+ {"DNS2", CmdPrompt, _UU("CMD_DhcpSet_Prompt_DNS2"), CmdEvalIp, NULL},
+ {"DOMAIN", CmdPrompt, _UU("CMD_DhcpSet_Prompt_DOMAIN"), NULL, NULL},
+ {"LOG", CmdPrompt, _UU("CMD_NatSet_Prompt_LOG"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ bool ok = true;
+
+ StrToIP(&t.DhcpLeaseIPStart, GetParamStr(o, "START"));
+ StrToIP(&t.DhcpLeaseIPEnd, GetParamStr(o, "END"));
+ StrToIP(&t.DhcpSubnetMask, GetParamStr(o, "MASK"));
+ t.DhcpExpireTimeSpan = GetParamInt(o, "EXPIRE");
+ StrToIP(&t.DhcpGatewayAddress, GetParamStr(o, "GW"));
+ StrToIP(&t.DhcpDnsServerAddress, GetParamStr(o, "DNS"));
+ StrToIP(&t.DhcpDnsServerAddress2, GetParamStr(o, "DNS2"));
+ StrCpy(t.DhcpDomainName, sizeof(t.DhcpDomainName), GetParamStr(o, "DOMAIN"));
+ t.SaveLog = GetParamYes(o, "LOG");
+
+ if (ok == false)
+ {
+ // Parameter is invalid
+ ret = ERR_INVALID_PARAMETER;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the lease table of virtual DHCP server function of the SecureNAT function
+UINT PsDhcpTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_DHCP t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumDHCP(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNew();
+ UINT i;
+
+ CtInsertColumn(ct, _UU("DHCP_DHCP_ID"), false);
+ CtInsertColumn(ct, _UU("DHCP_LEASED_TIME"), false);
+ CtInsertColumn(ct, _UU("DHCP_EXPIRE_TIME"), false);
+ CtInsertColumn(ct, _UU("DHCP_MAC_ADDRESS"), false);
+ CtInsertColumn(ct, _UU("DHCP_IP_ADDRESS"), false);
+ CtInsertColumn(ct, _UU("DHCP_HOSTNAME"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_DHCP_ITEM *e = &t.Items[i];
+ wchar_t tmp0[MAX_SIZE];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t tmp5[MAX_SIZE];
+ char str[MAX_SIZE];
+
+ // ID
+ UniToStru(tmp0, e->Id);
+
+ // Time
+ GetDateTimeStrEx64(tmp1, sizeof(tmp1), SystemToLocal64(e->LeasedTime), NULL);
+ GetDateTimeStrEx64(tmp2, sizeof(tmp2), SystemToLocal64(e->ExpireTime), NULL);
+
+ MacToStr(str, sizeof(str), e->MacAddress);
+ StrToUni(tmp3, sizeof(tmp3), str);
+
+ IPToStr32(str, sizeof(str), e->IpAddress);
+ StrToUni(tmp4, sizeof(tmp4), str);
+
+ StrToUni(tmp5, sizeof(tmp5), e->Hostname);
+
+ CtInsert(ct,
+ tmp0, tmp1, tmp2, tmp3, tmp4, tmp5);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumDhcp(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the list of Virtual HUB management options
+UINT PsAdminOptionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ADMIN_OPTION t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubAdminOptions(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNewStandardEx();
+ UINT i;
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ ADMIN_OPTION *e = &t.Items[i];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+
+ StrToUni(tmp1, sizeof(tmp1), e->Name);
+ UniToStru(tmp2, e->Value);
+
+ CtInsert(ct, tmp1, tmp2, GetHubAdminOptionHelpString(e->Name));
+
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcAdminOption(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the value of a Virtual HUB management option
+UINT PsAdminOptionSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ADMIN_OPTION t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_AdminOptionSet_Prompt_name"), CmdEvalNotEmpty, NULL},
+ {"VALUE", CmdPrompt, _UU("CMD_AdminOptionSet_Prompt_VALUE"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubAdminOptions(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ bool b = false;
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ if (StrCmpi(t.Items[i].Name, GetParamStr(o, "[name]")) == 0)
+ {
+ t.Items[i].Value = GetParamInt(o, "VALUE");
+ b = true;
+ }
+ }
+
+ if (b == false)
+ {
+ // An error has occured
+ ret = ERR_OBJECT_NOT_FOUND;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ FreeRpcAdminOption(&t);
+ return ret;
+ }
+ else
+ {
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScSetHubAdminOptions(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+ }
+
+ FreeRpcAdminOption(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the list of Virtual HUB extended options
+UINT PsExtOptionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ADMIN_OPTION t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubExtOptions(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNewStandardEx();
+ UINT i;
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ ADMIN_OPTION *e = &t.Items[i];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+
+ StrToUni(tmp1, sizeof(tmp1), e->Name);
+ UniToStru(tmp2, e->Value);
+
+ CtInsert(ct, tmp1, tmp2, GetHubAdminOptionHelpString(e->Name));
+
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcAdminOption(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the value of a Virtual HUB extended option
+UINT PsExtOptionSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ADMIN_OPTION t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_AdminOptionSet_Prompt_name"), CmdEvalNotEmpty, NULL},
+ {"VALUE", CmdPrompt, _UU("CMD_AdminOptionSet_Prompt_VALUE"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubExtOptions(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ bool b = false;
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ if (StrCmpi(t.Items[i].Name, GetParamStr(o, "[name]")) == 0)
+ {
+ t.Items[i].Value = GetParamInt(o, "VALUE");
+ b = true;
+ }
+ }
+
+ if (b == false)
+ {
+ // An error has occured
+ ret = ERR_OBJECT_NOT_FOUND;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ FreeRpcAdminOption(&t);
+ return ret;
+ }
+ else
+ {
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScSetHubExtOptions(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+ }
+
+ FreeRpcAdminOption(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the list of revoked certificate list
+UINT PsCrlList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_CRL t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumCrl(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ CT *ct = CtNew();
+
+ CtInsertColumn(ct, _UU("CMD_ID"), false);
+ CtInsertColumn(ct, _UU("SM_CRL_COLUMN_1"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ wchar_t tmp[64];
+ RPC_ENUM_CRL_ITEM *e = &t.Items[i];
+
+ UniToStru(tmp, e->Key);
+ CtInsert(ct, tmp, e->CrlInfo);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumCrl(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Add a revoked certificate
+UINT PsCrlAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CRL t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"SERIAL", NULL, NULL, NULL, NULL},
+ {"MD5", NULL, NULL, NULL, NULL},
+ {"SHA1", NULL, NULL, NULL, NULL},
+ {"CN", NULL, NULL, NULL, NULL},
+ {"O", NULL, NULL, NULL, NULL},
+ {"OU", NULL, NULL, NULL, NULL},
+ {"C", NULL, NULL, NULL, NULL},
+ {"ST", NULL, NULL, NULL, NULL},
+ {"L", NULL, NULL, NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ {
+ bool param_exists = false;
+ CRL *crl = ZeroMalloc(sizeof(CRL));
+ NAME *n;
+ n = crl->Name = ZeroMalloc(sizeof(NAME));
+
+ if (IsEmptyStr(GetParamStr(o, "CN")) == false)
+ {
+ n->CommonName = CopyUniStr(GetParamUniStr(o, "CN"));
+ param_exists = true;
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "O")) == false)
+ {
+ n->CommonName = CopyUniStr(GetParamUniStr(o, "O"));
+ param_exists = true;
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "OU")) == false)
+ {
+ n->CommonName = CopyUniStr(GetParamUniStr(o, "OU"));
+ param_exists = true;
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "C")) == false)
+ {
+ n->CommonName = CopyUniStr(GetParamUniStr(o, "C"));
+ param_exists = true;
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "ST")) == false)
+ {
+ n->CommonName = CopyUniStr(GetParamUniStr(o, "ST"));
+ param_exists = true;
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "L")) == false)
+ {
+ n->CommonName = CopyUniStr(GetParamUniStr(o, "L"));
+ param_exists = true;
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "SERIAL")) == false)
+ {
+ BUF *b;
+
+ b = StrToBin(GetParamStr(o, "SERIAL"));
+
+ if (b != NULL && b->Size >= 1)
+ {
+ crl->Serial = NewXSerial(b->Buf, b->Size);
+ param_exists = true;
+ }
+
+ FreeBuf(b);
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "MD5")) == false)
+ {
+ BUF *b;
+
+ b = StrToBin(GetParamStr(o, "MD5"));
+
+ if (b != NULL && b->Size == MD5_SIZE)
+ {
+ Copy(crl->DigestMD5, b->Buf, MD5_SIZE);
+ param_exists = true;
+ }
+
+ FreeBuf(b);
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "SHA1")) == false)
+ {
+ BUF *b;
+
+ b = StrToBin(GetParamStr(o, "SHA1"));
+
+ if (b != NULL && b->Size == SHA1_SIZE)
+ {
+ Copy(crl->DigestSHA1, b->Buf, SHA1_SIZE);
+ param_exists = true;
+ }
+
+ FreeBuf(b);
+ }
+
+ t.Crl = crl;
+
+ if (param_exists == false)
+ {
+ FreeRpcCrl(&t);
+ ret = ERR_INVALID_PARAMETER;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ // RPC call
+ ret = ScAddCrl(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCrl(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the revoked certificate
+UINT PsCrlDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CRL t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_CrlDel_Prompt_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Key = GetParamInt(o, "[id]");
+
+ // RPC call
+ ret = ScDelCrl(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCrl(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the revoked certificate
+UINT PsCrlGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CRL t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_CrlGet_Prompt_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Key = GetParamInt(o, "[id]");
+
+ // RPC call
+ ret = ScGetCrl(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Show contents
+ CT *ct = CtNewStandard();
+ CRL *crl = t.Crl;
+ NAME *n;
+
+ if (crl != NULL)
+ {
+ n = crl->Name;
+
+ if (n != NULL)
+ {
+ if (UniIsEmptyStr(n->CommonName) == false)
+ {
+ CtInsert(ct, _UU("CMD_CrlGet_CN"), n->CommonName);
+ }
+ if (UniIsEmptyStr(n->Organization) == false)
+ {
+ CtInsert(ct, _UU("CMD_CrlGet_O"), n->Organization);
+ }
+ if (UniIsEmptyStr(n->Unit) == false)
+ {
+ CtInsert(ct, _UU("CMD_CrlGet_OU"), n->Unit);
+ }
+ if (UniIsEmptyStr(n->Country) == false)
+ {
+ CtInsert(ct, _UU("CMD_CrlGet_C"), n->Country);
+ }
+ if (UniIsEmptyStr(n->State) == false)
+ {
+ CtInsert(ct, _UU("CMD_CrlGet_ST"), n->State);
+ }
+ if (UniIsEmptyStr(n->Local) == false)
+ {
+ CtInsert(ct, _UU("CMD_CrlGet_L"), n->Local);
+ }
+ }
+
+ if (crl->Serial != NULL && crl->Serial->size >= 1)
+ {
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+
+ BinToStrEx(str, sizeof(str), crl->Serial->data, crl->Serial->size);
+ StrToUni(tmp, sizeof(tmp), str);
+
+ CtInsert(ct, _UU("CMD_CrlGet_SERI"), tmp);
+ }
+
+ if (IsZero(crl->DigestMD5, MD5_SIZE) == false)
+ {
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+
+ BinToStrEx(str, sizeof(str), crl->DigestMD5, MD5_SIZE);
+ StrToUni(tmp, sizeof(tmp), str);
+
+ CtInsert(ct, _UU("CMD_CrlGet_MD5_HASH"), tmp);
+ }
+
+ if (IsZero(crl->DigestSHA1, SHA1_SIZE) == false)
+ {
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+
+ BinToStrEx(str, sizeof(str), crl->DigestSHA1, SHA1_SIZE);
+ StrToUni(tmp, sizeof(tmp), str);
+
+ CtInsert(ct, _UU("CMD_CrlGet_SHA1_HASH"), tmp);
+ }
+ }
+ CtFree(ct, c);
+ }
+
+ FreeRpcCrl(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the rules of IP access control list
+UINT PsAcList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_AC_LIST t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetAcList(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ CT *ct;
+
+ ct = CtNew();
+ CtInsertColumn(ct, _UU("SM_AC_COLUMN_1"), true);
+ CtInsertColumn(ct, _UU("SM_AC_COLUMN_2"), true);
+ CtInsertColumn(ct, _UU("SM_AC_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_AC_COLUMN_4"), false);
+
+ for (i = 0;i < LIST_NUM(t.o);i++)
+ {
+ wchar_t tmp1[32], *tmp2, tmp3[MAX_SIZE], tmp4[32];
+ char *tmp_str;
+ AC *ac = LIST_DATA(t.o, i);
+
+ UniToStru(tmp1, ac->Id);
+ tmp2 = ac->Deny ? _UU("SM_AC_DENY") : _UU("SM_AC_PASS");
+ tmp_str = GenerateAcStr(ac);
+ StrToUni(tmp3, sizeof(tmp3), tmp_str);
+
+ Free(tmp_str);
+
+ UniToStru(tmp4, ac->Priority);
+
+ CtInsert(ct, tmp1, tmp4, tmp2, tmp3);
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeRpcAcList(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Add a rule to the IP access control list (IPv4)
+UINT PsAcAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_AC_LIST t;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX mm =
+ {
+ "CMD_AcAdd_Eval_PRIORITY", 1, 4294967295UL,
+ };
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[allow|deny]", CmdPrompt, _UU("CMD_AcAdd_Prompt_AD"), CmdEvalNotEmpty, NULL},
+ {"PRIORITY", CmdPrompt, _UU("CMD_AcAdd_Prompt_PRIORITY"), CmdEvalMinMax, &mm},
+ {"IP", CmdPrompt, _UU("CMD_AcAdd_Prompt_IP"), CmdEvalIpAndMask4, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetAcList(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Add a new item to the list
+ AC *ac = ZeroMalloc(sizeof(AC));
+ char *test = GetParamStr(o, "[allow|deny]");
+ UINT u_ip, u_mask;
+
+ if (StartWith("deny", test))
+ {
+ ac->Deny = true;
+ }
+
+ ParseIpAndMask4(GetParamStr(o, "IP"), &u_ip, &u_mask);
+ UINTToIP(&ac->IpAddress, u_ip);
+
+ if (u_mask == 0xffffffff)
+ {
+ ac->Masked = false;
+ }
+ else
+ {
+ ac->Masked = true;
+ UINTToIP(&ac->SubnetMask, u_mask);
+ }
+
+ ac->Priority = GetParamInt(o, "PRIORITY");
+
+ Insert(t.o, ac);
+
+ ret = ScSetAcList(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeRpcAcList(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Add a rule to the IP access control list (IPv6)
+UINT PsAcAdd6(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_AC_LIST t;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX mm =
+ {
+ "CMD_AcAdd6_Eval_PRIORITY", 1, 4294967295UL,
+ };
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[allow|deny]", CmdPrompt, _UU("CMD_AcAdd6_Prompt_AD"), CmdEvalNotEmpty, NULL},
+ {"PRIORITY", CmdPrompt, _UU("CMD_AcAdd6_Prompt_PRIORITY"), CmdEvalMinMax, &mm},
+ {"IP", CmdPrompt, _UU("CMD_AcAdd6_Prompt_IP"), CmdEvalIpAndMask6, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetAcList(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Add a new item to the list
+ AC *ac = ZeroMalloc(sizeof(AC));
+ char *test = GetParamStr(o, "[allow|deny]");
+ IP u_ip, u_mask;
+
+ if (StartWith("deny", test))
+ {
+ ac->Deny = true;
+ }
+
+ ParseIpAndMask6(GetParamStr(o, "IP"), &u_ip, &u_mask);
+ Copy(&ac->IpAddress, &u_ip, sizeof(IP));
+
+ if (SubnetMaskToInt6(&u_mask) == 128)
+ {
+ ac->Masked = false;
+ }
+ else
+ {
+ ac->Masked = true;
+ Copy(&ac->SubnetMask, &u_mask, sizeof(IP));
+ }
+
+ ac->Priority = GetParamInt(o, "PRIORITY");
+
+ Insert(t.o, ac);
+
+ ret = ScSetAcList(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeRpcAcList(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Run the debug command
+UINT PsDebug(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ UINT id;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", NULL, NULL, NULL, NULL},
+ {"ARG", NULL, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ id = GetParamInt(o, "[id]");
+
+ if (true)
+ {
+ RPC_TEST t;
+ UINT ret;
+
+ c->Write(c, _UU("CMD_Debug_Msg1"));
+
+ Zero(&t, sizeof(t));
+
+ t.IntValue = id;
+ StrCpy(t.StrValue, sizeof(t.StrValue), GetParamStr(o, "ARG"));
+
+ ret = ScDebug(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[sizeof(t.StrValue)];
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_Debug_Msg2"), t.StrValue);
+ c->Write(c, tmp);
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Flush the configuration file on the server
+UINT PsFlush(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (true)
+ {
+ RPC_TEST t;
+ UINT ret;
+ wchar_t tmp[MAX_SIZE];
+ char sizestr[MAX_SIZE];
+
+ c->Write(c, _UU("CMD_Flush_Msg1"));
+
+ Zero(&t, sizeof(t));
+
+ ret = ScFlush(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ToStr3(sizestr, sizeof(sizestr), (UINT64)t.IntValue);
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_Flush_Msg2"), sizestr);
+ c->Write(c, tmp);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Crash
+UINT PsCrash(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ char *yes;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[yes]", CmdPrompt, _UU("CMD_Crash_Confirm"), NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ yes = GetParamStr(o, "[yes]");
+
+ if (StrCmpi(yes, "yes") != 0)
+ {
+ c->Write(c, _UU("CMD_Crash_Aborted"));
+ }
+ else
+ {
+ RPC_TEST t;
+ UINT ret;
+
+ c->Write(c, _UU("CMD_Crash_Msg"));
+
+ Zero(&t, sizeof(t));
+
+ ret = ScCrash(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Remove a rule in the IP access control list
+UINT PsAcDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_AC_LIST t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_AcDel_Prompt_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetAcList(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Remove matched ID
+ UINT i;
+ bool b = false;
+
+ for (i = 0;i < LIST_NUM(t.o);i++)
+ {
+ AC *ac = LIST_DATA(t.o, i);
+
+ if (ac->Id == GetParamInt(o, "[id]"))
+ {
+ Delete(t.o, ac);
+ Free(ac);
+ b = true;
+ break;
+ }
+ }
+
+ if (b == false)
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ FreeRpcAcList(&t);
+ }
+ else
+ {
+ ret = ScSetAcList(ps->Rpc, &t);
+ }
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeRpcAcList(&t);
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable / Disable the IPsec VPN server function
+UINT PsIPsecEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ IPSEC_SERVICES t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"L2TP", CmdPrompt, _UU("CMD_IPsecEnable_Prompt_L2TP"), CmdEvalNotEmpty, NULL},
+ {"L2TPRAW", CmdPrompt, _UU("CMD_IPsecEnable_Prompt_L2TPRAW"), CmdEvalNotEmpty, NULL},
+ {"ETHERIP", CmdPrompt, _UU("CMD_IPsecEnable_Prompt_ETHERIP"), CmdEvalNotEmpty, NULL},
+ {"PSK", CmdPrompt, _UU("CMD_IPsecEnable_Prompt_PSK"), CmdEvalNotEmpty, NULL},
+ {"DEFAULTHUB", CmdPrompt, _UU("CMD_IPsecEnable_Prompt_DEFAULTHUB"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.L2TP_IPsec = GetParamYes(o, "L2TP");
+ t.L2TP_Raw = GetParamYes(o, "L2TPRAW");
+ t.EtherIP_IPsec = GetParamYes(o, "ETHERIP");
+ StrCpy(t.IPsec_Secret, sizeof(t.IPsec_Secret), GetParamStr(o, "PSK"));
+ StrCpy(t.L2TP_DefaultHub, sizeof(t.L2TP_DefaultHub), GetParamStr(o, "DEFAULTHUB"));
+
+ // RPC call
+ ret = ScSetIPsecServices(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the current configuration of IPsec VPN server function
+UINT PsIPsecGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ IPSEC_SERVICES t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetIPsecServices(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_PATH];
+ CT *ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_IPsecGet_PRINT_L2TP"), _UU(t.L2TP_IPsec ? "SEC_YES" : "SEC_NO"));
+ CtInsert(ct, _UU("CMD_IPsecGet_PRINT_L2TPRAW"), _UU(t.L2TP_Raw ? "SEC_YES" : "SEC_NO"));
+ CtInsert(ct, _UU("CMD_IPsecGet_PRINT_ETHERIP"), _UU(t.EtherIP_IPsec ? "SEC_YES" : "SEC_NO"));
+
+ StrToUni(tmp, sizeof(tmp), t.IPsec_Secret);
+ CtInsert(ct, _UU("CMD_IPsecGet_PRINT_PSK"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.L2TP_DefaultHub);
+ CtInsert(ct, _UU("CMD_IPsecGet_PRINT_DEFAULTHUB"), tmp);
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Add connection settings for accepting connections from client devices of EtherIP / L2TPv3 over IPsec server function
+UINT PsEtherIpClientAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ ETHERIP_ID t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[ID]", CmdPrompt, _UU("CMD_EtherIpClientAdd_Prompt_ID"), CmdEvalNotEmpty, NULL},
+ {"HUB", CmdPrompt, _UU("CMD_EtherIpClientAdd_Prompt_HUB"), CmdEvalNotEmpty, NULL},
+ {"USERNAME", CmdPrompt, _UU("CMD_EtherIpClientAdd_Prompt_USERNAME"), CmdEvalNotEmpty, NULL},
+ {"PASSWORD", CmdPrompt, _UU("CMD_EtherIpClientAdd_Prompt_PASSWORD"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Id, sizeof(t.Id), GetParamStr(o, "[ID]"));
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "HUB"));
+ StrCpy(t.UserName, sizeof(t.UserName), GetParamStr(o, "USERNAME"));
+ StrCpy(t.Password, sizeof(t.Password), GetParamStr(o, "PASSWORD"));
+
+ // RPC call
+ ret = ScAddEtherIpId(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the connection settings for accepting connections from client devices of EtherIP / L2TPv3 over IPsec server function
+UINT PsEtherIpClientDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ ETHERIP_ID t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[ID]", CmdPrompt, _UU("CMD_EtherIpClientDelete_Prompt_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Id, sizeof(t.Id), GetParamStr(o, "[ID]"));
+
+ // RPC call
+ ret = ScDeleteEtherIpId(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Show the list of connection settings for accepting connections from client devices of EtherIP / L2TPv3 over IPsec server function
+UINT PsEtherIpClientList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_ETHERIP_ID t;
+ UINT i;
+ CT *b;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScEnumEtherIpId(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ b = CtNew();
+
+ CtInsertColumn(b, _UU("SM_ETHERIP_COLUMN_0"), false);
+ CtInsertColumn(b, _UU("SM_ETHERIP_COLUMN_1"), false);
+ CtInsertColumn(b, _UU("SM_ETHERIP_COLUMN_2"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ ETHERIP_ID *d = &t.IdList[i];
+ wchar_t id[MAX_SIZE], hubname[MAX_SIZE], username[MAX_SIZE];
+
+ StrToUni(id, sizeof(id), d->Id);
+ StrToUni(hubname, sizeof(hubname), d->HubName);
+ StrToUni(username, sizeof(username), d->UserName);
+
+ CtInsert(b, id, hubname, username);
+ }
+
+ CtFree(b, c);
+
+ FreeRpcEnumEtherIpId(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable / disable the OpenVPN compatible server function
+UINT PsOpenVpnEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ OPENVPN_SSTP_CONFIG t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[yes|no]", CmdPrompt, _UU("CMD_OpenVpnEnable_Prompt_[yes|no]"), CmdEvalNotEmpty, NULL},
+ {"PORTS", CmdPrompt, _UU("CMD_OpenVpnEnable_Prompt_PORTS"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetOpenVpnSstpConfig(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ t.EnableOpenVPN = GetParamYes(o, "[yes|no]");
+ StrCpy(t.OpenVPNPortList, sizeof(t.OpenVPNPortList), GetParamStr(o, "PORTS"));
+
+ // RPC call
+ ret = ScSetOpenVpnSstpConfig(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the current settings for the OpenVPN compatible server function
+UINT PsOpenVpnGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ OPENVPN_SSTP_CONFIG t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetOpenVpnSstpConfig(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_PATH];
+ CT *ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_OpenVpnGet_PRINT_Enabled"), _UU(t.EnableOpenVPN ? "SEC_YES" : "SEC_NO"));
+
+ StrToUni(tmp, sizeof(tmp), t.OpenVPNPortList);
+ CtInsert(ct, _UU("CMD_OpenVpnGet_PRINT_Ports"), tmp);
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Generate a OpenVPN sample configuration file that can connect to the OpenVPN compatible server function
+UINT PsOpenVpnMakeConfig(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_READ_LOG_FILE t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[ZIP_FileName]", CmdPrompt, _UU("CMD_OpenVpnMakeConfig_Prompt_ZIP"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScMakeOpenVpnConfigFile(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Determine the file name to save
+ wchar_t filename[MAX_SIZE];
+ wchar_t tmp[MAX_SIZE];
+
+ UniStrCpy(filename, sizeof(filename), GetParamUniStr(o, "[ZIP_FileName]"));
+
+ if (UniEndWith(filename, L".zip") == false)
+ {
+ UniStrCat(filename, sizeof(filename), L".zip");
+ }
+
+ if (DumpBufW(t.Buffer, filename) == false)
+ {
+ ret = ERR_INTERNAL_ERROR;
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_OpenVpnMakeConfig_ERROR"), filename);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_OpenVpnMakeConfig_OK"), filename);
+ }
+
+ c->Write(c, tmp);
+
+ FreeRpcReadLogFile(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Enable / disable the Microsoft SSTP VPN compatible server function
+UINT PsSstpEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ OPENVPN_SSTP_CONFIG t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[yes|no]", CmdPrompt, _UU("CMD_SstpEnable_Prompt_[yes|no]"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetOpenVpnSstpConfig(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ t.EnableSSTP = GetParamYes(o, "[yes|no]");
+
+ // RPC call
+ ret = ScSetOpenVpnSstpConfig(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the current settings for the Microsoft SSTP VPN compatible server function
+UINT PsSstpGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ OPENVPN_SSTP_CONFIG t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetOpenVpnSstpConfig(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_SstpEnable_PRINT_Enabled"), _UU(t.EnableSSTP ? "SEC_YES" : "SEC_NO"));
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Register to the VPN Server by creating a new self-signed certificate with the specified CN (Common Name)
+UINT PsServerCertRegenerate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_TEST t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[CN]", CmdPrompt, _UU("CMD_ServerCertRegenerate_Prompt_CN"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.StrValue, sizeof(t.StrValue), GetParamStr(o, "[CN]"));
+
+ // RPC call
+ ret = ScRegenerateServerCert(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable / disable the VPN over ICMP / VPN over DNS server function
+UINT PsVpnOverIcmpDnsEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SPECIAL_LISTENER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"ICMP", CmdPrompt, _UU("CMD_VpnOverIcmpDnsEnable_Prompt_ICMP"), CmdEvalNotEmpty, NULL},
+ {"DNS", CmdPrompt, _UU("CMD_VpnOverIcmpDnsEnable_Prompt_DNS"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.VpnOverIcmpListener = GetParamYes(o, "ICMP");
+ t.VpnOverDnsListener = GetParamYes(o, "DNS");
+
+ // RPC call
+ ret = ScSetSpecialListener(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get current settings of VPN over ICMP / VPN over DNS server function
+UINT PsVpnOverIcmpDnsGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SPECIAL_LISTENER t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetSpecialListener(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_VpnOverIcmpDnsGet_PRINT_ICMP"), _UU(t.VpnOverIcmpListener ? "SEC_YES" : "SEC_NO"));
+ CtInsert(ct, _UU("CMD_VpnOverIcmpDnsGet_PRINT_DNS"), _UU(t.VpnOverDnsListener ? "SEC_YES" : "SEC_NO"));
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable / disable the VPN Azure function
+UINT PsVpnAzureSetEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_AZURE_STATUS t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[yes|no]", CmdPrompt, _UU("VpnAzureSetEnable_PROMPT"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.IsEnabled = GetParamYes(o, "[yes|no]");
+
+ // RPC call
+ ret = ScSetAzureStatus(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the current state of the VPN Azure function
+UINT PsVpnAzureGetStatus(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_AZURE_STATUS t;
+ DDNS_CLIENT_STATUS t2;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ Zero(&t2, sizeof(t2));
+
+ // RPC call
+ ret = ScGetAzureStatus(ps->Rpc, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ ret = ScGetDDnsClientStatus(ps->Rpc, &t2);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_VpnAzureGetStatus_PRINT_ENABLED"), _UU(t.IsEnabled ? "SEC_YES" : "SEC_NO"));
+
+ if (t.IsEnabled)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), L"%S%S", t2.CurrentHostName, AZURE_DOMAIN_SUFFIX);
+
+ CtInsert(ct, _UU("CMD_VpnAzureGetStatus_PRINT_CONNECTED"), _UU(t.IsConnected ? "SEC_YES" : "SEC_NO"));
+ CtInsert(ct, _UU("CMD_VpnAzureGetStatus_PRINT_HOSTNAME"), tmp);
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the current state of the dynamic DNS function
+UINT PsDynamicDnsGetStatus(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ DDNS_CLIENT_STATUS t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetDDnsClientStatus(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNewStandard();
+ wchar_t tmp[MAX_SIZE];
+
+ // FQDN
+ if (IsEmptyStr(t.CurrentFqdn) == false)
+ {
+ StrToUni(tmp, sizeof(tmp), t.CurrentFqdn);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_DDNS_FQDN_EMPTY"));
+ }
+ CtInsert(ct, _UU("CMD_DynamicDnsGetStatus_PRINT_FQDN"), tmp);
+
+ // Hostname
+ if (IsEmptyStr(t.CurrentHostName) == false)
+ {
+ StrToUni(tmp, sizeof(tmp), t.CurrentHostName);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_DDNS_FQDN_EMPTY"));
+ }
+ CtInsert(ct, _UU("CMD_DynamicDnsGetStatus_PRINT_HOSTNAME"), tmp);
+
+ // Suffix
+ if (IsEmptyStr(t.DnsSuffix) == false)
+ {
+ StrToUni(tmp, sizeof(tmp), t.DnsSuffix);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_DDNS_FQDN_EMPTY"));
+ }
+ CtInsert(ct, _UU("CMD_DynamicDnsGetStatus_PRINT_SUFFIX"), tmp);
+
+ // IPv4
+ if (t.Err_IPv4 == ERR_NO_ERROR)
+ {
+ StrToUni(tmp, sizeof(tmp), t.CurrentIPv4);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _E(t.Err_IPv4));
+ }
+ CtInsert(ct, _UU("CMD_DynamicDnsGetStatus_PRINT_IPv4"), tmp);
+
+ // IPv6
+ if (t.Err_IPv6 == ERR_NO_ERROR)
+ {
+ StrToUni(tmp, sizeof(tmp), t.CurrentIPv6);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _E(t.Err_IPv6));
+ }
+ CtInsert(ct, _UU("CMD_DynamicDnsGetStatus_PRINT_IPv6"), tmp);
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Configure the dynamic DNS host name
+UINT PsDynamicDnsSetHostname(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_TEST t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[hostname]", CmdPrompt, _UU("CMD_DynamicDnsSetHostname_Prompt_hostname"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.StrValue, sizeof(t.StrValue), GetParamStr(o, "[hostname]"));
+
+ // RPC call
+ ret = ScChangeDDnsClientHostname(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Register a new license key
+UINT PsLicenseAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_TEST t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[key]", CmdPrompt, _UU("CMD_LicenseAdd_Prompt_Key"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.StrValue, sizeof(t.StrValue), GetParamStr(o, "[key]"));
+
+ // RPC call
+ ret = ScAddLicenseKey(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the registered license
+UINT PsLicenseDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_TEST t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_LicenseDel_Prompt_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.IntValue = GetParamInt(o, "[id]");
+
+ // RPC call
+ ret = ScDelLicenseKey(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+
+
+// Get the registered license list
+UINT PsLicenseList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_LICENSE_KEY t;
+ CT *ct;
+ UINT i;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScEnumLicenseKey(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNew();
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_4"), false);
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_5"), false);
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_6"), false);
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_7"), false);
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_8"), false);
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_9"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ wchar_t tmp1[32], tmp2[LICENSE_KEYSTR_LEN + 1], tmp3[LICENSE_MAX_PRODUCT_NAME_LEN + 1],
+ *tmp4, tmp5[128], tmp6[LICENSE_LICENSEID_STR_LEN + 1], tmp7[64],
+ tmp8[64], tmp9[64];
+ RPC_ENUM_LICENSE_KEY_ITEM *e = &t.Items[i];
+
+ UniToStru(tmp1, e->Id);
+ StrToUni(tmp2, sizeof(tmp2), e->LicenseKey);
+ StrToUni(tmp3, sizeof(tmp3), e->LicenseName);
+ tmp4 = LiGetLicenseStatusStr(e->Status);
+ if (e->Expires == 0)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_LICENSE_NO_EXPIRES"));
+ }
+ else
+ {
+ GetDateStrEx64(tmp5, sizeof(tmp5), e->Expires, NULL);
+ }
+ StrToUni(tmp6, sizeof(tmp6), e->LicenseId);
+ UniToStru(tmp7, e->ProductId);
+ UniFormat(tmp8, sizeof(tmp8), L"%I64u", e->SystemId);
+ UniToStru(tmp9, e->SerialId);
+
+ CtInsert(ct,
+ tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9);
+ }
+
+ CtFreeEx(ct, c, true);
+
+ FreeRpcEnumLicenseKey(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the license status of the current VPN Server
+UINT PsLicenseStatus(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_LICENSE_STATUS st;
+ CT *ct;
+ wchar_t tmp[MAX_SIZE];
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&st, sizeof(st));
+
+ // RPC call
+ ret = ScGetLicenseStatus(ps->Rpc, &st);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNewStandard();
+
+ if (st.EditionId == LICENSE_EDITION_VPN3_NO_LICENSE)
+ {
+ CtInsert(ct, _UU("SM_NO_LICENSE_COLUMN"), _UU("SM_NO_LICENSE"));
+ }
+ else
+ {
+ // Product edition name
+ StrToUni(tmp, sizeof(tmp), st.EditionStr);
+ CtInsert(ct, _UU("SM_LICENSE_STATUS_EDITION"), tmp);
+
+ // Release date
+ if (st.ReleaseDate != 0)
+ {
+ GetDateStrEx64(tmp, sizeof(tmp), st.ReleaseDate, NULL);
+ CtInsert(ct, _UU("SM_LICENSE_STATUS_RELEASE"), tmp);
+ }
+
+ // Current system ID
+ UniFormat(tmp, sizeof(tmp), L"%I64u", st.SystemId);
+ CtInsert(ct, _UU("SM_LICENSE_STATUS_SYSTEM_ID"), tmp);
+
+ // Expiration date of the current license product
+ if (st.SystemExpires == 0)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_NO_EXPIRES"));
+ }
+ else
+ {
+ GetDateStrEx64(tmp, sizeof(tmp), st.SystemExpires, NULL);
+ }
+ CtInsert(ct, _UU("SM_LICENSE_STATUS_EXPIRES"), tmp);
+
+ // Subscription (support) contract
+ if (st.NeedSubscription == false)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_STATUS_SUBSCRIPTION_NONEED"));
+ }
+ else
+ {
+ if (st.SubscriptionExpires == 0)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_STATUS_SUBSCRIPTION_NONE"));
+ }
+ else
+ {
+ wchar_t dtstr[MAX_PATH];
+
+ GetDateStrEx64(dtstr, sizeof(dtstr), st.SubscriptionExpires, NULL);
+
+ UniFormat(tmp, sizeof(tmp),
+ st.IsSubscriptionExpired ? _UU("SM_LICENSE_STATUS_SUBSCRIPTION_EXPIRED") : _UU("SM_LICENSE_STATUS_SUBSCRIPTION_VALID"),
+ dtstr);
+ }
+ }
+ CtInsert(ct, _UU("SM_LICENSE_STATUS_SUBSCRIPTION"), tmp);
+
+ if (st.NeedSubscription == false && st.SubscriptionExpires != 0)
+ {
+ wchar_t dtstr[MAX_PATH];
+
+ GetDateStrEx64(dtstr, sizeof(dtstr), st.SubscriptionExpires, NULL);
+
+ CtInsert(ct, _UU("SM_LICENSE_STATUS_SUBSCRIPTION_BUILD_STR"), tmp);
+ }
+
+ if (GetCapsBool(ps->CapsList, "b_vpn3"))
+ {
+ // Maximum creatable number of users
+ if (st.NumClientConnectLicense == INFINITE)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_INFINITE"));
+ }
+ else
+ {
+ UniToStru(tmp, st.NumClientConnectLicense);
+ }
+ CtInsert(ct, _UU("SM_LICENSE_NUM_CLIENT"), tmp);
+ }
+
+ // Available number of concurrent client connections
+ if (st.NumBridgeConnectLicense == INFINITE)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_INFINITE"));
+ }
+ else
+ {
+ UniToStru(tmp, st.NumBridgeConnectLicense);
+ }
+ CtInsert(ct, _UU("SM_LICENSE_NUM_BRIDGE"), tmp);
+
+ // Availability of enterprise features
+ CtInsert(ct, _UU("SM_LICENSE_STATUS_ENTERPRISE"),
+ st.AllowEnterpriseFunction ? _UU("SM_LICENSE_STATUS_ENTERPRISE_YES") : _UU("SM_LICENSE_STATUS_ENTERPRISE_NO"));
+ }
+
+ CtFreeEx(ct, c, false);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+
+// Get the cluster configuration
+UINT PsClusterSettingGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_FARM t;
+ CT *ct;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ ret = ScGetFarmSetting(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ if (t.Weight == 0)
+ {
+ t.Weight = FARM_DEFAULT_WEIGHT;
+ }
+
+ // Show the cluster configuration
+ ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_ClusterSettingGet_Current"),
+ GetServerTypeStr(t.ServerType));
+
+ if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ CtInsert(ct, _UU("CMD_ClusterSettingGet_ControllerOnly"), t.ControllerOnly ? _UU("SEC_YES") : _UU("SEC_NO"));
+ }
+
+ if (t.ServerType != SERVER_TYPE_STANDALONE)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniToStru(tmp, t.Weight);
+
+ CtInsert(ct, _UU("CMD_ClusterSettingGet_Weight"), tmp);
+ }
+
+ if (t.ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ wchar_t tmp[MAX_SIZE];
+ UINT i;
+
+ // Public IP address
+ if (t.PublicIp != 0)
+ {
+ IPToUniStr32(tmp, sizeof(tmp), t.PublicIp);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CMD_ClusterSettingGet_None"));
+ }
+
+ CtInsert(ct, _UU("CMD_ClusterSettingGet_PublicIp"), tmp);
+
+ // Public port list
+ tmp[0] = 0;
+ for (i = 0;i < t.NumPort;i++)
+ {
+ wchar_t tmp2[64];
+
+ UniFormat(tmp2, sizeof(tmp2), L"%u, ", t.Ports[i]);
+
+ UniStrCat(tmp, sizeof(tmp), tmp2);
+ }
+
+ if (UniEndWith(tmp, L", "))
+ {
+ tmp[UniStrLen(tmp) - 2] = 0;
+ }
+
+ CtInsert(ct, _UU("CMD_ClusterSettingGet_PublicPorts"), tmp);
+
+ // Controller to connect
+ UniFormat(tmp, sizeof(tmp), L"%S:%u", t.ControllerName, t.ControllerPort);
+ CtInsert(ct, _UU("CMD_ClusterSettingGet_Controller"), tmp);
+ }
+
+ CtFree(ct, c);
+
+ FreeRpcFarm(&t);
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the server password
+UINT PsServerPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_SET_PASSWORD t;
+ char *pw;
+ PARAM args[] =
+ {
+ {"[password]", CmdPromptChoosePassword, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ pw = GetParamStr(o, "[password]");
+
+ Zero(&t, sizeof(t));
+ Hash(t.HashedPassword, pw, StrLen(pw), true);
+
+ ret = ScSetServerPassword(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Password decision prompt (for Prompt function)
+wchar_t *CmdPromptChoosePassword(CONSOLE *c, void *param)
+{
+ char *s;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ s = CmdPasswordPrompt(c);
+
+ if (s == NULL)
+ {
+ return NULL;
+ }
+ else
+ {
+ wchar_t *ret = CopyStrToUni(s);
+
+ Free(s);
+
+ return ret;
+ }
+}
+
+// Password input prompt (general-purpose)
+char *CmdPasswordPrompt(CONSOLE *c)
+{
+ char *pw1, *pw2;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ c->Write(c, _UU("CMD_VPNCMD_PWPROMPT_0"));
+
+RETRY:
+ c->Write(c, L"");
+
+
+ pw1 = c->ReadPassword(c, _UU("CMD_VPNCMD_PWPROMPT_1"));
+ if (pw1 == NULL)
+ {
+ return NULL;
+ }
+
+ pw2 = c->ReadPassword(c, _UU("CMD_VPNCMD_PWPROMPT_2"));
+ if (pw2 == NULL)
+ {
+ Free(pw1);
+ return NULL;
+ }
+
+ c->Write(c, L"");
+
+ if (StrCmp(pw1, pw2) != 0)
+ {
+ Free(pw1);
+ Free(pw2);
+ c->Write(c, _UU("CMD_VPNCMD_PWPROMPT_3"));
+ goto RETRY;
+ }
+
+ Free(pw1);
+
+ return pw2;
+}
+
+// Disable the listener
+UINT PsListenerDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_LISTENER t;
+ PARAM args[] =
+ {
+ {"[port]", CmdPromptPort, _UU("CMD_ListenerDisable_PortPrompt"), CmdEvalPort, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.Enable = false;
+ t.Port = ToInt(GetParamStr(o, "[port]"));
+
+ ret = ScEnableListener(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable the listener
+UINT PsListenerEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_LISTENER t;
+ PARAM args[] =
+ {
+ {"[port]", CmdPromptPort, _UU("CMD_ListenerEnable_PortPrompt"), CmdEvalPort, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.Enable = true;
+ t.Port = ToInt(GetParamStr(o, "[port]"));
+
+ ret = ScEnableListener(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Draw a row of console table
+void CtPrintRow(CONSOLE *c, UINT num, UINT *widths, wchar_t **strings, bool *rights, char separate_char)
+{
+ UINT i;
+ wchar_t *buf;
+ UINT buf_size;
+ bool is_sep_line = true;
+ // Validate arguments
+ if (c == NULL || num == 0 || widths == NULL || strings == NULL || rights == NULL)
+ {
+ return;
+ }
+
+ buf_size = 32;
+ for (i = 0;i < num;i++)
+ {
+ buf_size += sizeof(wchar_t) * widths[i] + 6;
+ }
+
+ buf = ZeroMalloc(buf_size);
+
+ for (i = 0;i < num;i++)
+ {
+ char *tmp;
+ wchar_t *space_string;
+ UINT w;
+ UINT space = 0;
+ wchar_t *string = strings[i];
+ wchar_t *tmp_line = NULL;
+
+ if (UniStrCmpi(string, L"---") == 0)
+ {
+ char *s = MakeCharArray('-', widths[i]);
+ tmp_line = string = CopyStrToUni(s);
+
+ Free(s);
+ }
+ else
+ {
+ is_sep_line = false;
+ }
+
+ w = UniStrWidth(string);
+
+ if (widths[i] >= w)
+ {
+ space = widths[i] - w;
+ }
+
+ tmp = MakeCharArray(' ', space);
+ space_string = CopyStrToUni(tmp);
+
+ if (rights[i] != false)
+ {
+ UniStrCat(buf, buf_size, space_string);
+ }
+
+ UniStrCat(buf, buf_size, string);
+
+ if (rights[i] == false)
+ {
+ UniStrCat(buf, buf_size, space_string);
+ }
+
+ Free(space_string);
+ Free(tmp);
+
+ if (i < (num - 1))
+ {
+ wchar_t tmp[4];
+ char str[2];
+
+ if (UniStrCmpi(strings[i], L"---") == 0)
+ {
+ str[0] = '+';
+ }
+ else
+ {
+ str[0] = separate_char;
+ }
+ str[1] = 0;
+
+ StrToUni(tmp, sizeof(tmp), str);
+
+ UniStrCat(buf, buf_size, tmp);
+ }
+
+ if (tmp_line != NULL)
+ {
+ Free(tmp_line);
+ }
+ }
+
+ UniTrimRight(buf);
+
+ if (is_sep_line)
+ {
+ if (UniStrLen(buf) > (c->GetWidth(c) - 1))
+ {
+ buf[c->GetWidth(c) - 1] = 0;
+ }
+ }
+
+ c->Write(c, buf);
+
+ Free(buf);
+}
+
+// Draw the console table in standard format
+void CtPrintStandard(CT *ct, CONSOLE *c)
+{
+ CT *t;
+ UINT i, j;
+ // Validate arguments
+ if (ct == NULL || c == NULL)
+ {
+ return;
+ }
+
+ t = CtNewStandard();
+ for (i = 0;i < LIST_NUM(ct->Rows);i++)
+ {
+ CTR *row = LIST_DATA(ct->Rows, i);
+
+ for (j = 0;j < LIST_NUM(ct->Columns);j++)
+ {
+ CTC *column = LIST_DATA(ct->Columns, j);
+
+ CtInsert(t, column->String, row->Strings[j]);
+ }
+
+ if (i != (LIST_NUM(ct->Rows) - 1))
+ {
+ CtInsert(t, L"---", L"---");
+ }
+ }
+
+ CtFree(t, c);
+}
+
+// Draw the console table
+void CtPrint(CT *ct, CONSOLE *c)
+{
+ UINT *widths;
+ UINT num;
+ UINT i, j;
+ wchar_t **header_strings;
+ bool *rights;
+ // Validate arguments
+ if (ct == NULL || c == NULL)
+ {
+ return;
+ }
+
+ num = LIST_NUM(ct->Columns);
+ widths = ZeroMalloc(sizeof(UINT) * num);
+
+ // Calculate the maximum character width of each column
+ for (i = 0;i < num;i++)
+ {
+ CTC *ctc = LIST_DATA(ct->Columns, i);
+ UINT w;
+
+ w = UniStrWidth(ctc->String);
+ widths[i] = MAX(widths[i], w);
+ }
+ for (j = 0;j < LIST_NUM(ct->Rows);j++)
+ {
+ CTR *ctr = LIST_DATA(ct->Rows, j);
+
+ for (i = 0;i < num;i++)
+ {
+ UINT w;
+
+ w = UniStrWidth(ctr->Strings[i]);
+ widths[i] = MAX(widths[i], w);
+ }
+ }
+
+ // Display the header part
+ header_strings = ZeroMalloc(sizeof(wchar_t *) * num);
+ rights = ZeroMalloc(sizeof(bool) * num);
+
+ for (i = 0;i < num;i++)
+ {
+ CTC *ctc = LIST_DATA(ct->Columns, i);
+
+ header_strings[i] = ctc->String;
+ rights[i] = ctc->Right;
+ }
+
+ CtPrintRow(c, num, widths, header_strings, rights, '|');
+
+ for (i = 0;i < num;i++)
+ {
+ char *s;
+
+ s = MakeCharArray('-', widths[i]);
+ header_strings[i] = CopyStrToUni(s);
+ Free(s);
+ }
+
+ CtPrintRow(c, num, widths, header_strings, rights, '+');
+
+ for (i = 0;i < num;i++)
+ {
+ Free(header_strings[i]);
+ }
+
+ // Display the data part
+ for (j = 0;j < LIST_NUM(ct->Rows);j++)
+ {
+ CTR *ctr = LIST_DATA(ct->Rows, j);
+
+ CtPrintRow(c, num, widths, ctr->Strings, rights, '|');
+ }
+
+ Free(rights);
+ Free(header_strings);
+ Free(widths);
+}
+
+// Escape the meta-characters in CSV
+void CtEscapeCsv(wchar_t *dst, UINT size, wchar_t *src){
+ UINT i;
+ UINT len = UniStrLen(src);
+ UINT idx;
+ BOOL need_to_escape = false;
+ wchar_t tmp[2]=L"*";
+
+ // Check the input value
+ if (src==NULL || dst==NULL)
+ {
+ return;
+ }
+
+ // If there is no character that need to be escaped in the input characters, copy it to the output
+ len = UniStrLen(src);
+ for (i=0; iColumns);
+ wchar_t buf[MAX_SIZE];
+ wchar_t fmtbuf[MAX_SIZE];
+
+ // Show the heading row
+ buf[0] = 0;
+ for(i=0; iColumns, i);
+ CtEscapeCsv(fmtbuf, MAX_SIZE, ctc->String);
+ UniStrCat(buf, MAX_SIZE, fmtbuf);
+ if(i != num_columns-1)
+ UniStrCat(buf, MAX_SIZE, L",");
+ }
+ c->Write(c, buf);
+
+ // Show the table body
+ for(j=0; jRows); j++)
+ {
+ CTR *ctr = LIST_DATA(ct->Rows, j);
+ buf[0] = 0;
+ for(i=0; iStrings[i]);
+ UniStrCat(buf, MAX_SIZE, fmtbuf);
+ if(i != num_columns-1)
+ UniStrCat(buf, MAX_SIZE, L",");
+ }
+ c->Write(c, buf);
+ }
+}
+
+// Delete the console table
+void CtFreeEx(CT *ct, CONSOLE *c, bool standard_view)
+{
+ UINT i, num;
+ // Validate arguments
+ if (ct == NULL)
+ {
+ return;
+ }
+
+ if (c != NULL)
+ {
+ if (c->ConsoleType == CONSOLE_CSV)
+ {
+ CtPrintCsv(ct, c);
+ }
+ else
+ {
+ if (standard_view == false)
+ {
+ CtPrint(ct, c);
+ }
+ else
+ {
+ CtPrintStandard(ct, c);
+ }
+ }
+ }
+
+ num = LIST_NUM(ct->Columns);
+
+ for (i = 0;i < LIST_NUM(ct->Rows);i++)
+ {
+ UINT j;
+ CTR *ctr = LIST_DATA(ct->Rows, i);
+
+ for (j = 0;j < num;j++)
+ {
+ Free(ctr->Strings[j]);
+ }
+
+ Free(ctr->Strings);
+ Free(ctr);
+ }
+
+ for (i = 0;i < LIST_NUM(ct->Columns);i++)
+ {
+ CTC *ctc = LIST_DATA(ct->Columns, i);
+
+ Free(ctc->String);
+ Free(ctc);
+ }
+
+ ReleaseList(ct->Columns);
+ ReleaseList(ct->Rows);
+
+ Free(ct);
+}
+void CtFree(CT *ct, CONSOLE *c)
+{
+ CtFreeEx(ct, c, false);
+}
+
+// Add a row to the table
+void CtInsert(CT *ct, ...)
+{
+ CTR *ctr;
+ UINT num, i;
+ va_list va;
+ // Validate arguments
+ if (ct == NULL)
+ {
+ return;
+ }
+
+ num = LIST_NUM(ct->Columns);
+
+ va_start(va, ct);
+
+ ctr = ZeroMalloc(sizeof(CTR));
+ ctr->Strings = ZeroMalloc(sizeof(wchar_t *) * num);
+
+ for (i = 0;i < num;i++)
+ {
+ wchar_t *s = va_arg(va, wchar_t *);
+
+ ctr->Strings[i] = CopyUniStr(s);
+ }
+
+ va_end(va);
+
+ Insert(ct->Rows, ctr);
+}
+
+// Add a column to the table
+void CtInsertColumn(CT *ct, wchar_t *str, bool right)
+{
+ CTC *ctc;
+ // Validate arguments
+ if (ct == NULL)
+ {
+ return;
+ }
+ if (str == NULL)
+ {
+ str = L"";
+ }
+
+ ctc = ZeroMalloc(sizeof(CTC));
+ ctc->String = CopyUniStr(str);
+ ctc->Right = right;
+
+ Insert(ct->Columns, ctc);
+}
+
+// Create a new console table
+CT *CtNew()
+{
+ CT *ct;
+
+ ct = ZeroMalloc(sizeof(CT));
+ ct->Columns = NewList(NULL);
+ ct->Rows = NewList(NULL);
+
+ return ct;
+}
+
+// Add a standard column to a column in a table
+CT *CtNewStandard()
+{
+ CT *ct = CtNew();
+
+ CtInsertColumn(ct, _UU("CMD_CT_STD_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("CMD_CT_STD_COLUMN_2"), false);
+
+ return ct;
+}
+CT *CtNewStandardEx()
+{
+ CT *ct = CtNew();
+
+ CtInsertColumn(ct, _UU("CMD_CT_STD_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("CMD_CT_STD_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("CMD_CT_STD_COLUMN_3"), false);
+
+ return ct;
+}
+
+// Get the TCP listener list
+UINT PsListenerList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_LISTENER_LIST t;
+ UINT i;
+ CT *ct;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ ret = ScEnumListener(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNew();
+
+ CtInsertColumn(ct, _UU("CM_LISTENER_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("CM_LISTENER_COLUMN_2"), false);
+
+ for (i = 0;i < t.NumPort;i++)
+ {
+ wchar_t *status = _UU("CM_LISTENER_OFFLINE");
+ wchar_t tmp[128];
+
+ if (t.Errors[i])
+ {
+ status = _UU("CM_LISTENER_ERROR");
+ }
+ else if (t.Enables[i])
+ {
+ status = _UU("CM_LISTENER_ONLINE");
+ }
+
+ UniFormat(tmp, sizeof(tmp), _UU("CM_LISTENER_TCP_PORT"), t.Ports[i]);
+
+ CtInsert(ct, tmp, status);
+ }
+
+ CtFree(ct, c);
+
+ FreeRpcListenerList(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the TCP listener
+UINT PsListenerDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_LISTENER t;
+ PARAM args[] =
+ {
+ {"[port]", CmdPromptPort, _UU("CMD_ListenerDelete_PortPrompt"), CmdEvalPort, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.Enable = true;
+ t.Port = ToInt(GetParamStr(o, "[port]"));
+
+ ret = ScDeleteListener(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Draw a row
+void CmdPrintRow(CONSOLE *c, wchar_t *title, wchar_t *tag, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ wchar_t buf2[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (title == NULL || c == NULL || tag == NULL)
+ {
+ return;
+ }
+
+ va_start(args, tag);
+ UniFormatArgs(buf, sizeof(buf), tag, args);
+
+ UniFormat(buf2, sizeof(buf2), L"[%s] %s", title, buf);
+
+ va_end(args);
+
+ c->Write(c, buf2);
+}
+
+// ServerInfoGet command
+UINT PsServerInfoGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_SERVER_INFO t;
+ CT *ct;
+ wchar_t tmp[MAX_SIZE];
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ ret = ScGetServerInfo(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNew();
+
+ CtInsertColumn(ct, _UU("SM_STATUS_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_STATUS_COLUMN_2"), false);
+
+ // Product name
+ StrToUni(tmp, sizeof(tmp), t.ServerProductName);
+ CtInsert(ct, _UU("SM_INFO_PRODUCT_NAME"), tmp);
+
+ // Version
+ StrToUni(tmp, sizeof(tmp), t.ServerVersionString);
+ CtInsert(ct, _UU("SM_INFO_VERSION"), tmp);
+
+ // Build
+ StrToUni(tmp, sizeof(tmp), t.ServerBuildInfoString);
+ CtInsert(ct, _UU("SM_INFO_BUILD"), tmp);
+
+ // Host name
+ StrToUni(tmp, sizeof(tmp), t.ServerHostName);
+ CtInsert(ct, _UU("SM_INFO_HOSTNAME"), tmp);
+
+ // Type
+ CtInsert(ct, _UU("SM_ST_SERVER_TYPE"), GetServerTypeStr(t.ServerType));
+
+ // OS
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsSystemName);
+ CtInsert(ct, _UU("SM_OS_SYSTEM_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsProductName);
+ CtInsert(ct, _UU("SM_OS_PRODUCT_NAME"), tmp);
+
+ if (t.OsInfo.OsServicePack != 0)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SM_OS_SP_TAG"), t.OsInfo.OsServicePack);
+ CtInsert(ct, _UU("SM_OS_SERVICE_PACK"), tmp);
+ }
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsVendorName);
+ CtInsert(ct, _UU("SM_OS_VENDER_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsVersion);
+ CtInsert(ct, _UU("SM_OS_VERSION"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.KernelName);
+ CtInsert(ct, _UU("SM_OS_KERNEL_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.KernelVersion);
+ CtInsert(ct, _UU("SM_OS_KERNEL_VERSION"), tmp);
+
+ CtFree(ct, c);
+
+ FreeRpcServerInfo(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the string for type of the HUB
+wchar_t *GetHubTypeStr(UINT type)
+{
+ if (type == HUB_TYPE_FARM_STATIC)
+ {
+ return _UU("SM_HUB_STATIC");
+ }
+ else if (type == HUB_TYPE_FARM_DYNAMIC)
+ {
+ return _UU("SM_HUB_DYNAMIC");
+ }
+ return _UU("SM_HUB_STANDALONE");
+}
+
+// Get a string of the type of server
+wchar_t *GetServerTypeStr(UINT type)
+{
+ if (type == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ return _UU("SM_FARM_CONTROLLER");
+ }
+ else if (type == SERVER_TYPE_FARM_MEMBER)
+ {
+ return _UU("SM_FARM_MEMBER");
+ }
+ return _UU("SM_SERVER_STANDALONE");
+}
+
+// ServerStatusGet command
+UINT PsServerStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_SERVER_STATUS t;
+ wchar_t tmp[MAX_PATH];
+ char tmp2[MAX_PATH];
+ CT *ct;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ ret = ScGetServerStatus(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNew();
+
+ CtInsertColumn(ct, _UU("SM_STATUS_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_STATUS_COLUMN_2"), false);
+
+ // Type of server
+ CtInsert(ct, _UU("SM_ST_SERVER_TYPE"),
+ t.ServerType == SERVER_TYPE_STANDALONE ? _UU("SM_SERVER_STANDALONE") :
+ t.ServerType == SERVER_TYPE_FARM_MEMBER ? _UU("SM_FARM_MEMBER") : _UU("SM_FARM_CONTROLLER"));
+
+ // Number of TCP connections
+ UniToStru(tmp, t.NumTcpConnections);
+ CtInsert(ct, _UU("SM_ST_NUM_TCP"), tmp);
+
+ if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ // Number of local TCP connections
+ UniToStru(tmp, t.NumTcpConnectionsLocal);
+ CtInsert(ct, _UU("SM_ST_NUM_TCP_LOCAL"), tmp);
+
+ // Number of remote TCP connections
+ UniToStru(tmp, t.NumTcpConnectionsRemote);
+ CtInsert(ct, _UU("SM_ST_NUM_TCP_REMOTE"), tmp);
+ }
+
+ // Number of Virtual HUBs
+ UniToStru(tmp, t.NumHubTotal);
+ CtInsert(ct, _UU("SM_ST_NUM_HUB_TOTAL"), tmp);
+
+ if (t.ServerType != SERVER_TYPE_STANDALONE)
+ {
+ // Number of static HUBs
+ UniToStru(tmp, t.NumHubStatic);
+ CtInsert(ct, _UU("SM_ST_NUM_HUB_STATIC"), tmp);
+
+ // Number of dynamic HUBs
+ UniToStru(tmp, t.NumHubDynamic);
+ CtInsert(ct, _UU("SM_ST_NUM_HUB_DYNAMIC"), tmp);
+ }
+
+ // Number of sessions
+ UniToStru(tmp, t.NumSessionsTotal);
+ CtInsert(ct, _UU("SM_ST_NUM_SESSION_TOTAL"), tmp);
+
+ if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ // Number of local sessions
+ UniToStru(tmp, t.NumSessionsLocal);
+ CtInsert(ct, _UU("SM_ST_NUM_SESSION_LOCAL"), tmp);
+
+ // Number of remote sessions
+ UniToStru(tmp, t.NumSessionsRemote);
+ CtInsert(ct, _UU("SM_ST_NUM_SESSION_REMOTE"), tmp);
+ }
+
+ // Number of MAC tables
+ UniToStru(tmp, t.NumMacTables);
+ CtInsert(ct, _UU("SM_ST_NUM_MAC_TABLE"), tmp);
+
+ // Number of IP tables
+ UniToStru(tmp, t.NumIpTables);
+ CtInsert(ct, _UU("SM_ST_NUM_IP_TABLE"), tmp);
+
+ // Number of users
+ UniToStru(tmp, t.NumUsers);
+ CtInsert(ct, _UU("SM_ST_NUM_USERS"), tmp);
+
+ // Number of groups
+ UniToStru(tmp, t.NumGroups);
+ CtInsert(ct, _UU("SM_ST_NUM_GROUPS"), tmp);
+
+ // Number of assigned licenses
+ UniToStru(tmp, t.AssignedClientLicenses);
+ CtInsert(ct, _UU("SM_ST_CLIENT_LICENSE"), tmp);
+
+ UniToStru(tmp, t.AssignedBridgeLicenses);
+ CtInsert(ct, _UU("SM_ST_BRIDGE_LICENSE"), tmp);
+
+ if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ UniToStru(tmp, t.AssignedClientLicensesTotal);
+ CtInsert(ct, _UU("SM_ST_CLIENT_LICENSE_EX"), tmp);
+
+ UniToStru(tmp, t.AssignedBridgeLicensesTotal);
+ CtInsert(ct, _UU("SM_ST_BRIDGE_LICENSE_EX"), tmp);
+ }
+
+ // Traffic
+ CmdInsertTrafficInfo(ct, &t.Traffic);
+
+ // Server start-up time
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.StartTime), NULL);
+ CtInsert(ct, _UU("SM_ST_START_TIME"), tmp);
+
+ // Current time
+ GetDateTimeStrMilli64(tmp2, sizeof(tmp2), SystemToLocal64(t.CurrentTime));
+ StrToUni(tmp, sizeof(tmp), tmp2);
+ CtInsert(ct, _UU("SM_ST_CURRENT_TIME"), tmp);
+
+ // Tick value
+ UniFormat(tmp, sizeof(tmp), L"%I64u", t.CurrentTick);
+ CtInsert(ct, _UU("SM_ST_CURRENT_TICK"), tmp);
+
+ // Memory information
+ if (t.MemInfo.TotalMemory != 0)
+ {
+ char vv[128];
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.TotalMemory);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ CtInsert(ct, _UU("SM_ST_TOTAL_MEMORY"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.UsedMemory);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ CtInsert(ct, _UU("SM_ST_USED_MEMORY"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.FreeMemory);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ CtInsert(ct, _UU("SM_ST_FREE_MEMORY"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.TotalPhys);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ CtInsert(ct, _UU("SM_ST_TOTAL_PHYS"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.UsedPhys);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ CtInsert(ct, _UU("SM_ST_USED_PHYS"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.FreePhys);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ CtInsert(ct, _UU("SM_ST_FREE_PHYS"), tmp);
+ }
+
+ CtFree(ct, c);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Add traffic information to LVB
+void CmdInsertTrafficInfo(CT *ct, TRAFFIC *t)
+{
+ wchar_t tmp[MAX_SIZE];
+ char vv[128];
+ // Validate arguments
+ if (ct == NULL || t == NULL)
+ {
+ return;
+ }
+
+ // Transmission information
+ ToStr3(vv, sizeof(vv), t->Send.UnicastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+ CtInsert(ct, _UU("SM_ST_SEND_UCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), t->Send.UnicastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("SM_ST_SEND_UCAST_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), t->Send.BroadcastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+ CtInsert(ct, _UU("SM_ST_SEND_BCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), t->Send.BroadcastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("SM_ST_SEND_BCAST_SIZE"), tmp);
+
+ // Reception information
+ ToStr3(vv, sizeof(vv), t->Recv.UnicastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+ CtInsert(ct, _UU("SM_ST_RECV_UCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), t->Recv.UnicastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("SM_ST_RECV_UCAST_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), t->Recv.BroadcastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+ CtInsert(ct, _UU("SM_ST_RECV_BCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), t->Recv.BroadcastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("SM_ST_RECV_BCAST_SIZE"), tmp);
+}
+
+// Input a port number
+wchar_t *CmdPromptPort(CONSOLE *c, void *param)
+{
+ wchar_t *prompt_str;
+
+ if (param != NULL)
+ {
+ prompt_str = (wchar_t *)param;
+ }
+ else
+ {
+ prompt_str = _UU("CMD_PROPMT_PORT");
+ }
+
+ return c->ReadLine(c, prompt_str, true);
+}
+
+// Verify the port number
+bool CmdEvalPort(CONSOLE *c, wchar_t *str, void *param)
+{
+ UINT i;
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ i = UniToInt(str);
+
+ if (i >= 1 && i <= 65535)
+ {
+ return true;
+ }
+
+ c->Write(c, _UU("CMD_EVAL_PORT"));
+
+ return false;
+}
+
+// ListenerCreate command
+UINT PsListenerCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_LISTENER t;
+ PARAM args[] =
+ {
+ {"[port]", CmdPromptPort, _UU("CMD_ListenerCreate_PortPrompt"), CmdEvalPort, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.Enable = true;
+ t.Port = ToInt(GetParamStr(o, "[port]"));
+
+ ret = ScCreateListener(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// About command
+UINT PsAbout(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ BUF *b;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ b = ReadDump("|legal.txt");
+
+ CmdPrintAbout(c);
+ c->Write(c, L"\r\n");
+
+ if (b != NULL)
+ {
+ wchar_t *s;
+
+ SeekBufToEnd(b);
+ WriteBufChar(b, 13);
+ WriteBufChar(b, 10);
+ WriteBufChar(b, 0);
+
+ s = CopyUtfToUni(b->Buf);
+
+ c->Write(c, s);
+
+ Free(s);
+ }
+
+ // Display the version information
+ c->Write(c, _UU("D_ABOUT@S_INFO3"));
+ c->Write(c, L"\r\n");
+ c->Write(c, _UU("D_ABOUT@S_INFO4"));
+ c->Write(c, L"\r\n");
+ CmdPrintAbout(c);
+ c->Write(c, L"\r\n");
+
+ FreeParamValueList(o);
+
+ FreeBuf(b);
+
+ return 0;
+}
+
+// Creat a new server management context
+PS *NewPs(CONSOLE *c, RPC *rpc, char *servername, UINT serverport, char *hubname, char *adminhub, wchar_t *cmdline)
+{
+ PS *ps;
+ // Validate arguments
+ if (c == NULL || rpc == NULL || servername == NULL)
+ {
+ return NULL;
+ }
+
+ if (IsEmptyStr(hubname))
+ {
+ hubname = NULL;
+ }
+ if (IsEmptyStr(adminhub))
+ {
+ adminhub = NULL;
+ }
+ if (UniIsEmptyStr(cmdline))
+ {
+ cmdline = NULL;
+ }
+
+ ps = ZeroMalloc(sizeof(PS));
+ ps->ConsoleForServer = true;
+ ps->ServerPort = serverport;
+ ps->ServerName = CopyStr(servername);
+ ps->Console = c;
+ ps->Rpc = rpc;
+ ps->HubName = CopyStr(hubname);
+ ps->LastError = 0;
+ ps->AdminHub = CopyStr(adminhub);
+ ps->CmdLine = CopyUniStr(cmdline);
+
+ return ps;
+}
+
+// Release the server management context
+void FreePs(PS *ps)
+{
+ // Validate arguments
+ if (ps == NULL)
+ {
+ return;
+ }
+
+ Free(ps->HubName);
+ Free(ps->AdminHub);
+ Free(ps->CmdLine);
+ Free(ps->ServerName);
+
+ Free(ps);
+}
+
+// Server Administration Tool
+UINT PsConnect(CONSOLE *c, char *host, UINT port, char *hub, char *adminhub, wchar_t *cmdline, char *password)
+{
+ UINT retcode = 0;
+ RPC *rpc = NULL;
+ CEDAR *cedar;
+ CLIENT_OPTION o;
+ UCHAR hashed_password[SHA1_SIZE];
+ bool b = false;
+ // Validate arguments
+ if (c == NULL || host == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ if (port == 0)
+ {
+ port = 443;
+ }
+ if (hub != NULL)
+ {
+ adminhub = NULL;
+ }
+
+ cedar = NewCedar(NULL, NULL);
+
+ Zero(&o, sizeof(o));
+ UniStrCpy(o.AccountName, sizeof(o.AccountName), L"VPNCMD");
+ StrCpy(o.Hostname, sizeof(o.Hostname), host);
+ o.Port = port;
+ o.ProxyType = PROXY_DIRECT;
+
+ Hash(hashed_password, password, StrLen(password), true);
+
+ if (IsEmptyStr(password) == false)
+ {
+ b = true;
+ }
+
+ // Connect
+ while (true)
+ {
+ UINT err;
+
+ rpc = AdminConnectEx(cedar, &o, hub, hashed_password, &err, CEDAR_CUI_STR);
+ if (rpc == NULL)
+ {
+ // Failure
+ retcode = err;
+
+ if (err == ERR_ACCESS_DENIED)
+ {
+ char *pass;
+ // Password is incorrect
+ if (b)
+ {
+ // Input the password
+ c->Write(c, _UU("CMD_VPNCMD_PASSWORD_1"));
+ }
+
+ b = true;
+
+ pass = c->ReadPassword(c, _UU("CMD_VPNCMD_PASSWORD_2"));
+ c->Write(c, L"");
+
+ if (pass != NULL)
+ {
+ Hash(hashed_password, pass, StrLen(pass), true);
+ Free(pass);
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ // Other errors
+ CmdPrintError(c, err);
+ break;
+ }
+ }
+ else
+ {
+ PS *ps;
+
+ // Success
+ ps = NewPs(c, rpc, host, port, hub, adminhub, cmdline);
+ PsMain(ps);
+ retcode = ps->LastError;
+ FreePs(ps);
+ AdminDisconnect(rpc);
+ break;
+ }
+ }
+
+ ReleaseCedar(cedar);
+
+ return retcode;
+}
+
+// Display the error
+void CmdPrintError(CONSOLE *c, UINT err)
+{
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_VPNCMD_ERROR"),
+ err, GetUniErrorStr(err));
+ c->Write(c, tmp);
+
+ if (err == ERR_DISCONNECTED)
+ {
+ c->Write(c, _UU("CMD_DISCONNECTED_MSG"));
+ }
+}
+
+// Display the version information
+void CmdPrintAbout(CONSOLE *c)
+{
+ CEDAR *cedar;
+ wchar_t tmp[MAX_SIZE];
+ char exe[MAX_PATH];
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ cedar = NewCedar(NULL, NULL);
+
+ GetExeName(exe, sizeof(exe));
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_VPNCMD_ABOUT"),
+ cedar->VerString, cedar->BuildInfo);
+
+ c->Write(c, tmp);
+
+ ReleaseCedar(cedar);
+}
+
+// Parse the host name and port number (Separated by @)
+bool ParseHostPortAtmark(char *src, char **host, UINT *port, UINT default_port)
+{
+ TOKEN_LIST *t;
+ bool ret = false;
+ // Validate arguments
+ if (src == NULL)
+ {
+ return false;
+ }
+
+ t = ParseToken(src, "@");
+ if (t == NULL)
+ {
+ return false;
+ }
+
+ if (port != NULL)
+ {
+ *port = 0;
+ }
+
+ if (default_port == 0)
+ {
+ if (t->NumTokens < 2)
+ {
+ FreeToken(t);
+ return false;
+ }
+
+ if (ToInt(t->Token[1]) == 0)
+ {
+ FreeToken(t);
+ return false;
+ }
+ }
+
+ if (t->NumTokens >= 2 && ToInt(t->Token[1]) == 0)
+ {
+ FreeToken(t);
+ return false;
+ }
+
+ if (t->NumTokens >= 1 && IsEmptyStr(t->Token[0]) == false)
+ {
+ ret = true;
+
+ if (host != NULL)
+ {
+ *host = CopyStr(t->Token[0]);
+ Trim(*host);
+ }
+
+ if (t->NumTokens >= 2)
+ {
+ if (port != NULL)
+ {
+ *port = ToInt(t->Token[1]);
+ }
+ }
+ }
+
+ if (port != NULL)
+ {
+ if (*port == 0)
+ {
+ *port = default_port;
+ }
+ }
+
+ FreeToken(t);
+
+ return ret;
+}
+
+// Parse the host name and port number
+bool ParseHostPort(char *src, char **host, UINT *port, UINT default_port)
+{
+ TOKEN_LIST *t;
+ bool ret = false;
+ // Validate arguments
+ if (src == NULL)
+ {
+ return false;
+ }
+
+ if (StartWith(src, "["))
+ {
+ if (InStr(src, "]"))
+ {
+ // Format of [target]:port
+ UINT i, n;
+ char tmp[MAX_SIZE];
+
+ StrCpy(tmp, sizeof(tmp), src);
+
+ n = SearchStrEx(tmp, "]", 0, false);
+ if (n != INFINITE)
+ {
+ UINT len = StrLen(tmp);
+
+ for (i = n;i < len;i++)
+ {
+ if (tmp[i] == ':')
+ {
+ tmp[i] = '@';
+ }
+ }
+ }
+
+ return ParseHostPortAtmark(tmp, host, port, default_port);
+ }
+ }
+
+ if (InStr(src, "@"))
+ {
+ // It is separated by @
+ return ParseHostPortAtmark(src, host, port, default_port);
+ }
+
+ t = ParseToken(src, ":");
+ if (t == NULL)
+ {
+ return false;
+ }
+
+ if (port != NULL)
+ {
+ *port = 0;
+ }
+
+ if (default_port == 0)
+ {
+ if (t->NumTokens < 2)
+ {
+ FreeToken(t);
+ return false;
+ }
+
+ if (ToInt(t->Token[1]) == 0)
+ {
+ FreeToken(t);
+ return false;
+ }
+ }
+
+ if (t->NumTokens >= 2 && ToInt(t->Token[1]) == 0)
+ {
+ FreeToken(t);
+ return false;
+ }
+
+ if (t->NumTokens >= 1 && IsEmptyStr(t->Token[0]) == false)
+ {
+ ret = true;
+
+ if (host != NULL)
+ {
+ *host = CopyStr(t->Token[0]);
+ Trim(*host);
+ }
+
+ if (t->NumTokens >= 2)
+ {
+ if (port != NULL)
+ {
+ *port = ToInt(t->Token[1]);
+ }
+ }
+ }
+
+ if (port != NULL)
+ {
+ if (*port == 0)
+ {
+ *port = default_port;
+ }
+ }
+
+ FreeToken(t);
+
+ return ret;
+}
+
+// Vpncmd command procedure
+UINT VpnCmdProc(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ char *target;
+ bool server = false;
+ bool client = false;
+ bool tools = false;
+ char *hostname = NULL;
+ char *password;
+ wchar_t *cmdline;
+ bool host_inputted = false;
+ UINT port = 0;
+ UINT retcode = 0;
+ PARAM args[] =
+ {
+ {"[host:port]", NULL, NULL, NULL, NULL},
+ {"CLIENT", NULL, NULL, NULL, NULL},
+ {"SERVER", NULL, NULL, NULL, NULL},
+ {"TOOLS", NULL, NULL, NULL, NULL},
+ {"HUB", NULL, NULL, NULL, NULL},
+ {"ADMINHUB", NULL, NULL, NULL, NULL},
+ {"PASSWORD", NULL, NULL, NULL, NULL},
+ {"IN", NULL, NULL, NULL, NULL},
+ {"OUT", NULL, NULL, NULL, NULL},
+ {"CMD", NULL, NULL, NULL, NULL},
+ {"CSV", NULL, NULL, NULL, NULL},
+ };
+
+#ifdef OS_WIN32
+ if (UniStrCmpi(str, L"/debug") == 0)
+ {
+ // Debug information write mode
+ Win32CmdDebug(false);
+ return 0;
+ }
+ if (UniStrCmpi(str, L"/debug_uac") == 0)
+ {
+ // Debug information write mode
+ Win32CmdDebug(true);
+ return 0;
+ }
+#endif // OS_WIN32
+
+ if (c->ConsoleType == CONSOLE_LOCAL)
+ {
+ // Initialize the execute path information
+ VpnCmdInitBootPath();
+ }
+
+ if(c->ConsoleType != CONSOLE_CSV)
+ {
+ CmdPrintAbout(c);
+ c->Write(c, L"");
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Specification of the mode of Tools or Server or Client
+ if ((GetParamStr(o, "CLIENT") == NULL && GetParamStr(o, "SERVER") == NULL && GetParamStr(o, "TOOLS") == NULL) ||
+ (GetParamStr(o, "CLIENT") != NULL && GetParamStr(o, "SERVER") != NULL && GetParamStr(o, "TOOLS") != NULL))
+ {
+ wchar_t *ret;
+ UINT code;
+ // The mode of Tools or Server or Client is not specified
+ c->Write(c, _UU("CMD_VPNCMD_CS_1"));
+
+ ret = c->ReadLine(c, _UU("CMD_VPNCMD_CS_2"), true);
+
+ code = UniToInt(ret);
+ Free(ret);
+
+ switch (code)
+ {
+ case 1:
+ // Server
+ server = true;
+ break;
+
+ case 2:
+ // Client
+ client = true;
+ break;
+
+ case 3:
+ // Tools
+ tools = true;
+ break;
+
+ default:
+ // Unspecified
+ FreeParamValueList(o);
+ return ERR_USER_CANCEL;
+ }
+
+ c->Write(c, L"");
+ }
+ else
+ {
+ if (GetParamStr(o, "SERVER") != NULL)
+ {
+ server = true;
+ }
+ else if (GetParamStr(o, "CLIENT") != NULL)
+ {
+ client = true;
+ }
+ else
+ {
+ tools = true;
+ }
+ }
+
+ // Destination host name
+ target = CopyStr(GetParamStr(o, "[host:port]"));
+
+ if (target == NULL && tools == false)
+ {
+ wchar_t *str;
+ // Input a host name
+ if (server)
+ {
+ c->Write(c, _UU("CMD_VPNCMD_HOST_1"));
+ }
+ else if (client)
+ {
+ c->Write(c, _UU("CMD_VPNCMD_HOST_2"));
+ }
+
+ str = c->ReadLine(c, _UU("CMD_VPNCMD_HOST_3"), true);
+ c->Write(c, L"");
+ target = CopyUniToStr(str);
+ Free(str);
+
+ if (target == NULL)
+ {
+ // Cancel
+ FreeParamValueList(o);
+ return ERR_USER_CANCEL;
+ }
+
+ if (IsEmptyStr(target))
+ {
+ Free(target);
+ target = CopyStr("localhost");
+ }
+ }
+ else
+ {
+ // User specifies a host name
+ host_inputted = true;
+ }
+
+ if (tools == false)
+ {
+ if (ParseHostPort(target, &hostname, &port, 443) == false)
+ {
+ c->Write(c, _UU("CMD_MSG_INVALID_HOSTNAME"));
+ Free(target);
+ FreeParamValueList(o);
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+
+ // Password
+ password = GetParamStr(o, "PASSWORD");
+ if (password == NULL)
+ {
+ password = "";
+ }
+
+ // Command line
+ cmdline = GetParamUniStr(o, "CMD");
+
+ if (server)
+ {
+ // Process as the server
+ char *hub;
+ char *adminhub = NULL;
+
+ hub = CopyStr(GetParamStr(o, "HUB"));
+ adminhub = GetParamStr(o, "ADMINHUB");
+
+ // Decide the Virtual HUB to be specified in the Virtual HUB management mode
+ if (hub == NULL)
+ {
+ if (host_inputted == false)
+ {
+ wchar_t *s;
+ // If the user does not specify a host name on the command line,
+ // get also a Virtual HUB name by displaying the prompt
+ c->Write(c, _UU("CMD_VPNCMD_HUB_1"));
+
+ s = c->ReadLine(c, _UU("CMD_VPNCMD_HUB_2"), true);
+
+ hub = CopyUniToStr(s);
+ Free(s);
+ }
+ }
+
+ if (IsEmptyStr(hub))
+ {
+ Free(hub);
+ hub = NULL;
+ }
+ if (IsEmptyStr(adminhub))
+ {
+ adminhub = NULL;
+ }
+
+ retcode = PsConnect(c, hostname, port, hub, adminhub, cmdline, password);
+
+ Free(hub);
+ }
+ else if (client)
+ {
+ // Treated as a client
+ Trim(target);
+
+ retcode = PcConnect(c, target, cmdline, password);
+ }
+ else if (tools)
+ {
+ // Treated as a VPN Tools
+ retcode = PtConnect(c, cmdline);
+ }
+
+ Free(hostname);
+ Free(target);
+ FreeParamValueList(o);
+
+ return retcode;
+}
+
+// Entry point of vpncmd
+UINT CommandMain(wchar_t *command_line)
+{
+ UINT ret = 0;
+ wchar_t *infile, *outfile;
+ char *a_infile, *a_outfile;
+ wchar_t *csvmode;
+ CONSOLE *c;
+
+ // Validate arguments
+ if (command_line == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Look ahead only items of /in and /out
+ infile = ParseCommand(command_line, L"in");
+ outfile = ParseCommand(command_line, L"out");
+ if (UniIsEmptyStr(infile))
+ {
+ Free(infile);
+ infile = NULL;
+ }
+ if (UniIsEmptyStr(outfile))
+ {
+ Free(outfile);
+ outfile = NULL;
+ }
+
+ a_infile = CopyUniToStr(infile);
+ a_outfile = CopyUniToStr(outfile);
+
+ // Allocate the local console
+ c = NewLocalConsole(infile, outfile);
+ if (c != NULL)
+ {
+ // Definition of commands of vpncmd
+ CMD cmd[] =
+ {
+ {"vpncmd", VpnCmdProc},
+ };
+
+ // Read ahead to check the CSV mode
+ csvmode = ParseCommand(command_line, L"csv");
+ if(csvmode != NULL)
+ {
+ Free(csvmode);
+ c->ConsoleType = CONSOLE_CSV;
+ }
+
+ if (DispatchNextCmdEx(c, command_line, ">", cmd, sizeof(cmd) / sizeof(cmd[0]), NULL) == false)
+ {
+ ret = ERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ ret = c->RetCode;
+ }
+
+ // Release the local console
+ c->Free(c);
+ }
+ else
+ {
+ Print("Error: Couldn't open local console.\n");
+ }
+
+ Free(a_infile);
+ Free(a_outfile);
+ Free(infile);
+ Free(outfile);
+
+ return ret;
+}
+
+#ifdef OS_WIN32
+// Debug information write mode
+void Win32CmdDebug(bool is_uac)
+{
+ wchar_t *dst;
+ wchar_t def_filename[MAX_SIZE];
+ SYSTEMTIME st;
+
+ InitWinUi(_UU("CMD_DEBUG_SOFTNAME"), NULL, 0);
+
+ UniPrint(_UU("CMD_DEBUG_PRINT"));
+
+ if (MsIsWin2000OrGreater() == false)
+ {
+ MsgBox(NULL, 0x00000040L, _UU("CMD_DEBUG_NOT_2000"));
+ goto LABEL_CLEANUP;
+ }
+
+ if ((MsIsVista() == false || is_uac) && MsIsAdmin() == false)
+ {
+ MsgBox(NULL, 0x00000040L, _UU("CMD_DEBUG_NOT_ADMIN"));
+ goto LABEL_CLEANUP;
+ }
+
+ if (MsIsVista() && MsIsAdmin() == false)
+ {
+ void *process_handle = NULL;
+
+ // Launch myself using the UAC
+ if (MsExecuteEx2W(MsGetExeFileNameW(), L"/debug_uac", &process_handle, true) == false)
+ {
+ MsgBox(NULL, 0x00000030L, _UU("CMD_DEBUG_UAC_FAILED"));
+ return;
+ }
+
+ MsCloseHandle(process_handle);
+ goto LABEL_CLEANUP;
+ }
+
+ LocalTime(&st);
+
+ UniFormat(def_filename, sizeof(def_filename), L"vpn_debuginfo_%04u%02u%02u_%02u%02u%02u.zip",
+ st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
+
+ // Specify the destination
+ dst = SaveDlg(NULL, _UU("DLG_ZIP_FILER"), _UU("CMD_DEBUG_SAVE_TITLE"), def_filename, L".zip");
+ if (dst != NULL)
+ {
+ if (MsSaveSystemInfo(dst) == false)
+ {
+ // Failure
+ MsgBoxEx(NULL, 0x00000030L, _UU("CMD_DEBUG_NG"), dst);
+ }
+ else
+ {
+ // Success
+ MsgBoxEx(NULL, 0x00000040L, _UU("CMD_DEBUG_OK"), dst);
+ }
+
+ Free(dst);
+ }
+
+LABEL_CLEANUP:
+ FreeWinUi();
+}
+
+#endif // OS_WIN32
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Command.h b/src/Cedar/Command.h
new file mode 100644
index 00000000..104b7869
--- /dev/null
+++ b/src/Cedar/Command.h
@@ -0,0 +1,648 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Command.h
+// Header of Command.c
+
+#ifndef COMMAND_H
+#define COMMAND_H
+
+// Constants
+#define TRAFFIC_DEFAULT_PORT 9821
+#define TRAFFIC_NUMTCP_MAX 32
+#define TRAFFIC_NUMTCP_DEFAULT 32
+#define TRAFFIC_SPAN_DEFAULT 15
+#define TRAFFIC_TYPE_DOWNLOAD 1
+#define TRAFFIC_TYPE_UPLOAD 2
+#define TRAFFIC_TYPE_FULL 0
+#define TRAFFIC_BUF_SIZE 65535
+#define TRAFFIC_VER_STR_SIZE 16
+#define TRAFFIC_VER_STR "TrafficServer\r\n"
+
+// Constants for Win32
+#define VPNCMD_BOOTSTRAP_REG_KEYNAME "Software\\" GC_REG_COMPANY_NAME "\\VPN Command Line Utility"
+#define VPNCMD_BOOTSTRAP_REG_VALUENAME_VER "InstalledVersion"
+#define VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH "InstalledPath"
+#define VPNCMD_BOOTSTRAP_FILENAME "|vpncmdsys.exe"
+#define VPNCMD_BOOTSTRAP_FILENAME_X64 "|vpncmdsys_x64.exe"
+#define VPNCMD_BOOTSTRAP_FILENAME_IA64 "|vpncmdsys_ia64.exe"
+
+
+// Traffic test results
+struct TT_RESULT
+{
+ bool Raw; // Whether raw data
+ bool Double; // Whether it is doubled
+ UINT64 NumBytesUpload; // Uploaded size
+ UINT64 NumBytesDownload; // Downloaded size
+ UINT64 NumBytesTotal; // Total size
+ UINT64 Span; // Period (in milliseconds)
+ UINT64 BpsUpload; // Upload throughput
+ UINT64 BpsDownload; // Download throughput
+ UINT64 BpsTotal; // Total throughput
+};
+
+// Text display function
+typedef void (TT_PRINT_PROC)(void *param, wchar_t *str);
+
+// Client side socket
+struct TTC_SOCK
+{
+ SOCK *Sock; // Socket
+ UINT State; // State
+ UINT64 NumBytes; // Transmitted bytes
+ bool Download; // Download socket
+ bool ServerUploadReportReceived; // Complete to receive the report of upload amount from the server
+ UINT64 NextSendRequestReportTick; // Time to request a next report
+ UINT Id;
+ bool HideErrMsg;
+};
+
+// Traffic test Client
+struct TTC
+{
+ TT_PRINT_PROC *Print; // Text display function
+ void *Param; // Any parameters
+ bool Double; // Double mode
+ bool Raw; // Raw data mode
+ UINT Port; // Port number
+ char Host[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT NumTcp; // Number of TCP connections
+ UINT Type; // Type
+ UINT64 Span; // Period
+ UINT64 RealSpan; // The actual span
+ THREAD *Thread; // Thread
+ volatile bool Halt; // Halting flag
+ bool *Cancel; // Halting flag 2
+ SOCK_EVENT *SockEvent; // Socket event
+ LIST *ItcSockList; // Client socket list
+ TT_RESULT Result; // Result
+ UINT ErrorCode; // Error code
+ bool AbnormalTerminated; // Abnormal termination
+ EVENT *StartEvent; // Start event
+ EVENT *InitedEvent; // Initialize completion notification event
+};
+
+// Server side socket
+struct TTS_SOCK
+{
+ SOCK *Sock; // Socket
+ UINT State; // State
+ UINT64 NumBytes; // Transmitted bytes
+ bool SockJoined; // Whether it has been added to the event
+ UINT Id; // ID
+ UINT64 LastWaitTick; // Retry waiting time to notify the size information to the client
+ UINT64 SessionId; // Session ID
+ bool NoMoreSendData; // Flag not to send more data
+ UINT64 FirstRecvTick; // Time which the data has been received last
+ UINT64 Span; // Period
+};
+
+// Traffic test server
+struct TTS
+{
+ TT_PRINT_PROC *Print; // Text display function
+ void *Param; // Any parameters
+ volatile bool Halt; // Halting flag
+ UINT Port; // Port number
+ THREAD *Thread; // Thread
+ THREAD *WorkThread; // Worker thread
+ THREAD *IPv6AcceptThread; // IPv6 Accept thread
+ SOCK *ListenSocket; // Socket to wait
+ SOCK *ListenSocketV6; // Socket to wait (IPv6)
+ UINT ErrorCode; // Error code
+ SOCK_EVENT *SockEvent; // Socket event
+ LIST *TtsSockList; // Server socket list
+ bool NewSocketArrived; // New socket has arrived
+ UINT IdSeed; // ID value
+};
+
+// VPN Tools context
+struct PT
+{
+ CONSOLE *Console; // Console
+ UINT LastError; // Last error
+ wchar_t *CmdLine; // Command line to execute
+};
+
+// Server management context
+struct PS
+{
+ bool ConsoleForServer; // Console for the server (always true)
+ CONSOLE *Console; // Console
+ RPC *Rpc; // RPC
+ char *ServerName; // Server name
+ UINT ServerPort; // Port number
+ char *HubName; // Virtual HUB name in the currently managed
+ UINT LastError; // Last error
+ char *AdminHub; // Virtual HUB to be managed by default
+ wchar_t *CmdLine; // Command line to execute
+ CAPSLIST *CapsList; // Caps list
+};
+
+// Client management context
+struct PC
+{
+ bool ConsoleForServer; // Console for the server (always false)
+ CONSOLE *Console; // Console
+ REMOTE_CLIENT *RemoteClient; // Remote client
+ char *ServerName; // Server name
+ UINT LastError; // Last error
+ wchar_t *CmdLine; // Command line
+};
+
+// A column of the table
+struct CTC
+{
+ wchar_t *String; // String
+ bool Right; // Right justification
+};
+
+// A row of the table
+struct CTR
+{
+ wchar_t **Strings; // String list
+};
+
+// Table for console
+struct CT
+{
+ LIST *Columns; // Column list
+ LIST *Rows; // Row list
+};
+
+UINT CommandMain(wchar_t *command_line);
+UINT VpnCmdProc(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+bool ParseHostPort(char *src, char **host, UINT *port, UINT default_port);
+bool ParseHostPortAtmark(char *src, char **host, UINT *port, UINT default_port);
+CT *CtNew();
+void CtFree(CT *ct, CONSOLE *c);
+void CtFreeEx(CT *ct, CONSOLE *c, bool standard_view);
+void CtInsertColumn(CT *ct, wchar_t *str, bool right);
+CT *CtNewStandard();
+CT *CtNewStandardEx();
+void CtInsert(CT *ct, ...);
+void CtPrint(CT *ct, CONSOLE *c);
+void CtPrintStandard(CT *ct, CONSOLE *c);
+void CtPrintRow(CONSOLE *c, UINT num, UINT *widths, wchar_t **strings, bool *rights, char separate_char);
+void VpnCmdInitBootPath();
+void OutRpcTtResult(PACK *p, TT_RESULT *t);
+void InRpcTtResult(PACK *p, TT_RESULT *t);
+
+void CmdPrintError(CONSOLE *c, UINT err);
+void CmdPrintAbout(CONSOLE *c);
+void CmdPrintRow(CONSOLE *c, wchar_t *title, wchar_t *tag, ...);
+wchar_t *CmdPromptPort(CONSOLE *c, void *param);
+wchar_t *CmdPromptChoosePassword(CONSOLE *c, void *param);
+bool CmdEvalPort(CONSOLE *c, wchar_t *str, void *param);
+void CmdInsertTrafficInfo(CT *ct, TRAFFIC *t);
+wchar_t *GetHubTypeStr(UINT type);
+wchar_t *GetServerTypeStr(UINT type);
+char *CmdPasswordPrompt(CONSOLE *c);
+bool CmdEvalIp(CONSOLE *c, wchar_t *str, void *param);
+wchar_t *PsClusterSettingMemberPromptIp(CONSOLE *c, void *param);
+bool CmdEvalHostAndPort(CONSOLE *c, wchar_t *str, void *param);
+LIST *StrToPortList(char *str);
+bool CmdEvalPortList(CONSOLE *c, wchar_t *str, void *param);
+wchar_t *PsClusterSettingMemberPromptPorts(CONSOLE *c, void *param);
+K *CmdLoadKey(CONSOLE *c, wchar_t *filename);
+bool CmdLoadCertAndKey(CONSOLE *c, X **xx, K **kk, wchar_t *cert_filename, wchar_t *key_filename);
+bool CmdEvalTcpOrUdp(CONSOLE *c, wchar_t *str, void *param);
+wchar_t *GetConnectionTypeStr(UINT type);
+bool CmdEvalHostAndSubnetMask4(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalNetworkAndSubnetMask4(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalNetworkAndSubnetMask6(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalNetworkAndSubnetMask46(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalIpAndMask4(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalIpAndMask6(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalIpAndMask46(CONSOLE *c, wchar_t *str, void *param);
+wchar_t *GetLogSwitchStr(UINT i);
+wchar_t *GetPacketLogNameStr(UINT i);
+UINT StrToLogSwitchType(char *str);
+UINT StrToPacketLogType(char *str);
+UINT StrToPacketLogSaveInfoType(char *str);
+wchar_t *GetProxyTypeStr(UINT i);
+wchar_t *GetClientAuthTypeStr(UINT i);
+void PrintPolicyList(CONSOLE *c, char *name);
+void PrintPolicy(CONSOLE *c, POLICY *pol, bool cascade_mode);
+bool EditPolicy(CONSOLE *c, POLICY *pol, char *name, char *value, bool cascade_mode);
+void CmdPrintStatusToListView(CT *ct, RPC_CLIENT_GET_CONNECTION_STATUS *s);
+void CmdPrintStatusToListViewEx(CT *ct, RPC_CLIENT_GET_CONNECTION_STATUS *s, bool server_mode);
+bool CmdEvalPassOrDiscard(CONSOLE *c, wchar_t *str, void *param);
+bool StrToPassOrDiscard(char *str);
+bool CmdEvalProtocol(CONSOLE *c, wchar_t *str, void *param);
+UINT StrToProtocol(char *str);
+bool CmdEvalPortRange(CONSOLE *c, wchar_t *str, void *param);
+bool ParsePortRange(char *str, UINT *start, UINT *end);
+wchar_t *GetAuthTypeStr(UINT id);
+UINT64 StrToDateTime64(char *str);
+bool CmdEvalDateTime(CONSOLE *c, wchar_t *str, void *param);
+void CmdPrintNodeInfo(CT *ct, NODE_INFO *info);
+wchar_t *GetProtocolName(UINT n);
+void CmdGenerateImportName(REMOTE_CLIENT *r, wchar_t *name, UINT size, wchar_t *old_name);
+bool CmdIsAccountName(REMOTE_CLIENT *r, wchar_t *name);
+wchar_t *GetSyslogSettingName(UINT n);
+
+
+void TtPrint(void *param, TT_PRINT_PROC *print_proc, wchar_t *str);
+void TtGenerateRandomData(UCHAR **buf, UINT *size);
+void TtsWorkerThread(THREAD *thread, void *param);
+void TtsListenThread(THREAD *thread, void *param);
+void TtsAcceptProc(TTS *tts, SOCK *listen_socket);
+void TtsIPv6AcceptThread(THREAD *thread, void *param);
+wchar_t *GetTtcTypeStr(UINT type);
+void TtcPrintSummary(TTC *ttc);
+void StopTtc(TTC *ttc);
+void TtcGenerateResult(TTC *ttc);
+void TtcThread(THREAD *thread, void *param);
+TTC *NewTtcEx(char *host, UINT port, UINT numtcp, UINT type, UINT64 span, bool dbl, bool raw, TT_PRINT_PROC *print_proc, void *param, EVENT *start_event, bool *cancel);
+TTC *NewTtc(char *host, UINT port, UINT numtcp, UINT type, UINT64 span, bool dbl, bool raw, TT_PRINT_PROC *print_proc, void *param);
+UINT FreeTtc(TTC *ttc, TT_RESULT *result);
+TTS *NewTts(UINT port, void *param, TT_PRINT_PROC *print_proc);
+UINT FreeTts(TTS *tts);
+void PtTrafficPrintProc(void *param, wchar_t *str);
+void TtcPrintResult(CONSOLE *c, TT_RESULT *res);
+
+
+bool SystemCheck();
+bool CheckKernel();
+bool CheckMemory();
+bool CheckStrings();
+bool CheckFileSystem();
+bool CheckThread();
+bool CheckNetwork();
+void InputToNull(void *p);
+UINT RetZero();
+
+void Win32CmdDebug(bool is_uac);
+
+
+UINT PtConnect(CONSOLE *c, wchar_t *cmdline);
+PT *NewPt(CONSOLE *c, wchar_t *cmdline);
+void FreePt(PT *pt);
+void PtMain(PT *pt);
+UINT PtMakeCert(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PtTrafficClient(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PtTrafficServer(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PtCheck(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+
+
+UINT PcConnect(CONSOLE *c, char *target, wchar_t *cmdline, char *password);
+PC *NewPc(CONSOLE *c, REMOTE_CLIENT *remote_client, char *servername, wchar_t *cmdline);
+void FreePc(PC *pc);
+void PcMain(PC *pc);
+UINT PcAbout(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcVersionGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcPasswordGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcCertList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcCertAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcCertDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcSecureList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcSecureSelect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcSecureGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicUpgrade(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicGetSetting(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicSetSetting(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountUsernameSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountAnonymousSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountEncryptDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountEncryptEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountCompressEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountCompressDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountProxyNone(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountProxyHttp(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountProxySocks(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountServerCertEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountServerCertDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountServerCertDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountServerCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountDetailSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountRename(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountConnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountDisconnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountNicSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountStatusShow(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountStatusHide(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountSecureCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountRetrySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountStartupSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountStartupRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountExport(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountImport(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcRemoteEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcRemoteDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcKeepEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcKeepDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcKeepSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcKeepGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+
+
+PS *NewPs(CONSOLE *c, RPC *rpc, char *servername, UINT serverport, char *hubname, char *adminhub, wchar_t *cmdline);
+void FreePs(PS *ps);
+UINT PsConnect(CONSOLE *c, char *host, UINT port, char *hub, char *adminhub, wchar_t *cmdline, char *password);
+void PsMain(PS *ps);
+UINT PsAbout(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerInfoGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsListenerCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsListenerDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsListenerList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsListenerEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsListenerDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterSettingGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterSettingStandalone(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterSettingController(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterSettingMember(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterMemberList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterMemberInfoGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterMemberCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterConnectionStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCrash(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsFlush(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDebug(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerKeyGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerCipherGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerCipherSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsKeepEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsKeepDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsKeepSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsKeepGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSyslogGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSyslogDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSyslogEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsConnectionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsConnectionGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsConnectionDisconnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsBridgeDeviceList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsBridgeList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsBridgeCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsBridgeDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCaps(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsReboot(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsConfigGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsConfigSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterStart(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterStop(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterIfList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterIfAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterIfDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterTableList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterTableAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterTableDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogFileList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogFileGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubCreateDynamic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubCreateStatic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubSetStatic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubSetDynamic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHub(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsOnline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsOffline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSetMaxSession(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSetHubPassword(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSetEnumAllow(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSetEnumDeny(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsOptionsGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRadiusServerSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRadiusServerDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRadiusServerGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogSwitchSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogPacketSaveType(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCAList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCAAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCADelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCAGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeUsernameSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeAnonymousSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadePasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeEncryptEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeEncryptDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeCompressEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeCompressDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeProxyNone(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeProxyHttp(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeProxySocks(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeServerCertEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeServerCertDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeServerCertDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeServerCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeDetailSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadePolicyRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadePolicySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsPolicyList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeRename(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeOnline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeOffline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessAddEx(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessAdd6(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessAddEx6(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserAnonymousSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserSignedSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserRadiusSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserNTLMSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserPolicyRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserPolicySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserExpiresSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupJoin(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupUnjoin(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupPolicyRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupPolicySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSessionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSessionGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSessionDisconnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsMacTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsMacDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsIpTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsIpDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSecureNatEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSecureNatDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSecureNatStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSecureNatHostGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSecureNatHostSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsNatGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsNatEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsNatDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsNatSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsNatTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDhcpGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDhcpEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDhcpDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDhcpSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDhcpTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAdminOptionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAdminOptionSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsExtOptionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsExtOptionSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCrlList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCrlAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCrlDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCrlGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAcList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAcAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAcAdd6(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAcGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAcDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLicenseAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLicenseDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLicenseList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLicenseStatus(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsIPsecEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsIPsecGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsEtherIpClientAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsEtherIpClientDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsEtherIpClientList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsOpenVpnEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsOpenVpnGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsOpenVpnMakeConfig(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSstpEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSstpGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerCertRegenerate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsVpnOverIcmpDnsEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsVpnOverIcmpDnsGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDynamicDnsGetStatus(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDynamicDnsSetHostname(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsVpnAzureSetEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsVpnAzureGetStatus(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+
+
+#endif // COMMAND_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Connection.c b/src/Cedar/Connection.c
new file mode 100644
index 00000000..5cc0296c
--- /dev/null
+++ b/src/Cedar/Connection.c
@@ -0,0 +1,3457 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Connection.c
+// Connection Manager
+
+#include "CedarPch.h"
+
+// Determine whether the socket is to use to send
+#define IS_SEND_TCP_SOCK(ts) \
+ ((ts->Direction == TCP_BOTH) || ((ts->Direction == TCP_SERVER_TO_CLIENT) && (s->ServerMode)) || ((ts->Direction == TCP_CLIENT_TO_SERVER) && (s->ServerMode == false)))
+
+// Determine whether the socket is to use to receive
+#define IS_RECV_TCP_SOCK(ts) \
+ ((ts->Direction == TCP_BOTH) || ((ts->Direction == TCP_SERVER_TO_CLIENT) && (s->ServerMode == false)) || ((ts->Direction == TCP_CLIENT_TO_SERVER) && (s->ServerMode)))
+
+// Conversion of SECURE_SIGN
+void InRpcSecureSign(SECURE_SIGN *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(SECURE_SIGN));
+ PackGetStr(p, "SecurePublicCertName", t->SecurePublicCertName, sizeof(t->SecurePublicCertName));
+ PackGetStr(p, "SecurePrivateKeyName", t->SecurePrivateKeyName, sizeof(t->SecurePrivateKeyName));
+ t->ClientCert = PackGetX(p, "ClientCert");
+ PackGetData2(p, "Random", t->Random, sizeof(t->Random));
+ PackGetData2(p, "Signature", t->Signature, sizeof(t->Signature));
+ t->UseSecureDeviceId = PackGetInt(p, "UseSecureDeviceId");
+ t->BitmapId = PackGetInt(p, "BitmapId");
+}
+void OutRpcSecureSign(PACK *p, SECURE_SIGN *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "SecurePublicCertName", t->SecurePublicCertName);
+ PackAddStr(p, "SecurePrivateKeyName", t->SecurePrivateKeyName);
+ PackAddX(p, "ClientCert", t->ClientCert);
+ PackAddData(p, "Random", t->Random, sizeof(t->Random));
+ PackAddData(p, "Signature", t->Signature, sizeof(t->Signature));
+ PackAddInt(p, "UseSecureDeviceId", t->UseSecureDeviceId);
+ PackAddInt(p, "BitmapId", t->BitmapId);
+}
+void FreeRpcSecureSign(SECURE_SIGN *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FreeX(t->ClientCert);
+}
+
+// Generate the next packet
+BUF *NewKeepPacket(bool server_mode)
+{
+ BUF *b = NewBuf();
+ char *string = KEEP_ALIVE_STRING;
+
+ WriteBuf(b, string, StrLen(string));
+
+ SeekBuf(b, 0, 0);
+
+ return b;
+}
+
+// KEEP thread
+void KeepThread(THREAD *thread, void *param)
+{
+ KEEP *k = (KEEP *)param;
+ SOCK *s;
+ char server_name[MAX_HOST_NAME_LEN + 1];
+ UINT server_port;
+ bool udp_mode;
+ bool enabled;
+ // Validate arguments
+ if (thread == NULL || k == NULL)
+ {
+ return;
+ }
+
+WAIT_FOR_ENABLE:
+ Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);
+
+ // Wait until it becomes enabled
+ while (true)
+ {
+ enabled = false;
+ Lock(k->lock);
+ {
+ if (k->Enable)
+ {
+ if (StrLen(k->ServerName) != 0 && k->ServerPort != 0 && k->Interval != 0)
+ {
+ StrCpy(server_name, sizeof(server_name), k->ServerName);
+ server_port = k->ServerPort;
+ udp_mode = k->UdpMode;
+ enabled = true;
+ }
+ }
+ }
+ Unlock(k->lock);
+ if (enabled)
+ {
+ break;
+ }
+ if (k->Halt)
+ {
+ return;
+ }
+ Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);
+ }
+
+ if (udp_mode == false)
+ {
+ // TCP mode
+ // Try until a success to connection
+ while (true)
+ {
+ UINT64 connect_started_tick;
+ bool changed = false;
+ Lock(k->lock);
+ {
+ if (StrCmpi(k->ServerName, server_name) != 0 ||
+ k->ServerPort != server_port || k->Enable == false ||
+ k->UdpMode)
+ {
+ changed = true;
+ }
+ }
+ Unlock(k->lock);
+ if (changed)
+ {
+ // Settings are changed
+ goto WAIT_FOR_ENABLE;
+ }
+
+ if (k->Halt)
+ {
+ // Stop
+ return;
+ }
+
+ // Attempt to connect to the server
+ connect_started_tick = Tick64();
+ s = ConnectEx2(server_name, server_port, KEEP_TCP_TIMEOUT, (bool *)&k->Halt);
+ if (s != NULL)
+ {
+ // Successful connection
+ break;
+ }
+
+ // Connection failure: Wait until timeout or the setting is changed
+ while (true)
+ {
+ changed = false;
+ if (k->Halt)
+ {
+ // Stop
+ return;
+ }
+ Lock(k->lock);
+ {
+ if (StrCmpi(k->ServerName, server_name) != 0 ||
+ k->ServerPort != server_port || k->Enable == false ||
+ k->UdpMode)
+ {
+ changed = true;
+ }
+ }
+ Unlock(k->lock);
+
+ if (changed)
+ {
+ // Settings are changed
+ goto WAIT_FOR_ENABLE;
+ }
+
+ if ((Tick64() - connect_started_tick) >= KEEP_RETRY_INTERVAL)
+ {
+ break;
+ }
+
+ Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);
+ }
+ }
+
+ // Success to connect the server
+ // Send and receive packet data periodically
+ if (s != NULL)
+ {
+ UINT64 last_packet_sent_time = 0;
+ while (true)
+ {
+ SOCKSET set;
+ UINT ret;
+ UCHAR buf[MAX_SIZE];
+ bool changed;
+
+ InitSockSet(&set);
+ AddSockSet(&set, s);
+
+ Select(&set, KEEP_POLLING_INTERVAL, k->Cancel, NULL);
+
+ ret = Recv(s, buf, sizeof(buf), false);
+ if (ret == 0)
+ {
+ // Disconnected
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ }
+
+ if (s != NULL)
+ {
+ if ((Tick64() - last_packet_sent_time) >= (UINT64)k->Interval)
+ {
+ BUF *b;
+
+ // Send the next packet
+ last_packet_sent_time = Tick64();
+
+ b = NewKeepPacket(k->Server);
+
+ ret = Send(s, b->Buf, b->Size, false);
+ FreeBuf(b);
+
+ if (ret == 0)
+ {
+ // Disconnected
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ }
+ }
+ }
+
+ changed = false;
+
+ Lock(k->lock);
+ {
+ if (StrCmpi(k->ServerName, server_name) != 0 ||
+ k->ServerPort != server_port || k->Enable == false ||
+ k->UdpMode)
+ {
+ changed = true;
+ }
+ }
+ Unlock(k->lock);
+
+ if (changed || s == NULL)
+ {
+ // Setting has been changed or disconnected
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ goto WAIT_FOR_ENABLE;
+ }
+ else
+ {
+ if (k->Halt)
+ {
+ // Stop
+ Disconnect(s);
+ ReleaseSock(s);
+ return;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ IP dest_ip;
+ // UDP mode
+ // Try to create socket until it successes
+ while (true)
+ {
+ UINT64 connect_started_tick;
+ bool changed = false;
+ Lock(k->lock);
+ {
+ if (StrCmpi(k->ServerName, server_name) != 0 ||
+ k->ServerPort != server_port || k->Enable == false ||
+ k->UdpMode == false)
+ {
+ changed = true;
+ }
+ }
+ Unlock(k->lock);
+ if (changed)
+ {
+ // Settings are changed
+ goto WAIT_FOR_ENABLE;
+ }
+
+ if (k->Halt)
+ {
+ // Stop
+ return;
+ }
+
+ // Attempt to create a socket
+ connect_started_tick = Tick64();
+
+ // Attempt to resolve the name first
+ if (GetIP(&dest_ip, server_name))
+ {
+ // After successful name resolution, create a socket
+ s = NewUDP(0);
+ if (s != NULL)
+ {
+ // Creating success
+ break;
+ }
+ }
+
+ // Failure to create: wait until timeout or the setting is changed
+ while (true)
+ {
+ changed = false;
+ if (k->Halt)
+ {
+ // Stop
+ return;
+ }
+ Lock(k->lock);
+ {
+ if (StrCmpi(k->ServerName, server_name) != 0 ||
+ k->ServerPort != server_port || k->Enable == false ||
+ k->UdpMode)
+ {
+ changed = true;
+ }
+ }
+ Unlock(k->lock);
+
+ if (changed)
+ {
+ // Settings are changed
+ goto WAIT_FOR_ENABLE;
+ }
+
+ if ((Tick64() - connect_started_tick) >= KEEP_RETRY_INTERVAL)
+ {
+ break;
+ }
+
+ Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);
+ }
+ }
+
+ // Send the packet data periodically
+ if (s != NULL)
+ {
+ UINT64 last_packet_sent_time = 0;
+ UINT num_ignore_errors = 0;
+ while (true)
+ {
+ SOCKSET set;
+ UINT ret;
+ UCHAR buf[MAX_SIZE];
+ bool changed;
+ IP src_ip;
+ UINT src_port;
+
+ InitSockSet(&set);
+ AddSockSet(&set, s);
+
+ Select(&set, KEEP_POLLING_INTERVAL, k->Cancel, NULL);
+
+ // Receive
+ ret = RecvFrom(s, &src_ip, &src_port, buf, sizeof(buf));
+ if (ret == 0)
+ {
+ if (s->IgnoreRecvErr == false)
+ {
+LABEL_DISCONNECTED:
+ // Disconnected
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ }
+ else
+ {
+ if ((num_ignore_errors++) >= MAX_NUM_IGNORE_ERRORS)
+ {
+ goto LABEL_DISCONNECTED;
+ }
+ }
+ }
+
+ if (s != NULL)
+ {
+ if ((Tick64() - last_packet_sent_time) >= (UINT64)k->Interval)
+ {
+ BUF *b;
+
+ // Send the next packet
+ last_packet_sent_time = Tick64();
+
+ b = NewKeepPacket(k->Server);
+
+ ret = SendTo(s, &dest_ip, server_port, b->Buf, b->Size);
+ FreeBuf(b);
+
+ if (ret == 0 && s->IgnoreSendErr == false)
+ {
+ // Disconnected
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ }
+ }
+ }
+
+ changed = false;
+
+ Lock(k->lock);
+ {
+ if (StrCmpi(k->ServerName, server_name) != 0 ||
+ k->ServerPort != server_port || k->Enable == false ||
+ k->UdpMode == false)
+ {
+ changed = true;
+ }
+ }
+ Unlock(k->lock);
+
+ if (changed || s == NULL)
+ {
+ // Setting has been changed or disconnected
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ goto WAIT_FOR_ENABLE;
+ }
+ else
+ {
+ if (k->Halt)
+ {
+ // Stop
+ Disconnect(s);
+ ReleaseSock(s);
+ return;
+ }
+ }
+ }
+ }
+ }
+}
+
+// Stop the KEEP
+void StopKeep(KEEP *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ k->Halt = true;
+ Set(k->HaltEvent);
+ Cancel(k->Cancel);
+
+ WaitThread(k->Thread, INFINITE);
+ ReleaseThread(k->Thread);
+ DeleteLock(k->lock);
+
+ ReleaseCancel(k->Cancel);
+ ReleaseEvent(k->HaltEvent);
+
+ Free(k);
+}
+
+// Start the KEEP
+KEEP *StartKeep()
+{
+ KEEP *k = ZeroMalloc(sizeof(KEEP));
+
+ k->lock = NewLock();
+ k->HaltEvent = NewEvent();
+ k->Cancel = NewCancel();
+
+ // Thread start
+ k->Thread = NewThread(KeepThread, k);
+
+ return k;
+}
+
+// Copy the client authentication data
+CLIENT_AUTH *CopyClientAuth(CLIENT_AUTH *a)
+{
+ CLIENT_AUTH *ret;
+ // Validate arguments
+ if (a == NULL)
+ {
+ return NULL;
+ }
+
+ ret = ZeroMallocEx(sizeof(CLIENT_AUTH), true);
+
+ ret->AuthType = a->AuthType;
+ StrCpy(ret->Username, sizeof(ret->Username), a->Username);
+
+ switch (a->AuthType)
+ {
+ case CLIENT_AUTHTYPE_ANONYMOUS:
+ // Anonymous authentication
+ break;
+
+ case CLIENT_AUTHTYPE_PASSWORD:
+ // Password authentication
+ Copy(ret->HashedPassword, a->HashedPassword, SHA1_SIZE);
+ break;
+
+ case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+ // Plaintext password authentication
+ StrCpy(ret->PlainPassword, sizeof(ret->PlainPassword), a->PlainPassword);
+ break;
+
+ case CLIENT_AUTHTYPE_CERT:
+ // Certificate authentication
+ ret->ClientX = CloneX(a->ClientX);
+ ret->ClientK = CloneK(a->ClientK);
+ break;
+
+ case CLIENT_AUTHTYPE_SECURE:
+ // Secure device authentication
+ StrCpy(ret->SecurePublicCertName, sizeof(ret->SecurePublicCertName), a->SecurePublicCertName);
+ StrCpy(ret->SecurePrivateKeyName, sizeof(ret->SecurePrivateKeyName), a->SecurePrivateKeyName);
+ break;
+ }
+
+ return ret;
+}
+
+// Write data to the transmit FIFO (automatic encryption)
+void WriteSendFifo(SESSION *s, TCPSOCK *ts, void *data, UINT size)
+{
+ // Validate arguments
+ if (s == NULL || ts == NULL || data == NULL)
+ {
+ return;
+ }
+
+ if (s->UseFastRC4)
+ {
+ Encrypt(ts->SendKey, data, data, size);
+ }
+
+ WriteFifo(ts->SendFifo, data, size);
+}
+
+// Write data to the reception FIFO (automatic deccyption)
+void WriteRecvFifo(SESSION *s, TCPSOCK *ts, void *data, UINT size)
+{
+ // Validate arguments
+ if (s == NULL || ts == NULL || data == NULL)
+ {
+ return;
+ }
+
+ if (s->UseFastRC4)
+ {
+ Encrypt(ts->RecvKey, data, data, size);
+ }
+
+ WriteFifo(ts->RecvFifo, data, size);
+}
+
+// TCP socket receive
+UINT TcpSockRecv(SESSION *s, TCPSOCK *ts, void *data, UINT size)
+{
+ // Receive
+ return Recv(ts->Sock, data, size, s->UseSSLDataEncryption);
+}
+
+// TCP socket send
+UINT TcpSockSend(SESSION *s, TCPSOCK *ts, void *data, UINT size)
+{
+ // Transmission
+ return Send(ts->Sock, data, size, s->UseSSLDataEncryption);
+}
+
+// Send the data as UDP packet
+void SendDataWithUDP(SOCK *s, CONNECTION *c)
+{
+ UCHAR *buf;
+ BUF *b;
+ UINT64 dummy_64 = 0;
+ UCHAR dummy_buf[16];
+ UINT64 now = Tick64();
+ UINT ret;
+ bool force_flag = false;
+ bool packet_sent = false;
+ // Validate arguments
+ if (s == NULL || c == NULL)
+ {
+ return;
+ }
+
+ // Allocate the temporary buffer in heap
+ if (c->RecvBuf == NULL)
+ {
+ c->RecvBuf = Malloc(RECV_BUF_SIZE);
+ }
+ buf = c->RecvBuf;
+
+ if (c->Udp->NextKeepAliveTime == 0 || c->Udp->NextKeepAliveTime <= now)
+ {
+ force_flag = true;
+ }
+
+ // Creating a buffer
+ while ((c->SendBlocks->num_item > 0) || force_flag)
+ {
+ UINT *key32;
+ UINT64 *seq;
+ char *sign;
+
+ force_flag = false;
+
+ // Assemble a buffer from the current queue
+ b = NewBuf();
+
+ // Keep an area for packet header (16 bytes)
+ WriteBuf(b, dummy_buf, sizeof(dummy_buf));
+
+ // Pack the packets in transmission queue
+ LockQueue(c->SendBlocks);
+ {
+ while (true)
+ {
+ BLOCK *block;
+
+ if (b->Size > UDP_BUF_SIZE)
+ {
+ break;
+ }
+ block = GetNext(c->SendBlocks);
+ if (block == NULL)
+ {
+ break;
+ }
+
+ if (block->Size != 0)
+ {
+ WriteBufInt(b, block->Size);
+ WriteBuf(b, block->Buf, block->Size);
+
+ c->Session->TotalSendSize += (UINT64)block->SizeofData;
+ c->Session->TotalSendSizeReal += (UINT64)block->Size;
+ }
+
+ FreeBlock(block);
+ break;
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+
+ // Write sequence number and session key
+ sign = (char *)(((UCHAR *)b->Buf));
+ key32 = (UINT *)(((UCHAR *)b->Buf + 4));
+ seq = (UINT64 *)(((UCHAR *)b->Buf + 8));
+ Copy(sign, SE_UDP_SIGN, 4);
+ *key32 = Endian32(c->Session->SessionKey32);
+ *seq = Endian64(c->Udp->Seq++); // Increment the sequence number
+
+// InsertQueue(c->Udp->BufferQueue, b);
+
+ packet_sent = true;
+/* }
+
+ // Send a buffer
+ while (c->Udp->BufferQueue->num_item != 0)
+ {
+ FIFO *f = c->Udp->BufferQueue->fifo;
+ BUF **pb = (BUF**)(((UCHAR *)f->p) + f->pos);
+ BUF *b = *pb;
+
+*/ ret = SendTo(s, &c->Udp->ip, c->Udp->port, b->Buf, b->Size);
+ if (ret == SOCK_LATER)
+ {
+ // Blocking
+ Debug(".");
+// break;
+ }
+ if (ret != b->Size)
+ {
+ if (s->IgnoreSendErr == false)
+ {
+ // Error
+ Debug("******* SendTo Error !!!\n");
+ }
+ }
+
+ // Memory release
+ FreeBuf(b);
+// GetNext(c->Udp->BufferQueue);
+ }
+
+ if (packet_sent)
+ {
+ // KeepAlive time update
+ c->Udp->NextKeepAliveTime = now + (UINT64)GenNextKeepAliveSpan(c);
+ }
+}
+
+// Write the data of the UDP packet to the connection
+void PutUDPPacketData(CONNECTION *c, void *data, UINT size)
+{
+ BUF *b;
+ char sign[4];
+ // Validate arguments
+ if (c == NULL || data == NULL)
+ {
+ return;
+ }
+
+ // Examine the protocol
+ if (c->Protocol != CONNECTION_UDP)
+ {
+ // UDP protocol is not used
+ return;
+ }
+
+ // Buffer configuration
+ b = NewBuf();
+ WriteBuf(b, data, size);
+
+ SeekBuf(b, 0, 0);
+ ReadBuf(b, sign, 4);
+
+ // Signature confirmation
+ if (Cmp(sign, SE_UDP_SIGN, 4) == 0)
+ {
+ UINT key32;
+
+ // Session key number
+ key32 = ReadBufInt(b);
+
+ if (c->Session->SessionKey32 == key32)
+ {
+ UINT64 seq;
+
+ // Read the Sequence number
+ ReadBuf(b, &seq, sizeof(seq));
+ seq = Endian64(seq);
+
+ if ((UINT)(seq - c->Udp->RecvSeq - (UINT64)1))
+ {
+ //Debug("** UDP Seq Lost %u\n", (UINT)(seq - c->Udp->RecvSeq - (UINT64)1));
+ }
+ c->Udp->RecvSeq = seq;
+
+ //Debug("SEQ: %I32u\n", seq);
+
+ while (true)
+ {
+ UINT size;
+
+ size = ReadBufInt(b);
+ if (size == 0)
+ {
+ break;
+ }
+ else if (size <= MAX_PACKET_SIZE)
+ {
+ void *tmp;
+ BLOCK *block;
+
+ tmp = Malloc(size);
+ if (ReadBuf(b, tmp, size) != size)
+ {
+ Free(tmp);
+ break;
+ }
+
+ // Block configuration
+ block = NewBlock(tmp, size, 0);
+
+ // Insert Block
+ InsertReveicedBlockToQueue(c, block);
+ }
+ }
+
+ // Update the last communication time
+ c->Session->LastCommTime = Tick64();
+ }
+ else
+ {
+ Debug("Invalid SessionKey: 0x%X\n", key32);
+ }
+ }
+
+ FreeBuf(b);
+}
+
+// Add a block to the receive queue
+void InsertReveicedBlockToQueue(CONNECTION *c, BLOCK *block)
+{
+ SESSION *s;
+ // Validate arguments
+ if (c == NULL || block == NULL)
+ {
+ return;
+ }
+
+ s = c->Session;
+
+ if (c->Protocol == CONNECTION_TCP)
+ {
+ s->TotalRecvSizeReal += block->SizeofData;
+ s->TotalRecvSize += block->Size;
+ }
+
+ LockQueue(c->ReceivedBlocks);
+ {
+ InsertQueue(c->ReceivedBlocks, block);
+ }
+ UnlockQueue(c->ReceivedBlocks);
+}
+
+// Generate the interval to the next Keep-Alive packet
+// (This should be a random number for the network load reduction)
+UINT GenNextKeepAliveSpan(CONNECTION *c)
+{
+ UINT a, b;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return INFINITE;
+ }
+
+ a = c->Session->Timeout;
+ b = rand() % (a / 2);
+ b = MAX(b, a / 5);
+
+ return b;
+}
+
+// send a Keep-Alive packet
+void SendKeepAlive(CONNECTION *c, TCPSOCK *ts)
+{
+ UINT size, i, num;
+ UINT size_be;
+ SESSION *s;
+ UCHAR *buf;
+ bool insert_natt_port = false;
+ // Validate arguments
+ if (c == NULL || ts == NULL)
+ {
+ return;
+ }
+
+ s = c->Session;
+
+ size = rand() % MAX_KEEPALIVE_SIZE;
+ num = KEEP_ALIVE_MAGIC;
+
+ if (s != NULL && s->UseUdpAcceleration && s->UdpAccel != NULL)
+ {
+ if (s->UdpAccel->MyPortByNatTServer != 0)
+ {
+ size = MAX(size, (StrLen(UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE) + sizeof(USHORT)));
+
+ insert_natt_port = true;
+ }
+ }
+
+ buf = MallocFast(size);
+
+ for (i = 0;i < size;i++)
+ {
+ buf[i] = rand();
+ }
+
+ if (insert_natt_port)
+ {
+ USHORT myport = Endian16((USHORT)s->UdpAccel->MyPortByNatTServer);
+
+ Copy(buf, UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE, StrLen(UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE));
+ Copy(buf + StrLen(UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE), &myport, sizeof(USHORT));
+ }
+
+ num = Endian32(num);
+ size_be = Endian32(size);
+ WriteSendFifo(c->Session, ts, &num, sizeof(UINT));
+ WriteSendFifo(c->Session, ts, &size_be, sizeof(UINT));
+ WriteSendFifo(c->Session, ts, buf, size);
+
+ c->Session->TotalSendSize += sizeof(UINT) * 2 + size;
+ c->Session->TotalSendSizeReal += sizeof(UINT) * 2 + size;
+
+ Free(buf);
+}
+
+// Transmission of block
+void ConnectionSend(CONNECTION *c)
+{
+ UINT i, num;
+ UINT64 now;
+ UINT min_count;
+ UINT64 max_recv_tick;
+ TCPSOCK **tcpsocks;
+ UINT size;
+ SESSION *s;
+ HUB *hub = NULL;
+ bool use_qos;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ s = c->Session;
+ use_qos = s->QoS;
+
+ if (s != NULL)
+ {
+ hub = s->Hub;
+ }
+
+ now = Tick64();
+
+ // Protocol
+ if (c->Protocol == CONNECTION_TCP)
+ {
+ // TCP
+ TCP *tcp = c->Tcp;
+ TCPSOCK *ts;
+ TCPSOCK *ts_hp;
+ UINT num_available;
+ bool is_rudp = false;
+ LockList(tcp->TcpSockList);
+ {
+ num = LIST_NUM(tcp->TcpSockList);
+ tcpsocks = ToArrayEx(tcp->TcpSockList, true);
+ }
+ UnlockList(tcp->TcpSockList);
+
+ if (s != NULL)
+ {
+ is_rudp = s->IsRUDPSession;
+ }
+
+ // Select the socket that will be used to send
+ // Select a socket which have least delay count
+ min_count = INFINITE;
+ max_recv_tick = 0;
+ ts = NULL;
+ ts_hp = NULL;
+
+ num_available = 0;
+
+ if (c->IsInProc == false)
+ {
+ for (i = 0;i < num;i++)
+ {
+ TCPSOCK *tcpsock = tcpsocks[i];
+ if (tcpsock->Sock->Connected && tcpsock->Sock->AsyncMode &&
+ IS_SEND_TCP_SOCK(tcpsock))
+ {
+ // Processing of KeepAlive
+ if (now >= tcpsock->NextKeepAliveTime || tcpsock->NextKeepAliveTime == 0 ||
+ (s != NULL && s->UseUdpAcceleration && s->UdpAccel != NULL && s->UdpAccel->MyPortByNatTServerChanged))
+ {
+ // Send the KeepAlive
+ SendKeepAlive(c, tcpsock);
+ tcpsock->NextKeepAliveTime = now + (UINT64)GenNextKeepAliveSpan(c);
+
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL)
+ {
+ s->UdpAccel->MyPortByNatTServerChanged = false;
+ }
+ }
+
+ // Count the number of available sockets to send
+ num_available++;
+
+ ts_hp = tcpsock;
+ }
+ }
+ }
+
+ for (i = 0;i < num;i++)
+ {
+ TCPSOCK *tcpsock = tcpsocks[i];
+ if (tcpsock->Sock->Connected && tcpsock->Sock->AsyncMode &&
+ IS_SEND_TCP_SOCK(tcpsock))
+ {
+ // Selection of the socket
+ bool b = false;
+
+ if (use_qos == false)
+ {
+ b = true;
+ }
+ else if (num_available < 2)
+ {
+ b = true;
+ }
+ else if (tcpsock != ts_hp)
+ {
+ b = true;
+ }
+
+ if (b)
+ {
+ if (is_rudp == false)
+ {
+ // Use a socket which have minimum delay occurrences in the case of such as a TCP socket
+ if (tcpsock->LateCount <= min_count)
+ {
+ min_count = tcpsock->LateCount;
+ ts = tcpsock;
+ }
+ }
+ else
+ {
+ // Use socket which have the largest last received time in the case of R-UDP socket
+ if (tcpsock->LastRecvTime >= max_recv_tick)
+ {
+ max_recv_tick = tcpsock->LastRecvTime;
+ ts = tcpsock;
+ }
+ }
+ }
+ }
+ }
+
+ if (ts_hp == NULL)
+ {
+ ts_hp = ts;
+ }
+
+ if (use_qos == false)
+ {
+ ts_hp = ts;
+ }
+
+ if (ts == NULL || ts_hp == NULL)
+ {
+ // The socket available to send doesn't currently exist
+ }
+ else
+ {
+ TCPSOCK *tss;
+ UINT j;
+ QUEUE *q;
+
+ if (s->UdpAccel != NULL)
+ {
+ UdpAccelSetTick(s->UdpAccel, now);
+ }
+
+ for (j = 0;j < 2;j++)
+ {
+ if (j == 0)
+ {
+ q = c->SendBlocks2;
+ tss = ts_hp;
+ }
+ else
+ {
+ q = c->SendBlocks;
+ tss = ts;
+ }
+ // I reserve the data to send on the selected socket ts
+ LockQueue(c->SendBlocks);
+ if (q->num_item != 0)
+ {
+ UINT num_data;
+ BLOCK *b;
+
+ if (tss->SendFifo->size >= MAX((MAX_SEND_SOCKET_QUEUE_SIZE / s->MaxConnection), MIN_SEND_SOCKET_QUEUE_SIZE))
+ {
+ // The size of the socket send queue is exceeded
+ // Unable to send
+ while (b = GetNext(q))
+ {
+ if (b != NULL)
+ {
+ c->CurrentSendQueueSize -= b->Size;
+ FreeBlock(b);
+ }
+ }
+ }
+ else
+ {
+ if (c->IsInProc == false)
+ {
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL && UdpAccelIsSendReady(s->UdpAccel, true))
+ {
+ // UDP acceleration mode
+ while (b = GetNext(q))
+ {
+ UdpAccelSendBlock(s->UdpAccel, b);
+
+ s->TotalSendSize += b->Size;
+ s->TotalSendSizeReal += b->Size;
+
+ c->CurrentSendQueueSize -= b->Size;
+
+ FreeBlock(b);
+ }
+ }
+ else if (s->IsRUDPSession && s->EnableBulkOnRUDP && ts->Sock != NULL && ts->Sock->BulkSendTube != NULL)
+ {
+ // R-UDP bulk transfer
+ TUBE *t = ts->Sock->BulkSendTube;
+ bool flush = false;
+ TCP_PAIR_HEADER h;
+
+ Zero(&h, sizeof(h));
+ h.EnableHMac = s->EnableHMacOnBulkOfRUDP;
+
+ while (b = GetNext(q))
+ {
+ if (b->Compressed == false)
+ {
+ // Uncompressed
+ TubeSendEx(t, b->Buf, b->Size, &h, true);
+
+ s->TotalSendSize += b->Size;
+ s->TotalSendSizeReal += b->Size;
+
+ c->CurrentSendQueueSize -= b->Size;
+ }
+ else
+ {
+ // Compressed
+ UCHAR *new_buf = Malloc(b->Size + sizeof(UINT64));
+
+ WRITE_UINT64(new_buf, CONNECTION_BULK_COMPRESS_SIGNATURE);
+
+ Copy(new_buf + sizeof(UINT64), b->Buf, b->Size);
+
+ TubeSendEx(t, new_buf, b->Size + sizeof(UINT64), &h, true);
+
+ s->TotalSendSize += b->SizeofData;
+ s->TotalSendSizeReal += b->Size;
+
+ c->CurrentSendQueueSize -= b->Size;
+ }
+
+ FreeBlock(b);
+
+ flush = true;
+ }
+
+ if (flush)
+ {
+ TubeFlush(t);
+ }
+ }
+ else
+ {
+ // TCP/IP socket
+ bool update_keepalive_timer = false;
+ // Number of data
+ num_data = Endian32(q->num_item);
+ PROBE_DATA2("WriteSendFifo num", &num_data, sizeof(UINT));
+ WriteSendFifo(s, tss, &num_data, sizeof(UINT));
+
+ s->TotalSendSize += sizeof(UINT);
+ s->TotalSendSizeReal += sizeof(UINT);
+
+ while (b = GetNext(q))
+ {
+ // Size data
+ UINT size_data;
+ size_data = Endian32(b->Size);
+ PROBE_DATA2("WriteSendFifo size", &size_data, sizeof(UINT));
+ WriteSendFifo(s, tss, &size_data, sizeof(UINT));
+
+ c->CurrentSendQueueSize -= b->Size;
+
+ s->TotalSendSize += sizeof(UINT);
+ s->TotalSendSizeReal += sizeof(UINT);
+
+ // Data body
+ PROBE_DATA2("WriteSendFifo data", b->Buf, b->Size);
+ WriteSendFifo(s, tss, b->Buf, b->Size);
+
+ s->TotalSendSize += b->SizeofData;
+ s->TotalSendSizeReal += b->Size;
+
+ update_keepalive_timer = true;
+
+ // Block release
+ FreeBlock(b);
+ }
+
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL && UdpAccelIsSendReady(s->UdpAccel, false))
+ {
+ update_keepalive_timer = false;
+ }
+
+ if (update_keepalive_timer)
+ {
+ // Increase the KeepAlive timer
+ tss->NextKeepAliveTime = now + (UINT64)GenNextKeepAliveSpan(c);
+ }
+ }
+ }
+ else
+ {
+ bool flush = false;
+ // In-process socket
+ while (b = GetNext(q))
+ {
+ TubeSendEx(ts->Sock->SendTube, b->Buf, b->Size, NULL, true);
+ flush = true;
+
+ s->TotalSendSize += b->Size;
+ s->TotalSendSizeReal += b->Size;
+
+ c->CurrentSendQueueSize -= b->Size;
+
+ FreeBlock(b);
+ }
+
+ if (flush)
+ {
+ TubeFlush(ts->Sock->SendTube);
+ }
+ }
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+ }
+ }
+
+ // Send the reserved data to send registered in each socket now
+ if (c->IsInProc == false)
+ {
+ for (i = 0;i < num;i++)
+ {
+ ts = tcpsocks[i];
+
+SEND_START:
+ if (ts->Sock->Connected == false)
+ {
+ s->LastTryAddConnectTime = Tick64();
+ // Communication is disconnected
+ LockList(tcp->TcpSockList);
+ {
+ // Remove the socket from socket list
+ Delete(tcp->TcpSockList, ts);
+ // Release of TCPSOCK
+ FreeTcpSock(ts);
+ // Decrement the count
+ Dec(c->CurrentNumConnection);
+ Debug("--- TCP Connection Decremented: %u (%s Line %u)\n", Count(c->CurrentNumConnection), __FILE__, __LINE__);
+ Debug("LIST_NUM(tcp->TcpSockList): %u\n", LIST_NUM(tcp->TcpSockList));
+ }
+ UnlockList(tcp->TcpSockList);
+
+ continue;
+ }
+
+ // Get Fifo size
+ if (ts->SendFifo->size != 0)
+ {
+ UCHAR *buf;
+ UINT want_send_size;
+ // Send only if the data to send exists by 1 byte or more
+ // Get the pointer to the buffer
+ buf = (UCHAR *)ts->SendFifo->p + ts->SendFifo->pos;
+ want_send_size = ts->SendFifo->size;
+
+ PROBE_DATA2("TcpSockSend", buf, want_send_size);
+ size = TcpSockSend(s, ts, buf, want_send_size);
+
+ if (size == 0)
+ {
+ // Disconnected
+ continue;
+ }
+ else if (size == SOCK_LATER)
+ {
+ // Packet is jammed
+ ts->LateCount++; // Increment of the delay counter
+ PROBE_STR("ts->LateCount++;");
+ }
+ else
+ {
+ // Packet is sent only by 'size'
+ // Advance FIFO
+ ReadFifo(ts->SendFifo, NULL, size);
+ if (size < want_send_size)
+ {
+ // Fail to transmit all of the data that has been scheduled
+#ifdef USE_PROBE
+ {
+ char tmp[MAX_SIZE];
+
+ snprintf(tmp, sizeof(tmp), "size < want_send_size: %u < %u",
+ size, want_send_size);
+
+ PROBE_STR(tmp);
+ }
+#endif // USE_PROBE
+ }
+ else
+ {
+ // Because sending all the packets is completed
+ // (The queue is exhausted), reset the delay counter
+ ts->LateCount = 0;
+
+ PROBE_STR("TcpSockSend All Completed");
+ }
+ // Updated the last communication date and time
+ c->Session->LastCommTime = now;
+
+ goto SEND_START;
+ }
+ }
+ }
+ }
+
+ Free(tcpsocks);
+ }
+ else if (c->Protocol == CONNECTION_UDP)
+ {
+ // UDP
+ UDP *udp = c->Udp;
+ SOCK *sock = NULL;
+
+ Lock(c->lock);
+ {
+ sock = udp->s;
+ if (sock != NULL)
+ {
+ AddRef(sock->ref);
+ }
+ }
+ Unlock(c->lock);
+
+ if (sock != NULL)
+ {
+ // Send with UDP
+
+ // KeepAlive sending
+ if ((udp->NextKeepAliveTime == 0 || udp->NextKeepAliveTime <= now) ||
+ (c->SendBlocks->num_item != 0) || (udp->BufferQueue->num_item != 0))
+ {
+ // Send the current queue with UDP
+ SendDataWithUDP(sock, c);
+ }
+ }
+
+ if (sock != NULL)
+ {
+ ReleaseSock(sock);
+ }
+ }
+ else if (c->Protocol == CONNECTION_HUB_SECURE_NAT)
+ {
+ // SecureNAT session
+ SNAT *snat = s->SecureNAT;
+ VH *v = snat->Nat->Virtual;
+
+ LockQueue(c->SendBlocks);
+ {
+ BLOCK *block;
+ UINT num_packet = 0;
+
+ if (hub != NULL)
+ {
+ NatSetHubOption(v, hub->Option);
+ }
+
+ while (block = GetNext(c->SendBlocks))
+ {
+ num_packet++;
+ c->CurrentSendQueueSize -= block->Size;
+ VirtualPutPacket(v, block->Buf, block->Size);
+ Free(block);
+ }
+
+ if (num_packet != 0)
+ {
+ VirtualPutPacket(v, NULL, 0);
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+ }
+ else if (c->Protocol == CONNECTION_HUB_LAYER3)
+ {
+ // Layer-3 session
+ L3IF *f = s->L3If;
+
+ LockQueue(c->SendBlocks);
+ {
+ BLOCK *block;
+ UINT num_packet = 0;
+
+ while (block = GetNext(c->SendBlocks))
+ {
+ num_packet++;
+ c->CurrentSendQueueSize -= block->Size;
+ L3PutPacket(f, block->Buf, block->Size);
+ Free(block);
+ }
+
+ if (num_packet != 0)
+ {
+ L3PutPacket(f, NULL, 0);
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+ }
+ else if (c->Protocol == CONNECTION_HUB_LINK_SERVER)
+ {
+ // HUB Link
+ LINK *k = (LINK *)s->Link;
+
+ if (k != NULL)
+ {
+ LockQueue(c->SendBlocks);
+ {
+ UINT num_blocks = 0;
+ LockQueue(k->SendPacketQueue);
+ {
+ BLOCK *block;
+
+ // Transfer the packet queue to the client thread
+ while (block = GetNext(c->SendBlocks))
+ {
+ num_blocks++;
+ c->CurrentSendQueueSize -= block->Size;
+ InsertQueue(k->SendPacketQueue, block);
+ }
+ }
+ UnlockQueue(k->SendPacketQueue);
+
+ if (num_blocks != 0)
+ {
+ // Issue of cancellation
+ Cancel(k->ClientSession->Cancel1);
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+ }
+ }
+ else if (c->Protocol == CONNECTION_HUB_BRIDGE)
+ {
+ // Local bridge
+ BRIDGE *b = s->Bridge;
+
+ if (b != NULL)
+ {
+ if (b->Active)
+ {
+ LockQueue(c->SendBlocks);
+ {
+ BLOCK *block;
+ UINT num_packet = c->SendBlocks->num_item; // Packet count
+
+ if (num_packet != 0)
+ {
+ // Packet data array
+ void **datas = MallocFast(sizeof(void *) * num_packet);
+ UINT *sizes = MallocFast(sizeof(UINT *) * num_packet);
+ UINT i;
+
+ i = 0;
+ while (block = GetNext(c->SendBlocks))
+ {
+ if (hub != NULL && hub->Option != NULL && hub->Option->DisableUdpFilterForLocalBridgeNic == false &&
+ b->Eth != NULL && IsDhcpPacketForSpecificMac(block->Buf, block->Size, b->Eth->MacAddress))
+ {
+ // DHCP Packet is filtered
+ datas[i] = NULL;
+ sizes[i] = 0;
+
+ Free(block->Buf);
+ }
+ else
+ {
+ datas[i] = block->Buf;
+ sizes[i] = block->Size;
+
+ if (block->Size > 1514)
+ {
+ NormalizeEthMtu(b, c, block->Size);
+ }
+ }
+
+ c->CurrentSendQueueSize -= block->Size;
+ Free(block);
+ i++;
+ }
+
+ // Write the packet
+ EthPutPackets(b->Eth, num_packet, datas, sizes);
+
+ Free(datas);
+ Free(sizes);
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+ }
+ }
+ }
+}
+
+// Reception of the block
+void ConnectionReceive(CONNECTION *c, CANCEL *c1, CANCEL *c2)
+{
+ UINT i, num;
+ SOCKSET set;
+ SESSION *s;
+ TCPSOCK **tcpsocks;
+ UCHAR *buf;
+ UINT size;
+ UINT64 now;
+ UINT time;
+ UINT num_delayed = 0;
+ bool no_spinlock_for_delay = false;
+ HUB *hub = NULL;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ PROBE_STR("ConnectionReceive");
+
+ s = c->Session;
+
+ if (s != NULL)
+ {
+ hub = s->Hub;
+ }
+
+ if (hub != NULL)
+ {
+ no_spinlock_for_delay = hub->Option->NoSpinLockForPacketDelay;
+ }
+
+ now = Tick64();
+
+ if (c->RecvBuf == NULL)
+ {
+ c->RecvBuf = Malloc(RECV_BUF_SIZE);
+ }
+ buf = c->RecvBuf;
+
+ // Protocol
+ if (c->Protocol == CONNECTION_TCP)
+ {
+ // TCP
+ TCP *tcp = c->Tcp;
+ UINT next_delay_packet_diff = 0;
+
+ // Disconnect if disconnection interval is specified
+ if (s->ServerMode == false)
+ {
+ if (s->ClientOption->ConnectionDisconnectSpan != 0)
+ {
+ LockList(tcp->TcpSockList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(tcp->TcpSockList);i++)
+ {
+ TCPSOCK *ts = LIST_DATA(tcp->TcpSockList, i);
+ if (ts->DisconnectTick != 0 &&
+ ts->DisconnectTick <= now)
+ {
+ Debug("ts->DisconnectTick <= now\n");
+ Disconnect(ts->Sock);
+ }
+ }
+ }
+ UnlockList(tcp->TcpSockList);
+ }
+ }
+
+ if (s->HalfConnection && (s->ServerMode == false))
+ {
+ // Check the direction of the current TCP connections.
+ // Disconnect one if the number of connections reaches
+ // the limit and has only one direction
+ LockList(tcp->TcpSockList);
+ {
+ UINT i, num;
+ UINT c2s, s2c;
+ c2s = s2c = 0;
+ num = LIST_NUM(tcp->TcpSockList);
+ if (num >= s->MaxConnection)
+ {
+ TCPSOCK *ts;
+ for (i = 0;i < num;i++)
+ {
+ ts = LIST_DATA(tcp->TcpSockList, i);
+ if (ts->Direction == TCP_SERVER_TO_CLIENT)
+ {
+ s2c++;
+ }
+ else
+ {
+ c2s++;
+ }
+ }
+ if (s2c == 0 || c2s == 0)
+ {
+ // Disconnect the last socket
+ Disconnect(ts->Sock);
+ Debug("Disconnect (s2c=%u, c2s=%u)\n", s2c, c2s);
+ }
+ }
+ }
+ UnlockList(tcp->TcpSockList);
+ }
+
+ // Initializing the socket set
+ InitSockSet(&set);
+ LockList(tcp->TcpSockList);
+ {
+ num = LIST_NUM(tcp->TcpSockList);
+ tcpsocks = ToArrayEx(tcp->TcpSockList, true);
+ }
+ UnlockList(tcp->TcpSockList);
+
+ for (i = 0;i < num;i++)
+ {
+ AddSockSet(&set, tcpsocks[i]->Sock);
+ }
+
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL)
+ {
+ if (s->UdpAccel->UdpSock != NULL)
+ {
+ AddSockSet(&set, s->UdpAccel->UdpSock);
+ }
+ }
+
+ // Select
+ time = SELECT_TIME;
+ if (s->VirtualHost)
+ {
+ time = MIN(time, SELECT_TIME_FOR_NAT);
+ }
+ next_delay_packet_diff = GetNextDelayedPacketTickDiff(s);
+ time = MIN(time, next_delay_packet_diff);
+ num_delayed = LIST_NUM(s->DelayedPacketList);
+
+ PROBE_STR("ConnectionReceive: Select 0");
+
+ if (s->Flag1 != set.NumSocket)
+ {
+ Select(&set, (num_delayed == 0 ? time : 1), c1, c2);
+ s->Flag1 = set.NumSocket;
+ }
+ else
+ {
+ if (no_spinlock_for_delay || time >= 50 || num_delayed == false)
+ {
+ Select(&set, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);
+ s->Flag1 = set.NumSocket;
+ }
+ else
+ {
+ YieldCpu();
+ }
+ }
+
+ PROBE_STR("ConnectionReceive: Select 1");
+
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL)
+ {
+ // Read the data received by the UDP If using the UDP acceleration mode
+ UdpAccelSetTick(s->UdpAccel, now);
+ UdpAccelPoll(s->UdpAccel);
+
+ if (s->UdpAccelMss == 0)
+ {
+ s->UdpAccelMss = UdpAccelCalcMss(s->UdpAccel);
+ }
+
+ while (true)
+ {
+ BLOCK *b = GetNext(s->UdpAccel->RecvBlockQueue);
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ if (b->Size > MAX_PACKET_SIZE)
+ {
+ // Packet size exceeded
+ FreeBlock(b);
+ }
+ else
+ {
+ // Add the data block to queue
+ InsertReveicedBlockToQueue(c, b);
+ }
+ }
+ }
+
+ {
+ bool new_status = UdpAccelIsSendReady(s->UdpAccel, true);
+
+ if (s->IsUsingUdpAcceleration != new_status)
+ {
+ Debug("UDP Status Changed: %u\n", new_status);
+ }
+
+ s->IsUsingUdpAcceleration = new_status;
+ }
+
+ // Read all the data that has arrived to the TCP socket
+ for (i = 0;i < num;i++)
+ {
+ TCPSOCK *ts = tcpsocks[i];
+ SOCK *sock = ts->Sock;
+
+ if (s->IsRUDPSession)
+ {
+ TUBE *t = sock->BulkRecvTube;
+
+ if (s->EnableBulkOnRUDP)
+ {
+ // R-UDP bulk transfer data reception
+ if (t != NULL && IsTubeConnected(t))
+ {
+ while (true)
+ {
+ TUBEDATA *d = TubeRecvAsync(t);
+ BLOCK *block;
+ if (d == NULL)
+ {
+ // All reception complete
+ break;
+ }
+
+ if (d->DataSize > sizeof(UINT64) && READ_UINT64(d->Data) == CONNECTION_BULK_COMPRESS_SIGNATURE)
+ {
+ // Compression
+ block = NewBlock(Clone(((UCHAR *)d->Data) + sizeof(UINT64),
+ d->DataSize - sizeof(UINT64)),
+ d->DataSize - sizeof(UINT64),
+ -1);
+ }
+ else
+ {
+ // Uncompressed
+ block = NewBlock(Clone(d->Data, d->DataSize), d->DataSize, 0);
+ }
+
+ if (block->Size > MAX_PACKET_SIZE)
+ {
+ // Packet size exceeded
+ FreeBlock(block);
+ }
+ else
+ {
+ // Add the data block to queue
+ InsertReveicedBlockToQueue(c, block);
+ }
+
+ FreeTubeData(d);
+
+ ts->LastCommTime = now;
+ ts->LastRecvTime = now;
+ c->Session->LastCommTime = now;
+ }
+ }
+ }
+ }
+
+ if (c->IsInProc)
+ {
+ TUBEDATA *d;
+ // Socket for in-process connection
+ if (IsTubeConnected(sock->RecvTube) == false)
+ {
+ // Communication is disconnected
+ goto DISCONNECT_THIS_TCP;
+ }
+
+ while (true)
+ {
+ BLOCK *block;
+ // Get the packet data from the tube
+ d = TubeRecvAsync(sock->RecvTube);
+ if (d == NULL)
+ {
+ // All acquisition completed
+ break;
+ }
+
+ block = NewBlock(Clone(d->Data, d->DataSize), d->DataSize, 0);
+
+ if (block->Size > MAX_PACKET_SIZE)
+ {
+ // Packet size exceeded
+ FreeBlock(block);
+ }
+ else
+ {
+ // Add the data block to queue
+ InsertReveicedBlockToQueue(c, block);
+ }
+
+ FreeTubeData(d);
+ }
+
+ c->Session->LastCommTime = now;
+ }
+ else
+ {
+ // A normal socket (Not in-process)
+ if (ts->WantSize == 0)
+ {
+ // Read for sizeof(UINT) first
+ ts->WantSize = sizeof(UINT);
+ }
+
+RECV_START:
+ // Receive
+ size = TcpSockRecv(s, ts, buf, RECV_BUF_SIZE);
+/*
+ // Experiment
+ if (c->ServerMode)
+ {
+ if ((ts->EstablishedTick + (UINT64)3000) <= now)
+ {
+ size = 0;
+ WHERE;
+ }
+ }*/
+
+ if (size == 0)
+ {
+DISCONNECT_THIS_TCP:
+ s->LastTryAddConnectTime = Tick64();
+ s->NumDisconnected++;
+ // Communication is disconnected
+ LockList(tcp->TcpSockList);
+ {
+ // Remove the socket from socket list
+ Delete(tcp->TcpSockList, ts);
+ // Release of TCPSOCK
+ FreeTcpSock(ts);
+ // Decrement
+ Dec(c->CurrentNumConnection);
+ Debug("--- TCP Connection Decremented: %u (%s Line %u)\n", Count(c->CurrentNumConnection), __FILE__, __LINE__);
+ Debug("LIST_NUM(tcp->TcpSockList): %u\n", LIST_NUM(tcp->TcpSockList));
+ }
+ UnlockList(tcp->TcpSockList);
+
+ continue;
+ }
+ else if (size == SOCK_LATER)
+ {
+ // State of waiting reception : don't do anything
+ if (IS_RECV_TCP_SOCK(ts))
+ {
+ if ((now > ts->LastCommTime) && ((now - ts->LastCommTime) >= ((UINT64)s->Timeout)))
+ {
+ // The connection has timed out
+ Debug("Connection %u Timeouted.\n", i);
+ goto DISCONNECT_THIS_TCP;
+ }
+ }
+ }
+ else
+ {
+ // Update the last communication time
+ ts->LastCommTime = now;
+ c->Session->LastCommTime = now;
+ ts->LastRecvTime = now;
+
+ // Write the received data into the FIFO
+ PROBE_DATA2("WriteRecvFifo", buf, size);
+ WriteRecvFifo(s, ts, buf, size);
+
+ // Stop receiving when the receive buffer is full
+ if (ts->RecvFifo->size < MAX_SEND_SOCKET_QUEUE_SIZE)
+ {
+ goto RECV_START;
+ }
+ }
+
+ // process the data written to FIFO
+ while (ts->RecvFifo->size >= ts->WantSize)
+ {
+ UCHAR *buf;
+ void *data;
+ BLOCK *block;
+ UINT sz;
+ // A sufficient amount of data is already stored
+ // Get the pointer of the data
+ buf = (UCHAR *)ts->RecvFifo->p + ts->RecvFifo->pos;
+
+ switch (ts->Mode)
+ {
+ case 0:
+ // The number of Data blocks
+ ts->WantSize = sizeof(UINT);
+ Copy(&sz, buf, sizeof(UINT));
+ PROBE_DATA2("ReadFifo 0", buf, sizeof(UINT));
+ sz = Endian32(sz);
+ ts->NextBlockNum = sz;
+ ReadFifo(ts->RecvFifo, NULL, sizeof(UINT));
+
+ s->TotalRecvSize += sizeof(UINT);
+ s->TotalRecvSizeReal += sizeof(UINT);
+
+ ts->CurrentPacketNum = 0;
+ if (ts->NextBlockNum != 0)
+ {
+ if (ts->NextBlockNum == KEEP_ALIVE_MAGIC)
+ {
+ ts->Mode = 3;
+ }
+ else
+ {
+ ts->Mode = 1;
+ }
+ }
+ break;
+
+ case 1:
+ // Data block size
+ Copy(&sz, buf, sizeof(UINT));
+ sz = Endian32(sz);
+ PROBE_DATA2("ReadFifo 1", buf, sizeof(UINT));
+ if (sz > (MAX_PACKET_SIZE * 2))
+ {
+ // received a strange data size
+ // TCP/IP Error?
+ Debug("%s %u sz > (MAX_PACKET_SIZE * 2)\n", __FILE__, __LINE__);
+ Disconnect(ts->Sock);
+ }
+ ts->NextBlockSize = MIN(sz, MAX_PACKET_SIZE * 2);
+ ReadFifo(ts->RecvFifo, NULL, sizeof(UINT));
+
+ s->TotalRecvSize += sizeof(UINT);
+ s->TotalRecvSizeReal += sizeof(UINT);
+
+ ts->WantSize = ts->NextBlockSize;
+ if (ts->WantSize != 0)
+ {
+ ts->Mode = 2;
+ }
+ else
+ {
+ ts->Mode = 1;
+ ts->WantSize = sizeof(UINT);
+ ts->CurrentPacketNum++;
+ if (ts->CurrentPacketNum >= ts->NextBlockNum)
+ {
+ ts->Mode = 0;
+ }
+ }
+ break;
+
+ case 2:
+ // Data block body
+ ts->WantSize = sizeof(UINT);
+ ts->CurrentPacketNum++;
+ data = MallocFast(ts->NextBlockSize);
+ Copy(data, buf, ts->NextBlockSize);
+ PROBE_DATA2("ReadFifo 2", buf, ts->NextBlockSize);
+ ReadFifo(ts->RecvFifo, NULL, ts->NextBlockSize);
+ block = NewBlock(data, ts->NextBlockSize, s->UseCompress ? -1 : 0);
+
+ if (block->Size > MAX_PACKET_SIZE)
+ {
+ // Packet size exceeded
+ FreeBlock(block);
+ }
+ else
+ {
+ // Add the data block to queue
+ InsertReveicedBlockToQueue(c, block);
+ }
+
+ if (ts->CurrentPacketNum >= ts->NextBlockNum)
+ {
+ // Reception of all the data blocks completed
+ ts->Mode = 0;
+ }
+ else
+ {
+ // Receive next data block size
+ ts->Mode = 1;
+ }
+ break;
+
+ case 3:
+ // Keep-Alive packet size
+ ts->Mode = 4;
+ Copy(&sz, buf, sizeof(UINT));
+ PROBE_DATA2("ReadFifo 3", buf, sizeof(UINT));
+ sz = Endian32(sz);
+ if (sz > MAX_KEEPALIVE_SIZE)
+ {
+ // received a strange data size
+ // TCP/IP Error?
+ Debug("%s %u sz > MAX_KEEPALIVE_SIZE\n", __FILE__, __LINE__);
+ Disconnect(ts->Sock);
+ }
+ ts->NextBlockSize = MIN(sz, MAX_KEEPALIVE_SIZE);
+ ReadFifo(ts->RecvFifo, NULL, sizeof(UINT));
+
+ s->TotalRecvSize += sizeof(UINT);
+ s->TotalRecvSizeReal += sizeof(UINT);
+
+ ts->WantSize = sz;
+ break;
+
+ case 4:
+ // Keep-Alive packet body
+ //Debug("KeepAlive Recved.\n");
+ ts->Mode = 0;
+ sz = ts->NextBlockSize;
+
+ if (sz >= (StrLen(UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE) + sizeof(USHORT)))
+ {
+ UCHAR *keep_alive_buffer = FifoPtr(ts->RecvFifo);
+
+ if (Cmp(keep_alive_buffer, UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE, StrLen(UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE)) == 0)
+ {
+ USHORT us = READ_USHORT(keep_alive_buffer + StrLen(UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE));
+
+ if (us != 0)
+ {
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL)
+ {
+ UINT port = (UINT)us;
+
+ if (s->UdpAccel->YourPortByNatTServer != port)
+ {
+ s->UdpAccel->YourPortByNatTServer = port;
+ s->UdpAccel->YourPortByNatTServerChanged = true;
+
+ Debug("s->UdpAccel->YourPortByNatTServer: %u\n",
+ s->UdpAccel->YourPortByNatTServer);
+ }
+ }
+ }
+ }
+ }
+
+ PROBE_DATA2("ReadFifo 4", NULL, 0);
+ ReadFifo(ts->RecvFifo, NULL, sz);
+
+ s->TotalRecvSize += sz;
+ s->TotalRecvSizeReal += sz;
+
+ ts->WantSize = sizeof(UINT);
+ break;
+ }
+ }
+ }
+ }
+
+ Free(tcpsocks);
+ }
+ else if (c->Protocol == CONNECTION_UDP)
+ {
+ // UDP
+ UDP *udp = c->Udp;
+ SOCK *sock = NULL;
+
+ if (s->ServerMode == false)
+ {
+ Lock(c->lock);
+ {
+ if (c->Udp->s != NULL)
+ {
+ sock = c->Udp->s;
+ if (sock != NULL)
+ {
+ AddRef(sock->ref);
+ }
+ }
+ }
+ Unlock(c->lock);
+
+ InitSockSet(&set);
+
+ if (sock != NULL)
+ {
+ AddSockSet(&set, sock);
+ }
+
+ Select(&set, SELECT_TIME, c1, c2);
+
+ if (sock != NULL)
+ {
+ IP ip;
+ UINT port;
+ UCHAR *buf;
+ UINT size;
+
+ while (true)
+ {
+ buf = c->RecvBuf;
+ size = RecvFrom(sock, &ip, &port, buf, RECV_BUF_SIZE);
+ if (size == 0 && sock->IgnoreRecvErr == false)
+ {
+ Debug("UDP Socket Disconnected.\n");
+ Lock(c->lock);
+ {
+ ReleaseSock(udp->s);
+ udp->s = NULL;
+ }
+ Unlock(c->lock);
+ break;
+ }
+ else if (size == SOCK_LATER)
+ {
+ break;
+ }
+ else
+ {
+ if (size)
+ {
+ PutUDPPacketData(c, buf, size);
+ }
+ }
+ }
+ }
+
+ if (sock != NULL)
+ {
+ Release(sock->ref);
+ }
+ }
+ else
+ {
+ Select(NULL, SELECT_TIME, c1, c2);
+ }
+ }
+ else if (c->Protocol == CONNECTION_HUB_SECURE_NAT)
+ {
+ SNAT *snat = c->Session->SecureNAT;
+ VH *v = snat->Nat->Virtual;
+ UINT size;
+ void *data;
+ UINT num;
+ UINT select_wait_time = SELECT_TIME_FOR_NAT;
+ UINT next_delay_packet_diff = 0;
+
+ if (snat->Nat != NULL && snat->Nat->Option.UseNat == false)
+ {
+ select_wait_time = SELECT_TIME;
+ }
+ else
+ {
+ if (snat->Nat != NULL)
+ {
+ LockList(v->NatTable);
+ {
+ if (LIST_NUM(v->NatTable) == 0 && LIST_NUM(v->ArpWaitTable) == 0)
+ {
+ select_wait_time = SELECT_TIME;
+ }
+ }
+ UnlockList(v->NatTable);
+ }
+ }
+
+ next_delay_packet_diff = GetNextDelayedPacketTickDiff(s);
+ select_wait_time = MIN(select_wait_time, next_delay_packet_diff);
+ num_delayed = LIST_NUM(s->DelayedPacketList);
+
+ if (no_spinlock_for_delay || select_wait_time >= 50 || num_delayed == false)
+ {
+ Select(NULL, (num_delayed == 0 ? select_wait_time :
+ (select_wait_time > 100 ? (select_wait_time - 100) : 1)), c1, c2);
+ }
+ else
+ {
+ YieldCpu();
+ }
+
+ num = 0;
+
+ if (hub != NULL)
+ {
+ NatSetHubOption(v, hub->Option);
+ }
+
+ // Receive a packet from the virtual machine
+ while (size = VirtualGetNextPacket(v, &data))
+ {
+ BLOCK *block;
+
+ // Generate packet block
+ block = NewBlock(data, size, 0);
+ if (block->Size > MAX_PACKET_SIZE)
+ {
+ // Packet size exceeded
+ FreeBlock(block);
+ }
+ else
+ {
+ // Add the data block to queue
+ InsertReveicedBlockToQueue(c, block);
+ }
+ num++;
+ if (num >= MAX_SEND_SOCKET_QUEUE_NUM)
+ {
+// WHERE;
+ break;
+ }
+ }
+ }
+ else if (c->Protocol == CONNECTION_HUB_LINK_SERVER)
+ {
+ // HUB Link
+ // Waiting Cancel simply
+ if (c->SendBlocks->num_item == 0)
+ {
+ UINT time = SELECT_TIME;
+ UINT next_delay_packet_diff = 0;
+
+ next_delay_packet_diff = GetNextDelayedPacketTickDiff(s);
+ time = MIN(time, next_delay_packet_diff);
+ num_delayed = LIST_NUM(s->DelayedPacketList);
+
+ if (no_spinlock_for_delay || time >= 50 || num_delayed == false)
+ {
+ Select(NULL, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);
+ }
+ else
+ {
+ YieldCpu();
+ }
+ }
+ }
+ else if (c->Protocol == CONNECTION_HUB_LAYER3)
+ {
+ // Layer-3 switch session
+ L3IF *f = s->L3If;
+ UINT size, num = 0;
+ void *data;
+
+ if (f->SendQueue->num_item == 0)
+ {
+ UINT time = SELECT_TIME_FOR_NAT;
+ UINT next_delay_packet_diff = 0;
+
+ if (f->ArpWaitTable != NULL)
+ {
+ LockList(f->ArpWaitTable);
+ {
+ if (LIST_NUM(f->ArpWaitTable) == 0)
+ {
+ time = SELECT_TIME;
+ }
+ }
+ UnlockList(f->ArpWaitTable);
+ }
+
+ next_delay_packet_diff = GetNextDelayedPacketTickDiff(s);
+ time = MIN(time, next_delay_packet_diff);
+ num_delayed = LIST_NUM(s->DelayedPacketList);
+
+ if (no_spinlock_for_delay || time >= 50 || num_delayed == false)
+ {
+ Select(NULL, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);
+ }
+ else
+ {
+ YieldCpu();
+ }
+ }
+
+ // Get the next packet
+ while (size = L3GetNextPacket(f, &data))
+ {
+ BLOCK *block = NewBlock(data, size, 0);
+ if (block->Size > MAX_PACKET_SIZE)
+ {
+ FreeBlock(block);
+ }
+ else
+ {
+ InsertReveicedBlockToQueue(c, block);
+ }
+
+ num++;
+ if (num >= MAX_SEND_SOCKET_QUEUE_NUM)
+ {
+ break;
+ }
+ }
+ }
+ else if (c->Protocol == CONNECTION_HUB_BRIDGE)
+ {
+ BRIDGE *b = c->Session->Bridge;
+
+ // Bridge session
+ if (b->Active)
+ {
+ void *data;
+ UINT ret;
+ UINT num = 0;
+ bool check_device_num = false;
+ UINT time = SELECT_TIME;
+ UINT next_delay_packet_diff = 0;
+
+ next_delay_packet_diff = GetNextDelayedPacketTickDiff(s);
+ time = MIN(time, next_delay_packet_diff);
+ num_delayed = LIST_NUM(s->DelayedPacketList);
+
+ // Bridge is operating
+ if (no_spinlock_for_delay || time >= 50 || num_delayed == false)
+ {
+ Select(NULL, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);
+ }
+ else
+ {
+ YieldCpu();
+ }
+
+ if ((b->LastNumDeviceCheck + BRIDGE_NUM_DEVICE_CHECK_SPAN) <= Tick64())
+ {
+ check_device_num = true;
+ b->LastNumDeviceCheck = Tick64();
+ }
+
+ // Get the next packet from the bridge
+ while (true)
+ {
+ if (check_device_num && b->LastNumDevice != GetEthDeviceHash())
+ {
+ ret = INFINITE;
+ }
+ else
+ {
+ ret = EthGetPacket(b->Eth, &data);
+ }
+
+#ifdef OS_WIN32
+ if (c->Session != NULL)
+ {
+ c->Session->BridgeIsEthLoopbackBlock = false;
+ if (b->Eth != NULL && b->Eth->LoopbackBlock)
+ {
+ // Check whether The Ethernet device in the bridge
+ // has the ability to block the loopback packet
+ c->Session->BridgeIsEthLoopbackBlock = true;
+ }
+ }
+#endif // OS_WIN32
+
+ if (ret == INFINITE)
+ {
+ // Error occured: stop the bridge
+ CloseEth(b->Eth);
+ b->Eth = NULL;
+ b->Active = false;
+ ReleaseCancel(s->Cancel2);
+ s->Cancel2 = NULL;
+
+ HLog(s->Hub, "LH_BRIDGE_2", s->Name, b->Name);
+ Debug("Bridge Device Error.\n");
+
+ break;
+ }
+ else if (ret == 0)
+ {
+ // There is no more packet to receive
+ break;
+ }
+ else
+ {
+ if (hub != NULL && hub->Option != NULL && hub->Option->DisableUdpFilterForLocalBridgeNic == false &&
+ b->Eth != NULL && IsDhcpPacketForSpecificMac(data, ret, b->Eth->MacAddress))
+ {
+ // DHCP Packet is filtered.
+ Free(data);
+ }
+ else
+ {
+ // Add the packet to queue
+ BLOCK *block = NewBlock(data, ret, 0);
+
+ PROBE_DATA2("ConnectionReceive: NewBlock", data, ret);
+
+ if (ret > 1514)
+ {
+ NormalizeEthMtu(b, c, ret);
+ }
+
+ if (block->Size > MAX_PACKET_SIZE)
+ {
+ // Packet size exceeded
+ FreeBlock(block);
+ }
+ else
+ {
+ InsertReveicedBlockToQueue(c, block);
+ }
+ num++;
+ if (num >= MAX_SEND_SOCKET_QUEUE_NUM)
+ {
+ // WHERE;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ ETH *e;
+ // Bridge is stopped cureently
+ Select(NULL, SELECT_TIME, c1, NULL);
+
+ if (b->LastBridgeTry == 0 || (b->LastBridgeTry + BRIDGE_TRY_SPAN) <= Tick64())
+ {
+ b->LastBridgeTry = Tick64();
+
+ // Try to open an Ethernet device
+ e = OpenEth(b->Name, b->Local, b->TapMode, b->TapMacAddress);
+ if (e != NULL)
+ {
+ // Success
+ b->Eth = e;
+ b->Active = true;
+ b->LastNumDeviceCheck = Tick64();
+ b->LastNumDevice = GetEthDeviceHash();
+
+ // Update the NIC name of the bridge
+#ifdef OS_WIN32
+ if (IsEmptyStr(e->Title) == false)
+ {
+ StrCpy(b->Name, sizeof(b->Name), e->Title);
+
+ if (b->ParentLocalBridge != NULL)
+ {
+ StrCpy(b->ParentLocalBridge->DeviceName, sizeof(b->ParentLocalBridge->DeviceName), e->Title);
+ }
+ }
+#endif // OS_WIN32
+
+ Debug("Bridge Open Succeed.\n");
+
+ HLog(c->Session->Hub, "LH_BRIDGE_1", c->Session->Name, b->Name);
+
+ s->Cancel2 = EthGetCancel(b->Eth);
+ }
+ }
+ }
+ }
+}
+
+// Normalize the MTU of the Ethernet device
+void NormalizeEthMtu(BRIDGE *b, CONNECTION *c, UINT packet_size)
+{
+ // Validate arguments
+ if (packet_size == 0 || b == NULL || c == NULL)
+ {
+ return;
+ }
+
+ // Raise the MTU when the packet exceeds the current MTU
+ if (EthIsChangeMtuSupported(b->Eth))
+ {
+ UINT currentMtu = EthGetMtu(b->Eth);
+ if (currentMtu != 0)
+ {
+ if (packet_size > currentMtu)
+ {
+ bool ok = EthSetMtu(b->Eth, packet_size);
+
+ if (ok)
+ {
+ HLog(c->Session->Hub, "LH_SET_MTU", c->Session->Name,
+ b->Name, currentMtu, packet_size, packet_size);
+ }
+ else
+ {
+ UINT64 now = Tick64();
+
+ if (b->LastChangeMtuError == 0 ||
+ now >= (b->LastChangeMtuError + 60000ULL))
+ {
+ HLog(c->Session->Hub, "LH_SET_MTU_ERROR", c->Session->Name,
+ b->Name, currentMtu, packet_size, packet_size);
+
+ b->LastChangeMtuError = now;
+ }
+ }
+ }
+ }
+ }
+}
+
+// Release of the block
+void FreeBlock(BLOCK *b)
+{
+ // Validate arguments
+ if (b == NULL)
+ {
+ return;
+ }
+
+ Free(b->Buf);
+ Free(b);
+}
+
+// Create a new block
+BLOCK *NewBlock(void *data, UINT size, int compress)
+{
+ BLOCK *b;
+ // Validate arguments
+ if (data == NULL)
+ {
+ return NULL;
+ }
+
+ b = MallocFast(sizeof(BLOCK));
+
+ b->PriorityQoS = b->Ttl = b->Param1 = 0;
+
+ if (compress == 0)
+ {
+ // Uncompressed
+ b->Compressed = FALSE;
+ b->Buf = data;
+ b->Size = size;
+ b->SizeofData = size;
+ }
+ else if (compress == 1)
+ {
+ UINT max_size;
+
+ // Compressed
+ b->Compressed = TRUE;
+ max_size = CalcCompress(size);
+ b->Buf = MallocFast(max_size);
+ b->Size = Compress(b->Buf, max_size, data, size);
+ b->SizeofData = size;
+
+ // Discard old data block
+ Free(data);
+ }
+ else
+ {
+ // Expand
+ UINT max_size;
+
+ b->Compressed = FALSE;
+ max_size = MAX_PACKET_SIZE;
+ b->Buf = MallocFast(max_size);
+ b->Size = Uncompress(b->Buf, max_size, data, size);
+ b->SizeofData = size;
+
+ // Discard old data
+ Free(data);
+ }
+
+ return b;
+}
+
+// Create a TCP socket
+TCPSOCK *NewTcpSock(SOCK *s)
+{
+ TCPSOCK *ts;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ ts = ZeroMalloc(sizeof(TCPSOCK));
+
+ ts->Sock = s;
+ AddRef(s->ref);
+
+ ts->RecvFifo = NewFifo();
+ ts->SendFifo = NewFifo();
+ ts->EstablishedTick = ts->LastRecvTime = ts->LastCommTime = Tick64();
+
+ // Unset the time-out value
+ SetTimeout(s, TIMEOUT_INFINITE);
+
+ return ts;
+}
+
+// Set a encryption key for the TCP socket
+void InitTcpSockRc4Key(TCPSOCK *ts, bool server_mode)
+{
+ RC4_KEY_PAIR *pair;
+ CRYPT *c1, *c2;
+ // Validate arguments
+ if (ts == NULL)
+ {
+ return;
+ }
+
+ pair = &ts->Rc4KeyPair;
+
+ c1 = NewCrypt(pair->ClientToServerKey, sizeof(pair->ClientToServerKey));
+ c2 = NewCrypt(pair->ServerToClientKey, sizeof(pair->ServerToClientKey));
+
+ if (server_mode)
+ {
+ ts->RecvKey = c1;
+ ts->SendKey = c2;
+ }
+ else
+ {
+ ts->SendKey = c1;
+ ts->RecvKey = c2;
+ }
+}
+
+// Release of TCP socket
+void FreeTcpSock(TCPSOCK *ts)
+{
+ // Validate arguments
+ if (ts == NULL)
+ {
+ return;
+ }
+
+ Disconnect(ts->Sock);
+ ReleaseSock(ts->Sock);
+ ReleaseFifo(ts->RecvFifo);
+ ReleaseFifo(ts->SendFifo);
+
+ if (ts->SendKey)
+ {
+ FreeCrypt(ts->SendKey);
+ }
+ if (ts->RecvKey)
+ {
+ FreeCrypt(ts->RecvKey);
+ }
+
+ Free(ts);
+}
+
+// Exit the tunneling mode of connection
+void EndTunnelingMode(CONNECTION *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Protocol
+ if (c->Protocol == CONNECTION_TCP)
+ {
+ // TCP
+ DisconnectTcpSockets(c);
+ }
+ else
+ {
+ // UDP
+ DisconnectUDPSockets(c);
+ }
+}
+
+// Shift the connection to tunneling mode
+void StartTunnelingMode(CONNECTION *c)
+{
+ SOCK *s;
+ TCP *tcp;
+ TCPSOCK *ts;
+ IP ip;
+ UINT port;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ tcp = c->Tcp;
+
+ // Protocol
+ if (c->Protocol == CONNECTION_TCP)
+ {
+ // TCP
+ s = c->FirstSock;
+
+ if (c->IsInProc)
+ {
+ AddRef(s->ref);
+ c->TubeSock = s;
+ }
+
+ ts = NewTcpSock(s);
+
+ if (c->ServerMode == false)
+ {
+ if (c->Session->ClientOption->ConnectionDisconnectSpan != 0)
+ {
+ ts->DisconnectTick = Tick64() + c->Session->ClientOption->ConnectionDisconnectSpan * (UINT64)1000;
+ }
+ }
+
+ LockList(tcp->TcpSockList);
+ {
+ Add(tcp->TcpSockList, ts);
+ }
+ UnlockList(tcp->TcpSockList);
+ ReleaseSock(s);
+ c->FirstSock = NULL;
+ }
+ else
+ {
+ // UDP
+ s = c->FirstSock;
+ Copy(&ip, &s->RemoteIP, sizeof(IP));
+ // May disconnect TCP connection at this point
+ c->FirstSock = NULL;
+ Disconnect(s);
+ ReleaseSock(s);
+
+ // Initialization of UDP structure
+ c->Udp = ZeroMalloc(sizeof(UDP));
+
+ if (c->ServerMode)
+ {
+ // Server mode
+ // Add an UDP Entry
+ AddUDPEntry(c->Cedar, c->Session);
+ c->Udp->s = NULL;
+ }
+ else
+ {
+ port = c->Session->ClientOption->PortUDP;
+ // Client mode
+ c->Udp->s = NewUDP(0);
+ // Write the IP address and port number
+ Copy(&c->Udp->ip, &ip, sizeof(IP));
+ c->Udp->port = port;
+ }
+
+ // Queue
+ c->Udp->BufferQueue = NewQueue();
+ }
+}
+
+// Generate a random value that depends on each machine
+UINT GetMachineRand()
+{
+ char pcname[MAX_SIZE];
+ UCHAR hash[SHA1_SIZE];
+
+ Zero(pcname, sizeof(pcname));
+ GetMachineName(pcname, sizeof(pcname));
+
+ HashSha1(hash, pcname, StrLen(pcname));
+
+ return READ_UINT(hash);
+}
+
+// Function that accepts a new connection
+void ConnectionAccept(CONNECTION *c)
+{
+ SOCK *s;
+ X *x;
+ K *k;
+ char tmp[128];
+ UCHAR openssl_check_buf[2];
+ char *error_details = NULL;
+ SERVER *server;
+ UCHAR *peek_buf = NULL;
+ UINT peek_buf_size = 1500;
+ char sni[128] = {0};
+ bool native1 = false; // Non-SNI flag
+ bool native2 = false; // Non-TLS flag
+ bool native3 = false; // SSLv2 flag
+ bool no_native = false;
+ UINT peek_size = 0;
+ UINT initial_timeout = CONNECTING_TIMEOUT;
+ bool no_peek_log = false;
+ UCHAR ctoken_hash[SHA1_SIZE];
+ bool no_write_ctoken_log = false;
+
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ Zero(ctoken_hash, sizeof(ctoken_hash));
+
+ peek_buf = ZeroMalloc(peek_buf_size);
+
+ Debug("ConnectionAccept()\n");
+
+ server = c->Cedar->Server;
+
+ // get a socket
+ s = c->FirstSock;
+ AddRef(s->ref);
+
+ Dec(c->Cedar->AcceptingSockets);
+
+ IPToStr(tmp, sizeof(tmp), &s->RemoteIP);
+
+ SLog(c->Cedar, "LS_CONNECTION_START_1", tmp, s->RemoteHostname, (IS_SPECIAL_PORT(s->RemotePort) ? 0 : s->RemotePort), c->Name);
+
+ // Timeout setting
+ initial_timeout += GetMachineRand() % (CONNECTING_TIMEOUT / 2);
+ SetTimeout(s, initial_timeout);
+
+
+ // Peek whether OpenSSL packet
+ if (s->IsReverseAcceptedSocket == false)
+ {
+ if (s->Type == SOCK_TCP && (c->Cedar != NULL && c->Cedar->Server != NULL && c->Cedar->Server->DisableOpenVPNServer == false))
+ {
+ if (Peek(s, openssl_check_buf, sizeof(openssl_check_buf)) == sizeof(openssl_check_buf))
+ {
+ if (OvsCheckTcpRecvBufIfOpenVPNProtocol(openssl_check_buf, sizeof(openssl_check_buf)))
+ {
+ // Detect OpenSSL packet
+ Debug("Detect OpenSSL on TCP!\n");
+
+ no_native = true;
+
+ if (OvsGetNoOpenVpnTcp() == false)
+ {
+ // Do OpenSSL processing
+ c->Type = CONNECTION_TYPE_OPENVPN;
+ if (OvsPerformTcpServer(c->Cedar, s) == false)
+ {
+ error_details = "OpenVPN_TCP_Aborted";
+ }
+ }
+
+ goto ERROR;
+ }
+ }
+ }
+
+
+ }
+
+ // Specify the encryption algorithm
+ Lock(c->Cedar->lock);
+ {
+ if (c->Cedar->CipherList != NULL)
+ {
+ SetWantToUseCipher(s, c->Cedar->CipherList);
+ }
+
+ x = CloneX(c->Cedar->ServerX);
+ k = CloneK(c->Cedar->ServerK);
+ }
+ Unlock(c->Cedar->lock);
+
+ // Start the SSL communication
+ Debug("StartSSL()\n");
+ if (StartSSL(s, x, k) == false)
+ {
+ // Failed
+ AddNoSsl(c->Cedar, &s->RemoteIP);
+ Debug("Failed to StartSSL.\n");
+ FreeX(x);
+ FreeK(k);
+
+ error_details = "StartSSL";
+
+ goto ERROR;
+ }
+
+ FreeX(x);
+ FreeK(k);
+
+ SLog(c->Cedar, "LS_SSL_START", c->Name, s->CipherName);
+
+ Copy(c->CToken_Hash, ctoken_hash, SHA1_SIZE);
+
+ // Accept the connection
+ if (ServerAccept(c) == false)
+ {
+ // Failed
+ Debug("ServerAccept Failed. Err = %u\n", c->Err);
+ goto ERROR;
+ }
+
+ if (c->flag1 == false)
+ {
+ Debug("%s %u c->flag1 == false\n", __FILE__, __LINE__);
+ Disconnect(s);
+ }
+ DelConnection(c->Cedar, c);
+ ReleaseSock(s);
+
+ Free(peek_buf);
+ return;
+
+ERROR:
+ Debug("ConnectionAccept() Error.\n");
+
+
+ Disconnect(s);
+ DelConnection(c->Cedar, c);
+ ReleaseSock(s);
+ Free(peek_buf);
+}
+
+// Stop the threads putting additional connection of all that are currently running
+void StopAllAdditionalConnectThread(CONNECTION *c)
+{
+ UINT i, num;
+ SOCK **socks;
+ THREAD **threads;
+ // Validate arguments
+ if (c == NULL || c->ServerMode != false)
+ {
+ return;
+ }
+
+ // Disconnect the socket first
+ LockList(c->ConnectingSocks);
+ {
+ num = LIST_NUM(c->ConnectingSocks);
+ socks = ToArray(c->ConnectingSocks);
+ DeleteAll(c->ConnectingSocks);
+ }
+ UnlockList(c->ConnectingSocks);
+ for (i = 0;i < num;i++)
+ {
+ Disconnect(socks[i]);
+ ReleaseSock(socks[i]);
+ }
+ Free(socks);
+
+ // Then, wait for the suspension of the thread
+ LockList(c->ConnectingThreads);
+ {
+ num = LIST_NUM(c->ConnectingThreads);
+ Debug("c->ConnectingThreads: %u\n", num);
+ threads = ToArray(c->ConnectingThreads);
+ DeleteAll(c->ConnectingThreads);
+ }
+ UnlockList(c->ConnectingThreads);
+ for (i = 0;i < num;i++)
+ {
+ WaitThread(threads[i], INFINITE);
+ ReleaseThread(threads[i]);
+ }
+ Free(threads);
+}
+
+// Stop the connection
+void StopConnection(CONNECTION *c, bool no_wait)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ Debug("Stop Connection: %s\n", c->Name);
+
+ // Stop flag
+ c->Halt = true;
+ Disconnect(c->FirstSock);
+
+ if (no_wait == false)
+ {
+ // Wait until the thread terminates
+ WaitThread(c->Thread, INFINITE);
+ }
+}
+
+// Close all the UDP socket
+void DisconnectUDPSockets(CONNECTION *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+ if (c->Protocol != CONNECTION_UDP)
+ {
+ return;
+ }
+
+ // Delete entry
+ if (c->ServerMode)
+ {
+ DelUDPEntry(c->Cedar, c->Session);
+ }
+
+ // Delete the UDP structure
+ if (c->Udp != NULL)
+ {
+ if (c->Udp->s != NULL)
+ {
+ ReleaseSock(c->Udp->s);
+ }
+ if (c->Udp->BufferQueue != NULL)
+ {
+ // Release of the queue
+ BUF *b;
+ while (b = GetNext(c->Udp->BufferQueue))
+ {
+ FreeBuf(b);
+ }
+ ReleaseQueue(c->Udp->BufferQueue);
+ }
+ Free(c->Udp);
+ c->Udp = NULL;
+ }
+
+ if (c->FirstSock != NULL)
+ {
+ Disconnect(c->FirstSock);
+ ReleaseSock(c->FirstSock);
+ c->FirstSock = NULL;
+ }
+}
+
+// Close all TCP connections
+void DisconnectTcpSockets(CONNECTION *c)
+{
+ UINT i, num;
+ TCP *tcp;
+ TCPSOCK **tcpsocks;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+ if (c->Protocol != CONNECTION_TCP)
+ {
+ return;
+ }
+
+ tcp = c->Tcp;
+ LockList(tcp->TcpSockList);
+ {
+ tcpsocks = ToArray(tcp->TcpSockList);
+ num = LIST_NUM(tcp->TcpSockList);
+ DeleteAll(tcp->TcpSockList);
+ }
+ UnlockList(tcp->TcpSockList);
+
+ if (num != 0)
+ {
+ Debug("--- SOCKET STATUS ---\n");
+ for (i = 0;i < num;i++)
+ {
+ TCPSOCK *ts = tcpsocks[i];
+ Debug(" SOCK %2u: %u\n", i, ts->Sock->SendSize);
+ FreeTcpSock(ts);
+ }
+ }
+
+ Free(tcpsocks);
+}
+
+// Clean up of the connection
+void CleanupConnection(CONNECTION *c)
+{
+ UINT i, num;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ DeleteLock(c->lock);
+ ReleaseCedar(c->Cedar);
+
+ switch (c->Protocol)
+ {
+ case CONNECTION_TCP:
+ // Release of TCP connection list
+ DisconnectTcpSockets(c);
+ break;
+
+ case CONNECTION_UDP:
+ break;
+ }
+
+ ReleaseList(c->Tcp->TcpSockList);
+ Free(c->Tcp);
+
+ ReleaseSock(c->FirstSock);
+ c->FirstSock = NULL;
+
+ ReleaseSock(c->TubeSock);
+ c->TubeSock = NULL;
+
+ ReleaseThread(c->Thread);
+ Free(c->Name);
+
+ // Release all the receive block and send block
+ if (c->SendBlocks)
+ {
+ LockQueue(c->SendBlocks);
+ {
+ BLOCK *b;
+ while (b = GetNext(c->SendBlocks))
+ {
+ FreeBlock(b);
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+ }
+ if (c->SendBlocks2)
+ {
+ LockQueue(c->SendBlocks2);
+ {
+ BLOCK *b;
+ while (b = GetNext(c->SendBlocks2))
+ {
+ FreeBlock(b);
+ }
+ }
+ UnlockQueue(c->SendBlocks2);
+ }
+ if (c->ReceivedBlocks)
+ {
+ LockQueue(c->ReceivedBlocks);
+ {
+ BLOCK *b;
+ while (b = GetNext(c->ReceivedBlocks))
+ {
+ FreeBlock(b);
+ }
+ }
+ UnlockQueue(c->ReceivedBlocks);
+ }
+
+ if (c->ConnectingThreads)
+ {
+ THREAD **threads;
+ LockList(c->ConnectingThreads);
+ {
+ num = LIST_NUM(c->ConnectingThreads);
+ threads = ToArray(c->ConnectingThreads);
+ for (i = 0;i < num;i++)
+ {
+ ReleaseThread(threads[i]);
+ }
+ Free(threads);
+ }
+ UnlockList(c->ConnectingThreads);
+ ReleaseList(c->ConnectingThreads);
+ }
+
+ if (c->ConnectingSocks)
+ {
+ SOCK **socks;
+ LockList(c->ConnectingSocks);
+ {
+ num = LIST_NUM(c->ConnectingSocks);
+ socks = ToArray(c->ConnectingSocks);
+ for (i = 0;i < num;i++)
+ {
+ Disconnect(socks[i]);
+ ReleaseSock(socks[i]);
+ }
+ Free(socks);
+ }
+ UnlockList(c->ConnectingSocks);
+ ReleaseList(c->ConnectingSocks);
+ }
+
+ if (c->RecvBuf)
+ {
+ Free(c->RecvBuf);
+ }
+
+ if (c->ServerX != NULL)
+ {
+ FreeX(c->ServerX);
+ }
+
+ if (c->ClientX != NULL)
+ {
+ FreeX(c->ClientX);
+ }
+
+ ReleaseQueue(c->ReceivedBlocks);
+ ReleaseQueue(c->SendBlocks);
+ ReleaseQueue(c->SendBlocks2);
+
+ DeleteCounter(c->CurrentNumConnection);
+
+ if (c->CipherName != NULL)
+ {
+ Free(c->CipherName);
+ }
+
+ Free(c);
+}
+
+// Release of the connection
+void ReleaseConnection(CONNECTION *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ if (Release(c->ref) == 0)
+ {
+ CleanupConnection(c);
+ }
+}
+
+// Comparison of connection
+int CompareConnection(void *p1, void *p2)
+{
+ CONNECTION *c1, *c2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ c1 = *(CONNECTION **)p1;
+ c2 = *(CONNECTION **)p2;
+ if (c1 == NULL || c2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(c1->Name, c2->Name);
+}
+
+// Creating a server connection
+CONNECTION *NewServerConnection(CEDAR *cedar, SOCK *s, THREAD *t)
+{
+ CONNECTION *c;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ c = ZeroMalloc(sizeof(CONNECTION));
+ c->ConnectedTick = Tick64();
+ c->lock = NewLock();
+ c->ref = NewRef();
+ c->Cedar = cedar;
+ AddRef(c->Cedar->ref);
+ c->Protocol = CONNECTION_TCP;
+ c->Type = CONNECTION_TYPE_INIT;
+ c->FirstSock = s;
+ if (s != NULL)
+ {
+ AddRef(c->FirstSock->ref);
+ Copy(&c->ClientIp, &s->RemoteIP, sizeof(IP));
+ StrCpy(c->ClientHostname, sizeof(c->ClientHostname), s->RemoteHostname);
+ }
+ c->Tcp = ZeroMalloc(sizeof(TCP));
+ c->Tcp->TcpSockList = NewList(NULL);
+ c->ServerMode = true;
+ c->Status = CONNECTION_STATUS_ACCEPTED;
+ c->Name = CopyStr("INITING");
+ c->Thread = t;
+ AddRef(t->ref);
+ c->CurrentNumConnection = NewCounter();
+ Inc(c->CurrentNumConnection);
+
+ c->ServerVer = cedar->Version;
+ c->ServerBuild = cedar->Build;
+ StrCpy(c->ServerStr, sizeof(c->ServerStr), cedar->ServerStr);
+ GetServerProductName(cedar->Server, c->ServerStr, sizeof(c->ServerStr));
+
+ if (s != NULL && s->RemoteX != NULL)
+ {
+ c->ServerX = CloneX(s->RemoteX);
+ }
+
+ if (s != NULL && s->Type == SOCK_INPROC)
+ {
+ // In-process socket
+ c->IsInProc = true;
+ }
+
+ // Creating a Queue
+ c->ReceivedBlocks = NewQueue();
+ c->SendBlocks = NewQueue();
+ c->SendBlocks2 = NewQueue();
+
+ return c;
+}
+
+// Creating a Client Connection
+CONNECTION *NewClientConnection(SESSION *s)
+{
+ return NewClientConnectionEx(s, NULL, 0, 0);
+}
+CONNECTION *NewClientConnectionEx(SESSION *s, char *client_str, UINT client_ver, UINT client_build)
+{
+ CONNECTION *c;
+
+ // Initialization of CONNECTION object
+ c = ZeroMalloc(sizeof(CONNECTION));
+ c->ConnectedTick = Tick64();
+ c->lock = NewLock();
+ c->ref = NewRef();
+ c->Cedar = s->Cedar;
+ AddRef(c->Cedar->ref);
+ c->Protocol = CONNECTION_TCP;
+ c->Tcp = ZeroMalloc(sizeof(TCP));
+ c->Tcp->TcpSockList = NewList(NULL);
+ c->ServerMode = false;
+ c->Status = CONNECTION_STATUS_CONNECTING;
+ c->Name = CopyStr("CLIENT_CONNECTION");
+ c->Session = s;
+ c->CurrentNumConnection = NewCounter();
+ c->LastCounterResetTick = Tick64();
+ Inc(c->CurrentNumConnection);
+
+ c->ConnectingThreads = NewList(NULL);
+ c->ConnectingSocks = NewList(NULL);
+
+ if (client_str == NULL)
+ {
+ c->ClientVer = s->Cedar->Version;
+ c->ClientBuild = s->Cedar->Build;
+
+ if (c->Session->VirtualHost == false)
+ {
+ if (c->Session->LinkModeClient == false)
+ {
+ StrCpy(c->ClientStr, sizeof(c->ClientStr), CEDAR_CLIENT_STR);
+ }
+ else
+ {
+ StrCpy(c->ClientStr, sizeof(c->ClientStr), CEDAR_SERVER_LINK_STR);
+ }
+ }
+ else
+ {
+ StrCpy(c->ClientStr, sizeof(c->ClientStr), CEDAR_ROUTER_STR);
+ }
+ }
+ else
+ {
+ c->ClientVer = client_ver;
+ c->ClientBuild = client_build;
+ StrCpy(c->ClientStr, sizeof(c->ClientStr), client_str);
+ }
+
+ // Server name and port number
+ StrCpy(c->ServerName, sizeof(c->ServerName), s->ClientOption->Hostname);
+ c->ServerPort = s->ClientOption->Port;
+
+ // TLS 1.0 using flag
+ c->DontUseTls1 = s->ClientOption->NoTls1;
+
+ // Create queues
+ c->ReceivedBlocks = NewQueue();
+ c->SendBlocks = NewQueue();
+ c->SendBlocks2 = NewQueue();
+
+ return c;
+}
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Connection.h b/src/Cedar/Connection.h
new file mode 100644
index 00000000..b83c3188
--- /dev/null
+++ b/src/Cedar/Connection.h
@@ -0,0 +1,341 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Connection.h
+// Header of Connection.c
+
+#ifndef CONNECTION_H
+#define CONNECTION_H
+
+// Magic number indicating that the packet is compressed
+#define CONNECTION_BULK_COMPRESS_SIGNATURE 0xDEADBEEFCAFEFACEULL
+
+#define KEEP_ALIVE_STRING "Internet Connection Keep Alive Packet"
+
+// KEEP CONNECT structure
+struct KEEP
+{
+ LOCK *lock; // Lock
+ bool Server; // Server mode
+ volatile bool Halt; // Stop flag
+ bool Enable; // Enable flag
+ char ServerName[MAX_HOST_NAME_LEN + 1]; // Server name
+ UINT ServerPort; // Server port number
+ bool UdpMode; // UDP mode
+ UINT Interval; // Packet transmission interval
+ THREAD *Thread; // Connection thread
+ EVENT *HaltEvent; // Stop event
+ CANCEL *Cancel; // Cancel
+};
+
+// SECURE_SIGN Structure
+struct SECURE_SIGN
+{
+ char SecurePublicCertName[MAX_SECURE_DEVICE_FILE_LEN + 1]; // Secure device certificate name
+ char SecurePrivateKeyName[MAX_SECURE_DEVICE_FILE_LEN + 1]; // Secure device secret key name
+ X *ClientCert; // Client certificate
+ UCHAR Random[SHA1_SIZE]; // Random value for signature
+ UCHAR Signature[128]; // Signed data
+ UINT UseSecureDeviceId;
+ UINT BitmapId; // Bitmap ID
+};
+
+// Function type declaration
+typedef bool (CHECK_CERT_PROC)(SESSION *s, CONNECTION *c, X *server_x, bool *expired);
+typedef bool (SECURE_SIGN_PROC)(SESSION *s, CONNECTION *c, SECURE_SIGN *sign);
+
+// RC4 key pair
+struct RC4_KEY_PAIR
+{
+ UCHAR ServerToClientKey[16];
+ UCHAR ClientToServerKey[16];
+};
+
+// Client Options
+struct CLIENT_OPTION
+{
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Connection setting name
+ char Hostname[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT Port; // Port number
+ UINT PortUDP; // UDP port number (0: Use only TCP)
+ UINT ProxyType; // Type of proxy
+ char ProxyName[MAX_HOST_NAME_LEN + 1]; // Proxy server name
+ UINT ProxyPort; // Port number of the proxy server
+ char ProxyUsername[MAX_PROXY_USERNAME_LEN + 1]; // Maximum user name length
+ char ProxyPassword[MAX_PROXY_PASSWORD_LEN + 1]; // Maximum password length
+ UINT NumRetry; // Automatic retries
+ UINT RetryInterval; // Retry interval
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB name
+ UINT MaxConnection; // Maximum number of concurrent TCP connections
+ bool UseEncrypt; // Use encrypted communication
+ bool UseCompress; // Use data compression
+ bool HalfConnection; // Use half connection in TCP
+ bool NoRoutingTracking; // Disable the routing tracking
+ char DeviceName[MAX_DEVICE_NAME_LEN + 1]; // VLAN device name
+ UINT AdditionalConnectionInterval; // Connection attempt interval when additional connection establish
+ UINT ConnectionDisconnectSpan; // Disconnection interval
+ bool HideStatusWindow; // Hide the status window
+ bool HideNicInfoWindow; // Hide the NIC status window
+ bool RequireMonitorMode; // Monitor port mode
+ bool RequireBridgeRoutingMode; // Bridge or routing mode
+ bool DisableQoS; // Disable the VoIP / QoS function
+ bool FromAdminPack; // For Administration Pack
+ bool NoTls1; // Do not use TLS 1.0
+ bool NoUdpAcceleration; // Do not use UDP acceleration mode
+ UCHAR HostUniqueKey[SHA1_SIZE]; // Host unique key
+};
+
+// Client authentication data
+struct CLIENT_AUTH
+{
+ UINT AuthType; // Authentication type
+ char Username[MAX_USERNAME_LEN + 1]; // User name
+ UCHAR HashedPassword[SHA1_SIZE]; // Hashed passwords
+ char PlainPassword[MAX_PASSWORD_LEN + 1]; // Password
+ X *ClientX; // Client certificate
+ K *ClientK; // Client private key
+ char SecurePublicCertName[MAX_SECURE_DEVICE_FILE_LEN + 1]; // Secure device certificate name
+ char SecurePrivateKeyName[MAX_SECURE_DEVICE_FILE_LEN + 1]; // Secure device secret key name
+ CHECK_CERT_PROC *CheckCertProc; // Server certificate confirmation procedure
+ SECURE_SIGN_PROC *SecureSignProc; // Security signing procedure
+};
+
+// TCP socket data structure
+struct TCPSOCK
+{
+ SOCK *Sock; // Socket
+ FIFO *RecvFifo; // Reception buffer
+ FIFO *SendFifo; // Transmission buffer
+ UINT Mode; // Read mode
+ UINT WantSize; // Requested data size
+ UINT NextBlockNum; // Total number of blocks that can be read next
+ UINT NextBlockSize; // Block size that is planned to read next
+ UINT CurrentPacketNum; // Current packet number
+ UINT64 LastCommTime; // Last communicated time
+ UINT64 LastRecvTime; // Time the last data received
+ UINT LateCount; // The number of delay occurences
+ UINT Direction; // Direction
+ UINT64 NextKeepAliveTime; // Next time to send a KeepAlive packet
+ RC4_KEY_PAIR Rc4KeyPair; // RC4 key pair
+ CRYPT *SendKey; // Transmission key
+ CRYPT *RecvKey; // Reception key
+ UINT64 DisconnectTick; // Time to disconnect this connection
+ UINT64 EstablishedTick; // Establishment time
+};
+
+// TCP communication data structure
+struct TCP
+{
+ LIST *TcpSockList; // TCP socket list
+};
+
+// UDP communication data structure
+struct UDP
+{
+ SOCK *s; // UDP socket (for transmission)
+ IP ip; // Destination IP address
+ UINT port; // Destination port number
+ UINT64 NextKeepAliveTime; // Next time to send a KeepAlive packet
+ UINT64 Seq; // Packet sequence number
+ UINT64 RecvSeq;
+ QUEUE *BufferQueue; // Queue of buffer to be sent
+};
+
+// Data block
+struct BLOCK
+{
+ BOOL Compressed; // Compression flag
+ UINT Size; // Block size
+ UINT SizeofData; // Data size
+ UCHAR *Buf; // Buffer
+ bool PriorityQoS; // Priority packet for VoIP / QoS function
+ UINT Ttl; // TTL value (Used only in ICMP NAT of Virtual.c)
+ UINT Param1; // Parameter 1
+};
+
+// Connection structure
+struct CONNECTION
+{
+ LOCK *lock; // Lock
+ REF *ref; // Reference counter
+ CEDAR *Cedar; // Cedar
+ struct SESSION *Session; // Session
+ UINT Protocol; // Protocol
+ SOCK *FirstSock; // Socket for negotiation
+ SOCK *TubeSock; // Socket for in-process communication
+ TCP *Tcp; // TCP communication data structure
+ UDP *Udp; // UDP communication data structure
+ bool ServerMode; // Server mode
+ UINT Status; // Status
+ char *Name; // Connection name
+ THREAD *Thread; // Thread
+ volatile bool Halt; // Stop flag
+ UCHAR Random[SHA1_SIZE]; // Random number for Authentication
+ UINT ServerVer; // Server version
+ UINT ServerBuild; // Server build number
+ UINT ClientVer; // Client version
+ UINT ClientBuild; // Client build number
+ char ServerStr[MAX_SERVER_STR_LEN + 1]; // Server string
+ char ClientStr[MAX_CLIENT_STR_LEN + 1]; // Client string
+ UINT Err; // Error value
+ bool ClientConnectError_NoSavePassword; // Don't save the password for the specified user name
+ QUEUE *ReceivedBlocks; // Block queue that is received
+ QUEUE *SendBlocks; // Block queue planned to be sent
+ QUEUE *SendBlocks2; // Send queue (high priority)
+ COUNTER *CurrentNumConnection; // Counter of the number of current connections
+ LIST *ConnectingThreads; // List of connected threads
+ LIST *ConnectingSocks; // List of the connected sockets
+ bool flag1; // Flag 1
+ UCHAR *RecvBuf; // Receive buffer
+ char ServerName[MAX_HOST_NAME_LEN + 1]; // Server name
+ UINT ServerPort; // Port number
+ bool RestoreServerNameAndPort; // Flag to restore the server name and port number to original
+ bool UseTicket; // Ticket using flag
+ UCHAR Ticket[SHA1_SIZE]; // Ticket
+ UINT CurrentSendQueueSize; // Total size of the transmission queue
+ X *ServerX; // Server certificate
+ X *ClientX; // Client certificate
+ char *CipherName; // Encryption algorithm name
+ UINT64 ConnectedTick; // Time it is connected
+ IP ClientIp; // Client IP address
+ char ClientHostname[MAX_HOST_NAME_LEN + 1]; // Client host name
+ UINT Type; // Type
+ bool DontUseTls1; // Do not use TLS 1.0
+ void *hWndForUI; // Parent window
+ bool IsInProc; // In-process
+ char InProcPrefix[64]; // Prefix
+ UINT AdditionalConnectionFailedCounter; // Additional connection failure counter
+ UINT64 LastCounterResetTick; // Time the counter was reset finally
+ bool WasSstp; // Processed the SSTP
+ bool WasDatProxy; // DAT proxy processed
+ UCHAR CToken_Hash[SHA1_SIZE]; // CTOKEN_HASH
+};
+
+
+
+// Function prototypes
+
+CONNECTION *NewClientConnection(SESSION *s);
+CONNECTION *NewClientConnectionEx(SESSION *s, char *client_str, UINT client_ver, UINT client_build);
+CONNECTION *NewServerConnection(CEDAR *cedar, SOCK *s, THREAD *t);
+void ReleaseConnection(CONNECTION *c);
+void CleanupConnection(CONNECTION *c);
+int CompareConnection(void *p1, void *p2);
+void StopConnection(CONNECTION *c, bool no_wait);
+void ConnectionAccept(CONNECTION *c);
+void StartTunnelingMode(CONNECTION *c);
+void EndTunnelingMode(CONNECTION *c);
+void DisconnectTcpSockets(CONNECTION *c);
+void ConnectionReceive(CONNECTION *c, CANCEL *c1, CANCEL *c2);
+void ConnectionSend(CONNECTION *c);
+TCPSOCK *NewTcpSock(SOCK *s);
+void FreeTcpSock(TCPSOCK *ts);
+BLOCK *NewBlock(void *data, UINT size, int compress);
+void FreeBlock(BLOCK *b);
+void StopAllAdditionalConnectThread(CONNECTION *c);
+UINT GenNextKeepAliveSpan(CONNECTION *c);
+void SendKeepAlive(CONNECTION *c, TCPSOCK *ts);
+void DisconnectUDPSockets(CONNECTION *c);
+void PutUDPPacketData(CONNECTION *c, void *data, UINT size);
+void SendDataWithUDP(SOCK *s, CONNECTION *c);
+void InsertReveicedBlockToQueue(CONNECTION *c, BLOCK *block);
+void InitTcpSockRc4Key(TCPSOCK *ts, bool server_mode);
+UINT TcpSockRecv(SESSION *s, TCPSOCK *ts, void *data, UINT size);
+UINT TcpSockSend(SESSION *s, TCPSOCK *ts, void *data, UINT size);
+void WriteSendFifo(SESSION *s, TCPSOCK *ts, void *data, UINT size);
+void WriteRecvFifo(SESSION *s, TCPSOCK *ts, void *data, UINT size);
+CLIENT_AUTH *CopyClientAuth(CLIENT_AUTH *a);
+BUF *NewKeepPacket(bool server_mode);
+void KeepThread(THREAD *thread, void *param);
+KEEP *StartKeep();
+void StopKeep(KEEP *k);
+void InRpcSecureSign(SECURE_SIGN *t, PACK *p);
+void OutRpcSecureSign(PACK *p, SECURE_SIGN *t);
+void FreeRpcSecureSign(SECURE_SIGN *t);
+void NormalizeEthMtu(BRIDGE *b, CONNECTION *c, UINT packet_size);
+UINT GetMachineRand();
+
+
+
+#endif // CONNECTION_H
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Console.c b/src/Cedar/Console.c
new file mode 100644
index 00000000..9c887feb
--- /dev/null
+++ b/src/Cedar/Console.c
@@ -0,0 +1,2510 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Console.c
+// Console Service
+
+#include "CedarPch.h"
+
+
+// Display the help for the command
+void PrintCmdHelp(CONSOLE *c, char *cmd_name, TOKEN_LIST *param_list)
+{
+ wchar_t tmp[MAX_SIZE];
+ wchar_t *buf;
+ UINT buf_size;
+ wchar_t *description, *args, *help;
+ UNI_TOKEN_LIST *t;
+ UINT width;
+ UINT i;
+ char *space;
+ // Validate arguments
+ if (c == NULL || cmd_name == NULL || param_list == NULL)
+ {
+ return;
+ }
+
+ width = GetConsoleWidth(c) - 2;
+
+ buf_size = sizeof(wchar_t) * (width + 32);
+ buf = Malloc(buf_size);
+
+ GetCommandHelpStr(cmd_name, &description, &args, &help);
+
+ space = MakeCharArray(' ', 2);
+
+ // Title
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_HELP_TITLE"), cmd_name);
+ c->Write(c, tmp);
+ c->Write(c, L"");
+
+ // Purpose
+ c->Write(c, _UU("CMD_HELP_DESCRIPTION"));
+ t = SeparateStringByWidth(description, width - 2);
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ UniFormat(buf, buf_size, L"%S%s", space, t->Token[i]);
+ c->Write(c, buf);
+ }
+ UniFreeToken(t);
+ c->Write(c, L"");
+
+ // Description
+ c->Write(c, _UU("CMD_HELP_HELP"));
+ t = SeparateStringByWidth(help, width - 2);
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ UniFormat(buf, buf_size, L"%S%s", space, t->Token[i]);
+ c->Write(c, buf);
+ }
+ UniFreeToken(t);
+ c->Write(c, L"");
+
+ // Usage
+ c->Write(c, _UU("CMD_HELP_USAGE"));
+ t = SeparateStringByWidth(args, width - 2);
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ UniFormat(buf, buf_size, L"%S%s", space, t->Token[i]);
+ c->Write(c, buf);
+ }
+ UniFreeToken(t);
+
+ // Arguments
+ if (param_list->NumTokens >= 1)
+ {
+ c->Write(c, L"");
+ c->Write(c, _UU("CMD_HELP_ARGS"));
+ PrintCandidateHelp(c, cmd_name, param_list, 2);
+ }
+
+ Free(space);
+
+ Free(buf);
+}
+
+// Evaluate whether it is SafeStr
+bool CmdEvalSafe(CONSOLE *c, wchar_t *str, void *param)
+{
+ wchar_t *p = (param == NULL) ? _UU("CMD_EVAL_SAFE") : (wchar_t *)param;
+
+ if (IsSafeUniStr(str))
+ {
+ return true;
+ }
+
+ c->Write(c, p);
+
+ return false;
+}
+
+// String input prompt
+wchar_t *CmdPrompt(CONSOLE *c, void *param)
+{
+ wchar_t *p = (param == NULL) ? _UU("CMD_PROMPT") : (wchar_t *)param;
+
+ return c->ReadLine(c, p, true);
+}
+
+// Evaluation whether the specified file exists
+bool CmdEvalIsFile(CONSOLE *c, wchar_t *str, void *param)
+{
+ wchar_t tmp[MAX_PATH];
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniStrCpy(tmp, sizeof(tmp), str);
+
+ if (IsEmptyUniStr(tmp))
+ {
+ c->Write(c, _UU("CMD_FILE_NAME_EMPTY"));
+ return false;
+ }
+
+ if (IsFileExistsW(tmp) == false)
+ {
+ wchar_t tmp2[MAX_SIZE];
+
+ UniFormat(tmp2, sizeof(tmp2), _UU("CMD_FILE_NOT_FOUND"), tmp);
+ c->Write(c, tmp2);
+
+ return false;
+ }
+
+ return true;
+}
+
+// Evaluation of integer
+bool CmdEvalInt1(CONSOLE *c, wchar_t *str, void *param)
+{
+ wchar_t *p = (param == NULL) ? _UU("CMD_EVAL_INT") : (wchar_t *)param;
+
+ if (UniToInt(str) == 0)
+ {
+ c->Write(c, p);
+
+ return false;
+ }
+
+ return true;
+}
+
+// Evaluation of the parameters that a blank cannot be specified to
+bool CmdEvalNotEmpty(CONSOLE *c, wchar_t *str, void *param)
+{
+ wchar_t *p = (param == NULL) ? _UU("CMD_EVAL_NOT_EMPTY") : (wchar_t *)param;
+
+ if (UniIsEmptyStr(str) == false)
+ {
+ return true;
+ }
+
+ c->Write(c, p);
+
+ return false;
+}
+
+// Evaluation function for minimum / maximum value of the parameter
+bool CmdEvalMinMax(CONSOLE *c, wchar_t *str, void *param)
+{
+ CMD_EVAL_MIN_MAX *e;
+ wchar_t *tag;
+ UINT v;
+ // Validate arguments
+ if (param == NULL)
+ {
+ return false;
+ }
+
+ e = (CMD_EVAL_MIN_MAX *)param;
+
+ if (e->StrName == NULL)
+ {
+ tag = _UU("CMD_EVAL_MIN_MAX");
+ }
+ else
+ {
+ tag = _UU(e->StrName);
+ }
+
+ v = UniToInt(str);
+
+ if (v >= e->MinValue && v <= e->MaxValue)
+ {
+ return true;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), tag, e->MinValue, e->MaxValue);
+ c->Write(c, tmp);
+
+ return false;
+ }
+}
+
+// Get the help string of command
+void GetCommandHelpStr(char *command_name, wchar_t **description, wchar_t **args, wchar_t **help)
+{
+ char tmp1[128], tmp2[128], tmp3[128];
+
+ Format(tmp1, sizeof(tmp1), "CMD_%s", command_name);
+ Format(tmp2, sizeof(tmp2), "CMD_%s_ARGS", command_name);
+ Format(tmp3, sizeof(tmp3), "CMD_%s_HELP", command_name);
+
+ if (description != NULL)
+ {
+ *description = _UU(tmp1);
+ if (UniIsEmptyStr(*description))
+ {
+ *description = _UU("CMD_UNKNOWM");
+ }
+ }
+
+ if (args != NULL)
+ {
+ *args = _UU(tmp2);
+ if (UniIsEmptyStr(*args))
+ {
+ *args = _UU("CMD_UNKNOWN_ARGS");
+ }
+ }
+
+ if (help != NULL)
+ {
+ *help = _UU(tmp3);
+ if (UniIsEmptyStr(*help))
+ {
+ *help = _UU("CMD_UNKNOWN_HELP");
+ }
+ }
+}
+
+// Get the help string for parameter
+void GetCommandParamHelpStr(char *command_name, char *param_name, wchar_t **description)
+{
+ char tmp[160];
+ if (description == NULL)
+ {
+ return;
+ }
+
+ Format(tmp, sizeof(tmp), "CMD_%s_%s", command_name, param_name);
+
+ *description = _UU(tmp);
+
+ if (UniIsEmptyStr(*description))
+ {
+ *description = _UU("CMD_UNKNOWN_PARAM");
+ }
+}
+
+// String comparison function
+int CompareCandidateStr(void *p1, void *p2)
+{
+ char *s1, *s2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ s1 = *(char **)p1;
+ s2 = *(char **)p2;
+ if (s1 == NULL || s2 == NULL)
+ {
+ return 0;
+ }
+
+ if (s1[0] == '[' && s2[0] != '[')
+ {
+ return -1;
+ }
+ else if (s2[0] == '[' && s1[0] != '[')
+ {
+ return 1;
+ }
+
+ return StrCmp(s1, s2);
+}
+
+// Display the help of the candidate list
+void PrintCandidateHelp(CONSOLE *c, char *cmd_name, TOKEN_LIST *candidate_list, UINT left_space)
+{
+ UINT console_width;
+ UINT max_keyword_width;
+ LIST *o;
+ UINT i;
+ wchar_t *tmpbuf;
+ UINT tmpbuf_size;
+ char *left_space_array;
+ char *max_space_array;
+ // Validate arguments
+ if (c == NULL || candidate_list == NULL)
+ {
+ return;
+ }
+
+ // Get the width of the screen
+ console_width = GetConsoleWidth(c) - 1;
+
+ tmpbuf_size = sizeof(wchar_t) * (console_width + 32);
+ tmpbuf = Malloc(tmpbuf_size);
+
+ left_space_array = MakeCharArray(' ', left_space);
+
+ // Sort and enlist the command name
+ // no need to sort the parameter name
+ o = NewListFast(cmd_name == NULL ? CompareCandidateStr : NULL);
+
+ max_keyword_width = 0;
+
+ for (i = 0;i < candidate_list->NumTokens;i++)
+ {
+ UINT keyword_width;
+
+ // Get the width of each keyword
+ Insert(o, candidate_list->Token[i]);
+
+ keyword_width = StrWidth(candidate_list->Token[i]);
+ if (cmd_name != NULL)
+ {
+ if (candidate_list->Token[i][0] != '[')
+ {
+ keyword_width += 1;
+ }
+ else
+ {
+ keyword_width -= 2;
+ }
+ }
+
+ max_keyword_width = MAX(max_keyword_width, keyword_width);
+ }
+
+ max_space_array = MakeCharArray(' ', max_keyword_width);
+
+ // Display the candidate
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ char tmp[128];
+ char *name = LIST_DATA(o, i);
+ UNI_TOKEN_LIST *t;
+ wchar_t *help;
+ UINT j;
+ UINT keyword_start_width = left_space;
+ UINT descript_start_width = left_space + max_keyword_width + 1;
+ UINT descript_width;
+ char *space;
+
+ if (console_width >= (descript_start_width + 5))
+ {
+ descript_width = console_width - descript_start_width - 3;
+ }
+ else
+ {
+ descript_width = 2;
+ }
+
+ // Generate the name
+ if (cmd_name != NULL && name[0] != '[')
+ {
+ // Prepend a "/" in the case of a parameter
+ Format(tmp, sizeof(tmp), "/%s", name);
+ }
+ else
+ {
+ // Use the characters as it is in the case of a command name
+ if (cmd_name == NULL)
+ {
+ StrCpy(tmp, sizeof(tmp), name);
+ }
+ else
+ {
+ StrCpy(tmp, sizeof(tmp), name + 1);
+ if (StrLen(tmp) >= 1)
+ {
+ tmp[StrLen(tmp) - 1] = 0;
+ }
+ }
+ }
+
+ // Get the help string
+ if (cmd_name == NULL)
+ {
+ GetCommandHelpStr(name, &help, NULL, NULL);
+ }
+ else
+ {
+ GetCommandParamHelpStr(cmd_name, name, &help);
+ }
+
+ space = MakeCharArray(' ', max_keyword_width - StrWidth(name) - (cmd_name == NULL ? 0 : (name[0] != '[' ? 1 : -2)));
+
+ t = SeparateStringByWidth(help, descript_width);
+
+ for (j = 0;j < t->NumTokens;j++)
+ {
+ if (j == 0)
+ {
+ UniFormat(tmpbuf, tmpbuf_size, L"%S%S%S - %s",
+ left_space_array, tmp, space, t->Token[j]);
+ }
+ else
+ {
+ UniFormat(tmpbuf, tmpbuf_size, L"%S%S %s",
+ left_space_array, max_space_array, t->Token[j]);
+ }
+
+ c->Write(c, tmpbuf);
+ }
+
+ Free(space);
+
+ UniFreeToken(t);
+ }
+
+ ReleaseList(o);
+
+ Free(max_space_array);
+ Free(tmpbuf);
+ Free(left_space_array);
+}
+
+// Acquisition whether word characters
+bool IsWordChar(wchar_t c)
+{
+ if (c >= L'a' && c <= 'z')
+ {
+ return true;
+ }
+ if (c >= L'A' && c <= 'Z')
+ {
+ return true;
+ }
+ if (c >= L'0' && c <= '9')
+ {
+ return true;
+ }
+ if (c == L'_')
+ {
+ return true;
+ }
+ if (c == L'.')
+ {
+ return true;
+ }
+ if (c == L'\"')
+ {
+ return true;
+ }
+ if (c == L'\'')
+ {
+ return true;
+ }
+ if (c == L',')
+ {
+ return true;
+ }
+ if (c == L')')
+ {
+ return true;
+ }
+ if (c == L']')
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Get the character width of the word that comes next
+UINT GetNextWordWidth(wchar_t *str)
+{
+ UINT i;
+ UINT ret;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return 0;
+ }
+
+ ret = 0;
+
+ for (i = 0;;i++)
+ {
+ wchar_t c = str[i];
+
+ if (c == 0)
+ {
+ break;
+ }
+
+ if (IsWordChar(c) == false)
+ {
+ break;
+ }
+
+ ret++;
+ }
+
+ return ret;
+}
+
+// Split a string into specified width
+UNI_TOKEN_LIST *SeparateStringByWidth(wchar_t *str, UINT width)
+{
+ UINT wp;
+ wchar_t *tmp;
+ UINT len, i;
+ LIST *o;
+ UNI_TOKEN_LIST *ret;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return UniNullToken();
+ }
+ if (width == 0)
+ {
+ width = 1;
+ }
+
+ o = NewListFast(NULL);
+
+ len = UniStrLen(str);
+ tmp = ZeroMalloc(sizeof(wchar_t) * (len + 32));
+ wp = 0;
+
+ for (i = 0;i < (len + 1);i++)
+ {
+ wchar_t c = str[i];
+ UINT next_word_width;
+ UINT remain_width;
+
+ switch (c)
+ {
+ case 0:
+ case L'\r':
+ case L'\n':
+ if (c == L'\r')
+ {
+ if (str[i + 1] == L'\n')
+ {
+ i++;
+ }
+ }
+
+ tmp[wp++] = 0;
+ wp = 0;
+
+ Insert(o, UniCopyStr(tmp));
+ break;
+
+ default:
+ next_word_width = GetNextWordWidth(&str[i]);
+ remain_width = (width - UniStrWidth(tmp));
+
+ if ((remain_width >= 1) && (next_word_width > remain_width) && (next_word_width <= width))
+ {
+ tmp[wp++] = 0;
+ wp = 0;
+
+ Insert(o, UniCopyStr(tmp));
+ }
+
+ tmp[wp++] = c;
+ tmp[wp] = 0;
+ if (UniStrWidth(tmp) >= width)
+ {
+ tmp[wp++] = 0;
+ wp = 0;
+
+ Insert(o, UniCopyStr(tmp));
+ }
+ break;
+ }
+ }
+
+ if (LIST_NUM(o) == 0)
+ {
+ Insert(o, CopyUniStr(L""));
+ }
+
+ ret = ZeroMalloc(sizeof(UNI_TOKEN_LIST));
+ ret->NumTokens = LIST_NUM(o);
+ ret->Token = ZeroMalloc(sizeof(wchar_t *) * ret->NumTokens);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ wchar_t *s = LIST_DATA(o, i);
+
+ UniTrimLeft(s);
+
+ ret->Token[i] = s;
+ }
+
+ ReleaseList(o);
+ Free(tmp);
+
+ return ret;
+}
+
+// Check whether the specified string means 'help'
+bool IsHelpStr(char *str)
+{
+ // Validate arguments
+ if (str == NULL)
+ {
+ return false;
+ }
+
+ if (StrCmpi(str, "help") == 0 || StrCmpi(str, "?") == 0 ||
+ StrCmpi(str, "man") == 0 || StrCmpi(str, "/man") == 0 ||
+ StrCmpi(str, "-man") == 0 || StrCmpi(str, "--man") == 0 ||
+ StrCmpi(str, "/help") == 0 || StrCmpi(str, "/?") == 0 ||
+ StrCmpi(str, "-help") == 0 || StrCmpi(str, "-?") == 0 ||
+ StrCmpi(str, "/h") == 0 || StrCmpi(str, "--help") == 0 ||
+ StrCmpi(str, "--?") == 0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Execution of the command
+bool DispatchNextCmd(CONSOLE *c, char *prompt, CMD cmd[], UINT num_cmd, void *param)
+{
+ return DispatchNextCmdEx(c, NULL, prompt, cmd, num_cmd, param);
+}
+bool DispatchNextCmdEx(CONSOLE *c, wchar_t *exec_command, char *prompt, CMD cmd[], UINT num_cmd, void *param)
+{
+ wchar_t *str;
+ wchar_t *tmp;
+ char *cmd_name;
+ bool b_exit = false;
+ wchar_t *cmd_param;
+ UINT ret = ERR_NO_ERROR;
+ TOKEN_LIST *t;
+ TOKEN_LIST *candidate;
+ bool no_end_crlf = false;
+ UINT i;
+ // Validate arguments
+ if (c == NULL || (num_cmd >= 1 && cmd == NULL))
+ {
+ return false;
+ }
+
+ if (exec_command == NULL)
+ {
+ // Show the prompt
+RETRY:
+ tmp = CopyStrToUni(prompt);
+ str = c->ReadLine(c, tmp, false);
+ Free(tmp);
+
+ if (str != NULL && IsEmptyUniStr(str))
+ {
+ Free(str);
+ goto RETRY;
+ }
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ // Use exec_command
+ if (UniStartWith(exec_command, L"vpncmd") == false)
+ {
+ if (prompt != NULL)
+ {
+ if (c->ConsoleType != CONSOLE_CSV)
+ {
+ UniFormat(tmp, sizeof(tmp), L"%S%s", prompt, exec_command);
+ c->Write(c, tmp);
+ }
+ }
+ }
+ str = CopyUniStr(exec_command);
+ }
+
+ if (str == NULL)
+ {
+ // User canceled
+ return false;
+ }
+
+ UniTrimCrlf(str);
+ UniTrim(str);
+
+ if (UniIsEmptyStr(str))
+ {
+ // Do Nothing
+ Free(str);
+ return true;
+ }
+
+ // Divide into command name and parameter
+ if (SeparateCommandAndParam(str, &cmd_name, &cmd_param) == false)
+ {
+ // Do Nothing
+ Free(str);
+ return true;
+ }
+
+ if (StrLen(cmd_name) >= 2 && cmd_name[0] == '?' && cmd_name[1] != '?')
+ {
+ char tmp[MAX_SIZE];
+ wchar_t *s;
+
+ StrCpy(tmp, sizeof(tmp), cmd_name + 1);
+ StrCpy(cmd_name, 0, tmp);
+
+ s = UniCopyStr(L"/?");
+ Free(cmd_param);
+
+ cmd_param = s;
+ }
+
+ if (StrLen(cmd_name) >= 2 && EndWith(cmd_name, "?") && cmd_name[StrLen(cmd_name) - 2] != '?')
+ {
+ wchar_t *s;
+
+ cmd_name[StrLen(cmd_name) - 1] = 0;
+
+ s = UniCopyStr(L"/?");
+ Free(cmd_param);
+
+ cmd_param = s;
+ }
+
+ // Get the candidate of command
+ t = ZeroMalloc(sizeof(TOKEN_LIST));
+ t->NumTokens = num_cmd;
+ t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ t->Token[i] = CopyStr(cmd[i].Name);
+ }
+
+ if (IsHelpStr(cmd_name))
+ {
+ if (UniIsEmptyStr(cmd_param))
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ // Display the list of commands that can be used
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_HELP_1"), t->NumTokens);
+ c->Write(c, tmp);
+
+ PrintCandidateHelp(c, NULL, t, 1);
+
+ c->Write(c, L"");
+ c->Write(c, _UU("CMD_HELP_2"));
+ }
+ else
+ {
+ char *cmd_name;
+
+ // Display the help for the specified command
+ if (SeparateCommandAndParam(cmd_param, &cmd_name, NULL))
+ {
+ bool b = true;
+
+ if (IsHelpStr(cmd_name))
+ {
+ b = false;
+ }
+
+ if (b)
+ {
+ wchar_t str[MAX_SIZE];
+
+ UniFormat(str, sizeof(str), L"%S /help", cmd_name);
+ DispatchNextCmdEx(c, str, NULL, cmd, num_cmd, param);
+ no_end_crlf = true;
+ }
+
+ Free(cmd_name);
+ }
+ }
+ }
+ else if (StrCmpi(cmd_name, "exit") == 0 || StrCmpi(cmd_name, "quit") == 0)
+ {
+ // Exit
+ b_exit = true;
+ }
+ else
+ {
+ candidate = GetRealnameCandidate(cmd_name, t);
+
+ if (candidate == NULL || candidate->NumTokens == 0)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ // No candidate
+ UniFormat(tmp, sizeof(tmp), _UU("CON_UNKNOWN_CMD"), cmd_name);
+ c->Write(c, tmp);
+
+ c->RetCode = ERR_BAD_COMMAND_OR_PARAM;
+ }
+ else if (candidate->NumTokens >= 2)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ // There is more than one candidate
+ UniFormat(tmp, sizeof(tmp), _UU("CON_AMBIGIOUS_CMD"), cmd_name);
+ c->Write(c, tmp);
+ c->Write(c, _UU("CON_AMBIGIOUS_CMD_1"));
+ PrintCandidateHelp(c, NULL, candidate, 1);
+ c->Write(c, _UU("CON_AMBIGIOUS_CMD_2"));
+
+ c->RetCode = ERR_BAD_COMMAND_OR_PARAM;
+ }
+ else
+ {
+ char *real_cmd_name;
+ UINT i;
+
+ // The candidate was shortlisted to one
+ real_cmd_name = candidate->Token[0];
+
+ for (i = 0;i < num_cmd;i++)
+ {
+ if (StrCmpi(cmd[i].Name, real_cmd_name) == 0)
+ {
+ if (cmd[i].Proc != NULL)
+ {
+ // Show the description of the command if it isn't in CSV mode
+ if(c->ConsoleType != CONSOLE_CSV)
+ {
+ wchar_t tmp[256];
+ wchar_t *note;
+
+ GetCommandHelpStr(cmd[i].Name, ¬e, NULL, NULL);
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_EXEC_MSG_NAME"), cmd[i].Name, note);
+ c->Write(c, tmp);
+ }
+
+ // Call the procedure of the command
+ ret = cmd[i].Proc(c, cmd[i].Name, cmd_param, param);
+
+ if (ret == INFINITE)
+ {
+ // Exit command
+ b_exit = true;
+ }
+ else
+ {
+ c->RetCode = ret;
+ }
+ }
+ }
+ }
+ }
+
+ FreeToken(candidate);
+ }
+
+ FreeToken(t);
+ Free(str);
+ Free(cmd_name);
+ Free(cmd_param);
+
+ if (no_end_crlf == false)
+ {
+ //c->Write(c, L"");
+ }
+
+ if (b_exit)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Get the width of the current console
+UINT GetConsoleWidth(CONSOLE *c)
+{
+ UINT size;
+
+ size = c->GetWidth(c);
+
+ if (size == 0)
+ {
+ size = 80;
+ }
+
+ if (size < 32)
+ {
+ size = 32;
+ }
+
+ if (size > 65536)
+ {
+ size = 65535;
+ }
+
+ return size;
+}
+
+// Separate the command line into the command and the parameters
+bool SeparateCommandAndParam(wchar_t *src, char **cmd, wchar_t **param)
+{
+ UINT i, len, wp;
+ wchar_t *tmp;
+ wchar_t *src_tmp;
+ // Validate arguments
+ if (src == NULL)
+ {
+ return false;
+ }
+ if (cmd != NULL)
+ {
+ *cmd = NULL;
+ }
+ if (param != NULL)
+ {
+ *param = NULL;
+ }
+
+ src_tmp = UniCopyStr(src);
+ UniTrimCrlf(src_tmp);
+ UniTrim(src_tmp);
+
+ len = UniStrLen(src_tmp);
+ tmp = Malloc(sizeof(wchar_t) * (len + 32));
+ wp = 0;
+
+ for (i = 0;i < (len + 1);i++)
+ {
+ wchar_t c = src_tmp[i];
+
+ switch (c)
+ {
+ case 0:
+ case L' ':
+ case L'\t':
+ tmp[wp] = 0;
+ if (UniIsEmptyStr(tmp))
+ {
+ Free(tmp);
+ Free(src_tmp);
+ return false;
+ }
+ if (cmd != NULL)
+ {
+ *cmd = CopyUniToStr(tmp);
+ Trim(*cmd);
+ }
+ goto ESCAPE;
+
+ default:
+ tmp[wp++] = c;
+ break;
+ }
+ }
+
+ESCAPE:
+ if (param != NULL)
+ {
+ *param = CopyUniStr(&src_tmp[wp]);
+ UniTrim(*param);
+ }
+
+ Free(tmp);
+ Free(src_tmp);
+
+ return true;
+}
+
+// Get the candidates list of of the real command name whose abbreviation matches to the command specified by the user
+TOKEN_LIST *GetRealnameCandidate(char *input_name, TOKEN_LIST *real_name_list)
+{
+ TOKEN_LIST *ret;
+ LIST *o;
+ UINT i;
+ bool ok = false;
+ // Validate arguments
+ if (input_name == NULL || real_name_list == NULL)
+ {
+ return NullToken();
+ }
+
+ o = NewListFast(NULL);
+
+ for (i = 0;i < real_name_list->NumTokens;i++)
+ {
+ char *name = real_name_list->Token[i];
+
+ // Search for an exact match with the highest priority first
+ if (StrCmpi(name, input_name) == 0)
+ {
+ Insert(o, name);
+ ok = true;
+ break;
+ }
+ }
+
+ if (ok == false)
+ {
+ // If there is no command to exact match, check whether it matches to a short form command
+ for (i = 0;i < real_name_list->NumTokens;i++)
+ {
+ char *name = real_name_list->Token[i];
+
+ if (IsOmissionName(input_name, name) || IsNameInRealName(input_name, name))
+ {
+ // A abbreviation is found
+ Insert(o, name);
+ ok = true;
+ }
+ }
+ }
+
+ if (ok)
+ {
+ // One or more candidate is found
+ ret = ListToTokenList(o);
+ }
+ else
+ {
+ ret = NullToken();
+ }
+
+ ReleaseList(o);
+
+ return ret;
+}
+
+// Check whether the command specified by the user is a abbreviation of existing commands
+bool IsOmissionName(char *input_name, char *real_name)
+{
+ char oname[128];
+ // Validate arguments
+ if (input_name == NULL || real_name == NULL)
+ {
+ return false;
+ }
+
+ if (IsAllUpperStr(real_name))
+ {
+ // Command of all capital letters do not take abbreviations
+ return false;
+ }
+
+ GetOmissionName(oname, sizeof(oname), real_name);
+
+ if (IsEmptyStr(oname))
+ {
+ return false;
+ }
+
+ if (StartWith(oname, input_name))
+ {
+ // Example: The oname of AccountSecureCertSet is "ascs".
+ // But if the user enters "asc", returns true
+ return true;
+ }
+
+ if (StartWith(input_name, oname))
+ {
+ // Example: When two commands AccountCreate and AccountConnect exist,
+ // if the user enter "aconnect" , only AccountConnect is true
+
+ if (EndWith(real_name, &input_name[StrLen(oname)]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Get the short name of the specified command
+void GetOmissionName(char *dst, UINT size, char *src)
+{
+ UINT i, len;
+ // Validate arguments
+ if (dst == NULL || src == NULL)
+ {
+ return;
+ }
+
+ StrCpy(dst, size, "");
+ len = StrLen(src);
+
+ for (i = 0;i < len;i++)
+ {
+ char c = src[i];
+
+ if ((c >= '0' && c <= '9') ||
+ (c >= 'A' && c <= 'Z'))
+ {
+ char tmp[2];
+ tmp[0] = c;
+ tmp[1] = 0;
+
+ StrCat(dst, size, tmp);
+ }
+ }
+}
+
+// Check whether the command specified by the user matches the existing commands
+bool IsNameInRealName(char *input_name, char *real_name)
+{
+ // Validate arguments
+ if (input_name == NULL || real_name == NULL)
+ {
+ return false;
+ }
+
+ if (StartWith(real_name, input_name))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Parse the command list
+LIST *ParseCommandList(CONSOLE *c, char *cmd_name, wchar_t *command, PARAM param[], UINT num_param)
+{
+ UINT i;
+ LIST *o;
+ bool ok = true;
+ TOKEN_LIST *param_list;
+ TOKEN_LIST *real_name_list;
+ bool help_mode = false;
+ wchar_t *tmp;
+ // Validate arguments
+ if (c == NULL || command == NULL || (num_param >= 1 && param == NULL) || cmd_name == NULL)
+ {
+ return NULL;
+ }
+
+ // Initialization
+ for (i = 0;i < num_param;i++)
+ {
+ if (IsEmptyStr(param[i].Name) == false)
+ {
+ if (param[i].Name[0] == '[')
+ {
+ param[i].Tmp = "";
+ }
+ else
+ {
+ param[i].Tmp = NULL;
+ }
+ }
+ else
+ {
+ param[i].Tmp = "";
+ }
+ }
+
+ real_name_list = ZeroMalloc(sizeof(TOKEN_LIST));
+ real_name_list->NumTokens = num_param;
+ real_name_list->Token = ZeroMalloc(sizeof(char *) * real_name_list->NumTokens);
+
+ for (i = 0;i < real_name_list->NumTokens;i++)
+ {
+ real_name_list->Token[i] = CopyStr(param[i].Name);
+ }
+
+ // Generate a list of parameter name specified by the user
+ param_list = GetCommandNameList(command);
+
+ for (i = 0;i < param_list->NumTokens;i++)
+ {
+ char *s = param_list->Token[i];
+
+ if (StrCmpi(s, "help") == 0 || StrCmpi(s, "?") == 0)
+ {
+ help_mode = true;
+ break;
+ }
+ }
+
+ tmp = ParseCommand(command, L"");
+ if (tmp != NULL)
+ {
+ if (UniStrCmpi(tmp, L"?") == 0)
+ {
+ help_mode = true;
+ }
+ Free(tmp);
+ }
+
+ if (help_mode)
+ {
+ // Show the help
+ PrintCmdHelp(c, cmd_name, real_name_list);
+ FreeToken(param_list);
+ FreeToken(real_name_list);
+ return NULL;
+ }
+
+ for (i = 0;i < param_list->NumTokens;i++)
+ {
+ // Get the corresponding commands for all parameter names which is specified by the user
+ TOKEN_LIST *candidate = GetRealnameCandidate(param_list->Token[i], real_name_list);
+
+ if (candidate != NULL && candidate->NumTokens >= 1)
+ {
+ if (candidate->NumTokens >= 2)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ // There is more than one candidate
+ UniFormat(tmp, sizeof(tmp), _UU("CON_AMBIGIOUS_PARAM"), param_list->Token[i]);
+ c->Write(c, tmp);
+ UniFormat(tmp, sizeof(tmp), _UU("CON_AMBIGIOUS_PARAM_1"), cmd_name);
+ c->Write(c, tmp);
+
+ PrintCandidateHelp(c, cmd_name, candidate, 1);
+
+ c->Write(c, _UU("CON_AMBIGIOUS_PARAM_2"));
+
+ ok = false;
+ }
+ else
+ {
+ UINT j;
+ char *real_name = candidate->Token[0];
+
+ // There is only one candidate
+ for (j = 0;j < num_param;j++)
+ {
+ if (StrCmpi(param[j].Name, real_name) == 0)
+ {
+ param[j].Tmp = param_list->Token[i];
+ }
+ }
+ }
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ // No candidate
+ UniFormat(tmp, sizeof(tmp), _UU("CON_INVALID_PARAM"), param_list->Token[i], cmd_name, cmd_name);
+ c->Write(c, tmp);
+
+ ok = false;
+ }
+
+ FreeToken(candidate);
+ }
+
+ if (ok == false)
+ {
+ FreeToken(param_list);
+ FreeToken(real_name_list);
+
+ return NULL;
+ }
+
+ // Creating a list
+ o = NewParamValueList();
+
+ // Read all the parameters of the specified name in the parameter list
+ for (i = 0;i < num_param;i++)
+ {
+ bool prompt_input_value = false;
+ PARAM *p = ¶m[i];
+
+ if (p->Tmp != NULL || p->PromptProc != NULL)
+ {
+ wchar_t *name = CopyStrToUni(p->Name);
+ wchar_t *tmp;
+ wchar_t *str;
+
+ if (p->Tmp != NULL)
+ {
+ tmp = CopyStrToUni(p->Tmp);
+ }
+ else
+ {
+ tmp = CopyStrToUni(p->Name);
+ }
+
+ str = ParseCommand(command, tmp);
+ Free(tmp);
+ if (str != NULL)
+ {
+ wchar_t *unistr;
+ bool ret;
+EVAL_VALUE:
+ // Reading succeeded
+ unistr = str;
+
+ if (p->EvalProc != NULL)
+ {
+ // Evaluate the value if EvalProc is specified
+ ret = p->EvalProc(c, unistr, p->EvalProcParam);
+ }
+ else
+ {
+ // Accept any value if EvalProc is not specified
+ ret = true;
+ }
+
+ if (ret == false)
+ {
+ // The specified value is invalid
+ if (p->PromptProc == NULL)
+ {
+ // Cancel
+ ok = false;
+ Free(name);
+ Free(str);
+ break;
+ }
+ else
+ {
+ // Request to re-enter
+ Free(str);
+ str = NULL;
+ goto SHOW_PROMPT;
+ }
+ }
+ else
+ {
+ PARAM_VALUE *v;
+ // Finished loading, add it to the list
+ v = ZeroMalloc(sizeof(PARAM_VALUE));
+ v->Name = CopyStr(p->Name);
+ v->StrValue = CopyUniToStr(str);
+ v->UniStrValue = CopyUniStr(str);
+ v->IntValue = ToInt(v->StrValue);
+ Insert(o, v);
+ }
+ }
+ else
+ {
+ // Failed to read. The parameter is not specified
+ if (p->PromptProc != NULL)
+ {
+ wchar_t *tmp;
+SHOW_PROMPT:
+ // Prompt because it is a mandatory parameter
+ tmp = p->PromptProc(c, p->PromptProcParam);
+ if (tmp == NULL)
+ {
+ // User canceled
+ ok = false;
+ Free(str);
+ Free(name);
+ break;
+ }
+ else
+ {
+ // Entered by the user
+ c->Write(c, L"");
+ str = tmp;
+ prompt_input_value = true;
+ goto EVAL_VALUE;
+ }
+ }
+ }
+
+ Free(str);
+ Free(name);
+ }
+ }
+
+ FreeToken(param_list);
+ FreeToken(real_name_list);
+
+ if (ok)
+ {
+ return o;
+ }
+ else
+ {
+ FreeParamValueList(o);
+ return NULL;
+ }
+}
+
+// Acquisition of [Yes] or [No]
+bool GetParamYes(LIST *o, char *name)
+{
+ char *s;
+ char tmp[64];
+ // Validate arguments
+ if (o == NULL)
+ {
+ return false;
+ }
+
+ s = GetParamStr(o, name);
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ StrCpy(tmp, sizeof(tmp), s);
+ Trim(tmp);
+
+ if (StartWith(tmp, "y"))
+ {
+ return true;
+ }
+
+ if (StartWith(tmp, "t"))
+ {
+ return true;
+ }
+
+ if (ToInt(tmp) != 0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Acquisition of parameter value Int
+UINT GetParamInt(LIST *o, char *name)
+{
+ PARAM_VALUE *v;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return 0;
+ }
+
+ v = FindParamValue(o, name);
+ if (v == NULL)
+ {
+ return 0;
+ }
+ else
+ {
+ return v->IntValue;
+ }
+}
+
+// Acquisition of parameter value Unicode string
+wchar_t *GetParamUniStr(LIST *o, char *name)
+{
+ PARAM_VALUE *v;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return NULL;
+ }
+
+ v = FindParamValue(o, name);
+ if (v == NULL)
+ {
+ return NULL;
+ }
+ else
+ {
+ return v->UniStrValue;
+ }
+}
+
+// Acquisition of the parameter value string
+char *GetParamStr(LIST *o, char *name)
+{
+ PARAM_VALUE *v;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return NULL;
+ }
+
+ v = FindParamValue(o, name);
+ if (v == NULL)
+ {
+ return NULL;
+ }
+ else
+ {
+ return v->StrValue;
+ }
+}
+
+// Acquisition of parameter value
+PARAM_VALUE *FindParamValue(LIST *o, char *name)
+{
+ PARAM_VALUE t, *ret;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return NULL;
+ }
+ if (name == NULL)
+ {
+ name = "";
+ }
+
+ Zero(&t, sizeof(t));
+ t.Name = name;
+
+ ret = Search(o, &t);
+
+ return ret;
+}
+
+// Release of the parameter value list
+void FreeParamValueList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ PARAM_VALUE *v = LIST_DATA(o, i);
+
+ Free(v->StrValue);
+ Free(v->UniStrValue);
+ Free(v->Name);
+ Free(v);
+ }
+
+ ReleaseList(o);
+}
+
+// Parameter value list sort function
+int CmpParamValue(void *p1, void *p2)
+{
+ PARAM_VALUE *v1, *v2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ v1 = *(PARAM_VALUE **)p1;
+ v2 = *(PARAM_VALUE **)p2;
+ if (v1 == NULL || v2 == NULL)
+ {
+ return 0;
+ }
+
+ if (IsEmptyStr(v1->Name) && IsEmptyStr(v2->Name))
+ {
+ return 0;
+ }
+ return StrCmpi(v1->Name, v2->Name);
+}
+
+// Generation of the parameter value list
+LIST *NewParamValueList()
+{
+ return NewListFast(CmpParamValue);
+}
+
+// Get the list of parameter names that were included in the entered command
+TOKEN_LIST *GetCommandNameList(wchar_t *str)
+{
+ TOKEN_LIST *t;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return NullToken();
+ }
+
+ Free(ParseCommandEx(str, L"dummy_str", &t));
+
+ return t;
+}
+
+// Get the commands that start with the specified name
+wchar_t *ParseCommand(wchar_t *str, wchar_t *name)
+{
+ return ParseCommandEx(str, name, NULL);
+}
+wchar_t *ParseCommandEx(wchar_t *str, wchar_t *name, TOKEN_LIST **param_list)
+{
+ UNI_TOKEN_LIST *t;
+ UINT i;
+ wchar_t *tmp;
+ wchar_t *ret = NULL;
+ LIST *o;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return NULL;
+ }
+ if (name != NULL && UniIsEmptyStr(name))
+ {
+ name = NULL;
+ }
+
+ o = NULL;
+ if (param_list != NULL)
+ {
+ o = NewListFast(CompareStr);
+ }
+
+ tmp = CopyUniStr(str);
+ UniTrim(tmp);
+
+ i = UniSearchStrEx(tmp, L"/CMD ", 0, false);
+
+ if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
+ {
+ i = INFINITE;
+ }
+ if (i == INFINITE)
+ {
+ i = UniSearchStrEx(tmp, L"/CMD\t", 0, false);
+ if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
+ {
+ i = INFINITE;
+ }
+ }
+ if (i == INFINITE)
+ {
+ i = UniSearchStrEx(tmp, L"/CMD:", 0, false);
+ if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
+ {
+ i = INFINITE;
+ }
+ }
+ if (i == INFINITE)
+ {
+ i = UniSearchStrEx(tmp, L"/CMD=", 0, false);
+ if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
+ {
+ i = INFINITE;
+ }
+ }
+ if (i == INFINITE)
+ {
+ i = UniSearchStrEx(tmp, L"-CMD ", 0, false);
+ if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
+ {
+ i = INFINITE;
+ }
+ }
+ if (i == INFINITE)
+ {
+ i = UniSearchStrEx(tmp, L"-CMD\t", 0, false);
+ if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
+ {
+ i = INFINITE;
+ }
+ }
+ if (i == INFINITE)
+ {
+ i = UniSearchStrEx(tmp, L"-CMD:", 0, false);
+ if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
+ {
+ i = INFINITE;
+ }
+ }
+ if (i == INFINITE)
+ {
+ i = UniSearchStrEx(tmp, L"-CMD=", 0, false);
+ if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
+ {
+ i = INFINITE;
+ }
+ }
+
+ if (i != INFINITE)
+ {
+ char *s = CopyStr("CMD");
+ if (InsertStr(o, s) == false)
+ {
+ Free(s);
+ }
+ if (UniStrCmpi(name, L"CMD") == 0)
+ {
+ ret = CopyUniStr(&str[i + 5]);
+ UniTrim(ret);
+ }
+ else
+ {
+ tmp[i] = 0;
+ }
+ }
+
+ if (ret == NULL)
+ {
+ t = UniParseCmdLine(tmp);
+
+ if (t != NULL)
+ {
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ wchar_t *token = t->Token[i];
+
+ if ((token[0] == L'-' && token[1] != L'-') ||
+ (UniStrCmpi(token, L"--help") == 0) ||
+ (token[0] == L'/' && token[1] != L'/'))
+ {
+ UINT i;
+
+ // Named parameter
+ // Examine whether there is a colon character
+
+ if (UniStrCmpi(token, L"--help") == 0)
+ {
+ token++;
+ }
+
+ i = UniSearchStrEx(token, L":", 0, false);
+ if (i == INFINITE)
+ {
+ i = UniSearchStrEx(token, L"=", 0, false);
+ }
+ if (i != INFINITE)
+ {
+ wchar_t *tmp;
+ char *a;
+
+ // There is a colon character
+ tmp = CopyUniStr(token);
+ tmp[i] = 0;
+
+ a = CopyUniToStr(&tmp[1]);
+ if (InsertStr(o, a) == false)
+ {
+ Free(a);
+ }
+
+ if (UniStrCmpi(name, &tmp[1]) == 0)
+ {
+ if (ret == NULL)
+ {
+ // Content
+ ret = UniCopyStr(&token[i + 1]);
+ }
+ }
+
+ Free(tmp);
+ }
+ else
+ {
+ // There is no colon character
+ char *a;
+
+ a = CopyUniToStr(&token[1]);
+ if (InsertStr(o, a) == false)
+ {
+ Free(a);
+ }
+
+ if (UniStrCmpi(name, &token[1]) == 0)
+ {
+ if (ret == NULL)
+ {
+ // Empty character
+ ret = UniCopyStr(L"");
+ }
+ }
+ }
+ }
+ else
+ {
+ // Nameless argument
+ if (name == NULL)
+ {
+ if (ret == NULL)
+ {
+ if (token[0] == L'-' && token[1] == L'-')
+ {
+ ret = UniCopyStr(&token[1]);
+ }
+ else if (token[0] == L'/' && token[1] == L'/')
+ {
+ ret = UniCopyStr(&token[1]);
+ }
+ else
+ {
+ ret = UniCopyStr(token);
+ }
+ }
+ }
+ }
+ }
+
+ UniFreeToken(t);
+ }
+ }
+
+ Free(tmp);
+
+ if (o != NULL)
+ {
+ TOKEN_LIST *t = ZeroMalloc(sizeof(TOKEN_LIST));
+ UINT i;
+
+ t->NumTokens = LIST_NUM(o);
+ t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ t->Token[i] = LIST_DATA(o, i);
+ }
+
+ ReleaseList(o);
+
+ *param_list = t;
+ }
+
+ if (UniStrCmpi(ret, L"none") == 0 || UniStrCmpi(ret, L"null") == 0)
+ {
+ // Null and none are reserved words
+ ret[0] = 0;
+ }
+
+ return ret;
+}
+char *ParseCommandA(wchar_t *str, char *name)
+{
+ wchar_t *tmp1, *tmp2;
+ char *ret;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return NULL;
+ }
+
+ if (name != NULL)
+ {
+ tmp1 = CopyStrToUni(name);
+ }
+ else
+ {
+ tmp1 = NULL;
+ }
+
+ tmp2 = ParseCommand(str, tmp1);
+
+ if (tmp2 == NULL)
+ {
+ ret = NULL;
+ }
+ else
+ {
+ ret = CopyUniToStr(tmp2);
+ Free(tmp2);
+ }
+
+ Free(tmp1);
+
+ return ret;
+}
+
+// Password prompt
+bool PasswordPrompt(char *password, UINT size)
+{
+ UINT wp;
+ bool escape = false;
+ void *console;
+ // Validate arguments
+ if (password == NULL || size <= 1)
+ {
+ if (size >= 1)
+ {
+ password[0] = 0;
+ }
+ return false;
+ }
+
+ wp = 0;
+
+ Zero(password, size);
+
+ console = SetConsoleRaw();
+
+ while (true)
+ {
+ int c;
+
+#ifdef OS_WIN32
+ c = getch();
+#else // OS_WIN32
+ c = getc(stdin);
+#endif // OS_WIN32
+
+ if (c >= 0x20 && c <= 0x7E)
+ {
+ // Character
+ if ((wp + 1) < size)
+ {
+ password[wp++] = (char)c;
+ putc('*', stdout);
+ }
+ }
+ else if (c == 0x03)
+ {
+ // Break
+ exit(0);
+ }
+ else if (c == 0x04 || c == 0x1a || c == 0x0D || c==0x0A)
+ {
+ // Exit
+ if (c == 0x04 || c == 0x1a)
+ {
+ escape = true;
+ }
+ break;
+ }
+ else if (c == 0xE0)
+ {
+ // Read one more character
+ c = getch();
+ if (c == 0x4B || c == 0x53)
+ {
+ // Backspace
+ goto BACKSPACE;
+ }
+ }
+ else if (c == 0x08)
+ {
+BACKSPACE:
+ // Backspace
+ if (wp >= 1)
+ {
+ password[--wp] = 0;
+ putc(0x08, stdout);
+ putc(' ', stdout);
+ putc(0x08, stdout);
+ }
+ }
+ }
+ Print("\n");
+
+ RestoreConsole(console);
+
+ return (escape ? false : true);
+}
+
+// Show the prompt
+wchar_t *Prompt(wchar_t *prompt_str)
+{
+ wchar_t *ret = NULL;
+ wchar_t *tmp = NULL;
+ // Validate arguments
+ if (prompt_str == NULL)
+ {
+ prompt_str = L"";
+ }
+
+#ifdef OS_WIN32
+ UniPrint(L"%s", prompt_str);
+ tmp = Malloc(MAX_PROMPT_STRSIZE);
+ if (fgetws(tmp, MAX_PROMPT_STRSIZE - 1, stdin) != NULL)
+ {
+ bool escape = false;
+ UINT i, len;
+
+ len = UniStrLen(tmp);
+ for (i = 0;i < len;i++)
+ {
+ if (tmp[i] == 0x04 || tmp[i] == 0x1A)
+ {
+ escape = true;
+ break;
+ }
+ }
+
+ if (escape == false)
+ {
+ UniTrimCrlf(tmp);
+
+ ret = UniCopyStr(tmp);
+ }
+ }
+ Free(tmp);
+#else // OS_WIN32
+ {
+ char *prompt = CopyUniToStr(prompt_str);
+ char *s = readline(prompt);
+ Free(prompt);
+
+ if (s != NULL)
+ {
+ TrimCrlf(s);
+ Trim(s);
+
+ if (IsEmptyStr(s) == false)
+ {
+ add_history(s);
+ }
+
+ ret = CopyStrToUni(s);
+
+ free(s);
+ }
+ }
+#endif // OS_WIN32
+
+ if (ret == NULL)
+ {
+ Print("\n");
+ }
+
+ return ret;
+}
+char *PromptA(wchar_t *prompt_str)
+{
+ wchar_t *str = Prompt(prompt_str);
+
+ if (str == NULL)
+ {
+ return NULL;
+ }
+ else
+ {
+ char *ret = CopyUniToStr(str);
+
+ Free(str);
+ return ret;
+ }
+}
+
+// Set the console to raw mode
+void *SetConsoleRaw()
+{
+#ifdef OS_UNIX
+ struct termios t, *ret;
+
+ Zero(&t, sizeof(t));
+ if (tcgetattr(0, &t) != 0)
+ {
+ // Failed
+ return NULL;
+ }
+
+ // Copy the current settings
+ ret = Clone(&t, sizeof(t));
+
+ // Change the settings
+ t.c_lflag &= (~ICANON);
+ t.c_lflag &= (~ECHO);
+ t.c_cc[VTIME] = 0;
+ t.c_cc[VMIN] = 1;
+ tcsetattr(0, TCSANOW, &t);
+
+ return ret;
+#else // OS_UNIX
+ return Malloc(0);
+#endif // OS_UNIX
+}
+
+// Restore the mode of the console
+void RestoreConsole(void *p)
+{
+#ifdef OS_UNIX
+ struct termios *t;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ t = (struct termios *)p;
+
+ // Restore the settings
+ tcsetattr(0, TCSANOW, t);
+
+ Free(t);
+#else // OS_UNIX
+ if (p != NULL)
+ {
+ Free(p);
+ }
+#endif // OS_UNIX
+}
+
+////////////////////////////
+// Local console function
+
+// Creating a new local console
+CONSOLE *NewLocalConsole(wchar_t *infile, wchar_t *outfile)
+{
+ IO *in_io = NULL, *out_io = NULL;
+ CONSOLE *c = ZeroMalloc(sizeof(CONSOLE));
+ LOCAL_CONSOLE_PARAM *p;
+ UINT old_size = 0;
+
+#ifdef OS_WIN32
+ if (MsGetConsoleWidth() == 80)
+ {
+ //old_size = MsSetConsoleWidth(WIN32_DEFAULT_CONSOLE_WIDTH);
+ }
+#endif // OS_WIN32
+
+ c->ConsoleType = CONSOLE_LOCAL;
+ c->Free = ConsoleLocalFree;
+ c->ReadLine = ConsoleLocalReadLine;
+ c->ReadPassword = ConsoleLocalReadPassword;
+ c->Write = ConsoleLocalWrite;
+ c->GetWidth = ConsoleLocalGetWidth;
+
+ if (UniIsEmptyStr(infile) == false)
+ {
+ // Input file is specified
+ in_io = FileOpenW(infile, false);
+ if (in_io == NULL)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), _UU("CON_INFILE_ERROR"), infile);
+ c->Write(c, tmp);
+ Free(c);
+ return NULL;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), _UU("CON_INFILE_START"), infile);
+ c->Write(c, tmp);
+ }
+ }
+
+ if (UniIsEmptyStr(outfile) == false)
+ {
+ // Output file is specified
+ out_io = FileCreateW(outfile);
+ if (out_io == NULL)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), _UU("CON_OUTFILE_ERROR"), outfile);
+ c->Write(c, tmp);
+ Free(c);
+
+ if (in_io != NULL)
+ {
+ FileClose(in_io);
+ }
+ return NULL;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), _UU("CON_OUTFILE_START"), outfile);
+ c->Write(c, tmp);
+ }
+ }
+
+ p = ZeroMalloc(sizeof(LOCAL_CONSOLE_PARAM));
+ c->Param = p;
+
+ p->InFile = in_io;
+ p->OutFile = out_io;
+ p->Win32_OldConsoleWidth = old_size;
+
+ if (in_io != NULL)
+ {
+ UINT size;
+ void *buf;
+
+ size = FileSize(in_io);
+ buf = ZeroMalloc(size + 1);
+ FileRead(in_io, buf, size);
+
+ p->InBuf = NewBuf();
+ WriteBuf(p->InBuf, buf, size);
+ Free(buf);
+
+ p->InBuf->Current = 0;
+ }
+
+ return c;
+}
+
+// Release Console
+void ConsoleLocalFree(CONSOLE *c)
+{
+ LOCAL_CONSOLE_PARAM *p;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ p = (LOCAL_CONSOLE_PARAM *)c->Param;
+
+#ifdef OS_WIN32
+ if (p->Win32_OldConsoleWidth != 0)
+ {
+ MsSetConsoleWidth(p->Win32_OldConsoleWidth);
+ }
+#endif // OS_WIN32
+
+ if (p != NULL)
+ {
+ if (p->InFile != NULL)
+ {
+ FileClose(p->InFile);
+ FreeBuf(p->InBuf);
+ }
+
+ if (p->OutFile != NULL)
+ {
+ FileClose(p->OutFile);
+ }
+
+ Free(p);
+ }
+
+ // Memory release
+ Free(c);
+}
+
+// Get the width of the screen
+UINT ConsoleLocalGetWidth(CONSOLE *c)
+{
+ UINT ret = 0;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return 0;
+ }
+
+#ifdef OS_WIN32
+ ret = MsGetConsoleWidth();
+#else // OS_WIN32
+ {
+ struct winsize t;
+
+ Zero(&t, sizeof(t));
+
+ if (ioctl(1, TIOCGWINSZ, &t) == 0)
+ {
+ ret = t.ws_col;
+ }
+ }
+#endif // OS_WIN32
+
+ return ret;
+}
+
+// Read one line from the console
+wchar_t *ConsoleLocalReadLine(CONSOLE *c, wchar_t *prompt, bool nofile)
+{
+ wchar_t *ret;
+ LOCAL_CONSOLE_PARAM *p;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+ p = (LOCAL_CONSOLE_PARAM *)c->Param;
+ if (prompt == NULL)
+ {
+ prompt = L">";
+ }
+
+ ConsoleWriteOutFile(c, prompt, false);
+
+ if (nofile == false && p->InBuf != NULL)
+ {
+ // Read the next line from the file
+ ret = ConsoleReadNextFromInFile(c);
+
+ if (ret != NULL)
+ {
+ // Display the pseudo prompt
+ UniPrint(L"%s", prompt);
+
+ // Display on the screen
+ UniPrint(L"%s\n", ret);
+ }
+ }
+ else
+ {
+ // Read the following line from the console
+ ret = Prompt(prompt);
+ }
+
+ if (ret != NULL)
+ {
+ ConsoleWriteOutFile(c, ret, true);
+ }
+ else
+ {
+ ConsoleWriteOutFile(c, _UU("CON_USER_CANCEL"), true);
+ }
+
+ return ret;
+}
+
+// Read the password from the console
+char *ConsoleLocalReadPassword(CONSOLE *c, wchar_t *prompt)
+{
+ char tmp[64];
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+ if (prompt == NULL)
+ {
+ prompt = L"Password>";
+ }
+
+ UniPrint(L"%s", prompt);
+ ConsoleWriteOutFile(c, prompt, false);
+
+ if (PasswordPrompt(tmp, sizeof(tmp)))
+ {
+ ConsoleWriteOutFile(c, L"********", true);
+ return CopyStr(tmp);
+ }
+ else
+ {
+ ConsoleWriteOutFile(c, _UU("CON_USER_CANCEL"), true);
+ return NULL;
+ }
+}
+
+// Display a string to the console
+bool ConsoleLocalWrite(CONSOLE *c, wchar_t *str)
+{
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniPrint(L"%s%s", str, (UniEndWith(str, L"\n") ? L"" : L"\n"));
+
+ ConsoleWriteOutFile(c, str, true);
+
+ return true;
+}
+
+// Read the next line from the input file
+wchar_t *ConsoleReadNextFromInFile(CONSOLE *c)
+{
+ LOCAL_CONSOLE_PARAM *p;
+ char *str;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ p = (LOCAL_CONSOLE_PARAM *)c->Param;
+
+ if (p->InBuf == NULL)
+ {
+ return NULL;
+ }
+
+ while (true)
+ {
+ str = CfgReadNextLine(p->InBuf);
+
+ if (str == NULL)
+ {
+ return NULL;
+ }
+
+ Trim(str);
+
+ if (IsEmptyStr(str) == false)
+ {
+ UINT size;
+ wchar_t *ret;
+
+ size = CalcUtf8ToUni((BYTE *)str, StrLen(str));
+ ret = ZeroMalloc(size + 32);
+ Utf8ToUni(ret, size, (BYTE *)str, StrLen(str));
+
+ Free(str);
+
+ return ret;
+ }
+
+ Free(str);
+ }
+}
+
+// Write when the output file is specified
+void ConsoleWriteOutFile(CONSOLE *c, wchar_t *str, bool add_last_crlf)
+{
+ LOCAL_CONSOLE_PARAM *p;
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return;
+ }
+
+ p = (LOCAL_CONSOLE_PARAM *)c->Param;
+
+ if (p != NULL && p->OutFile != NULL)
+ {
+ wchar_t *tmp = UniNormalizeCrlf(str);
+ UINT utf8_size;
+ UCHAR *utf8;
+
+ utf8_size = CalcUniToUtf8(tmp);
+ utf8 = ZeroMalloc(utf8_size + 1);
+ UniToUtf8(utf8, utf8_size + 1, tmp);
+
+ FileWrite(p->OutFile, utf8, utf8_size);
+
+ if (UniEndWith(str, L"\n") == false && add_last_crlf)
+ {
+ char *crlf = "\r\n";
+ FileWrite(p->OutFile, "\r\n", StrLen(crlf));
+ }
+
+ Free(utf8);
+ Free(tmp);
+ }
+
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Console.h b/src/Cedar/Console.h
new file mode 100644
index 00000000..45f111a6
--- /dev/null
+++ b/src/Cedar/Console.h
@@ -0,0 +1,222 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Console.h
+// Header of Console.c
+
+#ifndef CONSOLE_H
+#define CONSOLE_H
+
+// Constant
+#define MAX_PROMPT_STRSIZE 65536
+#define WIN32_DEFAULT_CONSOLE_WIDTH 100
+
+// Types of console
+#define CONSOLE_LOCAL 0 // Local console
+#define CONSOLE_CSV 1 // CSV output mode
+
+// Parameters completion prompt function
+typedef wchar_t *(PROMPT_PROC)(CONSOLE *c, void *param);
+
+// Parameter validation prompt function
+typedef bool (EVAL_PROC)(CONSOLE *c, wchar_t *str, void *param);
+
+// Definition of the parameter item
+struct PARAM
+{
+ char *Name; // Parameter name
+ PROMPT_PROC *PromptProc; // Prompt function that automatically invoked if the parameter is not specified
+ // (This is not called in the case of NULL)
+ void *PromptProcParam; // Any pointers to pass to the prompt function
+ EVAL_PROC *EvalProc; // Parameter string validation function
+ void *EvalProcParam; // Any pointers to be passed to the validation function
+ char *Tmp; // Temporary variable
+};
+
+// Parameter value of the internal data
+struct PARAM_VALUE
+{
+ char *Name; // Name
+ char *StrValue; // String value
+ wchar_t *UniStrValue; // Unicode string value
+ UINT IntValue; // Integer value
+};
+
+// Console service structure
+struct CONSOLE
+{
+ UINT ConsoleType; // Type of console
+ UINT RetCode; // The last exit code
+ void *Param; // Data of any
+ void (*Free)(CONSOLE *c); // Release function
+ wchar_t *(*ReadLine)(CONSOLE *c, wchar_t *prompt, bool nofile); // Function to read one line
+ char *(*ReadPassword)(CONSOLE *c, wchar_t *prompt); // Function to read the password
+ bool (*Write)(CONSOLE *c, wchar_t *str); // Function to write a string
+ UINT (*GetWidth)(CONSOLE *c); // Get the width of the screen
+};
+
+// Local console parameters
+struct LOCAL_CONSOLE_PARAM
+{
+ IO *InFile; // Input file
+ BUF *InBuf; // Input buffer
+ IO *OutFile; // Output file
+ UINT Win32_OldConsoleWidth; // Previous console size
+};
+
+// Command procedure
+typedef UINT (COMMAND_PROC)(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+
+// Definition of command
+struct CMD
+{
+ char *Name; // Command name
+ COMMAND_PROC *Proc; // Procedure function
+};
+
+// Evaluate the minimum / maximum value of the parameter
+struct CMD_EVAL_MIN_MAX
+{
+ char *StrName;
+ UINT MinValue, MaxValue;
+};
+
+
+// Function prototype
+wchar_t *Prompt(wchar_t *prompt_str);
+char *PromptA(wchar_t *prompt_str);
+bool PasswordPrompt(char *password, UINT size);
+void *SetConsoleRaw();
+void RestoreConsole(void *p);
+wchar_t *ParseCommandEx(wchar_t *str, wchar_t *name, TOKEN_LIST **param_list);
+wchar_t *ParseCommand(wchar_t *str, wchar_t *name);
+TOKEN_LIST *GetCommandNameList(wchar_t *str);
+char *ParseCommandA(wchar_t *str, char *name);
+LIST *NewParamValueList();
+int CmpParamValue(void *p1, void *p2);
+void FreeParamValueList(LIST *o);
+PARAM_VALUE *FindParamValue(LIST *o, char *name);
+char *GetParamStr(LIST *o, char *name);
+wchar_t *GetParamUniStr(LIST *o, char *name);
+UINT GetParamInt(LIST *o, char *name);
+bool GetParamYes(LIST *o, char *name);
+LIST *ParseCommandList(CONSOLE *c, char *cmd_name, wchar_t *command, PARAM param[], UINT num_param);
+bool IsNameInRealName(char *input_name, char *real_name);
+void GetOmissionName(char *dst, UINT size, char *src);
+bool IsOmissionName(char *input_name, char *real_name);
+TOKEN_LIST *GetRealnameCandidate(char *input_name, TOKEN_LIST *real_name_list);
+bool SeparateCommandAndParam(wchar_t *src, char **cmd, wchar_t **param);
+UINT GetConsoleWidth(CONSOLE *c);
+bool DispatchNextCmd(CONSOLE *c, char *prompt, CMD cmd[], UINT num_cmd, void *param);
+bool DispatchNextCmdEx(CONSOLE *c, wchar_t *exec_command, char *prompt, CMD cmd[], UINT num_cmd, void *param);
+void PrintCandidateHelp(CONSOLE *c, char *cmd_name, TOKEN_LIST *candidate_list, UINT left_space);
+UNI_TOKEN_LIST *SeparateStringByWidth(wchar_t *str, UINT width);
+UINT GetNextWordWidth(wchar_t *str);
+bool IsWordChar(wchar_t c);
+void GetCommandHelpStr(char *command_name, wchar_t **description, wchar_t **args, wchar_t **help);
+void GetCommandParamHelpStr(char *command_name, char *param_name, wchar_t **description);
+bool CmdEvalMinMax(CONSOLE *c, wchar_t *str, void *param);
+wchar_t *CmdPrompt(CONSOLE *c, void *param);
+bool CmdEvalNotEmpty(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalInt1(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalIsFile(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalSafe(CONSOLE *c, wchar_t *str, void *param);
+void PrintCmdHelp(CONSOLE *c, char *cmd_name, TOKEN_LIST *param_list);
+int CompareCandidateStr(void *p1, void *p2);
+bool IsHelpStr(char *str);
+
+CONSOLE *NewLocalConsole(wchar_t *infile, wchar_t *outfile);
+void ConsoleLocalFree(CONSOLE *c);
+wchar_t *ConsoleLocalReadLine(CONSOLE *c, wchar_t *prompt, bool nofile);
+char *ConsoleLocalReadPassword(CONSOLE *c, wchar_t *prompt);
+bool ConsoleLocalWrite(CONSOLE *c, wchar_t *str);
+void ConsoleWriteOutFile(CONSOLE *c, wchar_t *str, bool add_last_crlf);
+wchar_t *ConsoleReadNextFromInFile(CONSOLE *c);
+UINT ConsoleLocalGetWidth(CONSOLE *c);
+
+
+#endif // CONSOLE_H
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/DDNS.c b/src/Cedar/DDNS.c
new file mode 100644
index 00000000..a74bb7a3
--- /dev/null
+++ b/src/Cedar/DDNS.c
@@ -0,0 +1,984 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// DDNS.c
+// Dynamic DNS Client
+
+#include "CedarPch.h"
+
+// Get the current status of the DDNS client
+void DCGetStatus(DDNS_CLIENT *c, DDNS_CLIENT_STATUS *st)
+{
+ // Validate arguments
+ if (c == NULL || st == NULL)
+ {
+ return;
+ }
+
+ Zero(st, sizeof(DDNS_CLIENT_STATUS));
+
+ Lock(c->Lock);
+ {
+ st->Err_IPv4 = c->Err_IPv4;
+ st->Err_IPv6 = c->Err_IPv6;
+
+ StrCpy(st->CurrentHostName, sizeof(st->CurrentHostName), c->CurrentHostName);
+ StrCpy(st->CurrentFqdn, sizeof(st->CurrentFqdn), c->CurrentFqdn);
+ StrCpy(st->DnsSuffix, sizeof(st->DnsSuffix), c->DnsSuffix);
+ StrCpy(st->CurrentIPv4, sizeof(st->CurrentIPv4), c->CurrentIPv4);
+ StrCpy(st->CurrentIPv6, sizeof(st->CurrentIPv6), c->CurrentIPv6);
+
+ StrCpy(st->CurrentAzureIp, sizeof(st->CurrentAzureIp), c->CurrentAzureIp);
+ st->CurrentAzureTimestamp = c->CurrentAzureTimestamp;
+ StrCpy(st->CurrentAzureSignature, sizeof(st->CurrentAzureSignature), c->CurrentAzureSignature);
+ StrCpy(st->AzureCertHash, sizeof(st->AzureCertHash), c->AzureCertHash);
+
+ Copy(&st->InternetSetting, &c->InternetSetting, sizeof(INTERNET_SETTING));
+ }
+ Unlock(c->Lock);
+}
+
+// Set the Internet settings
+void DCSetInternetSetting(DDNS_CLIENT *c, INTERNET_SETTING *t)
+{
+ // Validate arguments
+ if (c == NULL || t == NULL)
+ {
+ return;
+ }
+
+ Copy(&c->InternetSetting, t, sizeof(INTERNET_SETTING));
+}
+
+// Get the Internet settings
+void DCGetInternetSetting(DDNS_CLIENT *c, INTERNET_SETTING *t)
+{
+ // Validate arguments
+ if (c == NULL || t == NULL)
+ {
+ return;
+ }
+
+ Copy(t, &c->InternetSetting, sizeof(INTERNET_SETTING));
+}
+
+// Changing the host name
+UINT DCChangeHostName(DDNS_CLIENT *c, char *hostname)
+{
+ UINT ret;
+ DDNS_REGISTER_PARAM p;
+ // Validate arguments
+ if (c == NULL || hostname == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ if (StrLen(hostname) > 32)
+ {
+ // The host name is too long
+ return ERR_DDNS_HOSTNAME_TOO_LONG;
+ }
+
+ Zero(&p, sizeof(p));
+
+ StrCpy(p.NewHostname, sizeof(p.NewHostname), hostname);
+
+ // Use one of IPv4 or IPv6 if it seems to be communication
+ if (c->Err_IPv4 == ERR_NO_ERROR)
+ {
+ // IPv4
+ ret = DCRegister(c, false, &p, NULL);
+ }
+ else if (c->Err_IPv6 == ERR_NO_ERROR)
+ {
+ // IPv6
+ ret = DCRegister(c, true, &p, NULL);
+ }
+ else
+ {
+ // Try both
+ ret = DCRegister(c, true, &p, NULL);
+ if (ret != ERR_NO_ERROR)
+ {
+ ret = DCRegister(c, false, &p, NULL);
+ }
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ DDNS_CLIENT_STATUS st;
+
+ DCGetStatus(c, &st);
+
+ SiApplyAzureConfig(c->Cedar->Server, &st);
+ }
+
+ return ret;
+}
+
+// DDNS client thread
+void DCThread(THREAD *thread, void *param)
+{
+ DDNS_CLIENT *c;
+ INTERRUPT_MANAGER *interrput;
+ UINT last_ip_hash = 0;
+ void *route_change_poller = NULL;
+ bool last_time_ip_changed = false;
+ UINT last_azure_ddns_trigger_int = 0;
+ UINT last_vgs_ddns_trigger_int = 0;
+ UINT n;
+ INTERNET_SETTING last_t;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ c = (DDNS_CLIENT *)param;
+
+ interrput = NewInterruptManager();
+
+ route_change_poller = NewRouteChange();
+ IsRouteChanged(route_change_poller);
+
+ Zero(&last_t, sizeof(last_t));
+
+ n = 0;
+
+ while (c->Halt == false)
+ {
+ UINT ip_hash = GetHostIPAddressHash32();
+ UINT interval;
+ UINT64 now = Tick64();
+ bool ip_changed = false;
+ bool azure_client_triggered = false;
+ bool internet_setting_changed = false;
+ bool vgs_server_triggered = false;
+
+
+ if (c->Cedar->Server != NULL && c->Cedar->Server->AzureClient != NULL)
+ {
+ if (c->Cedar->Server->AzureClient->DDnsTriggerInt != last_azure_ddns_trigger_int)
+ {
+ azure_client_triggered = true;
+ last_azure_ddns_trigger_int = c->Cedar->Server->AzureClient->DDnsTriggerInt;
+ last_time_ip_changed = false;
+ Debug("DDNS Thread Triggered by AzureClient.\n");
+ }
+ }
+
+ if (Cmp(&last_t, &c->InternetSetting, sizeof(INTERNET_SETTING)) != 0)
+ {
+ Copy(&last_t, &c->InternetSetting, sizeof(INTERNET_SETTING));
+ internet_setting_changed = true;
+ last_time_ip_changed = false;
+ }
+
+ if (ip_hash != last_ip_hash)
+ {
+ last_time_ip_changed = false;
+ Debug("DDNS Thread Triggered by IP Hash Changed.\n");
+ }
+
+ if ((ip_hash != last_ip_hash) || (IsRouteChanged(route_change_poller)) || azure_client_triggered || internet_setting_changed || vgs_server_triggered)
+ {
+ if (last_time_ip_changed == false)
+ {
+ // Call all getting functions from the beginning if the routing
+ // table or the IP address of this host has changed
+ c->NextRegisterTick_IPv4 = 0;
+ c->NextRegisterTick_IPv6 = 0;
+ c->NextGetMyIpTick_IPv4 = 0;
+ c->NextGetMyIpTick_IPv6 = 0;
+
+ last_ip_hash = ip_hash;
+
+ last_time_ip_changed = true;
+
+ ip_changed = true;
+
+ Debug("DDNS Internet Condition Changed.\n");
+ }
+ }
+ else
+ {
+ last_time_ip_changed = false;
+ }
+
+ if ((n++) >= 1)
+ {
+ // Self IPv4 address acquisition
+ if (c->NextGetMyIpTick_IPv4 == 0 || now >= c->NextGetMyIpTick_IPv4)
+ {
+ UINT next_interval;
+ char ip[MAX_SIZE];
+
+ Zero(ip, sizeof(ip));
+ c->Err_IPv4_GetMyIp = DCGetMyIp(c, false, ip, sizeof(ip), NULL);
+
+ if (c->Err_IPv4_GetMyIp == ERR_NO_ERROR)
+ {
+ if (StrCmpi(c->LastMyIPv4, ip) != 0)
+ {
+ ip_changed = true;
+ StrCpy(c->LastMyIPv4, sizeof(c->LastMyIPv4), ip);
+ }
+
+ next_interval = GenRandInterval(DDNS_GETMYIP_INTERVAL_OK_MIN, DDNS_GETMYIP_INTERVAL_OK_MAX);
+ }
+ else
+ {
+ if (IsEmptyStr(c->LastMyIPv4) == false)
+ {
+ ip_changed = true;
+ }
+
+ Zero(c->LastMyIPv4, sizeof(c->LastMyIPv4));
+ next_interval = GenRandInterval(DDNS_GETMYIP_INTERVAL_NG_MIN, DDNS_GETMYIP_INTERVAL_NG_MAX);
+ }
+
+ c->NextGetMyIpTick_IPv4 = Tick64() + (UINT64)next_interval;
+
+ AddInterrupt(interrput, c->NextGetMyIpTick_IPv4);
+ }
+
+ // Self IPv6 address acquisition
+ if (c->NextGetMyIpTick_IPv6 == 0 || now >= c->NextGetMyIpTick_IPv6)
+ {
+ UINT next_interval;
+ char ip[MAX_SIZE];
+
+ Zero(ip, sizeof(ip));
+ c->Err_IPv6_GetMyIp = DCGetMyIp(c, true, ip, sizeof(ip), NULL);
+
+ if (c->Err_IPv6_GetMyIp == ERR_NO_ERROR)
+ {
+ if (StrCmpi(c->LastMyIPv6, ip) != 0)
+ {
+ ip_changed = true;
+ StrCpy(c->LastMyIPv6, sizeof(c->LastMyIPv6), ip);
+ }
+
+ next_interval = GenRandInterval(DDNS_GETMYIP_INTERVAL_OK_MIN, DDNS_GETMYIP_INTERVAL_OK_MAX);
+ }
+ else
+ {
+ if (IsEmptyStr(c->LastMyIPv6) == false)
+ {
+ ip_changed = true;
+ }
+
+ Zero(c->LastMyIPv6, sizeof(c->LastMyIPv6));
+ next_interval = GenRandInterval(DDNS_GETMYIP_INTERVAL_NG_MIN, DDNS_GETMYIP_INTERVAL_NG_MAX);
+ }
+
+ c->NextGetMyIpTick_IPv6 = Tick64() + (UINT64)next_interval;
+
+ AddInterrupt(interrput, c->NextGetMyIpTick_IPv6);
+ }
+ }
+
+ if (ip_changed)
+ {
+ c->NextRegisterTick_IPv4 = 0;
+ c->NextRegisterTick_IPv6 = 0;
+ }
+
+ // IPv4 host registration
+ if (c->NextRegisterTick_IPv4 == 0 || now >= c->NextRegisterTick_IPv4)
+ {
+ UINT next_interval;
+
+ c->Err_IPv4 = DCRegister(c, false, NULL, NULL);
+
+ if (c->Err_IPv4 == ERR_NO_ERROR)
+ {
+ next_interval = GenRandInterval(DDNS_REGISTER_INTERVAL_OK_MIN, DDNS_REGISTER_INTERVAL_OK_MAX);
+ }
+ else
+ {
+ next_interval = GenRandInterval(DDNS_REGISTER_INTERVAL_NG_MIN, DDNS_REGISTER_INTERVAL_NG_MAX);
+ }
+ //next_interval = 0;
+
+ c->NextRegisterTick_IPv4 = Tick64() + (UINT64)next_interval;
+
+ if (true)
+ {
+ DDNS_CLIENT_STATUS st;
+
+ DCGetStatus(c, &st);
+
+ SiApplyAzureConfig(c->Cedar->Server, &st);
+ }
+
+ AddInterrupt(interrput, c->NextRegisterTick_IPv4);
+ }
+
+ if (c->Halt)
+ {
+ break;
+ }
+
+ // IPv6 host registration
+ if (c->NextRegisterTick_IPv6 == 0 || now >= c->NextRegisterTick_IPv6)
+ {
+ UINT next_interval;
+
+ c->Err_IPv6 = DCRegister(c, true, NULL, NULL);
+
+ if (c->Err_IPv6 == ERR_NO_ERROR)
+ {
+ next_interval = GenRandInterval(DDNS_REGISTER_INTERVAL_OK_MIN, DDNS_REGISTER_INTERVAL_OK_MAX);
+ }
+ else
+ {
+ next_interval = GenRandInterval(DDNS_REGISTER_INTERVAL_NG_MIN, DDNS_REGISTER_INTERVAL_NG_MAX);
+ }
+
+ c->NextRegisterTick_IPv6 = Tick64() + (UINT64)next_interval;
+
+ if (true)
+ {
+ DDNS_CLIENT_STATUS st;
+
+ DCGetStatus(c, &st);
+
+ SiApplyAzureConfig(c->Cedar->Server, &st);
+ }
+
+ AddInterrupt(interrput, c->NextRegisterTick_IPv6);
+ }
+
+ interval = GetNextIntervalForInterrupt(interrput);
+ interval = MIN(interval, 1234);
+
+ if (n == 1)
+ {
+ interval = MIN(interval, 0);
+ }
+
+ if (c->Halt)
+ {
+ break;
+ }
+
+ if (c->KeyChanged)
+ {
+ c->KeyChanged = false;
+ c->NextRegisterTick_IPv4 = c->NextRegisterTick_IPv6 = 0;
+
+ interval = 0;
+ }
+
+ if (last_time_ip_changed)
+ {
+ if (c->Cedar->Server != NULL && c->Cedar->Server->AzureClient != NULL)
+ {
+ c->Cedar->Server->AzureClient->IpStatusRevision++;
+ }
+ }
+
+ Wait(c->Event, interval);
+ }
+
+ FreeRouteChange(route_change_poller);
+ FreeInterruptManager(interrput);
+}
+
+// Command to update immediately
+void DCUpdateNow(DDNS_CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->NextRegisterTick_IPv4 = c->NextRegisterTick_IPv6 = 0;
+
+ Set(c->Event);
+}
+
+// Execution of registration
+UINT DCRegister(DDNS_CLIENT *c, bool ipv6, DDNS_REGISTER_PARAM *p, char *replace_v6)
+{
+ char *url;
+ char url2[MAX_SIZE];
+ char url3[MAX_SIZE];
+ PACK *req, *ret;
+ char key_str[MAX_SIZE];
+ UCHAR machine_key[SHA1_SIZE];
+ char machine_key_str[MAX_SIZE];
+ char machine_name[MAX_SIZE];
+ BUF *cert_hash;
+ UINT err = ERR_INTERNAL_ERROR;
+ UCHAR key_hash[SHA1_SIZE];
+ char key_hash_str[MAX_SIZE];
+ bool use_azure = false;
+ char current_azure_ip[MAX_SIZE];
+ INTERNET_SETTING t;
+ UINT build = 0;
+ bool use_https = false;
+ bool use_vgs = false;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ Zero(current_azure_ip, sizeof(current_azure_ip));
+
+ GetCurrentMachineIpProcessHash(machine_key);
+ BinToStr(machine_key_str, sizeof(machine_key_str), machine_key, sizeof(machine_key));
+
+ GetMachineHostName(machine_name, sizeof(machine_name));
+ StrLower(machine_name);
+
+ if (ipv6 == false)
+ {
+ url = DDNS_URL_V4_GLOBAL;
+
+ if (IsUseAlternativeHostname())
+ {
+ url = DDNS_URL_V4_ALT;
+ }
+ }
+ else
+ {
+ url = DDNS_URL_V6_GLOBAL;
+
+ if (IsUseAlternativeHostname())
+ {
+ url = DDNS_URL_V6_ALT;
+ }
+
+ if (replace_v6)
+ {
+ url = replace_v6;
+ }
+ }
+
+ Zero(&t, sizeof(t));
+ if (ipv6 == false)
+ {
+ // Proxy Setting
+ Copy(&t, &c->InternetSetting, sizeof(INTERNET_SETTING));
+ }
+
+ if (ipv6 == false)
+ {
+ // Get the current status of the VPN Azure Client
+ if (c->Cedar->Server != NULL)
+ {
+ AZURE_CLIENT *ac = c->Cedar->Server->AzureClient;
+
+ if (ac != NULL)
+ {
+ use_azure = SiIsAzureEnabled(c->Cedar->Server);
+
+ if (use_azure)
+ {
+ Lock(ac->Lock);
+ {
+ StrCpy(current_azure_ip, sizeof(current_azure_ip), ac->ConnectingAzureIp);
+ }
+ Unlock(ac->Lock);
+ }
+ }
+ }
+ }
+
+ req = NewPack();
+ BinToStr(key_str, sizeof(key_str), c->Key, sizeof(c->Key));
+ StrUpper(key_str);
+ PackAddStr(req, "key", key_str);
+
+ // Build Number
+ build = c->Cedar->Build;
+
+
+ PackAddInt(req, "build", build);
+ PackAddInt(req, "osinfo", GetOsInfo()->OsType);
+ PackAddInt(req, "is_64bit", Is64());
+#ifdef OS_WIN32
+ PackAddInt(req, "is_windows_64bit", MsIs64BitWindows());
+#endif // OS_WIN32
+ PackAddBool(req, "is_softether", true);
+ PackAddBool(req, "is_packetix", false);
+ PackAddStr(req, "machine_key", machine_key_str);
+ PackAddStr(req, "machine_name", machine_name);
+ PackAddInt(req, "lasterror_ipv4", c->Err_IPv4_GetMyIp);
+ PackAddInt(req, "lasterror_ipv6", c->Err_IPv6_GetMyIp);
+ PackAddBool(req, "use_azure", use_azure);
+ PackAddStr(req, "product_str", CEDAR_PRODUCT_STR);
+ PackAddInt(req, "ddns_protocol_version", DDNS_VERSION);
+
+
+ if (use_azure)
+ {
+ Debug("current_azure_ip = %s\n", current_azure_ip);
+ PackAddStr(req, "current_azure_ip", current_azure_ip);
+ }
+
+ HashSha1(key_hash, key_str, StrLen(key_str));
+ BinToStr(key_hash_str, sizeof(key_hash_str), key_hash, sizeof(key_hash));
+ StrLower(key_hash_str);
+
+ if (p != NULL)
+ {
+ if (IsEmptyStr(p->NewHostname) == false)
+ {
+ PackAddStr(req, "new_hostname", p->NewHostname);
+ }
+ }
+
+
+
+ cert_hash = StrToBin(DDNS_CERT_HASH);
+
+ Format(url2, sizeof(url2), "%s?v=%I64u", url, Rand64());
+ Format(url3, sizeof(url3), url2, key_hash_str[0], key_hash_str[1], key_hash_str[2], key_hash_str[3]);
+
+ if (use_https == false)
+ {
+ ReplaceStr(url3, sizeof(url3), url3, "https://", "http://");
+ }
+
+ ReplaceStr(url3, sizeof(url3), url3, ".servers", ".open.servers");
+
+ Debug("WpcCall: %s\n", url3);
+ ret = WpcCallEx(url3, &t, DDNS_CONNECT_TIMEOUT, DDNS_COMM_TIMEOUT, "register", req,
+ NULL, NULL, ((cert_hash != NULL && cert_hash->Size == SHA1_SIZE) ? cert_hash->Buf : NULL), NULL, DDNS_RPC_MAX_RECV_SIZE);
+ Debug("WpcCall Ret: %u\n", ret);
+
+ FreeBuf(cert_hash);
+
+ FreePack(req);
+
+ err = GetErrorFromPack(ret);
+
+ ExtractAndApplyDynList(ret);
+
+ // Status update
+ Lock(c->Lock);
+ {
+ if (err == ERR_NO_ERROR)
+ {
+ char snat_t[MAX_SIZE];
+
+ // Current host name
+ PackGetStr(ret, "current_hostname", c->CurrentHostName, sizeof(c->CurrentHostName));
+ PackGetStr(ret, "current_fqdn", c->CurrentFqdn, sizeof(c->CurrentFqdn));
+ PackGetStr(ret, "current_ipv4", c->CurrentIPv4, sizeof(c->CurrentIPv4));
+ PackGetStr(ret, "current_ipv6", c->CurrentIPv6, sizeof(c->CurrentIPv6));
+ PackGetStr(ret, "dns_suffix", c->DnsSuffix, sizeof(c->DnsSuffix));
+
+ // SecureNAT connectivity check parameters
+ Zero(snat_t, sizeof(snat_t));
+ PackGetStr(ret, "snat_t", snat_t, sizeof(snat_t));
+ NnSetSecureNatTargetHostname(snat_t);
+
+ if (ipv6 == false)
+ {
+ char cert_hash[MAX_SIZE];
+
+ PackGetStr(ret, "current_azure_ip", c->CurrentAzureIp, sizeof(c->CurrentAzureIp));
+ c->CurrentAzureTimestamp = PackGetInt64(ret, "current_azure_timestamp");
+ PackGetStr(ret, "current_azure_signature", c->CurrentAzureSignature, sizeof(c->CurrentAzureSignature));
+
+ Zero(cert_hash, sizeof(cert_hash));
+ PackGetStr(ret, "azure_cert_hash", cert_hash, sizeof(cert_hash));
+
+ if (IsEmptyStr(cert_hash) == false)
+ {
+ StrCpy(c->AzureCertHash, sizeof(c->AzureCertHash), cert_hash);
+ }
+ }
+
+ StrCpy(c->Cedar->CurrentDDnsFqdn, sizeof(c->Cedar->CurrentDDnsFqdn), c->CurrentFqdn);
+
+ Debug("current_hostname=%s, current_fqdn=%s, current_ipv4=%s, current_ipv6=%s, current_azure_ip=%s, CurrentAzureTimestamp=%I64u, CurrentAzureSignature=%s, CertHash=%s\n",
+ c->CurrentHostName, c->CurrentFqdn,
+ c->CurrentIPv4, c->CurrentIPv6,
+ c->CurrentAzureIp, c->CurrentAzureTimestamp, c->CurrentAzureSignature, c->AzureCertHash);
+ }
+ }
+ Unlock(c->Lock);
+
+ if (IsEmptyStr(c->CurrentFqdn) == false)
+ {
+ SetCurrentDDnsFqdn(c->CurrentFqdn);
+ }
+
+
+ FreePack(ret);
+
+ UniDebug(L"DCRegister Error: %s\n", _E(err));
+
+ if (err == ERR_DUPLICATE_DDNS_KEY)
+ {
+ // Key duplication
+ DCGenNewKey(c->Key);
+ c->KeyChanged = true;
+ }
+
+ if (err == ERR_DISCONNECTED)
+ {
+ err = ERR_DDNS_DISCONNECTED;
+ }
+
+ if (IsUseAlternativeHostname() == false)
+ {
+ if (err == ERR_CONNECT_FAILED)
+ {
+ if (ipv6 && replace_v6 == NULL)
+ {
+ UINT type = DetectFletsType();
+
+ if (type & FLETS_DETECT_TYPE_EAST_BFLETS_PRIVATE && err != ERR_NO_ERROR)
+ {
+ err = DCRegister(c, ipv6, p, DDNS_REPLACE_URL_FOR_EAST_BFLETS);
+ }
+
+ if (type & FLETS_DETECT_TYPE_EAST_NGN_PRIVATE && err != ERR_NO_ERROR)
+ {
+ err = DCRegister(c, ipv6, p, DDNS_REPLACE_URL_FOR_EAST_NGN);
+ }
+
+ if (type & FLETS_DETECT_TYPE_WEST_NGN_PRIVATE && err != ERR_NO_ERROR)
+ {
+ err = DCRegister(c, ipv6, p, DDNS_REPLACE_URL_FOR_WEST_NGN);
+ }
+ }
+ }
+ }
+
+ return err;
+}
+
+// Get the self IP address
+UINT DCGetMyIp(DDNS_CLIENT *c, bool ipv6, char *dst, UINT dst_size, char *replace_v6)
+{
+ UINT ret = ERR_INTERNAL_ERROR;
+
+ ret = DCGetMyIpMain(c, ipv6, dst, dst_size, false, replace_v6);
+
+
+ if (ret == ERR_NO_ERROR)
+ {
+ IP ip;
+
+ if (StrToIP(&ip, dst))
+ {
+ if (ipv6 == false && IsIP4(&ip))
+ {
+ SetCurrentGlobalIP(&ip, false);
+ }
+ else if (ipv6 && IsIP6(&ip))
+ {
+ SetCurrentGlobalIP(&ip, true);
+ }
+ }
+ }
+
+ return ret;
+}
+UINT DCGetMyIpMain(DDNS_CLIENT *c, bool ipv6, char *dst, UINT dst_size, bool use_ssl, char *replace_v6)
+{
+ char *url;
+ char url2[MAX_SIZE];
+ UINT ret = ERR_INTERNAL_ERROR;
+ URL_DATA data;
+ BUF *recv;
+ BUF *cert_hash;
+ // Validate arguments
+ if (dst == NULL || c == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ if (ipv6 == false)
+ {
+ url = DDNS_URL2_V4_GLOBAL;
+
+ if (IsUseAlternativeHostname())
+ {
+ url = DDNS_URL2_V4_ALT;
+ }
+ }
+ else
+ {
+ url = DDNS_URL2_V6_GLOBAL;
+
+ if (IsUseAlternativeHostname())
+ {
+ url = DDNS_URL2_V6_ALT;
+ }
+
+ if (replace_v6)
+ {
+ url = replace_v6;
+ }
+ }
+
+ Format(url2, sizeof(url2), "%s?v=%I64u", url, Rand64());
+
+ if (use_ssl)
+ {
+ ReplaceStr(url2, sizeof(url2), url2, "http://", "https://");
+ }
+
+ if (ParseUrl(&data, url2, false, NULL) == false)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ cert_hash = StrToBin(DDNS_CERT_HASH);
+
+ recv = HttpRequest(&data, (ipv6 ? NULL : &c->InternetSetting), DDNS_CONNECT_TIMEOUT, DDNS_COMM_TIMEOUT, &ret, false, NULL, NULL,
+ NULL, ((cert_hash != NULL && cert_hash->Size == SHA1_SIZE) ? cert_hash->Buf : NULL));
+
+ FreeBuf(cert_hash);
+
+ if (recv != NULL)
+ {
+ char *str = ZeroMalloc(recv->Size + 1);
+ Copy(str, recv->Buf, recv->Size);
+
+ if (StartWith(str, "IP=") == false)
+ {
+ ret = ERR_PROTOCOL_ERROR;
+ }
+ else
+ {
+ StrCpy(dst, dst_size, str + 3);
+ ret = ERR_NO_ERROR;
+ }
+
+ Free(str);
+ FreeBuf(recv);
+ }
+
+ if (IsUseAlternativeHostname() == false)
+ {
+ if (ret == ERR_CONNECT_FAILED)
+ {
+ if (ipv6 && replace_v6 == NULL && use_ssl == false)
+ {
+ UINT type = DetectFletsType();
+
+ if (type & FLETS_DETECT_TYPE_EAST_BFLETS_PRIVATE && ret != ERR_NO_ERROR)
+ {
+ ret = DCGetMyIpMain(c, ipv6, dst, dst_size, use_ssl, DDNS_REPLACE_URL2_FOR_EAST_BFLETS);
+ }
+
+ if (type & FLETS_DETECT_TYPE_EAST_NGN_PRIVATE && ret != ERR_NO_ERROR)
+ {
+ ret = DCGetMyIpMain(c, ipv6, dst, dst_size, use_ssl, DDNS_REPLACE_URL2_FOR_EAST_NGN);
+ }
+
+ if (type & FLETS_DETECT_TYPE_WEST_NGN_PRIVATE && ret != ERR_NO_ERROR)
+ {
+ ret = DCGetMyIpMain(c, ipv6, dst, dst_size, use_ssl, DDNS_REPLACE_URL2_FOR_WEST_NGN);
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+// Creating a DDNS client
+DDNS_CLIENT *NewDDNSClient(CEDAR *cedar, UCHAR *key, INTERNET_SETTING *t)
+{
+ DDNS_CLIENT *c;
+ UCHAR key_hash[SHA1_SIZE];
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ c = ZeroMalloc(sizeof(DDNS_CLIENT));
+ c->Cedar = cedar;
+ AddRef(c->Cedar->ref);
+
+ c->Err_IPv4 = c->Err_IPv6 = ERR_TRYING_TO_CONNECT;
+
+ if (key == NULL)
+ {
+ // Create a new key
+ DCGenNewKey(c->Key);
+ }
+ else
+ {
+ // Set the key
+ Copy(c->Key, key, SHA1_SIZE);
+ }
+
+ HashSha1(key_hash, c->Key, sizeof(c->Key));
+
+
+ if (t != NULL)
+ {
+ Copy(&c->InternetSetting, t, sizeof(INTERNET_SETTING));
+ }
+
+ c->Lock = NewLock();
+
+ // Thread creation
+ c->Event = NewEvent();
+ c->Thread = NewThread(DCThread, c);
+
+ return c;
+}
+
+// Release of DDNS client
+void FreeDDNSClient(DDNS_CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Stop the thread
+ c->Halt = true;
+ Set(c->Event);
+
+ WaitThread(c->Thread, INFINITE);
+ ReleaseThread(c->Thread);
+
+ ReleaseEvent(c->Event);
+
+ ReleaseCedar(c->Cedar);
+ DeleteLock(c->Lock);
+
+ Free(c);
+}
+
+// Create a new key
+void DCGenNewKey(UCHAR *key)
+{
+ BUF *b;
+ UINT64 tick;
+ UCHAR hash[SHA1_SIZE];
+ UCHAR rand[SHA1_SIZE];
+ UINT i;
+ // Validate arguments
+ if (key == NULL)
+ {
+ return;
+ }
+
+ b = NewBuf();
+
+ Rand(rand, sizeof(rand));
+ WriteBuf(b, rand, sizeof(rand));
+
+ tick = TickHighres64();
+ WriteBufInt64(b, tick);
+
+ tick = Tick64();
+ WriteBufInt64(b, tick);
+
+ tick = SystemTime64();
+ WriteBufInt64(b, tick);
+
+ GetCurrentMachineIpProcessHash(hash);
+ WriteBuf(b, hash, sizeof(hash));
+
+ HashSha1(key, b->Buf, b->Size);
+ Rand(rand, sizeof(rand));
+
+ for (i = 0;i < SHA1_SIZE;i++)
+ {
+ key[i] = key[i] ^ rand[i];
+ }
+
+ FreeBuf(b);
+}
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/DDNS.h b/src/Cedar/DDNS.h
new file mode 100644
index 00000000..a2c05761
--- /dev/null
+++ b/src/Cedar/DDNS.h
@@ -0,0 +1,215 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// DDNS.h
+// Header of DDNS.c
+
+#ifndef DDNS_H
+#define DDNS_H
+
+// Certificate hash
+#define DDNS_CERT_HASH "EFAC5FA0CDD14E0F864EED58A73C35D7E33B62F3"
+
+// Destination URL
+#define DDNS_URL_V4_GLOBAL "https://x%c.x%c.x%c.x%c.servers.ddns.softether-network.net/ddns/ddns.aspx"
+#define DDNS_URL_V6_GLOBAL "https://x%c.x%c.x%c.x%c.servers-v6.ddns.softether-network.net/ddns/ddns.aspx"
+#define DDNS_URL2_V4_GLOBAL "http://get-my-ip.ddns.softether-network.net/ddns/getmyip.ashx"
+#define DDNS_URL2_V6_GLOBAL "http://get-my-ip-v6.ddns.softether-network.net/ddns/getmyip.ashx"
+
+#define DDNS_REPLACE_URL_FOR_EAST_BFLETS "https://senet-flets.v6.softether.co.jp/ddns/ddns.aspx"
+#define DDNS_REPLACE_URL_FOR_EAST_NGN "https://senet.aoi.flets-east.jp/ddns/ddns.aspx"
+#define DDNS_REPLACE_URL_FOR_WEST_NGN "https://senet.p-ns.flets-west.jp/ddns/ddns.aspx"
+
+#define DDNS_REPLACE_URL2_FOR_EAST_BFLETS "http://senet-flets.v6.softether.co.jp/ddns/getmyip.ashx"
+#define DDNS_REPLACE_URL2_FOR_EAST_NGN "http://senet.aoi.flets-east.jp/ddns/getmyip.ashx"
+#define DDNS_REPLACE_URL2_FOR_WEST_NGN "http://senet.p-ns.flets-west.jp/ddns/getmyip.ashx"
+
+// For China: Free version
+#define DDNS_URL_V4_ALT "https://x%c.x%c.x%c.x%c.servers.ddns.uxcom.jp/ddns/ddns.aspx"
+#define DDNS_URL_V6_ALT "https://x%c.x%c.x%c.x%c.servers-v6.ddns.uxcom.jp/ddns/ddns.aspx"
+#define DDNS_URL2_V4_ALT "http://get-my-ip.ddns.uxcom.jp/ddns/getmyip.ashx"
+#define DDNS_URL2_V6_ALT "http://get-my-ip-v6.ddns.uxcom.jp/ddns/getmyip.ashx"
+
+#define DDNS_RPC_MAX_RECV_SIZE DYN32(DDNS_RPC_MAX_RECV_SIZE, (128 * 1024 * 1024))
+
+// Connection Timeout
+#define DDNS_CONNECT_TIMEOUT DYN32(DDNS_CONNECT_TIMEOUT, (15 * 1000))
+
+// Communication time-out
+#define DDNS_COMM_TIMEOUT DYN32(DDNS_COMM_TIMEOUT, (60 * 1000))
+
+// Maximum length of the host name
+#define DDNS_MAX_HOSTNAME 31
+
+// DDNS Version
+#define DDNS_VERSION 1
+
+// Period until the next registration in case of success
+#define DDNS_REGISTER_INTERVAL_OK_MIN DYN32(DDNS_REGISTER_INTERVAL_OK_MIN, (1 * 60 * 60 * 1000))
+#define DDNS_REGISTER_INTERVAL_OK_MAX DYN32(DDNS_REGISTER_INTERVAL_OK_MAX, (2 * 60 * 60 * 1000))
+
+// Period until the next registration in case of failure
+#define DDNS_REGISTER_INTERVAL_NG_MIN DYN32(DDNS_REGISTER_INTERVAL_NG_MIN, (1 * 60 * 1000))
+#define DDNS_REGISTER_INTERVAL_NG_MAX DYN32(DDNS_REGISTER_INTERVAL_NG_MAX, (5 * 60 * 1000))
+
+// The self IP address acquisition interval (If last trial succeeded)
+#define DDNS_GETMYIP_INTERVAL_OK_MIN DYN32(DDNS_GETMYIP_INTERVAL_OK_MIN, (10 * 60 * 1000))
+#define DDNS_GETMYIP_INTERVAL_OK_MAX DYN32(DDNS_GETMYIP_INTERVAL_OK_MAX, (20 * 60 * 1000))
+
+// The self IP address acquisition interval (If last trial failed)
+#define DDNS_GETMYIP_INTERVAL_NG_MIN DYN32(DDNS_GETMYIP_INTERVAL_NG_MIN, (1 * 60 * 1000))
+#define DDNS_GETMYIP_INTERVAL_NG_MAX DYN32(DDNS_GETMYIP_INTERVAL_NG_MAX, (5 * 60 * 1000))
+
+// Time difference to communicate with the DDNS server after a predetermined time has elapsed since the VPN Azure is disconnected
+#define DDNS_VPN_AZURE_CONNECT_ERROR_DDNS_RETRY_TIME_DIFF DYN32(DDNS_VPN_AZURE_CONNECT_ERROR_DDNS_RETRY_TIME_DIFF, (120 * 1000))
+#define DDNS_VPN_AZURE_CONNECT_ERROR_DDNS_RETRY_TIME_DIFF_MAX DYN32(DDNS_VPN_AZURE_CONNECT_ERROR_DDNS_RETRY_TIME_DIFF_MAX, (10 * 60 * 1000))
+
+// DDNS Client
+struct DDNS_CLIENT
+{
+ CEDAR *Cedar; // Cedar
+ THREAD *Thread; // Thread
+ UCHAR Key[SHA1_SIZE]; // Key
+ LOCK *Lock; // Lock
+ volatile bool Halt; // Halt flag
+ EVENT *Event; // Halt event
+ char CurrentHostName[DDNS_MAX_HOSTNAME + 1]; // Current host name
+ char CurrentFqdn[MAX_SIZE]; // Current FQDN
+ char DnsSuffix[MAX_SIZE]; // DNS suffix
+ char CurrentIPv4[MAX_SIZE]; // Current IPv4 address
+ char CurrentIPv6[MAX_SIZE]; // Current IPv6 address
+ UINT Err_IPv4, Err_IPv6; // Last error
+ UINT Err_IPv4_GetMyIp, Err_IPv6_GetMyIp; // Last error (obtaining self IP address)
+ bool KeyChanged; // Flag to indicate that the key has been changed
+ char LastMyIPv4[MAX_SIZE]; // Self IPv4 address that were acquired on last
+ char LastMyIPv6[MAX_SIZE]; // Self IPv6 address that were acquired on last
+ char CurrentAzureIp[MAX_SIZE]; // IP address of Azure Server to be used
+ UINT64 CurrentAzureTimestamp; // Time stamp to be presented to the Azure Server
+ char CurrentAzureSignature[MAX_SIZE]; // Signature to be presented to the Azure Server
+ char AzureCertHash[MAX_SIZE]; // Azure Server certificate hash
+ INTERNET_SETTING InternetSetting; // Internet connection settings
+
+ UINT64 NextRegisterTick_IPv4, NextRegisterTick_IPv6; // Next register time
+ UINT64 NextGetMyIpTick_IPv4, NextGetMyIpTick_IPv6; // Next self IP acquisition time
+};
+
+// DDNS Register Param
+struct DDNS_REGISTER_PARAM
+{
+ char NewHostname[DDNS_MAX_HOSTNAME + 1]; // Host name after the change
+};
+
+// The current status of the DDNS
+struct DDNS_CLIENT_STATUS
+{
+ UINT Err_IPv4, Err_IPv6; // Last error
+ char CurrentHostName[DDNS_MAX_HOSTNAME + 1]; // Current host name
+ char CurrentFqdn[MAX_SIZE]; // Current FQDN
+ char DnsSuffix[MAX_SIZE]; // DNS suffix
+ char CurrentIPv4[MAX_SIZE]; // Current IPv4 address
+ char CurrentIPv6[MAX_SIZE]; // Current IPv6 address
+ char CurrentAzureIp[MAX_SIZE]; // IP address of Azure Server to be used
+ UINT64 CurrentAzureTimestamp; // Time stamp to be presented to the Azure Server
+ char CurrentAzureSignature[MAX_SIZE]; // Signature to be presented to the Azure Server
+ char AzureCertHash[MAX_SIZE]; // Azure Server certificate hash
+ INTERNET_SETTING InternetSetting; // Internet settings
+};
+
+// Function prototype
+DDNS_CLIENT *NewDDNSClient(CEDAR *cedar, UCHAR *key, INTERNET_SETTING *t);
+void FreeDDNSClient(DDNS_CLIENT *c);
+void DCGenNewKey(UCHAR *key);
+void DCThread(THREAD *thread, void *param);
+UINT DCRegister(DDNS_CLIENT *c, bool ipv6, DDNS_REGISTER_PARAM *p, char *replace_v6);
+UINT DCGetMyIpMain(DDNS_CLIENT *c, bool ipv6, char *dst, UINT dst_size, bool use_ssl, char *replace_v6);
+UINT DCGetMyIp(DDNS_CLIENT *c, bool ipv6, char *dst, UINT dst_size, char *replace_v6);
+void DCUpdateNow(DDNS_CLIENT *c);
+void DCGetStatus(DDNS_CLIENT *c, DDNS_CLIENT_STATUS *st);
+UINT DCChangeHostName(DDNS_CLIENT *c, char *hostname);
+void DCSetInternetSetting(DDNS_CLIENT *c, INTERNET_SETTING *t);
+void DCGetInternetSetting(DDNS_CLIENT *c, INTERNET_SETTING *t);
+
+#endif // DDNS_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Database.c b/src/Cedar/Database.c
new file mode 100644
index 00000000..5e1b3dd1
--- /dev/null
+++ b/src/Cedar/Database.c
@@ -0,0 +1,239 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Database.c
+// License database
+
+#include "CedarPch.h"
+
+// Get the License status string
+wchar_t *LiGetLicenseStatusStr(UINT i)
+{
+ wchar_t *ret = _UU("LICENSE_STATUS_OTHERERROR");
+
+ switch (i)
+ {
+ case LICENSE_STATUS_OK:
+ ret = _UU("LICENSE_STATUS_OK");
+ break;
+
+ case LICENSE_STATUS_EXPIRED:
+ ret = _UU("LICENSE_STATUS_EXPIRED");
+ break;
+
+ case LICENSE_STATUS_ID_DIFF:
+ ret = _UU("LICENSE_STATUS_ID_DIFF");
+ break;
+
+ case LICENSE_STATUS_DUP:
+ ret = _UU("LICENSE_STATUS_DUP");
+ break;
+
+ case LICENSE_STATUS_INSUFFICIENT:
+ ret = _UU("LICENSE_STATUS_INSUFFICIENT");
+ break;
+
+ case LICENSE_STATUS_COMPETITION:
+ ret = _UU("LICENSE_STATUS_COMPETITION");
+ break;
+
+ case LICENSE_STATUS_NONSENSE:
+ ret = _UU("LICENSE_STATUS_NONSENSE");
+ break;
+
+ case LICENSE_STATUS_CPU:
+ ret = _UU("LICENSE_STATUS_CPU");
+ break;
+ }
+
+ return ret;
+}
+
+static char *li_keybit_chars = "ABCDEFGHJKLMNPQRSTUVWXYZ12345678";
+
+// Convert the string to a key bit
+bool LiStrToKeyBit(UCHAR *keybit, char *keystr)
+{
+ UINT x[36];
+ UINT i, wp;
+ char *str;
+ // Validate arguments
+ if (keybit == NULL || keystr == NULL)
+ {
+ return false;
+ }
+
+ str = CopyStr(keystr);
+ Trim(str);
+
+ wp = 0;
+ if (StrLen(str) != 41)
+ {
+ Free(str);
+ return false;
+ }
+
+ for (i = 0;i < 36;i++)
+ {
+ char c = str[wp++];
+ UINT j;
+
+ if (((i % 6) == 5) && (i != 35))
+ {
+ if (str[wp++] != '-')
+ {
+ Free(str);
+ return false;
+ }
+ }
+
+ x[i] = INFINITE;
+ for (j = 0;j < 32;j++)
+ {
+ if (ToUpper(c) == li_keybit_chars[j])
+ {
+ x[i] = j;
+ }
+ }
+
+ if (x[i] == INFINITE)
+ {
+ Free(str);
+ return false;
+ }
+ }
+
+ Zero(keybit, 23);
+
+ keybit[0] = x[0] << 1 | x[1] >> 4;
+ keybit[1] = x[1] << 4 | x[2] >> 1;
+ keybit[2] = x[2] << 7 | x[3] << 2 | x[4] >> 3;
+ keybit[3] = x[4] << 5 | x[5];
+
+ keybit[4] = x[6] << 3 | x[7] >> 2;
+ keybit[5] = x[7] << 6 | x[8] << 1 | x[9] >> 4;
+ keybit[6] = x[9] << 4 | x[10] >> 1;
+ keybit[7] = x[10] << 7 | x[11] << 2 | x[12] >> 3;
+ keybit[8] = x[12] << 5 | x[13];
+
+ keybit[9] = x[14] << 3 | x[15] >> 2;
+ keybit[10] = x[15] << 6 | x[16] << 1 | x[17] >> 4;
+ keybit[11] = x[17] << 4 | x[18] >> 1;
+ keybit[12] = x[18] << 7 | x[19] << 2 | x[20] >> 3;
+ keybit[13] = x[20] << 5 | x[21];
+
+ keybit[14] = x[22] << 3 | x[23] >> 2;
+ keybit[15] = x[23] << 6 | x[24] << 1 | x[25] >> 4;
+ keybit[16] = x[25] << 4 | x[26] >> 1;
+ keybit[17] = x[26] << 7 | x[27] << 2 | x[28] >> 3;
+ keybit[18] = x[28] << 5 | x[29];
+
+ keybit[19] = x[30] << 3 | x[31] >> 2;
+ keybit[20] = x[31] << 6 | x[32] << 1 | x[33] >> 4;
+ keybit[21] = x[33] << 4 | x[34] >> 1;
+ keybit[22] = x[34] << 7 | x[35] << 2;
+
+ Free(str);
+
+ return true;
+}
+
+// Determine whether the string is a license key
+bool LiIsLicenseKey(char *str)
+{
+ UCHAR keybit[23];
+ // Validate arguments
+ if (str == NULL)
+ {
+ return false;
+ }
+
+ if (LiStrToKeyBit(keybit, str) == false)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Database.h b/src/Cedar/Database.h
new file mode 100644
index 00000000..e62680e2
--- /dev/null
+++ b/src/Cedar/Database.h
@@ -0,0 +1,98 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Database.h
+// Header of Database.c
+
+#ifndef DATABASE_H
+#define DATABASE_H
+
+wchar_t *LiGetLicenseStatusStr(UINT i);
+bool LiIsLicenseKey(char *str);
+bool LiStrToKeyBit(UCHAR *keybit, char *keystr);
+
+
+#endif // DATABASE_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/EM.c b/src/Cedar/EM.c
new file mode 100644
index 00000000..dafcc6ea
--- /dev/null
+++ b/src/Cedar/EM.c
@@ -0,0 +1,1476 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// EM.c
+// EtherLogger Manager for Win32
+
+#include
+
+#ifdef WIN32
+
+#define SM_C
+#define CM_C
+#define NM_C
+#define EM_C
+
+#define _WIN32_WINNT 0x0502
+#define WINVER 0x0502
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "CMInner.h"
+#include "SMInner.h"
+#include "NMInner.h"
+#include "EMInner.h"
+#include "../PenCore/resource.h"
+
+
+// License registration process
+void EmLicenseAddDlgOnOk(HWND hWnd, RPC *s)
+{
+}
+
+// Shift treatment of text input
+void EmLicenseAddDlgShiftTextItem(HWND hWnd, UINT id1, UINT id2, UINT *next_focus)
+{
+ char *s;
+ // Validate arguments
+ if (hWnd == NULL || next_focus == NULL)
+ {
+ return;
+ }
+
+ s = GetTextA(hWnd, id1);
+ if (StrLen(s) >= 6)
+ {
+ char *s2 = CopyStr(s);
+ char tmp[MAX_SIZE];
+ s2[6] = 0;
+ SetTextA(hWnd, id1, s2);
+ Free(s2);
+
+ if (id2 != 0)
+ {
+ GetTxtA(hWnd, id2, tmp, sizeof(tmp));
+
+ StrCat(tmp, sizeof(tmp), s + 6);
+ ReplaceStrEx(tmp, sizeof(tmp), tmp, "-", "", false);
+
+ SetTextA(hWnd, id2, tmp);
+
+ *next_focus = id2;
+ }
+ else
+ {
+ *next_focus = IDOK;
+ }
+ }
+
+ Free(s);
+}
+
+// Make a text from the input data
+void EmLicenseAddDlgGetText(HWND hWnd, char *str, UINT size)
+{
+ char *k1, *k2, *k3, *k4, *k5, *k6;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return;
+ }
+
+ k1 = GetTextA(hWnd, B_KEY1);
+ k2 = GetTextA(hWnd, B_KEY2);
+ k3 = GetTextA(hWnd, B_KEY3);
+ k4 = GetTextA(hWnd, B_KEY4);
+ k5 = GetTextA(hWnd, B_KEY5);
+ k6 = GetTextA(hWnd, B_KEY6);
+
+ Format(str, size, "%s-%s-%s-%s-%s-%s", k1, k2, k3, k4, k5, k6);
+
+ Free(k1);
+ Free(k2);
+ Free(k3);
+ Free(k4);
+ Free(k5);
+ Free(k6);
+}
+
+// License addition dialog update
+void EmLicenseAddDlgUpdate(HWND hWnd, RPC *s)
+{
+}
+
+// License addition dialog initialization
+void EmLicenseAddDlgInit(HWND hWnd, RPC *s)
+{
+ HFONT h;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ h = GetFont("Arial", 10, true, false, false, false);
+ SetFont(hWnd, B_KEY1, h);
+ SetFont(hWnd, B_KEY2, h);
+ SetFont(hWnd, B_KEY3, h);
+ SetFont(hWnd, B_KEY4, h);
+ SetFont(hWnd, B_KEY5, h);
+ SetFont(hWnd, B_KEY6, h);
+
+ DlgFont(hWnd, S_INFO, 10, true);
+
+ EmLicenseAddDlgUpdate(hWnd, s);
+}
+
+// License addition dialog
+UINT EmLicenseAddDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ RPC *s = (RPC *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ EmLicenseAddDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case B_KEY1:
+ case B_KEY2:
+ case B_KEY3:
+ case B_KEY4:
+ case B_KEY5:
+ case B_KEY6:
+ switch (HIWORD(wParam))
+ {
+ case EN_CHANGE:
+ EmLicenseAddDlgUpdate(hWnd, s);
+
+ switch (LOWORD(wParam))
+ {
+ case B_KEY2:
+ if (GetTextLen(hWnd, B_KEY2, true) == 0)
+ {
+ FocusEx(hWnd, B_KEY1);
+ }
+ break;
+ case B_KEY3:
+ if (GetTextLen(hWnd, B_KEY3, true) == 0)
+ {
+ FocusEx(hWnd, B_KEY2);
+ }
+ break;
+ case B_KEY4:
+ if (GetTextLen(hWnd, B_KEY4, true) == 0)
+ {
+ FocusEx(hWnd, B_KEY3);
+ }
+ break;
+ case B_KEY5:
+ if (GetTextLen(hWnd, B_KEY5, true) == 0)
+ {
+ FocusEx(hWnd, B_KEY4);
+ }
+ break;
+ case B_KEY6:
+ if (GetTextLen(hWnd, B_KEY6, true) == 0)
+ {
+ FocusEx(hWnd, B_KEY5);
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ EmLicenseAddDlgOnOk(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Add a license
+bool EmLicenseAdd(HWND hWnd, RPC *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ return Dialog(hWnd, D_EM_LICENSE_ADD, EmLicenseAddDlg, s);
+}
+
+// License dialog initialization
+void EmLicenseDlgInit(HWND hWnd, RPC *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_CERT);
+
+ DlgFont(hWnd, S_BOLD, 0, true);
+ DlgFont(hWnd, S_BOLD2, 0, true);
+
+ LvInit(hWnd, L_LIST);
+ LvSetStyle(hWnd, L_LIST, LVS_EX_GRIDLINES);
+ LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_LICENSE_COLUMN_1"), 50);
+ LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_LICENSE_COLUMN_2"), 100);
+ LvInsertColumn(hWnd, L_LIST, 2, _UU("SM_LICENSE_COLUMN_3"), 290);
+ LvInsertColumn(hWnd, L_LIST, 3, _UU("SM_LICENSE_COLUMN_4"), 150);
+ LvInsertColumn(hWnd, L_LIST, 4, _UU("SM_LICENSE_COLUMN_5"), 120);
+ LvInsertColumn(hWnd, L_LIST, 5, _UU("SM_LICENSE_COLUMN_6"), 250);
+ LvInsertColumn(hWnd, L_LIST, 6, _UU("SM_LICENSE_COLUMN_7"), 100);
+ LvInsertColumn(hWnd, L_LIST, 7, _UU("SM_LICENSE_COLUMN_8"), 100);
+ LvInsertColumn(hWnd, L_LIST, 8, _UU("SM_LICENSE_COLUMN_9"), 100);
+
+ LvInitEx(hWnd, L_STATUS, true);
+ LvInsertColumn(hWnd, L_STATUS, 0, _UU("SM_STATUS_COLUMN_1"), 100);
+ LvInsertColumn(hWnd, L_STATUS, 1, _UU("SM_STATUS_COLUMN_2"), 100);
+
+ EmLicenseDlgRefresh(hWnd, s);
+}
+
+// License dialog update
+void EmLicenseDlgRefresh(HWND hWnd, RPC *s)
+{
+ RPC_ENUM_LICENSE_KEY t;
+ RPC_EL_LICENSE_STATUS st;
+ UINT i;
+ wchar_t tmp[MAX_SIZE];
+ LVB *b;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+
+ if (CALL(hWnd, EcEnumLicenseKey(s, &t)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ b = LvInsertStart();
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ wchar_t tmp1[32], tmp2[LICENSE_KEYSTR_LEN + 1], tmp3[LICENSE_MAX_PRODUCT_NAME_LEN + 1],
+ *tmp4, tmp5[128], tmp6[LICENSE_LICENSEID_STR_LEN + 1], tmp7[64],
+ tmp8[64], tmp9[64];
+ RPC_ENUM_LICENSE_KEY_ITEM *e = &t.Items[i];
+
+ UniToStru(tmp1, e->Id);
+ StrToUni(tmp2, sizeof(tmp2), e->LicenseKey);
+ StrToUni(tmp3, sizeof(tmp3), e->LicenseName);
+ tmp4 = LiGetLicenseStatusStr(e->Status);
+ if (e->Expires == 0)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_LICENSE_NO_EXPIRES"));
+ }
+ else
+ {
+ GetDateStrEx64(tmp5, sizeof(tmp5), e->Expires, NULL);
+ }
+ StrToUni(tmp6, sizeof(tmp6), e->LicenseId);
+ UniToStru(tmp7, e->ProductId);
+ UniFormat(tmp8, sizeof(tmp8), L"%I64u", e->SystemId);
+ UniToStru(tmp9, e->SerialId);
+
+ LvInsertAdd(b,
+ e->Status == LICENSE_STATUS_OK ? ICO_PASS : ICO_DISCARD,
+ (void *)e->Id, 9,
+ tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9);
+ }
+
+ LvInsertEnd(b, hWnd, L_LIST);
+
+ FreeRpcEnumLicenseKey(&t);
+
+ Zero(&st, sizeof(st));
+
+ if (CALL(hWnd, EcGetLicenseStatus(s, &st)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ b = LvInsertStart();
+
+ if (st.Valid == false)
+ {
+ LvInsertAdd(b, 0, NULL, 2, _UU("EM_NO_LICENSE_COLUMN"), _UU("EM_NO_LICENSE"));
+ }
+ else
+ {
+ // Current system ID
+ UniFormat(tmp, sizeof(tmp), L"%I64u", st.SystemId);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_SYSTEM_ID"), tmp);
+
+ // Expiration date of the current license product
+ if (st.SystemExpires == 0)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_NO_EXPIRES"));
+ }
+ else
+ {
+ GetDateStrEx64(tmp, sizeof(tmp), st.SystemExpires, NULL);
+ }
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_EXPIRES"), tmp);
+ }
+
+ LvInsertEnd(b, hWnd, L_STATUS);
+
+ if (LvNum(hWnd, L_STATUS) >= 1)
+ {
+ LvAutoSize(hWnd, L_STATUS);
+ }
+
+ EmLicenseDlgUpdate(hWnd, s);
+}
+
+// License dialog control update
+void EmLicenseDlgUpdate(HWND hWnd, RPC *s)
+{
+ bool b = false;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ b = LvIsSingleSelected(hWnd, L_LIST);
+
+ SetEnable(hWnd, B_DEL, b);
+ SetEnable(hWnd, IDOK, b);
+}
+
+// License dialog
+UINT EmLicenseDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ RPC *s = (RPC *)param;
+ NMHDR *n;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ EmLicenseDlgInit(hWnd, s);
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ case L_STATUS:
+ EmLicenseDlgUpdate(hWnd, s);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ if (IsEnable(hWnd, IDOK))
+ {
+ UINT i = LvGetSelected(hWnd, L_LIST);
+
+ if (i != INFINITE)
+ {
+ char *s = LvGetStrA(hWnd, L_LIST, i, 5);
+ char tmp[MAX_SIZE];
+
+ Format(tmp, sizeof(tmp), _SS("LICENSE_SUPPORT_URL"), s);
+ ShellExecute(hWnd, "open", tmp, NULL, NULL, SW_SHOW);
+
+ Free(s);
+ }
+ }
+ break;
+
+ case B_OBTAIN:
+ ShellExecute(hWnd, "open", _SS("LICENSE_INFO_URL"), NULL, NULL, SW_SHOW);
+ break;
+
+ case B_ADD:
+ if (EmLicenseAdd(hWnd, s))
+ {
+ EmLicenseDlgRefresh(hWnd, s);
+ }
+ break;
+
+ case B_DEL:
+ if (IsEnable(hWnd, B_DEL))
+ {
+ UINT id = (UINT)LvGetParam(hWnd, L_LIST, LvGetSelected(hWnd, L_LIST));
+
+ if (id != 0)
+ {
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("SM_LICENSE_DELETE_MSG")) == IDYES)
+ {
+ RPC_TEST t;
+
+ Zero(&t, sizeof(t));
+ t.IntValue = id;
+
+ if (CALL(hWnd, EcDelLicenseKey(s, &t)))
+ {
+ EmLicenseDlgRefresh(hWnd, s);
+ }
+ }
+ }
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_LIST);
+
+ return 0;
+}
+
+
+
+
+
+// Change Password dialog
+UINT EmPasswordDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ RPC *r = (RPC *)param;
+ char pass1[MAX_PATH];
+ char pass2[MAX_PATH];
+ UCHAR hash[SHA1_SIZE];
+ RPC_SET_PASSWORD t;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ Focus(hWnd, E_PASSWORD1);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ GetTxtA(hWnd, E_PASSWORD1, pass1, sizeof(pass1));
+ Hash(hash, pass1, StrLen(pass1), true);
+ Zero(&t, sizeof(t));
+ Copy(t.HashedPassword, hash, SHA1_SIZE);
+ if (CALL(hWnd, EcSetPassword(r, &t)) == false)
+ {
+ break;
+ }
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_PASSWORD_SET"));
+ EndDialog(hWnd, 1);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+
+ switch (LOWORD(wParam))
+ {
+ case E_PASSWORD1:
+ case E_PASSWORD2:
+ GetTxtA(hWnd, E_PASSWORD1, pass1, sizeof(pass1));
+ GetTxtA(hWnd, E_PASSWORD2, pass2, sizeof(pass2));
+ SetEnable(hWnd, IDOK, StrCmp(pass1, pass2) == 0 ? true : false);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Copy the state of the dialog to the HUB_LOG
+void EmDlgToHubLog(HWND hWnd, HUB_LOG *g)
+{
+ // Validate arguments
+ if (hWnd == NULL || g == NULL)
+ {
+ return;
+ }
+
+ Zero(g, sizeof(HUB_LOG));
+ g->PacketLogSwitchType = CbGetSelect(hWnd, C_PACKET_SWITCH);
+ g->PacketLogConfig[0] = IsChecked(hWnd, B_PACKET_0_0) ? 0 : IsChecked(hWnd, B_PACKET_0_1) ? 1 : 2;
+ g->PacketLogConfig[1] = IsChecked(hWnd, B_PACKET_1_0) ? 0 : IsChecked(hWnd, B_PACKET_1_1) ? 1 : 2;
+ g->PacketLogConfig[2] = IsChecked(hWnd, B_PACKET_2_0) ? 0 : IsChecked(hWnd, B_PACKET_2_1) ? 1 : 2;
+ g->PacketLogConfig[3] = IsChecked(hWnd, B_PACKET_3_0) ? 0 : IsChecked(hWnd, B_PACKET_3_1) ? 1 : 2;
+ g->PacketLogConfig[4] = IsChecked(hWnd, B_PACKET_4_0) ? 0 : IsChecked(hWnd, B_PACKET_4_1) ? 1 : 2;
+ g->PacketLogConfig[5] = IsChecked(hWnd, B_PACKET_5_0) ? 0 : IsChecked(hWnd, B_PACKET_5_1) ? 1 : 2;
+ g->PacketLogConfig[6] = IsChecked(hWnd, B_PACKET_6_0) ? 0 : IsChecked(hWnd, B_PACKET_6_1) ? 1 : 2;
+ g->PacketLogConfig[7] = IsChecked(hWnd, B_PACKET_7_0) ? 0 : IsChecked(hWnd, B_PACKET_7_1) ? 1 : 2;
+}
+
+// Copy the HUB_LOG to the state of the dialog
+void EmHubLogToDlg(HWND hWnd, HUB_LOG *g)
+{
+ // Validate arguments
+ if (hWnd == NULL || g == NULL)
+ {
+ return;
+ }
+
+ CbSelect(hWnd, C_PACKET_SWITCH, g->PacketLogSwitchType);
+
+ Check(hWnd, B_PACKET_0_0, g->PacketLogConfig[0] == 0);
+ Check(hWnd, B_PACKET_0_1, g->PacketLogConfig[0] == 1);
+ Check(hWnd, B_PACKET_0_2, g->PacketLogConfig[0] == 2);
+
+ Check(hWnd, B_PACKET_1_0, g->PacketLogConfig[1] == 0);
+ Check(hWnd, B_PACKET_1_1, g->PacketLogConfig[1] == 1);
+ Check(hWnd, B_PACKET_1_2, g->PacketLogConfig[1] == 2);
+
+ Check(hWnd, B_PACKET_2_0, g->PacketLogConfig[2] == 0);
+ Check(hWnd, B_PACKET_2_1, g->PacketLogConfig[2] == 1);
+ Check(hWnd, B_PACKET_2_2, g->PacketLogConfig[2] == 2);
+
+ Check(hWnd, B_PACKET_3_0, g->PacketLogConfig[3] == 0);
+ Check(hWnd, B_PACKET_3_1, g->PacketLogConfig[3] == 1);
+ Check(hWnd, B_PACKET_3_2, g->PacketLogConfig[3] == 2);
+
+ Check(hWnd, B_PACKET_4_0, g->PacketLogConfig[4] == 0);
+ Check(hWnd, B_PACKET_4_1, g->PacketLogConfig[4] == 1);
+ Check(hWnd, B_PACKET_4_2, g->PacketLogConfig[4] == 2);
+
+ Check(hWnd, B_PACKET_5_0, g->PacketLogConfig[5] == 0);
+ Check(hWnd, B_PACKET_5_1, g->PacketLogConfig[5] == 1);
+ Check(hWnd, B_PACKET_5_2, g->PacketLogConfig[5] == 2);
+
+ Check(hWnd, B_PACKET_6_0, g->PacketLogConfig[6] == 0);
+ Check(hWnd, B_PACKET_6_1, g->PacketLogConfig[6] == 1);
+ Check(hWnd, B_PACKET_6_2, g->PacketLogConfig[6] == 2);
+
+ Check(hWnd, B_PACKET_7_0, g->PacketLogConfig[7] == 0);
+ Check(hWnd, B_PACKET_7_1, g->PacketLogConfig[7] == 1);
+ Check(hWnd, B_PACKET_7_2, g->PacketLogConfig[7] == 2);
+}
+
+// Initialize
+void EmAddInit(HWND hWnd, EM_ADD *p)
+{
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ // Initialize controls
+ CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_0"), 0);
+ CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_1"), 1);
+ CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_2"), 2);
+ CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_3"), 3);
+ CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_4"), 4);
+ CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_5"), 5);
+
+ if (p->NewMode)
+ {
+ // Newly creation mode
+ RPC_ENUM_DEVICE t;
+ HUB_LOG g;
+
+ Zero(&g, sizeof(g));
+ g.PacketLogSwitchType = LOG_SWITCH_DAY;
+ g.PacketLogConfig[PACKET_LOG_TCP_CONN] = g.PacketLogConfig[PACKET_LOG_DHCP] = 1;
+
+ EmHubLogToDlg(hWnd, &g);
+
+ Zero(&t, sizeof(t));
+ if (CALL(hWnd, EcEnumAllDevice(p->Rpc, &t)))
+ {
+ UINT i;
+ CbSetHeight(hWnd, C_DEVICE, 18);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_DEVICE_ITEM *dev = &t.Items[i];
+ wchar_t tmp[MAX_SIZE];
+
+ StrToUni(tmp, sizeof(tmp), dev->DeviceName);
+
+ CbAddStr(hWnd, C_DEVICE, tmp, 0);
+ }
+
+ FreeRpcEnumDevice(&t);
+ }
+
+ SetText(hWnd, 0, _UU("EM_ADD_NEW"));
+ }
+ else
+ {
+ // Edit mode (to obtain a configuration)
+ wchar_t tmp[MAX_PATH];
+ RPC_ADD_DEVICE t;
+ Hide(hWnd, R_PROMISCUS);
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), p->DeviceName);
+
+ if (CALL(hWnd, EcGetDevice(p->Rpc, &t)))
+ {
+ EmHubLogToDlg(hWnd, &t.LogSetting);
+ }
+ else
+ {
+ Close(hWnd);
+ }
+
+ StrToUni(tmp, sizeof(tmp), p->DeviceName);
+ CbAddStr(hWnd, C_DEVICE, tmp, 0);
+
+ Disable(hWnd, C_DEVICE);
+
+ SetText(hWnd, 0, _UU("EM_ADD_EDIT"));
+ }
+
+ EmAddUpdate(hWnd, p);
+}
+
+// [OK] button
+void EmAddOk(HWND hWnd, EM_ADD *p)
+{
+ RPC_ADD_DEVICE t;
+ wchar_t *tmp;
+ char *name;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ EmDlgToHubLog(hWnd, &t.LogSetting);
+ tmp = CbGetStr(hWnd, C_DEVICE);
+ name = CopyUniToStr(tmp);
+
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), name);
+
+ if (p->NewMode)
+ {
+ t.NoPromiscus = IsChecked(hWnd, R_PROMISCUS);
+ }
+
+ if (p->NewMode)
+ {
+ if (CALL(hWnd, EcAddDevice(p->Rpc, &t)))
+ {
+ Close(hWnd);
+ }
+ }
+ else
+ {
+ if (CALL(hWnd, EcSetDevice(p->Rpc, &t)))
+ {
+ Close(hWnd);
+ }
+ }
+
+ Free(name);
+ Free(tmp);
+}
+
+// Control update
+void EmAddUpdate(HWND hWnd, EM_ADD *p)
+{
+ wchar_t *tmp;
+ char *name;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ tmp = CbGetStr(hWnd, C_DEVICE);
+ name = CopyUniToStr(tmp);
+
+ Trim(name);
+
+ if (StrLen(name) == 0)
+ {
+ Disable(hWnd, IDOK);
+ }
+ else
+ {
+ Enable(hWnd, IDCANCEL);
+ }
+
+ Free(name);
+ Free(tmp);
+}
+
+// Device Add / Edit dialog
+UINT EmAddDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ EM_ADD *p = (EM_ADD *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ EmAddInit(hWnd, p);
+ break;
+
+ case WM_COMMAND:
+ EmAddUpdate(hWnd, p);
+ switch (wParam)
+ {
+ case IDOK:
+ EmAddOk(hWnd, p);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Add or edit
+void EmAdd(HWND hWnd, RPC *r, char *device_name)
+{
+ EM_ADD p;
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ Zero(&p, sizeof(p));
+
+ p.Rpc = r;
+
+ if (device_name != NULL)
+ {
+ StrCpy(p.DeviceName, sizeof(p.DeviceName), device_name);
+ }
+ else
+ {
+ p.NewMode = true;
+ }
+
+ Dialog(hWnd, D_EM_ADD, EmAddDlg, &p);
+}
+
+// Initialize
+void EmMainInit(HWND hWnd, RPC *r)
+{
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ LvInit(hWnd, L_LIST);
+ LvInsertColumn(hWnd, L_LIST, 0, _UU("EM_MAIN_COLUMN_1"), 300);
+ LvInsertColumn(hWnd, L_LIST, 1, _UU("EM_MAIN_COLUMN_2"), 150);
+
+ SetIcon(hWnd, 0, ICO_NIC_ONLINE);
+
+ EmMainRefresh(hWnd, r);
+
+ SetTimer(hWnd, 1, 1000, NULL);
+}
+
+// Control update
+void EmMainUpdate(HWND hWnd, RPC *r)
+{
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ SetEnable(hWnd, IDOK, LvIsMasked(hWnd, L_LIST) && LvIsMultiMasked(hWnd, L_LIST) == false);
+ SetEnable(hWnd, B_DELETE, LvIsMasked(hWnd, L_LIST) && LvIsMultiMasked(hWnd, L_LIST) == false);
+}
+
+// Update
+void EmMainRefresh(HWND hWnd, RPC *r)
+{
+ RPC_ENUM_DEVICE t;
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+
+ if (CALL(hWnd, EcEnumDevice(r, &t)))
+ {
+ UINT i;
+ LVB *b;
+
+ b = LvInsertStart();
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ wchar_t tmp[MAX_PATH];
+ RPC_ENUM_DEVICE_ITEM *dev = &t.Items[i];
+
+ StrToUni(tmp, sizeof(tmp), dev->DeviceName);
+
+ LvInsertAdd(b,
+ dev->Active ? ICO_NIC_ONLINE : ICO_NIC_OFFLINE,
+ NULL,
+ 2,
+ tmp,
+ dev->Active ? _UU("EM_MAIN_OK") : _UU("EM_MAIN_ERROR"));
+ }
+
+ LvInsertEnd(b, hWnd, L_LIST);
+
+ FreeRpcEnumDevice(&t);
+
+ SetShow(hWnd, B_LICENSE, t.IsLicenseSupported);
+ }
+ else
+ {
+ Close(hWnd);
+ }
+
+ EmMainUpdate(hWnd, r);
+}
+
+// Main dialog procedure
+UINT EmMainDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ NMHDR *n;
+ RPC *r = (RPC *)param;
+ UINT i;
+ char *name;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ EmMainInit(hWnd, r);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ // Edit
+ i = LvGetSelected(hWnd, L_LIST);
+ if (i != INFINITE)
+ {
+ wchar_t *tmp;
+ tmp = LvGetStr(hWnd, L_LIST, i, 0);
+ if (tmp != NULL)
+ {
+ name = CopyUniToStr(tmp);
+ EmAdd(hWnd, r, name);
+ Free(tmp);
+ Free(name);
+ }
+ }
+ break;
+
+ case B_PASSWORD:
+ // Admin password
+ Dialog(hWnd, D_EM_PASSWORD, EmPasswordDlg, r);
+ break;
+
+ case B_LICENSE:
+ // Admin password
+ Dialog(hWnd, D_EM_LICENSE, EmLicenseDlg, r);
+ break;
+
+ case B_ADD:
+ // Add
+ EmAdd(hWnd, r, NULL);
+ EmMainRefresh(hWnd, r);
+ break;
+
+ case B_DELETE:
+ // Delete
+ i = LvGetSelected(hWnd, L_LIST);
+ if (i != INFINITE)
+ {
+ wchar_t *tmp;
+ tmp = LvGetStr(hWnd, L_LIST, i, 0);
+ if (tmp != NULL)
+ {
+ RPC_DELETE_DEVICE t;
+ wchar_t msg[MAX_SIZE];
+ name = CopyUniToStr(tmp);
+ UniFormat(msg, sizeof(msg), _UU("EM_DELETE_CONFIRM"), name);
+ if (MsgBox(hWnd, MB_YESNO | MB_ICONEXCLAMATION | MB_DEFBUTTON2, msg) == IDYES)
+ {
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), name);
+ if (CALL(hWnd, EcDelDevice(r, &t)))
+ {
+ EmMainRefresh(hWnd, r);
+ }
+ }
+ Free(tmp);
+ Free(name);
+ }
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+ EmMainRefresh(hWnd, r);
+ SetTimer(hWnd, 1, 1000, NULL);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->code)
+ {
+ case NM_DBLCLK:
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ if (IsEnable(hWnd, IDOK))
+ {
+ Command(hWnd, IDOK);
+ }
+ break;
+ }
+ break;
+ case LVN_ITEMCHANGED:
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ EmMainUpdate(hWnd, r);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Installation of WinPcap
+void EmInstallWinPcap(HWND hWnd, RPC *r)
+{
+ wchar_t temp_name[MAX_SIZE];
+ HGLOBAL g;
+ HINSTANCE h;
+ HRSRC hr;
+ UINT size;
+ void *data;
+ IO *io;
+
+ // Ask whether the user want to start the installation
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("EM_WPCAP_INSTALL")) == IDNO)
+ {
+ return;
+ }
+
+ // Generate a temporary file name
+ UniFormat(temp_name, sizeof(temp_name), L"%s\\winpcap_installer.exe", MsGetTempDirW());
+
+ // Read from the resource
+ h = GetUiDll();
+ hr = FindResource(h, MAKEINTRESOURCE(BIN_WINPCAP), "BIN");
+ if (hr == NULL)
+ {
+RES_ERROR:
+ MsgBox(hWnd, MB_ICONSTOP, _UU("EM_RESOURCE"));
+ return;
+ }
+
+ g = LoadResource(h, hr);
+ if (g == NULL)
+ {
+ goto RES_ERROR;
+ }
+
+ size = SizeofResource(h, hr);
+ data = LockResource(g);
+
+ if (data == NULL)
+ {
+ goto RES_ERROR;
+ }
+
+ // Write to a temporary file
+ io = FileCreateW(temp_name);
+ if (io == NULL)
+ {
+ goto RES_ERROR;
+ }
+
+ FileWrite(io, data, size);
+ FileClose(io);
+
+ // Run
+ if (RunW(temp_name, NULL, false, true) == false)
+ {
+ // Failure
+ FileDeleteW(temp_name);
+ goto RES_ERROR;
+ }
+
+ FileDeleteW(temp_name);
+
+ if (r == NULL)
+ {
+ return;
+ }
+
+ // Message after the end
+ if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) == false)
+ {
+ // Need to restart the computer
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("EM_WPCAP_REBOOT1"));
+ }
+ else
+ {
+ // Need to restart the service
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("EM_WPCAP_REBOOT2")) == IDNO)
+ {
+ // Not restart
+ }
+ else
+ {
+ // Restart
+ RPC_TEST t;
+ RPC_BRIDGE_SUPPORT t2;
+ Zero(&t, sizeof(t));
+ EcRebootServer(r, &t);
+
+ SleepThread(500);
+
+ Zero(&t2, sizeof(t2));
+ CALL(hWnd, EcGetBridgeSupport(r, &t2));
+ }
+ }
+}
+
+// Main screen
+void EMMain(RPC *r)
+{
+ RPC_BRIDGE_SUPPORT t;
+
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+ // Examine the bridge support status of the server side first
+ Zero(&t, sizeof(t));
+ if (CALLEX(NULL, ScGetBridgeSupport(r, &t)) == ERR_NO_ERROR)
+ {
+ if (t.IsBridgeSupportedOs == false)
+ {
+ // OS does not support the bridge
+ MsgBox(NULL, MB_ICONEXCLAMATION, _UU("EM_UNSUPPORTED"));
+ return;
+ }
+
+ if (t.IsWinPcapNeeded)
+ {
+ if (r->Sock->RemoteIP.addr[0] != 127)
+ {
+ // WinPcap is required, but can not do anything because it is in remote management mode
+ MsgBox(NULL, MB_ICONINFORMATION, _UU("EM_WPCAP_REMOTE"));
+ return;
+ }
+ else
+ {
+ // WinPcap is required, and it's in local management mode
+ if (MsIsAdmin())
+ {
+ // Administrators
+ EmInstallWinPcap(NULL, r);
+ return;
+ }
+ else
+ {
+ // Non-Administrators
+ MsgBox(NULL, MB_ICONINFORMATION, _UU("EM_WPCAP_ROOT"));
+ return;
+ }
+ }
+ }
+ }
+
+ Dialog(NULL, D_EM_MAIN, EmMainDlg, r);
+}
+
+// Remote connection dialog procedure
+UINT EmRemoteDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ WINUI_REMOTE *r = (WINUI_REMOTE *)param;
+ CEDAR *c;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ RemoteDlgInit(hWnd, r);
+ SetTimer(hWnd, 1, 100, NULL);
+ break;
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+ RemoteDlgRefresh(hWnd, r);
+ SetTimer(hWnd, 1, 100, NULL);
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case R_LOCAL:
+ if (IsChecked(hWnd, R_LOCAL) == false)
+ {
+ SetTextA(hWnd, C_HOSTNAME, "");
+ RemoteDlgRefresh(hWnd, r);
+ FocusEx(hWnd, C_HOSTNAME);
+ }
+ else
+ {
+ SetTextA(hWnd, C_HOSTNAME, "localhost");
+ RemoteDlgRefresh(hWnd, r);
+ Focus(hWnd, IDOK);
+ }
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ case IDOK:
+ RemoteDlgOnOk(hWnd, r);
+ break;
+ case B_ABOUT:
+ c = NewCedar(NULL, NULL);
+ About(hWnd, c, _UU("PRODUCT_NAME_ELOGMGR"));
+ ReleaseCedar(c);
+ }
+ switch (LOWORD(wParam))
+ {
+ case R_LOCAL:
+ case C_HOSTNAME:
+ RemoteDlgRefresh(hWnd, r);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ FreeCandidateList(r->CandidateList);
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Remote connection dialog
+char *EmRemoteDlg()
+{
+ WINUI_REMOTE r;
+
+ Zero(&r, sizeof(r));
+ r.RegKeyName = EM_REG_KEY;
+ r.Caption = _UU("EM_TITLE");
+ r.Title = _UU("EM_REMOTE_TITLE");
+ r.Icon = ICO_USER_ADMIN;
+ r.DefaultHostname = NULL;
+
+ if (Dialog(NULL, D_EM_REMOTE, EmRemoteDlgProc, &r) == false)
+ {
+ return NULL;
+ }
+
+ return r.Hostname;
+}
+
+// Start the EtherLogger Manager
+void EMExec()
+{
+ char *host;
+ char *ret;
+ bool cancel_now = false;
+ TOKEN_LIST *t;
+ UINT port = EL_ADMIN_PORT;
+ InitWinUi(_UU("EM_TITLE"), _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+
+ while (true)
+ {
+ ret = EmRemoteDlg();
+
+ if (ret != NULL)
+ {
+ t = ParseToken(ret, ":");
+ if (t->NumTokens == 1 || t->NumTokens == 2)
+ {
+ RPC *rpc = NULL;
+ bool ok = false;
+ UINT ret;
+ host = t->Token[0];
+ if (t->NumTokens == 2)
+ {
+ port = ToInt(t->Token[1]);
+ }
+ else
+ {
+ port = EL_ADMIN_PORT;
+ }
+
+ // Try without a password first
+ ret = EcConnect(host, port, "", &rpc);
+RETRY:
+ if (ret != ERR_NO_ERROR && ret != ERR_AUTH_FAILED)
+ {
+ // Connection failed
+ CALL(NULL, ret);
+ }
+ else
+ {
+ if (ret == ERR_NO_ERROR)
+ {
+ // Successful connection
+ ok = true;
+ }
+ else
+ {
+ // Password required
+ char *pass = SmPassword(NULL, host);
+ if (pass == NULL)
+ {
+ // Cancel
+ cancel_now = true;
+ }
+ else
+ {
+ // Retry
+ ret = EcConnect(host, port, pass, &rpc);
+ Free(pass);
+ if (ret == ERR_NO_ERROR)
+ {
+ ok = true;
+ }
+ else
+ {
+ goto RETRY;
+ }
+ }
+ }
+ }
+
+ if (ok)
+ {
+ // Main screen
+ EMMain(rpc);
+
+ // Disconnect
+ EcDisconnect(rpc);
+ cancel_now = true;
+ }
+ FreeToken(t);
+ }
+ Free(ret);
+ }
+ else
+ {
+ cancel_now = true;
+ }
+
+ if (cancel_now)
+ {
+ break;
+ }
+ }
+
+ FreeWinUi();
+}
+
+#endif // WIN32
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/EM.h b/src/Cedar/EM.h
new file mode 100644
index 00000000..fd133fe9
--- /dev/null
+++ b/src/Cedar/EM.h
@@ -0,0 +1,96 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// EM.h
+// Header of EM.c
+
+#ifndef EM_H
+#define EM_H
+
+// Public function
+void EMExec();
+
+#endif // EM_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/EMInner.h b/src/Cedar/EMInner.h
new file mode 100644
index 00000000..b6aea06d
--- /dev/null
+++ b/src/Cedar/EMInner.h
@@ -0,0 +1,122 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// EMInner.h
+// Inner header of EM.c
+
+// Constants
+#define EM_REG_KEY "Software\\" GC_REG_COMPANY_NAME "\\EtherLogger\\Manager"
+
+// Innner structure
+typedef struct EM_ADD
+{
+ RPC *Rpc;
+ bool NewMode;
+ char DeviceName[MAX_SIZE];
+} EM_ADD;
+
+// Inner functions
+void EMMain(RPC *r);
+UINT EmMainDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void EmMainInit(HWND hWnd, RPC *r);
+void EmMainUpdate(HWND hWnd, RPC *r);
+void EmMainRefresh(HWND hWnd, RPC *r);
+void EmAdd(HWND hWnd, RPC *r, char *device_name);
+UINT EmAddDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void EmAddInit(HWND hWnd, EM_ADD *p);
+void EmDlgToHubLog(HWND hWnd, HUB_LOG *g);
+void EmHubLogToDlg(HWND hWnd, HUB_LOG *g);
+void EmAddOk(HWND hWnd, EM_ADD *p);
+void EmAddUpdate(HWND hWnd, EM_ADD *p);
+UINT EmPasswordDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+UINT EmLicenseDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void EmLicenseDlgInit(HWND hWnd, RPC *s);
+void EmLicenseDlgRefresh(HWND hWnd, RPC *s);
+void EmLicenseDlgUpdate(HWND hWnd, RPC *s);
+bool EmLicenseAdd(HWND hWnd, RPC *s);
+UINT EmLicenseAddDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void EmLicenseAddDlgInit(HWND hWnd, RPC *s);
+void EmLicenseAddDlgUpdate(HWND hWnd, RPC *s);
+void EmLicenseAddDlgShiftTextItem(HWND hWnd, UINT id1, UINT id2, UINT *next_focus);
+void EmLicenseAddDlgGetText(HWND hWnd, char *str, UINT size);
+void EmLicenseAddDlgOnOk(HWND hWnd, RPC *s);
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/EtherLog.c b/src/Cedar/EtherLog.c
new file mode 100644
index 00000000..c3d44955
--- /dev/null
+++ b/src/Cedar/EtherLog.c
@@ -0,0 +1,1356 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// EtherLog.c
+// EtherLogger program
+
+#include "CedarPch.h"
+
+static LOCK *el_lock = NULL;
+static EL *el = NULL;
+
+// RPC functional related macro
+#define DECLARE_RPC_EX(rpc_name, data_type, function, in_rpc, out_rpc, free_rpc) \
+ else if (StrCmpi(name, rpc_name) == 0) \
+ { \
+ data_type t; \
+ Zero(&t, sizeof(t)); \
+ in_rpc(&t, p); \
+ err = function(e, &t); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ out_rpc(ret, &t); \
+ } \
+ free_rpc(&t); \
+ ok = true; \
+ }
+#define DECLARE_RPC(rpc_name, data_type, function, in_rpc, out_rpc) \
+ else if (StrCmpi(name, rpc_name) == 0) \
+ { \
+ data_type t; \
+ Zero(&t, sizeof(t)); \
+ in_rpc(&t, p); \
+ err = function(e, &t); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ out_rpc(ret, &t); \
+ } \
+ ok = true; \
+ }
+#define DECLARE_SC_EX(rpc_name, data_type, function, in_rpc, out_rpc, free_rpc) \
+ UINT function(RPC *r, data_type *t) \
+ { \
+ PACK *p, *ret; \
+ UINT err; \
+ if (r == NULL || t == NULL) \
+ { \
+ return ERR_INTERNAL_ERROR; \
+ } \
+ p = NewPack(); \
+ out_rpc(p, t); \
+ free_rpc(t); \
+ Zero(t, sizeof(data_type)); \
+ ret = AdminCall(r, rpc_name, p); \
+ err = GetErrorFromPack(ret); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ in_rpc(t, ret); \
+ } \
+ FreePack(ret); \
+ return err; \
+ }
+#define DECLARE_SC(rpc_name, data_type, function, in_rpc, out_rpc) \
+ UINT function(RPC *r, data_type *t) \
+ { \
+ PACK *p, *ret; \
+ UINT err; \
+ if (r == NULL || t == NULL) \
+ { \
+ return ERR_INTERNAL_ERROR; \
+ } \
+ p = NewPack(); \
+ out_rpc(p, t); \
+ ret = AdminCall(r, rpc_name, p); \
+ err = GetErrorFromPack(ret); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ in_rpc(t, ret); \
+ } \
+ FreePack(ret); \
+ return err; \
+ }
+
+// RPC client disconnect
+void EcDisconnect(RPC *rpc)
+{
+ // Validate arguments
+ if (rpc == NULL)
+ {
+ return;
+ }
+
+ RpcFree(rpc);
+}
+
+// RPC client connect
+UINT EcConnect(char *host, UINT port, char *password, RPC **rpc)
+{
+ SOCK *s;
+ UCHAR password_hash[SHA1_SIZE];
+ UCHAR rand[SHA1_SIZE];
+ UCHAR response[SHA1_SIZE];
+ bool retcode;
+ // Validate arguments
+ if (host == NULL)
+ {
+ host = "localhost";
+ }
+ if (port == 0)
+ {
+ port = EL_ADMIN_PORT;
+ }
+ if (password == NULL)
+ {
+ password = "";
+ }
+ if (rpc == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ // Connect to the server
+ s = Connect(host, port);
+ if (s == NULL)
+ {
+ // Connection failure
+ return ERR_CONNECT_FAILED;
+ }
+
+ SetTimeout(s, 5000);
+
+ // Hash the password
+ Hash(password_hash, password, StrLen(password), true);
+
+ // Receive the random number
+ Zero(rand, sizeof(rand));
+ RecvAll(s, rand, sizeof(rand), false);
+ SecurePassword(response, password_hash, rand);
+
+ // Send a response
+ SendAll(s, response, sizeof(response), false);
+
+ // Receive results
+ retcode = false;
+ if (RecvAll(s, &retcode, sizeof(retcode), false) == false)
+ {
+ // Disconnect
+ ReleaseSock(s);
+ return ERR_PROTOCOL_ERROR;
+ }
+ retcode = Endian32(retcode);
+
+ if (retcode == false)
+ {
+ // Password incorrect
+ ReleaseSock(s);
+ return ERR_AUTH_FAILED;
+ }
+
+ // Successful connection
+ SetTimeout(s, INFINITE);
+
+ *rpc = StartRpcClient(s, NULL);
+
+ ReleaseSock(s);
+
+ return ERR_NO_ERROR;
+}
+
+// RPC server function
+PACK *ElRpcServer(RPC *r, char *name, PACK *p)
+{
+ EL *e = (EL *)r->Param;
+ PACK *ret;
+ UINT err;
+ bool ok;
+ // Validate arguments
+ if (r == NULL || name == NULL || p == NULL || e == NULL)
+ {
+ return NULL;
+ }
+
+ ret = NewPack();
+ err = ERR_NO_ERROR;
+ ok = false;
+
+ if (0) {}
+
+ DECLARE_RPC("AddDevice", RPC_ADD_DEVICE, EtAddDevice, InRpcAddDevice, OutRpcAddDevice)
+ DECLARE_RPC("DelDevice", RPC_DELETE_DEVICE, EtDelDevice, InRpcDeleteDevice, OutRpcDeleteDevice)
+ DECLARE_RPC("SetDevice", RPC_ADD_DEVICE, EtSetDevice, InRpcAddDevice, OutRpcAddDevice)
+ DECLARE_RPC("GetDevice", RPC_ADD_DEVICE, EtGetDevice, InRpcAddDevice, OutRpcAddDevice)
+ DECLARE_RPC_EX("EnumDevice", RPC_ENUM_DEVICE, EtEnumDevice, InRpcEnumDevice, OutRpcEnumDevice, FreeRpcEnumDevice)
+ DECLARE_RPC("SetPassword", RPC_SET_PASSWORD, EtSetPassword, InRpcSetPassword, OutRpcSetPassword)
+ DECLARE_RPC_EX("EnumAllDevice", RPC_ENUM_DEVICE, EtEnumAllDevice, InRpcEnumDevice, OutRpcEnumDevice, FreeRpcEnumDevice)
+ DECLARE_RPC("AddLicenseKey", RPC_TEST, EtAddLicenseKey, InRpcTest, OutRpcTest)
+ DECLARE_RPC("DelLicenseKey", RPC_TEST, EtDelLicenseKey, InRpcTest, OutRpcTest)
+ DECLARE_RPC_EX("EnumLicenseKey", RPC_ENUM_LICENSE_KEY, EtEnumLicenseKey, InRpcEnumLicenseKey, OutRpcEnumLicenseKey, FreeRpcEnumLicenseKey)
+ DECLARE_RPC("GetLicenseStatus", RPC_EL_LICENSE_STATUS, EtGetLicenseStatus, InRpcElLicenseStatus, OutRpcElLicenseStatus)
+ DECLARE_RPC("GetBridgeSupport", RPC_BRIDGE_SUPPORT, EtGetBridgeSupport, InRpcBridgeSupport, OutRpcBridgeSupport)
+ DECLARE_RPC("RebootServer", RPC_TEST, EtRebootServer, InRpcTest, OutRpcTest)
+
+ if (ok == false)
+ {
+ err = ERR_NOT_SUPPORTED;
+ }
+
+ PackAddInt(ret, "error", err);
+
+ return ret;
+}
+
+DECLARE_SC("AddDevice", RPC_ADD_DEVICE, EcAddDevice, InRpcAddDevice, OutRpcAddDevice)
+DECLARE_SC("DelDevice", RPC_DELETE_DEVICE, EcDelDevice, InRpcDeleteDevice, OutRpcDeleteDevice)
+DECLARE_SC("SetDevice", RPC_ADD_DEVICE, EcSetDevice, InRpcAddDevice, OutRpcAddDevice)
+DECLARE_SC("GetDevice", RPC_ADD_DEVICE, EcGetDevice, InRpcAddDevice, OutRpcAddDevice)
+DECLARE_SC_EX("EnumDevice", RPC_ENUM_DEVICE, EcEnumDevice, InRpcEnumDevice, OutRpcEnumDevice, FreeRpcEnumDevice)
+DECLARE_SC("SetPassword", RPC_SET_PASSWORD, EcSetPassword, InRpcSetPassword, OutRpcSetPassword)
+DECLARE_SC_EX("EnumAllDevice", RPC_ENUM_DEVICE, EcEnumAllDevice, InRpcEnumDevice, OutRpcEnumDevice, FreeRpcEnumDevice)
+DECLARE_SC("AddLicenseKey", RPC_TEST, EcAddLicenseKey, InRpcTest, OutRpcTest)
+DECLARE_SC("DelLicenseKey", RPC_TEST, EcDelLicenseKey, InRpcTest, OutRpcTest)
+DECLARE_SC_EX("EnumLicenseKey", RPC_ENUM_LICENSE_KEY, EcEnumLicenseKey, InRpcEnumLicenseKey, OutRpcEnumLicenseKey, FreeRpcEnumLicenseKey)
+DECLARE_SC("GetLicenseStatus", RPC_EL_LICENSE_STATUS, EcGetLicenseStatus, InRpcElLicenseStatus, OutRpcElLicenseStatus)
+DECLARE_SC("GetBridgeSupport", RPC_BRIDGE_SUPPORT, EcGetBridgeSupport, InRpcBridgeSupport, OutRpcBridgeSupport)
+DECLARE_SC("RebootServer", RPC_TEST, EcRebootServer, InRpcTest, OutRpcTest)
+
+// Thread to restart the server
+void EiRebootServerThread(THREAD *thread, void *param)
+{
+ // Validate arguments
+ if (thread == NULL)
+ {
+ return;
+ }
+
+ if (el == NULL)
+ {
+ return;
+ }
+
+ // Stopping the server
+ ElStop();
+
+ // Starting the server
+ ElStart();
+}
+
+// Restarting the server
+void EiRebootServer()
+{
+ THREAD *t;
+
+ t = NewThread(EiRebootServerThread, NULL);
+ ReleaseThread(t);
+}
+
+// RPC to restart server
+UINT EtRebootServer(EL *a, RPC_TEST *t)
+{
+
+ EiRebootServer();
+
+ return ERR_NO_ERROR;
+}
+
+// Get support information for the local bridge
+UINT EtGetBridgeSupport(EL *a, RPC_BRIDGE_SUPPORT *t)
+{
+ Zero(t, sizeof(RPC_BRIDGE_SUPPORT));
+
+ t->IsBridgeSupportedOs = IsBridgeSupported();
+ t->IsWinPcapNeeded = IsNeedWinPcap();
+
+ return ERR_NO_ERROR;
+}
+
+// Update the status by checking the all licenses
+void ElCheckLicense(EL_LICENSE_STATUS *st, LICENSE *e)
+{
+}
+
+// Save by analyzing the status of the current license
+void ElParseCurrentLicenseStatus(LICENSE_SYSTEM *s, EL_LICENSE_STATUS *st)
+{
+}
+
+// Get a license status
+UINT EtGetLicenseStatus(EL *e, RPC_EL_LICENSE_STATUS *t)
+{
+ UINT ret = ERR_NO_ERROR;
+ LICENSE_SYSTEM *ls = e->LicenseSystem;
+
+ if (ls == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ Zero(t, sizeof(RPC_EL_LICENSE_STATUS));
+
+ // Get the current license status
+ ElParseCurrentLicenseStatus(ls, e->LicenseStatus);
+
+ t->Valid = e->LicenseStatus->Valid;
+ t->SystemId = e->LicenseStatus->SystemId;
+ t->SystemExpires = e->LicenseStatus->Expires;
+
+ return ret;
+}
+
+// Enumerate the license keys
+UINT EtEnumLicenseKey(EL *el, RPC_ENUM_LICENSE_KEY *t)
+{
+ return ERR_NOT_SUPPORTED;
+}
+
+// Add a license key
+UINT EtAddLicenseKey(EL *e, RPC_TEST *t)
+{
+ return ERR_NOT_SUPPORTED;
+}
+
+// Delete the license key
+UINT EtDelLicenseKey(EL *e, RPC_TEST *t)
+{
+ return ERR_NOT_SUPPORTED;
+}
+
+// Password setting
+UINT EtSetPassword(EL *e, RPC_SET_PASSWORD *t)
+{
+ Copy(e->HashedPassword, t->HashedPassword, SHA1_SIZE);
+
+ ElSaveConfig(e);
+
+ return ERR_NO_ERROR;
+}
+
+// Add a device
+UINT EtAddDevice(EL *e, RPC_ADD_DEVICE *t)
+{
+ if (ElAddCaptureDevice(e, t->DeviceName, &t->LogSetting, t->NoPromiscus) == false)
+ {
+ return ERR_CAPTURE_DEVICE_ADD_ERROR;
+ }
+
+ ElSaveConfig(e);
+
+ return ERR_NO_ERROR;
+}
+
+// Remove the device
+UINT EtDelDevice(EL *e, RPC_DELETE_DEVICE *t)
+{
+ if (ElDeleteCaptureDevice(e, t->DeviceName) == false)
+ {
+ return ERR_CAPTURE_NOT_FOUND;
+ }
+
+ ElSaveConfig(e);
+
+ return ERR_NO_ERROR;
+}
+
+// Get the device
+UINT EtGetDevice(EL *e, RPC_ADD_DEVICE *t)
+{
+ UINT ret = ERR_CAPTURE_NOT_FOUND;
+
+ LockList(e->DeviceList);
+ {
+ EL_DEVICE *d, a;
+ Zero(&a, sizeof(a));
+ StrCpy(a.DeviceName, sizeof(a.DeviceName), t->DeviceName);
+
+ d = Search(e->DeviceList, &a);
+
+ if (d != NULL)
+ {
+ ret = ERR_NO_ERROR;
+
+ Copy(&t->LogSetting, &d->LogSetting, sizeof(HUB_LOG));
+ t->NoPromiscus = d->NoPromiscus;
+ }
+ }
+ UnlockList(e->DeviceList);
+
+ return ret;
+}
+
+// Device Setting
+UINT EtSetDevice(EL *e, RPC_ADD_DEVICE *t)
+{
+ if (ElSetCaptureDeviceLogSetting(e, t->DeviceName, &t->LogSetting) == false)
+ {
+ return ERR_CAPTURE_NOT_FOUND;
+ }
+
+ ElSaveConfig(e);
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate all devices
+UINT EtEnumAllDevice(EL *e, RPC_ENUM_DEVICE *t)
+{
+ TOKEN_LIST *eth;
+ UINT i;
+ if (IsEthSupported() == false)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ FreeRpcEnumDevice(t);
+ Zero(t, sizeof(RPC_ENUM_DEVICE));
+
+ eth = GetEthList();
+
+ t->NumItem = eth->NumTokens;
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_DEVICE_ITEM) * t->NumItem);
+
+ for (i = 0;i < eth->NumTokens;i++)
+ {
+ char *name = eth->Token[i];
+ RPC_ENUM_DEVICE_ITEM *item = &t->Items[i];
+
+ StrCpy(item->DeviceName, sizeof(item->DeviceName), name);
+ }
+
+ FreeToken(eth);
+
+ return ERR_NO_ERROR;
+}
+
+// Device enumeration
+UINT EtEnumDevice(EL *e, RPC_ENUM_DEVICE *t)
+{
+ bool is_beta_expired = ElIsBetaExpired();
+
+ if (is_beta_expired)
+ {
+ // The beta version has expired
+ return ERR_BETA_EXPIRES;
+ }
+
+ FreeRpcEnumDevice(t);
+ Zero(t, sizeof(RPC_ENUM_DEVICE));
+
+ LockList(e->DeviceList);
+ {
+ UINT i;
+
+ t->NumItem = LIST_NUM(e->DeviceList);
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_DEVICE_ITEM) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_DEVICE_ITEM *d = &t->Items[i];
+ EL_DEVICE *eld = LIST_DATA(e->DeviceList, i);
+
+ StrCpy(d->DeviceName, sizeof(d->DeviceName), eld->DeviceName);
+ d->Active = eld->Active && ((ELOG_IS_BETA || e->LicenseStatus->Valid) ? true : false);
+ }
+ }
+ UnlockList(e->DeviceList);
+
+ return ERR_NO_ERROR;
+}
+
+void InRpcAddDevice(RPC_ADD_DEVICE *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ADD_DEVICE));
+ PackGetStr(p, "DeviceName", t->DeviceName, sizeof(t->DeviceName));
+ t->NoPromiscus = PackGetInt(p, "NoPromiscus");
+ t->LogSetting.PacketLogSwitchType = PackGetInt(p, "PacketLogSwitchType");
+
+ for (i = 0;i < NUM_PACKET_LOG;i++)
+ {
+ t->LogSetting.PacketLogConfig[i] = PackGetIntEx(p, "PacketLogConfig", i);
+ }
+}
+
+void OutRpcAddDevice(PACK *p, RPC_ADD_DEVICE *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "DeviceName", t->DeviceName);
+ PackAddInt(p, "NoPromiscus", t->NoPromiscus);
+ PackAddInt(p, "PacketLogSwitchType", t->LogSetting.PacketLogSwitchType);
+
+ for (i = 0;i < NUM_PACKET_LOG;i++)
+ {
+ PackAddIntEx(p, "PacketLogConfig", t->LogSetting.PacketLogConfig[i], i, NUM_PACKET_LOG);
+ }
+}
+
+void InRpcDeleteDevice(RPC_DELETE_DEVICE *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_DELETE_DEVICE));
+ PackGetStr(p, "DeviceName", t->DeviceName, sizeof(t->DeviceName));
+}
+
+void OutRpcDeleteDevice(PACK *p, RPC_DELETE_DEVICE *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "DeviceName", t->DeviceName);
+}
+
+void InRpcEnumDevice(RPC_ENUM_DEVICE *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_DEVICE));
+ t->NumItem = PackGetInt(p, "NumItem");
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_DEVICE_ITEM) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_DEVICE_ITEM *d = &t->Items[i];
+
+ PackGetStrEx(p, "DeviceName", d->DeviceName, sizeof(d->DeviceName), i);
+ d->Active = PackGetBoolEx(p, "Active", i);
+ }
+
+ t->IsLicenseSupported = PackGetBool(p, "IsLicenseSupported");
+}
+
+void OutRpcEnumDevice(PACK *p, RPC_ENUM_DEVICE *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_DEVICE_ITEM *d = &t->Items[i];
+
+ PackAddStrEx(p, "DeviceName", d->DeviceName, i, t->NumItem);
+ PackAddBoolEx(p, "Active", d->Active, i, t->NumItem);
+ }
+
+ PackAddBool(p, "IsLicenseSupported", t->IsLicenseSupported);
+}
+
+void FreeRpcEnumDevice(RPC_ENUM_DEVICE *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_LICENSE_STATUS
+void InRpcElLicenseStatus(RPC_EL_LICENSE_STATUS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_EL_LICENSE_STATUS));
+
+ t->Valid = PackGetBool(p, "Valid");
+ t->SystemId = PackGetInt64(p, "SystemId");
+ t->SystemExpires = PackGetInt64(p, "SystemExpires");
+}
+void OutRpcElLicenseStatus(PACK *p, RPC_EL_LICENSE_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "Valid", t->Valid);
+ PackAddInt64(p, "SystemId", t->SystemId);
+ PackAddInt64(p, "SystemExpires", t->SystemExpires);
+}
+
+// Listener thread
+void ElListenerProc(THREAD *thread, void *param)
+{
+ TCP_ACCEPTED_PARAM *data = (TCP_ACCEPTED_PARAM *)param;
+ EL *e;
+ SOCK *s;
+ UCHAR rand[SHA1_SIZE];
+ UCHAR pass1[SHA1_SIZE], pass2[SHA1_SIZE];
+ // Validate arguments
+ if (data == NULL || thread == NULL)
+ {
+ return;
+ }
+
+ e = (EL *)data->r->ThreadParam;
+ s = data->s;
+ AddRef(s->ref);
+ SetTimeout(s, 5000);
+ LockList(e->AdminThreadList);
+ {
+ AddRef(thread->ref);
+ AddRef(s->ref);
+ Insert(e->AdminThreadList, thread);
+ Insert(e->AdminSockList, s);
+ }
+ UnlockList(e->AdminThreadList);
+ NoticeThreadInit(thread);
+
+ // Submit a challenge
+ Rand(rand, sizeof(rand));
+ SendAll(s, rand, sizeof(rand), false);
+
+ // Receive a response
+ SecurePassword(pass1, e->HashedPassword, rand);
+ Zero(pass2, sizeof(pass2));
+ RecvAll(s, pass2, sizeof(pass2), false);
+
+ if (Cmp(pass1, pass2, SHA1_SIZE) != 0)
+ {
+ // Password incorrect
+ bool code = false;
+ code = Endian32(code);
+ SendAll(s, &code, sizeof(code), false);
+ }
+ else
+ {
+ // Password match
+ bool code = true;
+ RPC *r;
+
+ code = Endian32(code);
+ SendAll(s, &code, sizeof(code), false);
+
+ SetTimeout(s, INFINITE);
+
+ // Start operation as a RPC server
+ r = StartRpcServer(s, ElRpcServer, e);
+ RpcServer(r);
+ RpcFree(r);
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+
+ LockList(e->AdminThreadList);
+ {
+ if (Delete(e->AdminThreadList, thread))
+ {
+ ReleaseThread(thread);
+ }
+ if (Delete(e->AdminSockList, s))
+ {
+ ReleaseSock(s);
+ }
+ }
+ UnlockList(e->AdminThreadList);
+}
+
+// Listener start
+void ElStartListener(EL *e)
+{
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ e->AdminThreadList = NewList(NULL);
+ e->AdminSockList = NewList(NULL);
+
+ e->Listener = NewListenerEx(e->Cedar, LISTENER_TCP, e->Port == 0 ? EL_ADMIN_PORT : e->Port,
+ ElListenerProc, e);
+}
+
+// Listener stop
+void ElStopListener(EL *e)
+{
+ UINT i;
+ THREAD **threads;
+ SOCK **socks;
+ UINT num_threads, num_socks;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ StopAllListener(e->Cedar);
+
+ LockList(e->AdminThreadList);
+ {
+ threads = ToArray(e->AdminThreadList);
+ num_threads = LIST_NUM(e->AdminThreadList);
+ DeleteAll(e->AdminThreadList);
+
+ socks = ToArray(e->AdminSockList);
+ num_socks = LIST_NUM(e->AdminSockList);
+ DeleteAll(e->AdminSockList);
+ }
+ UnlockList(e->AdminThreadList);
+
+ for (i = 0;i < num_socks;i++)
+ {
+ Disconnect(socks[i]);
+ ReleaseSock(socks[i]);
+ }
+
+ for (i = 0;i < num_threads;i++)
+ {
+ WaitThread(threads[i], INFINITE);
+ ReleaseThread(threads[i]);
+ }
+
+ Free(threads);
+ Free(socks);
+
+ ReleaseList(e->AdminSockList);
+ ReleaseList(e->AdminThreadList);
+
+ ReleaseListener(e->Listener);
+}
+
+// Update the log configuration of the capture device
+bool ElSetCaptureDeviceLogSetting(EL *e, char *name, HUB_LOG *log)
+{
+ EL_DEVICE *d;
+ bool ret = false;
+ // Validate arguments
+ if (e == NULL || log == NULL || name == NULL)
+ {
+ return false;
+ }
+
+ LockList(e->DeviceList);
+ {
+ EL_DEVICE t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), name);
+
+ d = Search(e->DeviceList, &t);
+
+ if (d != NULL)
+ {
+ Copy(&d->LogSetting, log, sizeof(HUB_LOG));
+
+ SetLogSwitchType(d->Logger, log->PacketLogSwitchType);
+
+ ret = true;
+ }
+ }
+ UnlockList(e->DeviceList);
+
+ return ret;
+}
+
+// Confirm whether the beta version has expired
+bool ElIsBetaExpired()
+{
+ SYSTEMTIME st;
+ UINT64 expires64;
+ UINT64 now64;
+ if (ELOG_IS_BETA == false)
+ {
+ return false;
+ }
+
+ Zero(&st, sizeof(st));
+
+ st.wYear = ELOG_BETA_EXPIRES_YEAR;
+ st.wMonth = ELOG_BETA_EXPIRES_MONTH;
+ st.wDay = ELOG_BETA_EXPIRES_DAY;
+
+ expires64 = SystemToUINT64(&st);
+ now64 = LocalTime64();
+
+ if (now64 >= expires64)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Capture thread
+void ElCaptureThread(THREAD *thread, void *param)
+{
+}
+
+// Delete the capture device
+bool ElDeleteCaptureDevice(EL *e, char *name)
+{
+ bool ret = false;
+ EL_DEVICE *d, t;
+ // Validate arguments
+ if (e == NULL || name == NULL)
+ {
+ return false;
+ }
+
+ LockList(e->DeviceList);
+ {
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), name);
+
+ d = Search(e->DeviceList, &t);
+
+ if (d != NULL)
+ {
+ // Stop capture
+ d->Halt = true;
+ Cancel(d->Cancel1);
+
+ // Wait for thread stop
+ WaitThread(d->Thread, INFINITE);
+ ReleaseThread(d->Thread);
+
+ // Release the memory
+ Delete(e->DeviceList, d);
+ Free(d);
+
+ ret = true;
+ }
+ }
+ UnlockList(e->DeviceList);
+
+ return ret;
+}
+
+// Add a capture device
+bool ElAddCaptureDevice(EL *e, char *name, HUB_LOG *log, bool no_promiscus)
+{
+ EL_DEVICE *d, t;
+ // Validate arguments
+ if (e == NULL || name == NULL || log == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), name);
+
+ LockList(e->DeviceList);
+ {
+ d = Search(e->DeviceList, &t);
+ if (d != NULL)
+ {
+ // Capture settings with the same name already exists
+ UnlockList(e->DeviceList);
+ return false;
+ }
+
+ // Add a device
+ d = ZeroMalloc(sizeof(EL_DEVICE));
+ StrCpy(d->DeviceName, sizeof(d->DeviceName), name);
+ Copy(&d->LogSetting, log, sizeof(HUB_LOG));
+ d->NoPromiscus = no_promiscus;
+ d->el = e;
+ Insert(e->DeviceList, d);
+
+ // Start the thread
+ d->Thread = NewThread(ElCaptureThread, d);
+ WaitThreadInit(d->Thread);
+ }
+ UnlockList(e->DeviceList);
+
+ ElSaveConfig(e);
+
+ return true;
+}
+
+// Write the license List
+void EiWriteLicenseManager(FOLDER *f, EL *s)
+{
+}
+
+// Read the license list
+void EiLoadLicenseManager(EL *s, FOLDER *f)
+{
+}
+
+// Configuration initialization
+void ElInitConfig(EL *e)
+{
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ // Device list initialization
+ e->DeviceList = NewList(ElCompareDevice);
+
+ // Read configuration file
+ ElLoadConfig(e);
+
+ // Write configuration file
+ ElSaveConfig(e);
+}
+
+// Write the configuration
+void ElSaveConfig(EL *e)
+{
+ FOLDER *root;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ root = CfgCreateFolder(NULL, TAG_ROOT);
+
+ ElSaveConfigToFolder(e, root);
+
+ SaveCfgRw(e->CfgRw, root);
+
+ CfgDeleteFolder(root);
+}
+
+// Write the configuration to the folder
+void ElSaveConfigToFolder(EL *e, FOLDER *root)
+{
+ UINT i;
+ FOLDER *devices;
+ // Validate arguments
+ if (e == NULL || root == NULL)
+ {
+ return;
+ }
+
+ CfgAddInt64(root, "AutoDeleteCheckDiskFreeSpaceMin", e->AutoDeleteCheckDiskFreeSpaceMin);
+
+ CfgAddInt(root, "AdminPort", e->Port);
+
+ CfgAddByte(root, "AdminPassword", e->HashedPassword, sizeof(e->HashedPassword));
+
+ if (ELOG_IS_BETA == false)
+ {
+ EiWriteLicenseManager(CfgCreateFolder(root, "LicenseManager"), e);
+ }
+
+ devices = CfgCreateFolder(root,"Devices");
+
+ LockList(e->DeviceList);
+ {
+ for (i = 0;i < LIST_NUM(e->DeviceList);i++)
+ {
+ FOLDER *f;
+ EL_DEVICE *d = LIST_DATA(e->DeviceList, i);
+
+ f = CfgCreateFolder(devices, d->DeviceName);
+ SiWriteHubLogCfgEx(f, &d->LogSetting, true);
+ CfgAddBool(f, "NoPromiscusMode", d->NoPromiscus);
+ }
+ }
+ UnlockList(e->DeviceList);
+}
+
+// Read the configuration from the folder
+void ElLoadConfigFromFolder(EL *e, FOLDER *root)
+{
+ UINT i;
+ TOKEN_LIST *t;
+ FOLDER *devices;
+
+ // Validate arguments
+ if (e == NULL || root == NULL)
+ {
+ return;
+ }
+
+ i = CfgGetInt(root, "AdminPort");
+ if (i >= 1 && i <= 65535)
+ {
+ e->Port = i;
+ }
+
+ e->AutoDeleteCheckDiskFreeSpaceMin = CfgGetInt64(root, "AutoDeleteCheckDiskFreeSpaceMin");
+ if (CfgIsItem(root, "AutoDeleteCheckDiskFreeSpaceMin") == false && e->AutoDeleteCheckDiskFreeSpaceMin == 0)
+ {
+ e->AutoDeleteCheckDiskFreeSpaceMin = DISK_FREE_SPACE_DEFAULT;
+ }
+
+ if (e->AutoDeleteCheckDiskFreeSpaceMin != 0)
+ {
+ if (e->AutoDeleteCheckDiskFreeSpaceMin < DISK_FREE_SPACE_MIN)
+ {
+ e->AutoDeleteCheckDiskFreeSpaceMin = DISK_FREE_SPACE_MIN;
+ }
+ }
+
+ if (CfgGetByte(root, "AdminPassword", e->HashedPassword, sizeof(e->HashedPassword)) != sizeof(e->HashedPassword))
+ {
+ Hash(e->HashedPassword, "", 0, true);
+ }
+
+ if (ELOG_IS_BETA == false)
+ {
+ EiLoadLicenseManager(e, CfgGetFolder(root, "LicenseManager"));
+ }
+
+ devices = CfgGetFolder(root, "Devices");
+ if(devices != NULL)
+ {
+ LockList(e->DeviceList);
+ {
+ t = CfgEnumFolderToTokenList(devices);
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ char *name = t->Token[i];
+ FOLDER *f = CfgGetFolder(devices, name);
+
+ if (f != NULL)
+ {
+ HUB_LOG g;
+
+ Zero(&g, sizeof(g));
+ SiLoadHubLogCfg(&g, f);
+ ElAddCaptureDevice(e, name, &g, CfgGetBool(f, "NoPromiscusMode"));
+ }
+ }
+ FreeToken(t);
+ }
+ UnlockList(e->DeviceList);
+ }
+}
+
+// Reading configuration
+bool ElLoadConfig(EL *e)
+{
+ FOLDER *root;
+ bool ret = false;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return false;
+ }
+
+ e->Port = EL_ADMIN_PORT;
+
+ e->CfgRw = NewCfgRw(&root, EL_CONFIG_FILENAME);
+
+ if (root != NULL)
+ {
+ ElLoadConfigFromFolder(e, root);
+
+ CfgDeleteFolder(root);
+ }
+ else
+ {
+ char *pass = "";
+ Hash(e->HashedPassword, pass, StrLen(pass), true);
+ e->AutoDeleteCheckDiskFreeSpaceMin = DISK_FREE_SPACE_DEFAULT;
+ }
+
+ return ret;
+}
+
+// Configuration release
+void ElFreeConfig(EL *e)
+{
+ UINT i;
+ LIST *o;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ // Write the configuration file
+ ElSaveConfig(e);
+ FreeCfgRw(e->CfgRw);
+
+ // Stop all capture
+ o = NewList(NULL);
+ LockList(e->DeviceList);
+ {
+ for (i = 0;i < LIST_NUM(e->DeviceList);i++)
+ {
+ EL_DEVICE *d = LIST_DATA(e->DeviceList, i);
+ Insert(o, CopyStr(d->DeviceName));
+ }
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ char *name = LIST_DATA(o, i);
+ ElDeleteCaptureDevice(e, name);
+ Free(name);
+ }
+ ReleaseList(o);
+ }
+ UnlockList(e->DeviceList);
+
+ ReleaseList(e->DeviceList);
+}
+
+// Comparison function of the device
+int ElCompareDevice(void *p1, void *p2)
+{
+ EL_DEVICE *d1, *d2;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ d1 = *(EL_DEVICE **)p1;
+ d2 = *(EL_DEVICE **)p2;
+ if (d1 == NULL || d2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(d1->DeviceName, d2->DeviceName);
+}
+
+// Clean-up the EL
+void CleanupEl(EL *e)
+{
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ // Stop Eraser
+ FreeEraser(e->Eraser);
+
+ // Stop Listener
+ ElStopListener(e);
+
+ // Setting release
+ ElFreeConfig(e);
+
+ // Free the license system
+ if(e->LicenseSystem != NULL)
+ {
+ }
+
+ // Free the license status
+ if(e->LicenseStatus != NULL)
+ {
+ Free(e->LicenseStatus);
+ }
+
+ // Ethernet release
+ FreeEth();
+
+ ReleaseCedar(e->Cedar);
+
+ DeleteLock(e->lock);
+
+ Free(e);
+}
+
+// Release the EL
+void ReleaseEl(EL *e)
+{
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ if (Release(e->ref) == 0)
+ {
+ CleanupEl(e);
+ }
+}
+
+// Create the EL
+EL *NewEl()
+{
+ EL *e;
+
+#ifdef OS_WIN32
+ RegistWindowsFirewallAll();
+#endif
+
+ e = ZeroMalloc(sizeof(EL));
+ e->lock = NewLock();
+ e->ref = NewRef();
+
+ e->Cedar = NewCedar(NULL, NULL);
+
+
+ // Ethernet initialization
+ InitEth();
+
+ // Setting initialization
+ ElInitConfig(e);
+
+ // Listener start
+ ElStartListener(e);
+
+ // Initialize the license status
+ ElParseCurrentLicenseStatus(e->LicenseSystem, e->LicenseStatus);
+
+ // Eraser start
+ e->Eraser = NewEraser(NULL, e->AutoDeleteCheckDiskFreeSpaceMin);
+
+ return e;
+}
+
+// EL start
+void ElStart()
+{
+ // Raise the priority
+ OSSetHighPriority();
+
+ Lock(el_lock);
+ {
+ el = NewEl();
+ }
+ Unlock(el_lock);
+}
+
+// EL stop
+void ElStop()
+{
+ Lock(el_lock);
+ {
+ ReleaseEl(el);
+ el = NULL;
+ }
+ Unlock(el_lock);
+}
+
+// EL initialization
+void ElInit()
+{
+ // Lock initialization
+ el_lock = NewLock();
+}
+
+// EL release
+void ElFree()
+{
+ // Lock release
+ DeleteLock(el_lock);
+ el_lock = NULL;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/EtherLog.h b/src/Cedar/EtherLog.h
new file mode 100644
index 00000000..499fd359
--- /dev/null
+++ b/src/Cedar/EtherLog.h
@@ -0,0 +1,255 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// EtherLog.h
+// Header of EtherLog.c
+
+#ifndef ETHERLOG_H
+#define ETHERLOG_H
+
+// Whether this is a beta version
+#define ELOG_IS_BETA true
+
+// Beta expiration date
+#define ELOG_BETA_EXPIRES_YEAR 2008
+#define ELOG_BETA_EXPIRES_MONTH 12
+#define ELOG_BETA_EXPIRES_DAY 2
+
+// Version information
+//#define EL_VER 201
+//#define EL_BUILD 1600
+//#define EL_BETA 1
+#define MAX_LOGGING_QUEUE_LEN 100000
+
+// RPC related
+struct RPC_ADD_DEVICE
+{
+ char DeviceName[MAX_SIZE]; // Device name
+ HUB_LOG LogSetting; // Log settings
+ bool NoPromiscus; // Without promiscuous mode
+};
+
+struct RPC_DELETE_DEVICE
+{
+ char DeviceName[MAX_SIZE]; // Device name
+};
+
+struct RPC_ENUM_DEVICE_ITEM
+{
+ char DeviceName[MAX_SIZE]; // Device name
+ bool Active; // Running flag
+};
+
+struct RPC_ENUM_DEVICE
+{
+ UINT NumItem; // Number of items
+ RPC_ENUM_DEVICE_ITEM *Items; // Items
+ bool IsLicenseSupported; // Whether the license system is supported
+};
+
+// License status of the service
+struct RPC_EL_LICENSE_STATUS
+{
+ BOOL Valid; // Enable flag
+ UINT64 SystemId; // System ID
+ UINT64 SystemExpires; // System expiration date
+};
+
+// Device
+struct EL_DEVICE
+{
+ EL *el; // EL
+ char DeviceName[MAX_SIZE]; // Device name
+ HUB_LOG LogSetting; // Log settings
+ THREAD *Thread; // Thread
+ CANCEL *Cancel1; // Cancel 1
+ CANCEL *Cancel2; // Cancel 2
+ volatile bool Halt; // Halting flag
+ bool Active; // Running flag
+ bool NoPromiscus; // Without promiscuous mode
+ LOG *Logger; // Logger
+};
+
+// License status
+struct EL_LICENSE_STATUS
+{
+ BOOL Valid; // Enable flag
+ UINT64 SystemId; // System ID
+ UINT64 Expires; // Expiration date
+};
+
+// EtherLogger
+struct EL
+{
+ LOCK *lock; // Lock
+ REF *ref; // Reference counter
+ CEDAR *Cedar; // Cedar
+ LIST *DeviceList; // Device list
+ CFG_RW *CfgRw; // Config R/W
+ UINT Port; // Port number
+ LISTENER *Listener; // Listener
+ UCHAR HashedPassword[SHA1_SIZE]; // Password
+ LIST *AdminThreadList; // Management thread list
+ LIST *AdminSockList; // Management socket list
+ LICENSE_SYSTEM *LicenseSystem; // License system
+ EL_LICENSE_STATUS *LicenseStatus; // License status
+ UINT64 AutoDeleteCheckDiskFreeSpaceMin; // Minimum free disk space
+ ERASER *Eraser; // Eraser
+};
+
+// Function prototype
+void ElInit();
+void ElFree();
+void ElStart();
+void ElStop();
+EL *NewEl();
+void ReleaseEl(EL *e);
+void CleanupEl(EL *e);
+void ElInitConfig(EL *e);
+void ElFreeConfig(EL *e);
+bool ElLoadConfig(EL *e);
+void ElLoadConfigFromFolder(EL *e, FOLDER *root);
+void ElSaveConfig(EL *e);
+void ElSaveConfigToFolder(EL *e, FOLDER *root);
+int ElCompareDevice(void *p1, void *p2);
+bool ElAddCaptureDevice(EL *e, char *name, HUB_LOG *log, bool no_promiscus);
+bool ElDeleteCaptureDevice(EL *e, char *name);
+bool ElSetCaptureDeviceLogSetting(EL *e, char *name, HUB_LOG *log);
+void ElCaptureThread(THREAD *thread, void *param);
+void ElStartListener(EL *e);
+void ElStopListener(EL *e);
+void ElListenerProc(THREAD *thread, void *param);
+PACK *ElRpcServer(RPC *r, char *name, PACK *p);
+void ElCheckLicense(EL_LICENSE_STATUS *st, LICENSE *e);
+void ElParseCurrentLicenseStatus(LICENSE_SYSTEM *s, EL_LICENSE_STATUS *st);
+bool ElIsBetaExpired();
+
+
+UINT EtAddDevice(EL *e, RPC_ADD_DEVICE *t);
+UINT EtDelDevice(EL *e, RPC_DELETE_DEVICE *t);
+UINT EtSetDevice(EL *e, RPC_ADD_DEVICE *t);
+UINT EtGetDevice(EL *e, RPC_ADD_DEVICE *t);
+UINT EtEnumDevice(EL *e, RPC_ENUM_DEVICE *t);
+UINT EtEnumAllDevice(EL *e, RPC_ENUM_DEVICE *t);
+UINT EtSetPassword(EL *e, RPC_SET_PASSWORD *t);
+UINT EtAddLicenseKey(EL *a, RPC_TEST *t);
+UINT EtDelLicenseKey(EL *a, RPC_TEST *t);
+UINT EtEnumLicenseKey(EL *a, RPC_ENUM_LICENSE_KEY *t);
+UINT EtGetLicenseStatus(EL *a, RPC_EL_LICENSE_STATUS *t);
+UINT EtGetBridgeSupport(EL *a, RPC_BRIDGE_SUPPORT *t);
+UINT EtRebootServer(EL *a, RPC_TEST *t);
+
+UINT EcAddDevice(RPC *r, RPC_ADD_DEVICE *t);
+UINT EcDelDevice(RPC *r, RPC_DELETE_DEVICE *t);
+UINT EcSetDevice(RPC *r, RPC_ADD_DEVICE *t);
+UINT EcGetDevice(RPC *r, RPC_ADD_DEVICE *t);
+UINT EcEnumDevice(RPC *r, RPC_ENUM_DEVICE *t);
+UINT EcEnumAllDevice(RPC *r, RPC_ENUM_DEVICE *t);
+UINT EcSetPassword(RPC *r, RPC_SET_PASSWORD *t);
+UINT EcAddLicenseKey(RPC *r, RPC_TEST *t);
+UINT EcDelLicenseKey(RPC *r, RPC_TEST *t);
+UINT EcEnumLicenseKey(RPC *r, RPC_ENUM_LICENSE_KEY *t);
+UINT EcGetLicenseStatus(RPC *r, RPC_EL_LICENSE_STATUS *t);
+UINT EcGetBridgeSupport(RPC *r, RPC_BRIDGE_SUPPORT *t);
+UINT EcRebootServer(RPC *r, RPC_TEST *t);
+
+UINT EcConnect(char *host, UINT port, char *password, RPC **rpc);
+void EcDisconnect(RPC *rpc);
+
+void InRpcAddDevice(RPC_ADD_DEVICE *t, PACK *p);
+void OutRpcAddDevice(PACK *p, RPC_ADD_DEVICE *t);
+void InRpcDeleteDevice(RPC_DELETE_DEVICE *t, PACK *p);
+void OutRpcDeleteDevice(PACK *p, RPC_DELETE_DEVICE *t);
+void InRpcEnumDevice(RPC_ENUM_DEVICE *t, PACK *p);
+void OutRpcEnumDevice(PACK *p, RPC_ENUM_DEVICE *t);
+void FreeRpcEnumDevice(RPC_ENUM_DEVICE *t);
+void InRpcEnumLicenseKey(RPC_ENUM_LICENSE_KEY *t, PACK *p);
+void OutRpcEnumLicenseKey(PACK *p, RPC_ENUM_LICENSE_KEY *t);
+void FreeRpcEnumLicenseKey(RPC_ENUM_LICENSE_KEY *t);
+void InRpcElLicenseStatus(RPC_EL_LICENSE_STATUS *t, PACK *p);
+void OutRpcElLicenseStatus(PACK *p, RPC_EL_LICENSE_STATUS *t);
+
+#endif // ETHERLOG_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Hub.c b/src/Cedar/Hub.c
new file mode 100644
index 00000000..bdd28564
--- /dev/null
+++ b/src/Cedar/Hub.c
@@ -0,0 +1,7123 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Hub.c
+// Virtual HUB module
+
+#include "CedarPch.h"
+
+static UCHAR broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+static char vgs_ua_str[9] = {0};
+static bool g_vgs_emb_tag = false;
+
+// A list of administration options that are currently supported and its default values
+// These names must be shorter than 64 bytes
+ADMIN_OPTION admin_options[] =
+{
+ {"allow_hub_admin_change_option", 0},
+ {"max_users", 0},
+ {"max_multilogins_per_user", 0},
+ {"max_groups", 0},
+ {"max_accesslists", 0},
+ {"max_sessions_client_bridge_apply", 0},
+ {"max_sessions", 0},
+ {"max_sessions_client", 0},
+ {"max_sessions_bridge", 0},
+ {"max_bitrates_download", 0},
+ {"max_bitrates_upload", 0},
+ {"deny_empty_password", 0},
+ {"deny_bridge", 0},
+ {"deny_routing", 0},
+ {"deny_qos", 0},
+ {"deny_change_user_password", 0},
+ {"no_change_users", 0},
+ {"no_change_groups", 0},
+ {"no_securenat", 0},
+ {"no_securenat_enablenat", 0},
+ {"no_securenat_enabledhcp", 0},
+ {"no_cascade", 0},
+ {"no_online", 0},
+ {"no_offline", 0},
+ {"no_change_log_config", 0},
+ {"no_disconnect_session", 0},
+ {"no_delete_iptable", 0},
+ {"no_delete_mactable", 0},
+ {"no_enum_session", 0},
+ {"no_query_session", 0},
+ {"no_change_admin_password", 0},
+ {"no_change_log_switch_type", 0},
+ {"no_change_access_list", 0},
+ {"no_change_access_control_list", 0},
+ {"no_change_cert_list", 0},
+ {"no_change_crl_list", 0},
+ {"no_read_log_file", 0},
+ {"deny_hub_admin_change_ext_option", 0},
+ {"no_delay_jitter_packet_loss", 0},
+ {"no_change_msg", 0},
+ {"no_access_list_include_file", 0},
+};
+
+UINT num_admin_options = sizeof(admin_options) / sizeof(ADMIN_OPTION);
+
+// Create a user list
+LIST *NewUserList()
+{
+ LIST *o = NewList(CompareUserList);
+
+ return o;
+}
+
+// Search whether the specified user matches to the user list (with cache expiration)
+bool IsUserMatchInUserListWithCacheExpires(LIST *o, char *filename, UINT64 user_hash, UINT64 lifetime)
+{
+ bool ret = false;
+ UINT64 now = Tick64();
+ // Validate arguments
+ if (o == NULL || filename == NULL || user_hash == 0)
+ {
+ return false;
+ }
+
+ LockList(o);
+ {
+ if (lifetime != 0)
+ {
+ if (o->Param1 == 0 || (now >= (o->Param1 + lifetime)))
+ {
+ DeleteAllUserListCache(o);
+
+ o->Param1 = now;
+ }
+ }
+
+ ret = IsUserMatchInUserList(o, filename, user_hash);
+ }
+ UnlockList(o);
+
+ return ret;
+}
+bool IsUserMatchInUserListWithCacheExpiresAcl(LIST *o, char *name_in_acl, UINT64 user_hash, UINT64 lifetime)
+{
+ char tmp[16];
+ bool exclude = false;
+ char filename[MAX_SIZE];
+ char filename2[MAX_SIZE];
+ bool is_full_path = false;
+ bool ret = false;
+ // Validate arguments
+ if (o == NULL || name_in_acl == NULL || user_hash == 0 || StrLen(name_in_acl) < 9)
+ {
+ return false;
+ }
+
+ StrCpy(tmp, sizeof(tmp), name_in_acl);
+ StrLower(tmp);
+
+ tmp[8] = 0;
+
+ if (Cmp(tmp, ACCESS_LIST_INCLUDED_PREFIX, 8) == 0)
+ {
+ // include
+ exclude = false;
+ }
+ else
+ {
+ // exclude
+ exclude = true;
+ }
+
+ // Extract the file name
+ StrCpy(filename, sizeof(filename), name_in_acl + 8);
+ Trim(filename);
+
+ // Identify whether the file name is an absolute path
+ if (filename[0] == '\\' || filename[0] == '/' || (filename[1] == ':' && filename[2] == '\\'))
+ {
+ is_full_path = true;
+ }
+
+ if (is_full_path == false)
+ {
+ // Prepend a '@' if the file name is a relative path
+ StrCpy(filename2, sizeof(filename2), "@");
+ StrCat(filename2, sizeof(filename2), filename);
+ StrCpy(filename, sizeof(filename), filename2);
+ }
+
+ ret = IsUserMatchInUserListWithCacheExpires(o, filename, user_hash, lifetime);
+
+ if (exclude)
+ {
+ ret = NEGATIVE_BOOL(ret);
+ }
+
+ return ret;
+}
+
+// Search whether the specified user matches to the user list
+bool IsUserMatchInUserList(LIST *o, char *filename, UINT64 user_hash)
+{
+ USERLIST *u;
+ bool ret = false;
+ // Validate arguments
+ if (o == NULL || filename == NULL || user_hash == 0)
+ {
+ return false;
+ }
+
+ LockList(o);
+ {
+ u = FindUserList(o, filename);
+ if (u == NULL)
+ {
+ u = LoadUserList(o, filename);
+ }
+
+ if (u != NULL)
+ {
+ ret = IsInt64InList(u->UserHashList, user_hash);
+ }
+ }
+ UnlockList(o);
+
+ return ret;
+}
+
+// Read the user list
+USERLIST *LoadUserList(LIST *o, char *filename)
+{
+ USERLIST *u;
+ BUF *b;
+ // Validate arguments
+ if (o == NULL || filename == NULL)
+ {
+ return NULL;
+ }
+
+ u = FindUserList(o, filename);
+
+ if (u != NULL)
+ {
+ Delete(o, u);
+
+ FreeUserListEntry(u);
+ }
+
+ u = ZeroMalloc(sizeof(USERLIST));
+
+ StrCpy(u->Filename, sizeof(u->Filename), filename);
+
+ u->UserHashList = NewInt64List(false);
+
+ b = ReadDumpWithMaxSize(filename, ACCESS_LIST_INCLUDE_FILE_MAX_SIZE);
+ if (b != NULL)
+ {
+ while (true)
+ {
+ char *line = CfgReadNextLine(b);
+ UINT64 ui;
+ if (line == NULL)
+ {
+ break;
+ }
+
+ Trim(line);
+
+ if (IsEmptyStr(line) == false)
+ {
+ if (StartWith(line, "#") == false &&
+ StartWith(line, "//") == false &&
+ StartWith(line, ";") == false)
+ {
+ ui = UsernameToInt64(line);
+
+ AddInt64Distinct(u->UserHashList, ui);
+ }
+ }
+
+ Free(line);
+ }
+
+ FreeBuf(b);
+ }
+
+ Add(o, u);
+
+ return u;
+}
+
+// Release the user list entry
+void FreeUserListEntry(USERLIST *u)
+{
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+
+ ReleaseInt64List(u->UserHashList);
+
+ Free(u);
+}
+
+// Search in user list
+USERLIST *FindUserList(LIST *o, char *filename)
+{
+ USERLIST t, *u;
+ // Validate arguments
+ if (o == NULL || filename == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Filename, sizeof(t.Filename), filename);
+
+ u = Search(o, &t);
+
+ return u;
+}
+
+// User list entry comparison function
+int CompareUserList(void *p1, void *p2)
+{
+ USERLIST *u1, *u2;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ u1 = *(USERLIST **)p1;
+ u2 = *(USERLIST **)p2;
+ if (u1 == NULL || u2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(u1->Filename, u2->Filename);
+}
+
+// Delete the cache of the all user list
+void DeleteAllUserListCache(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ LockList(o);
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ USERLIST *u = LIST_DATA(o, i);
+
+ FreeUserListEntry(u);
+ }
+
+ DeleteAll(o);
+ }
+ UnlockList(o);
+}
+
+// Release the user list
+void FreeUserList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ USERLIST *u = LIST_DATA(o, i);
+
+ FreeUserListEntry(u);
+ }
+
+ ReleaseList(o);
+}
+
+// Get whether the specified message is a URL string
+bool IsURLMsg(wchar_t *str, char *url, UINT url_size)
+{
+ UNI_TOKEN_LIST *t;
+ bool ret = false;
+ UINT i;
+ UINT n = 0;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return false;
+ }
+
+ t = UniParseToken(str, L"\r\n");
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ wchar_t *str = t->Token[i];
+
+ if (IsEmptyUniStr(str) == false)
+ {
+ n++;
+
+ UniTrim(str);
+
+ if (n == 1)
+ {
+ if (UniStartWith(str, L"http://") ||
+ UniStartWith(str, L"https://") ||
+ UniStartWith(str, L"ftp://"))
+ {
+ ret = true;
+
+ UniToStr(url, url_size, str);
+ }
+ }
+ }
+ }
+
+ if (n != 1)
+ {
+ ret = false;
+ }
+
+ UniFreeToken(t);
+
+ return ret;
+}
+
+// Get data from RPC_ADMIN_OPTION
+UINT GetHubAdminOptionData(RPC_ADMIN_OPTION *ao, char *name)
+{
+ UINT i;
+ // Validate arguments
+ if (ao == NULL || name == NULL)
+ {
+ return INFINITE;
+ }
+
+ for (i = 0;i < ao->NumItem;i++)
+ {
+ ADMIN_OPTION *a = &ao->Items[i];
+
+ if (StrCmpi(a->Name, name) == 0)
+ {
+ return a->Value;
+ }
+ }
+
+ return INFINITE;
+}
+void GetHubAdminOptionDataAndSet(RPC_ADMIN_OPTION *ao, char *name, UINT *dest)
+{
+ UINT value;
+ // Validate arguments
+ if (ao == NULL || name == NULL || dest == NULL)
+ {
+ return;
+ }
+
+ value = GetHubAdminOptionData(ao, name);
+ if (value == INFINITE)
+ {
+ return;
+ }
+
+ *dest = value;
+}
+
+// Set the contents of the HUB_OPTION based on the data
+void DataToHubOptionStruct(HUB_OPTION *o, RPC_ADMIN_OPTION *ao)
+{
+ // Validate arguments
+ if (o == NULL || ao == NULL)
+ {
+ return;
+ }
+
+ GetHubAdminOptionDataAndSet(ao, "NoAddressPollingIPv4", &o->NoArpPolling);
+ GetHubAdminOptionDataAndSet(ao, "NoAddressPollingIPv6", &o->NoIPv6AddrPolling);
+ GetHubAdminOptionDataAndSet(ao, "NoIpTable", &o->NoIpTable);
+ GetHubAdminOptionDataAndSet(ao, "NoMacAddressLog", &o->NoMacAddressLog);
+ GetHubAdminOptionDataAndSet(ao, "ManageOnlyPrivateIP", &o->ManageOnlyPrivateIP);
+ GetHubAdminOptionDataAndSet(ao, "ManageOnlyLocalUnicastIPv6", &o->ManageOnlyLocalUnicastIPv6);
+ GetHubAdminOptionDataAndSet(ao, "DisableIPParsing", &o->DisableIPParsing);
+ GetHubAdminOptionDataAndSet(ao, "YieldAfterStorePacket", &o->YieldAfterStorePacket);
+ GetHubAdminOptionDataAndSet(ao, "NoSpinLockForPacketDelay", &o->NoSpinLockForPacketDelay);
+ GetHubAdminOptionDataAndSet(ao, "BroadcastStormDetectionThreshold", &o->BroadcastStormDetectionThreshold);
+ GetHubAdminOptionDataAndSet(ao, "ClientMinimumRequiredBuild", &o->ClientMinimumRequiredBuild);
+ GetHubAdminOptionDataAndSet(ao, "FilterPPPoE", &o->FilterPPPoE);
+ GetHubAdminOptionDataAndSet(ao, "FilterOSPF", &o->FilterOSPF);
+ GetHubAdminOptionDataAndSet(ao, "FilterIPv4", &o->FilterIPv4);
+ GetHubAdminOptionDataAndSet(ao, "FilterIPv6", &o->FilterIPv6);
+ GetHubAdminOptionDataAndSet(ao, "FilterNonIP", &o->FilterNonIP);
+ GetHubAdminOptionDataAndSet(ao, "NoIPv4PacketLog", &o->NoIPv4PacketLog);
+ GetHubAdminOptionDataAndSet(ao, "NoIPv6PacketLog", &o->NoIPv6PacketLog);
+ GetHubAdminOptionDataAndSet(ao, "FilterBPDU", &o->FilterBPDU);
+ GetHubAdminOptionDataAndSet(ao, "NoIPv6DefaultRouterInRAWhenIPv6", &o->NoIPv6DefaultRouterInRAWhenIPv6);
+ GetHubAdminOptionDataAndSet(ao, "NoLookBPDUBridgeId", &o->NoLookBPDUBridgeId);
+ GetHubAdminOptionDataAndSet(ao, "NoManageVlanId", &o->NoManageVlanId);
+ GetHubAdminOptionDataAndSet(ao, "VlanTypeId", &o->VlanTypeId);
+ GetHubAdminOptionDataAndSet(ao, "FixForDLinkBPDU", &o->FixForDLinkBPDU);
+ GetHubAdminOptionDataAndSet(ao, "RequiredClientId", &o->RequiredClientId);
+ GetHubAdminOptionDataAndSet(ao, "AdjustTcpMssValue", &o->AdjustTcpMssValue);
+ GetHubAdminOptionDataAndSet(ao, "DisableAdjustTcpMss", &o->DisableAdjustTcpMss);
+ GetHubAdminOptionDataAndSet(ao, "NoDhcpPacketLogOutsideHub", &o->NoDhcpPacketLogOutsideHub);
+ GetHubAdminOptionDataAndSet(ao, "DisableHttpParsing", &o->DisableHttpParsing);
+ GetHubAdminOptionDataAndSet(ao, "DisableUdpAcceleration", &o->DisableUdpAcceleration);
+ GetHubAdminOptionDataAndSet(ao, "DisableUdpFilterForLocalBridgeNic", &o->DisableUdpFilterForLocalBridgeNic);
+ GetHubAdminOptionDataAndSet(ao, "ApplyIPv4AccessListOnArpPacket", &o->ApplyIPv4AccessListOnArpPacket);
+ GetHubAdminOptionDataAndSet(ao, "RemoveDefGwOnDhcpForLocalhost", &o->RemoveDefGwOnDhcpForLocalhost);
+ GetHubAdminOptionDataAndSet(ao, "SecureNAT_MaxTcpSessionsPerIp", &o->SecureNAT_MaxTcpSessionsPerIp);
+ GetHubAdminOptionDataAndSet(ao, "SecureNAT_MaxTcpSynSentPerIp", &o->SecureNAT_MaxTcpSynSentPerIp);
+ GetHubAdminOptionDataAndSet(ao, "SecureNAT_MaxUdpSessionsPerIp", &o->SecureNAT_MaxUdpSessionsPerIp);
+ GetHubAdminOptionDataAndSet(ao, "SecureNAT_MaxDnsSessionsPerIp", &o->SecureNAT_MaxDnsSessionsPerIp);
+ GetHubAdminOptionDataAndSet(ao, "SecureNAT_MaxIcmpSessionsPerIp", &o->SecureNAT_MaxIcmpSessionsPerIp);
+ GetHubAdminOptionDataAndSet(ao, "AccessListIncludeFileCacheLifetime", &o->AccessListIncludeFileCacheLifetime);
+ GetHubAdminOptionDataAndSet(ao, "DisableKernelModeSecureNAT", &o->DisableKernelModeSecureNAT);
+ GetHubAdminOptionDataAndSet(ao, "DisableUserModeSecureNAT", &o->DisableUserModeSecureNAT);
+ GetHubAdminOptionDataAndSet(ao, "DisableCheckMacOnLocalBridge", &o->DisableCheckMacOnLocalBridge);
+ GetHubAdminOptionDataAndSet(ao, "DisableCorrectIpOffloadChecksum", &o->DisableCorrectIpOffloadChecksum);
+ GetHubAdminOptionDataAndSet(ao, "BroadcastLimiterStrictMode", &o->BroadcastLimiterStrictMode);
+ GetHubAdminOptionDataAndSet(ao, "MaxLoggedPacketsPerMinute", &o->MaxLoggedPacketsPerMinute);
+ GetHubAdminOptionDataAndSet(ao, "DoNotSaveHeavySecurityLogs", &o->DoNotSaveHeavySecurityLogs);
+}
+
+// Convert the contents of the HUB_OPTION to data
+void HubOptionStructToData(RPC_ADMIN_OPTION *ao, HUB_OPTION *o, char *hub_name)
+{
+ LIST *aol;
+ UINT i;
+ // Validate arguments
+ if (ao == NULL || o == NULL || hub_name == NULL)
+ {
+ return;
+ }
+
+ aol = NewListFast(NULL);
+
+ Add(aol, NewAdminOption("NoAddressPollingIPv4", o->NoArpPolling));
+ Add(aol, NewAdminOption("NoAddressPollingIPv6", o->NoIPv6AddrPolling));
+ Add(aol, NewAdminOption("NoIpTable", o->NoIpTable));
+ Add(aol, NewAdminOption("NoMacAddressLog", o->NoMacAddressLog));
+ Add(aol, NewAdminOption("ManageOnlyPrivateIP", o->ManageOnlyPrivateIP));
+ Add(aol, NewAdminOption("ManageOnlyLocalUnicastIPv6", o->ManageOnlyLocalUnicastIPv6));
+ Add(aol, NewAdminOption("DisableIPParsing", o->DisableIPParsing));
+ Add(aol, NewAdminOption("YieldAfterStorePacket", o->YieldAfterStorePacket));
+ Add(aol, NewAdminOption("NoSpinLockForPacketDelay", o->NoSpinLockForPacketDelay));
+ Add(aol, NewAdminOption("BroadcastStormDetectionThreshold", o->BroadcastStormDetectionThreshold));
+ Add(aol, NewAdminOption("ClientMinimumRequiredBuild", o->ClientMinimumRequiredBuild));
+ Add(aol, NewAdminOption("FilterPPPoE", o->FilterPPPoE));
+ Add(aol, NewAdminOption("FilterOSPF", o->FilterOSPF));
+ Add(aol, NewAdminOption("FilterIPv4", o->FilterIPv4));
+ Add(aol, NewAdminOption("FilterIPv6", o->FilterIPv6));
+ Add(aol, NewAdminOption("FilterNonIP", o->FilterNonIP));
+ Add(aol, NewAdminOption("NoIPv4PacketLog", o->NoIPv4PacketLog));
+ Add(aol, NewAdminOption("NoIPv6PacketLog", o->NoIPv6PacketLog));
+ Add(aol, NewAdminOption("FilterBPDU", o->FilterBPDU));
+ Add(aol, NewAdminOption("NoIPv6DefaultRouterInRAWhenIPv6", o->NoIPv6DefaultRouterInRAWhenIPv6));
+ Add(aol, NewAdminOption("NoLookBPDUBridgeId", o->NoLookBPDUBridgeId));
+ Add(aol, NewAdminOption("NoManageVlanId", o->NoManageVlanId));
+ Add(aol, NewAdminOption("VlanTypeId", o->VlanTypeId));
+ Add(aol, NewAdminOption("FixForDLinkBPDU", o->FixForDLinkBPDU));
+ Add(aol, NewAdminOption("RequiredClientId", o->RequiredClientId));
+ Add(aol, NewAdminOption("AdjustTcpMssValue", o->AdjustTcpMssValue));
+ Add(aol, NewAdminOption("DisableAdjustTcpMss", o->DisableAdjustTcpMss));
+ Add(aol, NewAdminOption("NoDhcpPacketLogOutsideHub", o->NoDhcpPacketLogOutsideHub));
+ Add(aol, NewAdminOption("DisableHttpParsing", o->DisableHttpParsing));
+ Add(aol, NewAdminOption("DisableUdpAcceleration", o->DisableUdpAcceleration));
+ Add(aol, NewAdminOption("DisableUdpFilterForLocalBridgeNic", o->DisableUdpFilterForLocalBridgeNic));
+ Add(aol, NewAdminOption("ApplyIPv4AccessListOnArpPacket", o->ApplyIPv4AccessListOnArpPacket));
+ Add(aol, NewAdminOption("RemoveDefGwOnDhcpForLocalhost", o->RemoveDefGwOnDhcpForLocalhost));
+ Add(aol, NewAdminOption("SecureNAT_MaxTcpSessionsPerIp", o->SecureNAT_MaxTcpSessionsPerIp));
+ Add(aol, NewAdminOption("SecureNAT_MaxTcpSynSentPerIp", o->SecureNAT_MaxTcpSynSentPerIp));
+ Add(aol, NewAdminOption("SecureNAT_MaxUdpSessionsPerIp", o->SecureNAT_MaxUdpSessionsPerIp));
+ Add(aol, NewAdminOption("SecureNAT_MaxDnsSessionsPerIp", o->SecureNAT_MaxDnsSessionsPerIp));
+ Add(aol, NewAdminOption("SecureNAT_MaxIcmpSessionsPerIp", o->SecureNAT_MaxIcmpSessionsPerIp));
+ Add(aol, NewAdminOption("AccessListIncludeFileCacheLifetime", o->AccessListIncludeFileCacheLifetime));
+ Add(aol, NewAdminOption("DisableKernelModeSecureNAT", o->DisableKernelModeSecureNAT));
+ Add(aol, NewAdminOption("DisableUserModeSecureNAT", o->DisableUserModeSecureNAT));
+ Add(aol, NewAdminOption("DisableCheckMacOnLocalBridge", o->DisableCheckMacOnLocalBridge));
+ Add(aol, NewAdminOption("DisableCorrectIpOffloadChecksum", o->DisableCorrectIpOffloadChecksum));
+ Add(aol, NewAdminOption("BroadcastLimiterStrictMode", o->BroadcastLimiterStrictMode));
+ Add(aol, NewAdminOption("MaxLoggedPacketsPerMinute", o->MaxLoggedPacketsPerMinute));
+ Add(aol, NewAdminOption("DoNotSaveHeavySecurityLogs", o->DoNotSaveHeavySecurityLogs));
+
+ Zero(ao, sizeof(RPC_ADMIN_OPTION));
+
+ StrCpy(ao->HubName, sizeof(ao->HubName), hub_name);
+
+ ao->NumItem = LIST_NUM(aol);
+ ao->Items = ZeroMalloc(sizeof(ADMIN_OPTION) * ao->NumItem);
+
+ for (i = 0;i < LIST_NUM(aol);i++)
+ {
+ ADMIN_OPTION *a = LIST_DATA(aol, i);
+
+ Copy(&ao->Items[i], a, sizeof(ADMIN_OPTION));
+
+ Free(a);
+ }
+
+ ReleaseList(aol);
+}
+
+// Create a new ADMIN OPTION
+ADMIN_OPTION *NewAdminOption(char *name, UINT value)
+{
+ ADMIN_OPTION *a;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(ADMIN_OPTION));
+ StrCpy(a->Name, sizeof(a->Name), name);
+ a->Value = value;
+
+ return a;
+}
+
+// Clone the AC list
+LIST *CloneAcList(LIST *o)
+{
+ LIST *ret;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return NULL;
+ }
+
+ ret = NewAcList();
+ SetAcList(ret, o);
+
+ return ret;
+}
+
+// Set all the AC list
+void SetAcList(LIST *o, LIST *src)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL || src == NULL)
+ {
+ return;
+ }
+
+ DelAllAc(o);
+
+ for (i = 0;i < LIST_NUM(src);i++)
+ {
+ AC *ac = LIST_DATA(src, i);
+
+ AddAc(o, ac);
+ }
+}
+
+// Remove all AC from the AC list
+void DelAllAc(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ AC *ac = LIST_DATA(o, i);
+
+ Free(ac);
+ }
+
+ DeleteAll(o);
+}
+
+// Release the AC list
+void FreeAcList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ AC *ac = LIST_DATA(o, i);
+
+ Free(ac);
+ }
+
+ ReleaseList(o);
+}
+
+// Generate a string that indicates the contents of the AC
+char *GenerateAcStr(AC *ac)
+{
+ char tmp[MAX_SIZE];
+ char ip[64], mask[64];
+
+ if (ac == NULL)
+ {
+ return NULL;
+ }
+
+ IPToStr(ip, sizeof(ip), &ac->IpAddress);
+ MaskToStr(mask, sizeof(mask), &ac->SubnetMask);
+
+ if (ac->Masked == false)
+ {
+ Format(tmp, sizeof(tmp), "%s", ip);
+ }
+ else
+ {
+ Format(tmp, sizeof(tmp), "%s/%s", ip, mask);
+ }
+
+ return CopyStr(tmp);
+}
+
+// Calculate whether the specified IP address is rejected by the access list
+bool IsIpDeniedByAcList(IP *ip, LIST *o)
+{
+ return false;
+}
+
+// Calculate whether the specified IP address is masked by the AC
+bool IsIpMaskedByAc(IP *ip, AC *ac)
+{
+ return false;
+}
+
+// Set the AC
+void SetAc(LIST *o, UINT id, AC *ac)
+{
+ // Validate arguments
+ if (o == NULL || id == 0 || ac == NULL)
+ {
+ return;
+ }
+
+ if (DelAc(o, id))
+ {
+ AddAc(o, ac);
+ }
+}
+
+// Get the AC
+AC *GetAc(LIST *o, UINT id)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL || id == 0)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ AC *ac = LIST_DATA(o, i);
+
+ if (ac->Id == id)
+ {
+ return Clone(ac, sizeof(AC));
+ }
+ }
+
+ return NULL;
+}
+
+// Delete the AC
+bool DelAc(LIST *o, UINT id)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL || id == 0)
+ {
+ return false;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ AC *ac = LIST_DATA(o, i);
+
+ if (ac->Id == id)
+ {
+ if (Delete(o, ac))
+ {
+ Free(ac);
+
+ NormalizeAcList(o);
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+// Add an AC to the list
+void AddAc(LIST *o, AC *ac)
+{
+ // Validate arguments
+ if (o == NULL || ac == NULL)
+ {
+ return;
+ }
+
+ if (LIST_NUM(o) < MAX_HUB_ACS)
+ {
+ Insert(o, Clone(ac, sizeof(AC)));
+
+ NormalizeAcList(o);
+ }
+}
+
+// Normalize the AC list
+void NormalizeAcList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ AC *ac = LIST_DATA(o, i);
+
+ if (IsIP6(&ac->IpAddress))
+ {
+ ac->IpAddress.ipv6_scope_id = 0;
+ }
+
+ ac->Id = (i + 1);
+ }
+}
+
+// Create a new AC list
+LIST *NewAcList()
+{
+ return NewList(CmpAc);
+}
+
+// AC comparison
+int CmpAc(void *p1, void *p2)
+{
+ AC *a1, *a2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ a1 = *(AC **)p1;
+ a2 = *(AC **)p2;
+ if (a1 == NULL || a2 == NULL)
+ {
+ return 0;
+ }
+ if (a1->Priority > a2->Priority)
+ {
+ return 1;
+ }
+ else if (a1->Priority < a2->Priority)
+ {
+ return -1;
+ }
+ else if (a1->Deny > a2->Deny)
+ {
+ return 1;
+ }
+ else if (a1->Deny < a2->Deny)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// Copy the CRL
+CRL *CopyCrl(CRL *crl)
+{
+ CRL *ret;
+ // Validate arguments
+ if (crl == NULL)
+ {
+ return NULL;
+ }
+
+ ret = ZeroMalloc(sizeof(CRL));
+
+ if (crl->Serial != NULL)
+ {
+ ret->Serial = NewXSerial(crl->Serial->data, crl->Serial->size);
+ }
+
+ ret->Name = CopyName(crl->Name);
+
+ Copy(ret->DigestMD5, crl->DigestMD5, MD5_SIZE);
+ Copy(ret->DigestSHA1, crl->DigestSHA1, SHA1_SIZE);
+
+ return ret;
+}
+
+// Release the CRL
+void FreeCrl(CRL *crl)
+{
+ // Validate arguments
+ if (crl == NULL)
+ {
+ return;
+ }
+
+ if (crl->Serial != NULL)
+ {
+ FreeXSerial(crl->Serial);
+ }
+
+ if (crl->Name != NULL)
+ {
+ FreeName(crl->Name);
+ }
+
+ Free(crl);
+}
+
+// Check whether the certificate has been disabled by searching the CRL list of Virtual HUB
+bool IsValidCertInHub(HUB *h, X *x)
+{
+ bool ret;
+ // Validate arguments
+ if (h == NULL || x == NULL)
+ {
+ return false;
+ }
+
+ if (h->HubDb == NULL)
+ {
+ return false;
+ }
+
+ if (IsXRevoked(x))
+ {
+ // Disabled by the CRL stored in the file
+ return false;
+ }
+
+ LockList(h->HubDb->CrlList);
+ {
+ ret = IsCertMatchCrlList(x, h->HubDb->CrlList);
+ }
+ UnlockList(h->HubDb->CrlList);
+
+ if (ret)
+ {
+ // This is invalid because it was matched
+ return false;
+ }
+
+ // This is valid because it wasn't matched
+ return true;
+}
+
+// Search whether the certificate matches the CRL list
+bool IsCertMatchCrlList(X *x, LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (x == NULL || o == NULL)
+ {
+ return false;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ CRL *crl = LIST_DATA(o, i);
+
+ if (IsCertMatchCrl(x, crl))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Convert the CRL to a string
+wchar_t *GenerateCrlStr(CRL *crl)
+{
+ wchar_t tmp[2048];
+ // Validate arguments
+ if (crl == NULL)
+ {
+ return NULL;
+ }
+
+ UniStrCpy(tmp, sizeof(tmp), L"");
+
+ if (crl->Name != NULL)
+ {
+ // Name information
+ wchar_t name[MAX_SIZE];
+
+ UniStrCat(tmp, sizeof(tmp), L"Subject=\"");
+
+ GetAllNameFromName(name, sizeof(name), crl->Name);
+ UniStrCat(tmp, sizeof(tmp), name);
+ UniStrCat(tmp, sizeof(tmp), L"\", ");
+ }
+
+ if (crl->Serial != NULL)
+ {
+ // Serial information
+ char str[128];
+ wchar_t uni[128];
+
+ BinToStrEx(str, sizeof(str), crl->Serial->data, crl->Serial->size);
+ StrToUni(uni, sizeof(uni), str);
+ UniStrCat(tmp, sizeof(tmp), L"Serial=\"");
+ UniStrCat(tmp, sizeof(tmp), uni);
+ UniStrCat(tmp, sizeof(tmp), L"\", ");
+ }
+
+ if (IsZero(crl->DigestMD5, MD5_SIZE) == false)
+ {
+ // MD5
+ char str[128];
+ wchar_t uni[128];
+
+ BinToStrEx(str, sizeof(str), crl->DigestMD5, MD5_SIZE);
+ StrToUni(uni, sizeof(uni), str);
+ UniStrCat(tmp, sizeof(tmp), L"MD5=\"");
+ UniStrCat(tmp, sizeof(tmp), uni);
+ UniStrCat(tmp, sizeof(tmp), L"\", ");
+ }
+
+ if (IsZero(crl->DigestSHA1, SHA1_SIZE) == false)
+ {
+ // MD5
+ char str[128];
+ wchar_t uni[128];
+
+ BinToStrEx(str, sizeof(str), crl->DigestSHA1, SHA1_SIZE);
+ StrToUni(uni, sizeof(uni), str);
+ UniStrCat(tmp, sizeof(tmp), L"SHA1=\"");
+ UniStrCat(tmp, sizeof(tmp), uni);
+ UniStrCat(tmp, sizeof(tmp), L"\", ");
+ }
+
+ if (UniEndWith(tmp, L", "))
+ {
+ tmp[UniStrLen(tmp) - 2] = 0;
+ }
+
+ return CopyUniStr(tmp);
+}
+
+// Check whether it matches the Certificate Revocation List entry
+bool IsCertMatchCrl(X *x, CRL *crl)
+{
+ bool b = true;
+ // Validate arguments
+ if (x == NULL || crl == NULL)
+ {
+ return false;
+ }
+
+ if (crl->Serial != NULL)
+ {
+ // If a serial number is defined in the CRL
+ if (x->serial == NULL || CompareXSerial(x->serial, crl->Serial) == false)
+ {
+ // Serial number mismatch
+ b = false;
+ }
+ }
+
+ if (IsZero(crl->DigestMD5, sizeof(crl->DigestMD5)) == false)
+ {
+ UCHAR test[MD5_SIZE];
+ // If a DigestMD5 is defined in the CRL
+ GetXDigest(x, test, false);
+
+ if (Cmp(test, crl->DigestMD5, MD5_SIZE) != 0)
+ {
+ b = false;
+ }
+ }
+
+ if (IsZero(crl->DigestSHA1, sizeof(crl->DigestSHA1)) == false)
+ {
+ UCHAR test[SHA1_SIZE];
+ // If a DigestSHA1 is defined in the CRL
+ GetXDigest(x, test, true);
+
+ if (Cmp(test, crl->DigestSHA1, SHA1_SIZE) != 0)
+ {
+ b = false;
+ }
+ }
+
+ if (crl->Name != NULL)
+ {
+ // If a name is defined in the CRL
+ NAME *xn, *cn;
+ xn = x->subject_name;
+ cn = crl->Name;
+
+ if (cn->CommonName != NULL && (UniIsEmptyStr(cn->CommonName) == false))
+ {
+ if (xn->CommonName == NULL || UniSoftStrCmp(xn->CommonName, cn->CommonName) != 0)
+ {
+ // CommonName mismatch
+ b = false;
+ }
+ }
+
+ if (cn->Organization != NULL && (UniIsEmptyStr(cn->Organization) == false))
+ {
+ if (xn->Organization == NULL || UniSoftStrCmp(xn->Organization, cn->Organization) != 0)
+ {
+ // Organization mismatch
+ b = false;
+ }
+ }
+
+ if (cn->Unit != NULL && (UniIsEmptyStr(cn->Unit) == false))
+ {
+ if (xn->Unit == NULL || UniSoftStrCmp(xn->Unit, cn->Unit) != 0)
+ {
+ // Unit mismatch
+ b = false;
+ }
+ }
+
+ if (cn->Country != NULL && (UniIsEmptyStr(cn->Country) == false))
+ {
+ if (xn->Country == NULL || UniSoftStrCmp(xn->Country, cn->Country) != 0)
+ {
+ // Country mismatch
+ b = false;
+ }
+ }
+
+ if (cn->State != NULL && (UniIsEmptyStr(cn->State) == false))
+ {
+ if (xn->State == NULL || UniSoftStrCmp(xn->State, cn->State) != 0)
+ {
+ // State mismatch
+ b = false;
+ }
+ }
+
+ if (cn->Local != NULL && (UniIsEmptyStr(cn->Local) == false))
+ {
+ if (xn->Local == NULL || UniSoftStrCmp(xn->Local, cn->Local) != 0)
+ {
+ // Local mismatch
+ b = false;
+ }
+ }
+ }
+
+ return b;
+}
+
+// Get the help string of administration options
+wchar_t *GetHubAdminOptionHelpString(char *name)
+{
+ char tmp[MAX_SIZE];
+ wchar_t *ret;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return L"";
+ }
+
+ Format(tmp, sizeof(tmp), "HUB_AO_%s", name);
+
+ ret = _UU(tmp);
+ if (UniIsEmptyStr(ret))
+ {
+ ret = _UU("HUB_AO_UNKNOWN");
+ }
+
+ return ret;
+}
+
+// Add the default administration options to the Virtual HUB
+void AddHubAdminOptionsDefaults(HUB *h, bool lock)
+{
+ UINT i;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ if (lock)
+ {
+ LockList(h->AdminOptionList);
+ }
+
+ for (i = 0;i < num_admin_options;i++)
+ {
+ ADMIN_OPTION *e = &admin_options[i];
+ ADMIN_OPTION t, *r;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), e->Name);
+
+ r = Search(h->AdminOptionList, &t);
+ if (r == NULL)
+ {
+ ADMIN_OPTION *a = ZeroMalloc(sizeof(ADMIN_OPTION));
+
+ StrCpy(a->Name, sizeof(a->Name), e->Name);
+ a->Value = e->Value;
+
+ Insert(h->AdminOptionList, a);
+ }
+ }
+
+ if (lock)
+ {
+ UnlockList(h->AdminOptionList);
+ }
+}
+
+// Delete all administration options of Virtual HUB
+void DeleteAllHubAdminOption(HUB *h, bool lock)
+{
+ UINT i;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ if (lock)
+ {
+ LockList(h->AdminOptionList);
+ }
+
+ for (i = 0;i < LIST_NUM(h->AdminOptionList);i++)
+ {
+ Free(LIST_DATA(h->AdminOptionList, i));
+ }
+
+ DeleteAll(h->AdminOptionList);
+
+ if (lock)
+ {
+ UnlockList(h->AdminOptionList);
+ }
+}
+
+// Get the administration options for the virtual HUB
+UINT GetHubAdminOptionEx(HUB *h, char *name, UINT default_value)
+{
+ UINT ret = default_value;
+ // Validate arguments
+ if (h == NULL || name == NULL)
+ {
+ return 0;
+ }
+
+ LockList(h->AdminOptionList);
+ {
+ ADMIN_OPTION *a, t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), name);
+ Trim(t.Name);
+
+ a = Search(h->AdminOptionList, &t);
+
+ if (a != NULL)
+ {
+ ret = a->Value;
+ }
+ }
+ UnlockList(h->AdminOptionList);
+
+ return ret;
+}
+UINT GetHubAdminOption(HUB *h, char *name)
+{
+ return GetHubAdminOptionEx(h, name, 0);
+}
+
+// Administration options
+int CompareAdminOption(void *p1, void *p2)
+{
+ ADMIN_OPTION *a1, *a2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ a1 = *(ADMIN_OPTION **)p1;
+ a2 = *(ADMIN_OPTION **)p2;
+ if (a1 == NULL || a2 == NULL)
+ {
+ return 0;
+ }
+ return StrCmpi(a1->Name, a2->Name);
+}
+
+// Start the watchdog
+void StartHubWatchDog(HUB *h)
+{
+ THREAD *t;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ h->HaltWatchDog = false;
+ h->WatchDogEvent = NewEvent();
+
+ t = NewThread(HubWatchDogThread, h);
+ WaitThreadInit(t);
+ ReleaseThread(t);
+}
+
+// Stop the watchdog
+void StopHubWatchDog(HUB *h)
+{
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ h->HaltWatchDog = true;
+ Set(h->WatchDogEvent);
+
+ WaitThread(h->WatchDogThread, INFINITE);
+ ReleaseThread(h->WatchDogThread);
+ h->WatchDogThread = NULL;
+ h->HaltWatchDog = false;
+
+ ReleaseEvent(h->WatchDogEvent);
+ h->WatchDogEvent = NULL;
+}
+
+// Watchdog thread
+void HubWatchDogThread(THREAD *t, void *param)
+{
+ UINT num_packets_v4 = 0;
+ UINT num_packets_v6 = 0;
+ HUB *hub;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ hub = (HUB *)param;
+
+ hub->WatchDogThread = t;
+ AddRef(t->ref);
+
+ NoticeThreadInit(t);
+
+ while (true)
+ {
+ LIST *o;
+ LIST *o2;
+ UINT i, num;
+ UINT interval;
+ UINT wait_time = 100;
+ if (hub->HaltWatchDog)
+ {
+ break;
+ }
+
+ o = NewListFast(NULL);
+ o2 = NewListFast(NULL);
+
+ // Send an ARP packet
+ LockList(hub->IpTable);
+ {
+ num = LIST_NUM(hub->IpTable);
+ for (i = 0;i < LIST_NUM(hub->IpTable);i++)
+ {
+ IP_TABLE_ENTRY *e = LIST_DATA(hub->IpTable, i);
+
+ if ((e->UpdatedTime + (UINT64)(IP_TABLE_EXPIRE_TIME)) > Tick64())
+ {
+ if (e->MacAddress[0] != 0xff || e->MacAddress[1] != 0xff || e->MacAddress[2] != 0xff ||
+ e->MacAddress[3] != 0xff || e->MacAddress[4] != 0xff || e->MacAddress[5] != 0xff)
+ {
+ if (hub->Option != NULL && hub->Option->NoArpPolling == false)
+ {
+ if (IsIP4(&e->Ip))
+ {
+ // IPv4
+ MAC_HEADER *mac = ZeroMalloc(sizeof(MAC_HEADER) + sizeof(ARPV4_HEADER));
+ ARPV4_HEADER *p = (ARPV4_HEADER *)(((UCHAR *)mac) + sizeof(MAC_HEADER));
+
+ Copy(mac->DestAddress, e->MacAddress, 6);
+ Copy(mac->SrcAddress, hub->HubMacAddr, 6);
+ mac->Protocol = Endian16(MAC_PROTO_ARPV4);
+
+ p->HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+ p->ProtocolType = Endian16(MAC_PROTO_IPV4);
+ p->HardwareSize = 6;
+ p->ProtocolSize = 4;
+ p->Operation = Endian16(ARP_OPERATION_REQUEST);
+ Copy(p->SrcAddress, hub->HubMacAddr, 6);
+ p->SrcIP = IPToUINT(&hub->HubIp);
+ p->TargetAddress[0] =
+ p->TargetAddress[1] =
+ p->TargetAddress[2] =
+ p->TargetAddress[3] =
+ p->TargetAddress[4] =
+ p->TargetAddress[5] = 0x00;
+ p->TargetIP = IPToUINT(&e->Ip);
+ Insert(o, mac);
+ }
+ }
+
+ if (hub->Option != NULL && hub->Option->NoIPv6AddrPolling == false)
+ {
+ if (IsIP6(&e->Ip))
+ {
+ // IPv6
+ BUF *buf;
+ IPV6_ADDR ip6addr;
+
+ if (IPToIPv6Addr(&ip6addr, &e->Ip))
+ {
+ buf = BuildICMPv6NeighborSoliciation(&hub->HubIpV6,
+ &ip6addr,
+ hub->HubMacAddr, ++hub->HubIP6Id);
+
+ if (buf != NULL)
+ {
+ BUF *buf2 = NewBuf();
+ MAC_HEADER mac;
+
+ Zero(&mac, sizeof(mac));
+
+ Copy(mac.DestAddress, e->MacAddress, 6);
+ Copy(mac.SrcAddress, hub->HubMacAddr, 6);
+ mac.Protocol = Endian16(MAC_PROTO_IPV6);
+
+ WriteBuf(buf2, &mac, sizeof(MAC_HEADER));
+
+ WriteBuf(buf2, buf->Buf, buf->Size);
+
+ FreeBuf(buf);
+
+ Insert(o2, buf2);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ UnlockList(hub->IpTable);
+
+ if ((LIST_NUM(o) + LIST_NUM(o2)) != 0)
+ {
+ interval = HUB_ARP_SEND_INTERVAL / (LIST_NUM(o) + LIST_NUM(o2));
+ }
+ else
+ {
+ interval = HUB_ARP_SEND_INTERVAL;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ PKT *packet;
+ void *p = LIST_DATA(o, i);
+
+ Wait(hub->WatchDogEvent, interval);
+ if (hub->HaltWatchDog)
+ {
+ for (;i < LIST_NUM(o);i++)
+ {
+ Free(LIST_DATA(o, i));
+ }
+ ReleaseList(o);
+
+ for (i = 0;i < LIST_NUM(o2);i++)
+ {
+ FreeBuf(LIST_DATA(o2, i));
+ }
+ ReleaseList(o2);
+ goto ESCAPE;
+ }
+
+ packet = ParsePacket((UCHAR *)p, sizeof(MAC_HEADER) + sizeof(ARPV4_HEADER));
+ if (packet != NULL)
+ {
+ StorePacket(hub, NULL, packet);
+ num_packets_v4++;
+ }
+ else
+ {
+ Free(p);
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o2);i++)
+ {
+ PKT *packet;
+ BUF *buf = LIST_DATA(o2, i);
+
+ Wait(hub->WatchDogEvent, interval);
+ if (hub->HaltWatchDog)
+ {
+ ReleaseList(o);
+
+ for (;i < LIST_NUM(o2);i++)
+ {
+ FreeBuf(LIST_DATA(o2, i));
+ }
+ ReleaseList(o2);
+ goto ESCAPE;
+ }
+
+ packet = ParsePacket(buf->Buf, buf->Size);
+ if (packet != NULL)
+ {
+ StorePacket(hub, NULL, packet);
+ num_packets_v6++;
+ }
+ else
+ {
+ Free(buf->Buf);
+ }
+
+ Free(buf);
+ }
+
+ ReleaseList(o);
+ ReleaseList(o2);
+
+ if (num == 0)
+ {
+ wait_time = HUB_ARP_SEND_INTERVAL;
+ }
+
+ Wait(hub->WatchDogEvent, wait_time);
+ }
+ESCAPE:
+ return;
+}
+
+// Eable / disable the SecureNAT
+void EnableSecureNAT(HUB *h, bool enable)
+{
+ EnableSecureNATEx(h, enable, false);
+}
+void EnableSecureNATEx(HUB *h, bool enable, bool no_change)
+{
+ bool for_cluster = false;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ if (h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ if (h->Type == HUB_TYPE_FARM_DYNAMIC)
+ {
+ for_cluster = true;
+ }
+ }
+
+ Lock(h->lock_online);
+ {
+ if (no_change == false)
+ {
+ h->EnableSecureNAT = enable;
+ }
+
+ if (h->EnableSecureNAT == false)
+ {
+STOP:
+ // Stop if it's already started
+ if (h->SecureNAT != NULL)
+ {
+ SnFreeSecureNAT(h->SecureNAT);
+ h->SecureNAT = NULL;
+ }
+ }
+ else
+ {
+ if (for_cluster)
+ {
+ if ((h->SecureNAT != NULL && LIST_NUM(h->SessionList) <= 1) ||
+ (h->SecureNAT == NULL && LIST_NUM(h->SessionList) == 0))
+ {
+ // It is in a start mode, but stop when there is no other sessions
+ // in the case of dynamic Virtual HUB
+ goto STOP;
+ }
+ }
+
+ // Start if the HUB is online and not started
+ if (h->SecureNAT == NULL && h->Offline == false)
+ {
+ h->SecureNAT = SnNewSecureNAT(h, h->SecureNATOption);
+ }
+ }
+ }
+ Unlock(h->lock_online);
+}
+
+// Convert an access list to a string
+void GetAccessListStr(char *str, UINT size, ACCESS *a)
+{
+ char tmp[MAX_SIZE];
+ char tmp1[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ bool l3 = false;
+ bool asterisk = false;
+ // Validate arguments
+ if (str == NULL || a == NULL)
+ {
+ return;
+ }
+
+ StrCpy(str, size, "");
+
+ if (a->IsIPv6 == false)
+ {
+ if (a->SrcIpAddress != 0 || a->SrcSubnetMask != 0)
+ {
+ IPToStr32(tmp1, sizeof(tmp1), a->SrcIpAddress);
+ MaskToStr32(tmp2, sizeof(tmp2), a->SrcSubnetMask);
+ Format(tmp, sizeof(tmp), "SrcIPv4=%s/%s, ", tmp1, tmp2);
+ StrCat(str, size, tmp);
+
+ l3 = true;
+ }
+
+ if (a->DestIpAddress != 0 || a->DestSubnetMask != 0)
+ {
+ IPToStr32(tmp1, sizeof(tmp1), a->DestIpAddress);
+ MaskToStr32(tmp2, sizeof(tmp2), a->DestSubnetMask);
+ Format(tmp, sizeof(tmp), "DstIPv4=%s/%s, ", tmp1, tmp2);
+ StrCat(str, size, tmp);
+
+ l3 = true;
+ }
+ }
+ else
+ {
+ if (IsZeroIP6Addr(&a->SrcIpAddress6) == false || IsZeroIP6Addr(&a->SrcSubnetMask6) == false)
+ {
+ IP6AddrToStr(tmp1, sizeof(tmp1), &a->SrcIpAddress6);
+ Mask6AddrToStr(tmp2, sizeof(tmp2), &a->SrcSubnetMask6);
+ Format(tmp, sizeof(tmp), "SrcIPv6=%s/%s, ", tmp1, tmp2);
+ StrCat(str, size, tmp);
+
+ l3 = true;
+ }
+
+ if (IsZeroIP6Addr(&a->DestIpAddress6) == false || IsZeroIP6Addr(&a->DestSubnetMask6) == false)
+ {
+ IP6AddrToStr(tmp1, sizeof(tmp1), &a->DestIpAddress6);
+ Mask6AddrToStr(tmp2, sizeof(tmp2), &a->DestSubnetMask6);
+ Format(tmp, sizeof(tmp), "DstIPv6=%s/%s, ", tmp1, tmp2);
+ StrCat(str, size, tmp);
+
+ l3 = true;
+ }
+ }
+
+ if (a->Protocol != 0)
+ {
+ StrCpy(tmp1, sizeof(tmp1), "");
+ switch (a->Protocol)
+ {
+ case 1:
+ StrCpy(tmp1, sizeof(tmp1), "ICMPv4");
+ break;
+ case 3:
+ StrCpy(tmp1, sizeof(tmp1), "GGP");
+ break;
+ case 6:
+ StrCpy(tmp1, sizeof(tmp1), "TCP");
+ break;
+ case 8:
+ StrCpy(tmp1, sizeof(tmp1), "EGP");
+ break;
+ case 12:
+ StrCpy(tmp1, sizeof(tmp1), "PUP");
+ break;
+ case 17:
+ StrCpy(tmp1, sizeof(tmp1), "UDP");
+ break;
+ case 20:
+ StrCpy(tmp1, sizeof(tmp1), "HMP");
+ break;
+ case 22:
+ StrCpy(tmp1, sizeof(tmp1), "XNS-IDP");
+ break;
+ case 27:
+ StrCpy(tmp1, sizeof(tmp1), "RDP");
+ break;
+ case 58:
+ StrCpy(tmp1, sizeof(tmp1), "ICMPv6");
+ break;
+ case 66:
+ StrCpy(tmp1, sizeof(tmp1), "RVD");
+ break;
+ }
+
+ if (IsEmptyStr(tmp1))
+ {
+ Format(tmp, sizeof(tmp), "Protocol=%s(%u), ", tmp1, a->Protocol);
+ }
+ else
+ {
+ Format(tmp, sizeof(tmp), "Protocol=%s, ", tmp1);
+ }
+
+ StrCat(str, size, tmp);
+
+ l3 = true;
+ }
+
+ if (a->SrcPortStart != 0)
+ {
+ if (a->SrcPortEnd == a->SrcPortStart)
+ {
+ Format(tmp, sizeof(tmp), "SrcPort=%u, ", a->SrcPortStart);
+ StrCat(str, size, tmp);
+ }
+ else
+ {
+ Format(tmp, sizeof(tmp), "SrcPort=%u-%u, ", a->SrcPortStart, a->SrcPortEnd);
+ StrCat(str, size, tmp);
+ }
+
+ l3 = true;
+ }
+
+ if (a->DestPortStart != 0)
+ {
+ if (a->DestPortEnd == a->DestPortStart)
+ {
+ Format(tmp, sizeof(tmp), "DstPort=%u, ", a->DestPortStart);
+ StrCat(str, size, tmp);
+ }
+ else
+ {
+ Format(tmp, sizeof(tmp), "DstPort=%u-%u, ", a->DestPortStart, a->DestPortEnd);
+ StrCat(str, size, tmp);
+ }
+
+ l3 = true;
+ }
+
+ if (StrLen(a->SrcUsername) != 0)
+ {
+ Format(tmp, sizeof(tmp), "SrcUser=%s, ", a->SrcUsername);
+ StrCat(str, size, tmp);
+ }
+
+ if (StrLen(a->DestUsername) != 0)
+ {
+ Format(tmp, sizeof(tmp), "DstUser=%s, ", a->DestUsername);
+ StrCat(str, size, tmp);
+ }
+
+ if (a->CheckSrcMac != false)
+ {
+ char mac[MAX_SIZE], mask[MAX_SIZE];
+ MacToStr(mac, sizeof(mac), a->SrcMacAddress);
+ MacToStr(mask, sizeof(mask), a->SrcMacMask);
+ Format(tmp, sizeof(tmp), "SrcMac=%s/%s, ", mac, mask);
+ StrCat(str, size, tmp);
+ }
+ if (a->CheckDstMac != false)
+ {
+ char mac[MAX_SIZE], mask[MAX_SIZE];
+ MacToStr(mac, sizeof(mac), a->DstMacAddress);
+ MacToStr(mask, sizeof(mask), a->DstMacMask);
+ Format(tmp, sizeof(tmp), "DstMac=%s/%s, ", mac, mask);
+ StrCat(str, size, tmp);
+ }
+
+ if (a->CheckTcpState)
+ {
+ if(a->Established)
+ {
+ StrCat(str, size, "Established, ");
+ }
+ else
+ {
+ StrCat(str, size, "Unestablished, ");
+ }
+
+ l3 = true;
+ }
+
+ if (a->Discard == false)
+ {
+ if (a->Delay >= 1)
+ {
+ Format(tmp, sizeof(tmp), "Delay=%u, ", a->Delay);
+ StrCat(str, size, tmp);
+ }
+
+ if (a->Jitter >= 1)
+ {
+ Format(tmp, sizeof(tmp), "Jitter=%u, ", a->Jitter);
+ StrCat(str, size, tmp);
+ }
+
+ if (a->Loss >= 1)
+ {
+ Format(tmp, sizeof(tmp), "Loss=%u, " , a->Loss);
+ StrCat(str, size, tmp);
+ }
+ }
+
+ if (IsEmptyStr(a->RedirectUrl) == false)
+ {
+ Format(tmp, sizeof(tmp), "RedirectUrl=%s, ", a->RedirectUrl);
+ StrCat(str, size, tmp);
+ }
+
+ if (StrLen(str) == 0)
+ {
+ asterisk = true;
+ }
+
+ if (l3)
+ {
+ if (a->IsIPv6)
+ {
+ StrCatLeft(str, size, "(ipv6) ");
+ }
+ else
+ {
+ StrCatLeft(str, size, "(ipv4) ");
+ }
+ }
+ else
+ {
+ StrCatLeft(str, size, "(ether) ");
+ }
+
+ if (EndWith(str, ", "))
+ {
+ str[StrLen(str) - 2] = 0;
+ }
+
+ if (asterisk)
+ {
+ StrCat(str, size, "*");
+ }
+}
+
+// Determine whether the access list can mask the packet
+bool IsPacketMaskedByAccessList(SESSION *s, PKT *p, ACCESS *a, UINT64 dest_username, UINT64 dest_groupname, SESSION *dest_session)
+{
+ UINT64 src_username;
+ UINT64 src_username_simple;
+ UINT64 src_groupname;
+ HUB_PA *pa;
+ IPV4_HEADER *ip = NULL;
+ IPV6_HEADER *ip6 = NULL;
+ bool is_ipv4_packet = false;
+ bool is_ipv6_packet = false;
+ // Validate arguments
+ if (s == NULL || p == NULL || a == NULL)
+ {
+ return false;
+ }
+ if (a->Active == false)
+ {
+ // Access list is inactive
+ return false;
+ }
+
+ pa = (HUB_PA *)s->PacketAdapter->Param;
+
+ // Hash of the source user name
+ src_username = pa->UsernameHash;
+ src_username_simple = pa->UsernameHashSimple;
+ src_groupname = pa->GroupnameHash;
+
+ // Determine the source and destination MAC address
+ if (a->CheckSrcMac != false)
+ {
+ UINT i;
+ for (i = 0; i < 6; i++)
+ {
+ if((a->SrcMacAddress[i] & a->SrcMacMask[i]) != (a->SrcMacMask[i] & p->MacAddressSrc[i]))
+ {
+ return false;
+ }
+ }
+ }
+
+ if (a->CheckDstMac != false)
+ {
+ UINT i;
+ for (i = 0; i < 6; i++)
+ {
+ if ((a->DstMacAddress[i] & a->DstMacMask[i]) != (a->DstMacMask[i] & p->MacAddressDest[i]))
+ {
+ return false;
+ }
+ }
+ }
+
+ // Check the source user name / group name
+ if (a->SrcUsernameHash != 0)
+ {
+ if (a->IsSrcUsernameIncludeOrExclude == false)
+ {
+ // It is specified as a regular user name
+ if ((a->SrcUsernameHash != src_username) && (a->SrcUsernameHash != src_groupname))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // It is specified in the form of a exclude:FILENAME or include:FILENAME
+ HUB *hub = s->Hub;
+
+ if (hub != NULL)
+ {
+ LIST *o = hub->UserList;
+
+ if (s->NormalClient == false)
+ {
+ // The internal session don't become target for format exclude: or include:
+ return false;
+ }
+
+ if (IsUserMatchInUserListWithCacheExpiresAcl(o, a->SrcUsername, src_username,
+ hub->Option->AccessListIncludeFileCacheLifetime * 1000) == false)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ // Check the destination user name / group name
+ if (a->DestUsernameHash != 0)
+ {
+ if (a->IsDestUsernameIncludeOrExclude == false)
+ {
+ // It is specified as a regular user name
+ if ((a->DestUsernameHash != dest_username) && (a->DestUsernameHash != dest_groupname))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // It is specified in the form of a exclude:FILENAME or include:FILENAME
+ HUB *hub = s->Hub;
+
+ if (hub != NULL)
+ {
+ LIST *o = hub->UserList;
+
+ if (dest_session != NULL && dest_session->NormalClient == false)
+ {
+ // The internal session don't become target for format exclude: or include:
+ return false;
+ }
+
+ if (IsUserMatchInUserListWithCacheExpiresAcl(o, a->DestUsername, dest_username,
+ hub->Option->AccessListIncludeFileCacheLifetime * 1000) == false)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ // Determine of the IP packet
+ if (p->TypeL3 != L3_IPV4)
+ {
+ is_ipv4_packet = false;
+ }
+ else
+ {
+ is_ipv4_packet = true;
+ }
+
+ if (p->TypeL3 != L3_IPV6)
+ {
+ is_ipv6_packet = false;
+ }
+ else
+ {
+ is_ipv6_packet = true;
+ }
+
+ if (is_ipv4_packet)
+ {
+ ip = p->L3.IPv4Header;
+ }
+
+ if (is_ipv6_packet)
+ {
+ ip6 = p->L3.IPv6Header;
+ }
+
+ if (a->IsIPv6 == false)
+ {
+ // IPv4
+
+ // Check the source IP address
+ if (a->SrcIpAddress != 0 || a->SrcSubnetMask != 0)
+ {
+ if (is_ipv4_packet == false)
+ {
+ if (p->TypeL3 == L3_ARPV4)
+ {
+ bool arp_match = false;
+ if (p->L3.ARPv4Header->HardwareSize == 6 &&
+ Endian16(p->L3.ARPv4Header->HardwareType) == ARP_HARDWARE_TYPE_ETHERNET &&
+ p->L3.ARPv4Header->ProtocolSize == 4 &&
+ Endian16(p->L3.ARPv4Header->ProtocolType) == 0x0800)
+ {
+ UINT uint_ip = p->L3.ARPv4Header->SrcIP;
+
+ if (uint_ip != 0 && uint_ip != 0xffffffff && !(IsHubIpAddress32(uint_ip) && IsHubMacAddress(p->MacAddressSrc)))
+ {
+ if ((uint_ip & a->SrcSubnetMask) != (a->SrcIpAddress & a->SrcSubnetMask))
+ {
+ }
+ else
+ {
+ arp_match = true;
+ }
+ }
+ }
+
+ if (arp_match == false)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if ((ip->SrcIP & a->SrcSubnetMask) != (a->SrcIpAddress & a->SrcSubnetMask))
+ {
+ return false;
+ }
+ }
+ }
+
+ // Check the destination IP address
+ if (a->DestIpAddress != 0 || a->DestSubnetMask != 0)
+ {
+ if (is_ipv4_packet == false)
+ {
+ if (p->TypeL3 == L3_ARPV4)
+ {
+ bool arp_match = false;
+ if (p->L3.ARPv4Header->HardwareSize == 6 &&
+ Endian16(p->L3.ARPv4Header->HardwareType) == ARP_HARDWARE_TYPE_ETHERNET &&
+ p->L3.ARPv4Header->ProtocolSize == 4 &&
+ Endian16(p->L3.ARPv4Header->ProtocolType) == 0x0800)
+ {
+ UINT uint_ip = p->L3.ARPv4Header->TargetIP;
+
+ if (uint_ip != 0 && uint_ip != 0xffffffff && !(IsHubIpAddress32(uint_ip) && IsHubMacAddress(p->MacAddressSrc)))
+ {
+ if ((uint_ip & a->DestSubnetMask) != (a->DestIpAddress & a->DestSubnetMask))
+ {
+ }
+ else
+ {
+ arp_match = true;
+ }
+ }
+ }
+
+ if (arp_match == false)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if ((ip->DstIP & a->DestSubnetMask) != (a->DestIpAddress & a->DestSubnetMask))
+ {
+ return false;
+ }
+ }
+ }
+ }
+ else
+ {
+ // IPv6
+
+ // Check the source IP address
+ if (IsZeroIP6Addr(&a->SrcIpAddress6) == false ||
+ IsZeroIP6Addr(&a->SrcSubnetMask6) == false)
+ {
+ if (is_ipv6_packet == false)
+ {
+ return false;
+ }
+ else
+ {
+ IP a_ip, a_subnet, p_ip;
+ IP and1, and2;
+
+ IPv6AddrToIP(&a_ip, &a->SrcIpAddress6);
+ IPv6AddrToIP(&a_subnet, &a->SrcSubnetMask6);
+ IPv6AddrToIP(&p_ip, &ip6->SrcAddress);
+
+ IPAnd6(&and1, &a_ip, &a_subnet);
+ IPAnd6(&and2, &p_ip, &a_subnet);
+
+ if (CmpIpAddr(&and1, &and2) != 0)
+ {
+ return false;
+ }
+ }
+ }
+
+ // Check the destination IP address
+ if (IsZeroIP6Addr(&a->DestIpAddress6) == false ||
+ IsZeroIP6Addr(&a->DestSubnetMask6) == false)
+ {
+ if (is_ipv6_packet == false)
+ {
+ return false;
+ }
+ else
+ {
+ IP a_ip, a_subnet, p_ip;
+ IP and1, and2;
+
+ IPv6AddrToIP(&a_ip, &a->DestIpAddress6);
+ IPv6AddrToIP(&a_subnet, &a->DestSubnetMask6);
+ IPv6AddrToIP(&p_ip, &ip6->DestAddress);
+
+ IPAnd6(&and1, &a_ip, &a_subnet);
+ IPAnd6(&and2, &p_ip, &a_subnet);
+
+ if (CmpIpAddr(&and1, &and2) != 0)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ // Don't match the packet of non-IPv4 and non-IPv6
+ if (is_ipv4_packet == false && is_ipv6_packet==false)
+ {
+ if (s->Hub != NULL && s->Hub->Option != NULL && s->Hub->Option->ApplyIPv4AccessListOnArpPacket)
+ {
+ // Match the ARP only if ApplyIPv4AccessListOnArpPacket option is enabled
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Check the protocol number
+ if (a->Protocol != 0)
+ {
+ if (a->IsIPv6 == false)
+ {
+ if (is_ipv4_packet == false)
+ {
+ return false;
+ }
+ else
+ {
+ if (ip->Protocol != a->Protocol)
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ if (is_ipv6_packet == false)
+ {
+ return false;
+ }
+ else
+ {
+ if (p->IPv6HeaderPacketInfo.Protocol != a->Protocol)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ // Check the port number
+ if (a->SrcPortStart != 0 || a->DestPortStart != 0 ||
+ a->SrcPortEnd != 0 || a->DestPortEnd != 0)
+ {
+ if ((a->IsIPv6 == false && is_ipv4_packet == false) ||
+ (a->IsIPv6 && is_ipv6_packet == false))
+ {
+ return false;
+ }
+ else
+ {
+ if (p->TypeL4 == L4_TCP)
+ {
+ TCP_HEADER *tcp = p->L4.TCPHeader;
+ // Check the source port
+ if (a->SrcPortStart != 0 || a->SrcPortEnd != 0)
+ {
+ UINT src_port = Endian16(tcp->SrcPort);
+ if (src_port < a->SrcPortStart || src_port > a->SrcPortEnd)
+ {
+ return false;
+ }
+ }
+
+ // Check the destination port number
+ if (a->DestPortStart != 0 || a->DestPortEnd != 0)
+ {
+ UINT dest_port = Endian16(tcp->DstPort);
+ if (dest_port < a->DestPortStart || dest_port > a->DestPortEnd)
+ {
+ return false;
+ }
+ }
+ }
+ else if (p->TypeL4 == L4_UDP)
+ {
+ UDP_HEADER *udp = p->L4.UDPHeader;
+ // Check the source port
+ if (a->SrcPortStart != 0 || a->SrcPortEnd != 0)
+ {
+ UINT src_port = Endian16(udp->SrcPort);
+ if (src_port < a->SrcPortStart || src_port > a->SrcPortEnd)
+ {
+ return false;
+ }
+ }
+
+ // Check the destination port number
+ if (a->DestPortStart != 0 || a->DestPortEnd != 0)
+ {
+ UINT dest_port = Endian16(udp->DstPort);
+ if (dest_port < a->DestPortStart || dest_port > a->DestPortEnd)
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ // When the port number is specified in the access list,
+ // The rule is applied only for UDP or TCP packets
+ return false;
+ }
+ }
+ }
+
+ // Check the status of the TCP connection
+ if (a->CheckTcpState != false)
+ {
+ if ((a->IsIPv6 == false && is_ipv4_packet == false) ||
+ (a->IsIPv6 && is_ipv6_packet == false))
+ {
+ return false;
+ }
+ else
+ {
+ if(p->TypeL4 == L4_TCP)
+ {
+ // by shimizu
+ TCP_HEADER *tcp = p->L4.TCPHeader;
+ bool est = true;
+
+ if ((tcp->Flag & TCP_SYN) && (!(tcp->Flag & TCP_ACK)))
+ {
+ est = false;
+ }
+
+ if((MAKEBOOL(a->Established) ^ MAKEBOOL(est)))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+// Apply the access list for packets to forward
+bool ApplyAccessListToForwardPacket(HUB *hub, SESSION *src_session, SESSION *dest_session, PKT *p)
+{
+ UINT i;
+ bool pass = true; // Pass by default
+ bool skip = true;
+ // Validate arguments
+ if (hub == NULL || src_session == NULL || p == NULL || dest_session == NULL)
+ {
+ return false;
+ }
+
+ // The access list is not re-applied for packets that have been already checked
+ if (p->AccessChecked)
+ {
+ return true;
+ }
+
+ LockList(hub->AccessList);
+ {
+ for (i = 0;i < LIST_NUM(hub->AccessList);i++)
+ {
+ ACCESS *a = LIST_DATA(hub->AccessList, i);
+
+ // Scan the entry only after the destination user name is specified.
+ if (a->DestUsernameHash != 0)
+ {
+ skip = false;
+ }
+
+ if (skip == false)
+ {
+ if (IsPacketMaskedByAccessList(src_session, p, a,
+ ((HUB_PA *)dest_session->PacketAdapter->Param)->UsernameHash,
+ ((HUB_PA *)dest_session->PacketAdapter->Param)->GroupnameHash,
+ dest_session))
+ {
+ // Determine the pass or discard the packet
+ pass = a->Discard ? false : true;
+
+ // Complete the scanning of the list here
+ break;
+ }
+ }
+ }
+ }
+ UnlockList(hub->AccessList);
+
+ return pass;
+}
+
+// Generate a HTTP payload for redirect
+BUF *BuildRedirectToUrlPayload(HUB *hub, SESSION *s, char *redirect_url)
+{
+ char html[MAX_REDIRECT_URL_LEN * 2 + 1 + MAX_SIZE];
+ char header[MAX_REDIRECT_URL_LEN * 2 + 1 + MAX_SIZE];
+ char redirect_url2[MAX_REDIRECT_URL_LEN * 2];
+ BUF *b;
+ // Validate arguments
+ if (hub == NULL || s == NULL || redirect_url == NULL)
+ {
+ return NULL;
+ }
+
+ StrCpy(redirect_url2, sizeof(redirect_url2), redirect_url);
+ Trim(redirect_url2);
+
+ if (InStr(redirect_url2, ACCESS_LIST_URL_INFO_TAG))
+ {
+ // Get the secret key string
+ char secret[MAX_SIZE];
+ char tmp[MAX_SIZE];
+ SYSTEMTIME st;
+ UINT i, len, isp;
+
+ isp = INFINITE;
+
+ SystemTime(&st);
+ ClearStr(secret, sizeof(secret));
+
+ len = StrLen(redirect_url2);
+
+ for (i = 0;i < len;i++)
+ {
+ char c = redirect_url2[i];
+ if (c == '|')
+ {
+ isp = i;
+ }
+ }
+
+ if (isp != INFINITE)
+ {
+ StrCpy(secret, sizeof(secret), redirect_url2 + isp + 1);
+ redirect_url2[isp] = 0;
+ }
+
+ Format(tmp, sizeof(tmp), "%s|%s|%r|%04u%02u%02u%02u%02u%02u%s",
+ s->Username, s->Name, &s->Connection->ClientIp,
+ st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, (IsEmptyStr(secret) ? "" : "|"));
+
+ if (IsEmptyStr(secret) == false)
+ {
+ // Calculate the hash
+ UCHAR hash[SHA1_SIZE];
+ char hash_str[MAX_SIZE];
+ BUF *b2 = NewBuf();
+
+ WriteBuf(b2, tmp, StrLen(tmp));
+ WriteBuf(b2, secret, StrLen(secret));
+
+ HashSha1(hash, b2->Buf, b2->Size);
+
+ BinToStr(hash_str, sizeof(hash_str), hash, sizeof(hash));
+
+ FreeBuf(b2);
+
+ StrCat(tmp, sizeof(tmp), hash_str);
+
+ // Replace
+ ReplaceStrEx(redirect_url2, sizeof(redirect_url2), redirect_url2,
+ ACCESS_LIST_URL_INFO_TAG, tmp, false);
+ }
+ }
+
+ Format(html, sizeof(html),
+ "Object moved\r\nObject moved to here.
\r\n\r\n\r\n",
+ redirect_url2);
+
+ Format(header, sizeof(header),
+ "HTTP/1.1 302 Found\r\nLocation: %s\r\nCache-Control: private\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: %u\r\n\r\n",
+ redirect_url2, StrLen(redirect_url2));
+
+ b = NewBuf();
+
+ WriteBuf(b, header, StrLen(header));
+ WriteBuf(b, html, StrLen(html));
+
+ return b;
+}
+
+// Rpely a TCP response packet to redirect forcibly to the specified URL
+void ForceRedirectToUrl(HUB *hub, SESSION *src_session, PKT *p, char *redirect_url)
+{
+ BUF *payload;
+ UINT tcp_size;
+ TCP_HEADER *tcp_data;
+ TCP_HEADER *src_tcp;
+ BUF *b;
+ // Validate arguments
+ if (hub == NULL || src_session == NULL || p == NULL || redirect_url == NULL)
+ {
+ return;
+ }
+ if (p->TypeL3 != L3_IPV4 && p->TypeL3 != L3_IPV6)
+ {
+ return;
+ }
+ if (p->TypeL4 != L4_TCP)
+ {
+ return;
+ }
+
+ src_tcp = p->L4.TCPHeader;
+ if (src_tcp == NULL)
+ {
+ return;
+ }
+
+ // Generate a payload to be sent
+ payload = BuildRedirectToUrlPayload(hub, src_session, redirect_url);
+ if (payload == NULL)
+ {
+ return;
+ }
+
+ // Generate a TCP packet
+ tcp_size = sizeof(TCP_HEADER) + payload->Size;
+ tcp_data = (TCP_HEADER *)ZeroMalloc(tcp_size);
+ tcp_data->SrcPort = src_tcp->DstPort;
+ tcp_data->DstPort = src_tcp->SrcPort;
+ tcp_data->SeqNumber = src_tcp->AckNumber;
+ tcp_data->AckNumber = Endian32(Endian32(src_tcp->SeqNumber) + p->PayloadSize);
+ TCP_SET_HEADER_SIZE(tcp_data, 5);
+ tcp_data->Flag = TCP_ACK | TCP_PSH;
+ tcp_data->WindowSize = Endian16(0xFFFF);
+ Copy(((UCHAR *)tcp_data) + sizeof(TCP_HEADER), payload->Buf, payload->Size);
+
+ // Calculate the TCP checksum
+ if (p->TypeL3 == L3_IPV4)
+ {
+ // IPv4
+ tcp_data->Checksum = CalcChecksumForIPv4(p->L3.IPv4Header->DstIP, p->L3.IPv4Header->SrcIP, IP_PROTO_TCP,
+ tcp_data, tcp_size, 0);
+ }
+ else
+ {
+ // IPv6
+ tcp_data->Checksum = CalcChecksumForIPv6(&p->IPv6HeaderPacketInfo.IPv6Header->DestAddress,
+ &p->IPv6HeaderPacketInfo.IPv6Header->SrcAddress, IP_PROTO_TCP, tcp_data, tcp_size, 0);
+ }
+
+ // Generate the Ethernet and IP packet
+ b = NewBuf();
+
+ // Destination MAC address
+ WriteBuf(b, p->MacHeader->SrcAddress, 6);
+ WriteBuf(b, p->MacHeader->DestAddress, 6);
+ WriteBuf(b, &p->MacHeader->Protocol, 2);
+
+ if (p->TypeL3 == L3_IPV4)
+ {
+ // IPv4
+ IPV4_HEADER v4;
+
+ Zero(&v4, sizeof(v4));
+
+ IPV4_SET_VERSION(&v4, 4);
+ IPV4_SET_HEADER_LEN(&v4, 5);
+ v4.TotalLength = Endian16((USHORT)(sizeof(IPV4_HEADER) + tcp_size));
+ v4.Identification = Endian16(Rand16());
+ IPV4_SET_FLAGS(&v4, 0x02);
+ v4.TimeToLive = 128;
+ v4.Protocol = IP_PROTO_TCP;
+ v4.SrcIP = p->L3.IPv4Header->DstIP;
+ v4.DstIP = p->L3.IPv4Header->SrcIP;
+ v4.Checksum = IpChecksum(&v4, sizeof(v4));
+
+ WriteBuf(b, &v4, sizeof(v4));
+ }
+ else
+ {
+ // IPv6
+ IPV6_HEADER v6;
+
+ Zero(&v6, sizeof(v6));
+
+ IPV6_SET_VERSION(&v6, 6);
+ v6.PayloadLength = Endian16(tcp_size);
+ v6.NextHeader = IP_PROTO_TCP;
+ v6.HopLimit = 64;
+
+ Copy(&v6.SrcAddress, &p->IPv6HeaderPacketInfo.IPv6Header->DestAddress, sizeof(IPV6_ADDR));
+ Copy(&v6.DestAddress, &p->IPv6HeaderPacketInfo.IPv6Header->SrcAddress, sizeof(IPV6_ADDR));
+
+ WriteBuf(b, &v6, sizeof(v6));
+ }
+
+ WriteBuf(b, tcp_data, tcp_size);
+
+ // Reply packet
+ StorePacketToHubPa((HUB_PA *)src_session->PacketAdapter->Param,
+ NULL, b->Buf, b->Size, NULL);
+
+ // Release the memory
+ Free(tcp_data);
+ FreeBuf(payload);
+ Free(b);
+}
+
+// Apply the access list for packets stored
+bool ApplyAccessListToStoredPacket(HUB *hub, SESSION *s, PKT *p)
+{
+ UINT i;
+ bool pass = true; // Pass by default
+ bool use_redirect_url = false;
+ char redirect_url[MAX_REDIRECT_URL_LEN + 1];
+ // Validate arguments
+ if (hub == NULL || s == NULL || p == NULL)
+ {
+ return false;
+ }
+
+ if (hub->Option != NULL && hub->Option->FilterPPPoE)
+ {
+ if (p->MacHeader != NULL)
+ {
+ USHORT proto = Endian16(p->MacHeader->Protocol);
+ if (proto == 0x8863 || proto == 0x8864)
+ {
+ // PPPoE Filter
+ return false;
+ }
+ }
+ }
+
+ if (hub->Option != NULL && hub->Option->FilterOSPF)
+ {
+ if (p->TypeL3 == L3_IPV4)
+ {
+ if (p->L3.IPv4Header != NULL)
+ {
+ if (p->L3.IPv4Header->Protocol == 89)
+ {
+ // OSPF Filter
+ return false;
+ }
+ }
+ }
+ }
+
+ if (hub->Option != NULL && hub->Option->FilterIPv4)
+ {
+ if (p->MacHeader != NULL)
+ {
+ USHORT proto = Endian16(p->MacHeader->Protocol);
+ if (proto == 0x0800 || proto == 0x0806)
+ {
+ // IPv4 Filter
+ return false;
+ }
+ }
+ }
+
+ if (hub->Option != NULL && hub->Option->FilterIPv6)
+ {
+ if (p->MacHeader != NULL)
+ {
+ USHORT proto = Endian16(p->MacHeader->Protocol);
+ if (proto == 0x86dd)
+ {
+ // IPv6 Filter
+ return false;
+ }
+ }
+ }
+
+ if (hub->Option != NULL && hub->Option->FilterNonIP)
+ {
+ if (p->MacHeader != NULL)
+ {
+ USHORT proto = Endian16(p->MacHeader->Protocol);
+ if (!(proto == 0x86dd || proto == 0x0800 || proto == 0x0806))
+ {
+ // Non-IP Filter
+ return false;
+ }
+ }
+ }
+
+ if (hub->Option != NULL && hub->Option->FilterBPDU)
+ {
+ if (p->MacHeader != NULL)
+ {
+ if (p->TypeL3 == L3_BPDU)
+ {
+ // BPDU Filter
+ return false;
+ }
+ }
+ }
+
+ LockList(hub->AccessList);
+ {
+ for (i = 0;i < LIST_NUM(hub->AccessList);i++)
+ {
+ ACCESS *a = LIST_DATA(hub->AccessList, i);
+
+ if (a->DestUsernameHash != 0)
+ {
+ // If a destination user name is specified, suspend the scanning of the list.
+ break;
+ }
+
+ if (IsPacketMaskedByAccessList(s, p, a, 0, 0, NULL))
+ {
+ // Determine the pass or discard the packet
+ pass = a->Discard ? false : true;
+
+ // Packets determined processing here is not scanned when leaving the HUB.
+ p->AccessChecked = true;
+
+ // Copy of the parameters of the delay jitter packet loss
+ p->Delay = a->Delay;
+ p->Jitter = a->Jitter;
+ p->Loss = a->Loss;
+
+ if (a->RedirectUrl[0] != 0)
+ {
+ // There is a setting of URL redirection in the access list
+ if ((p->TypeL3 == L3_IPV4 || p->TypeL3 == L3_IPV6) &&
+ p->TypeL4 == L4_TCP)
+ {
+ TCP_HEADER *tcp = p->L4.TCPHeader;
+
+ // Examine whether this packet is a TCP data packet
+ if (tcp != NULL)
+ {
+ if (tcp->Flag & TCP_ACK)
+ {
+ if ((tcp->Flag & TCP_SYN) == 0 &&
+ (tcp->Flag & TCP_RST) == 0 &&
+ (tcp->Flag & TCP_URG) == 0)
+ {
+ if (p->PayloadSize != 0)
+ {
+ // Do URL redirection
+ use_redirect_url = true;
+ StrCpy(redirect_url, sizeof(redirect_url), a->RedirectUrl);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Complete the scanning of the list here
+ break;
+ }
+ }
+ }
+ UnlockList(hub->AccessList);
+
+ if (pass)
+ {
+ if (s != NULL && s->FirstTimeHttpRedirect && s->FirstTimeHttpAccessCheckIp != 0)
+ {
+ if ((p->TypeL3 == L3_IPV4 || p->TypeL3 == L3_IPV6) &&
+ p->TypeL4 == L4_TCP)
+ {
+ TCP_HEADER *tcp = p->L4.TCPHeader;
+
+ // Examine whether this packet is a TCP data packet
+ if (tcp != NULL)
+ {
+ if (tcp->DstPort == Endian16(80))
+ {
+ if (p->L3.IPv4Header->DstIP == s->FirstTimeHttpAccessCheckIp)
+ {
+ s->FirstTimeHttpRedirect = false;
+ }
+ else if (tcp->Flag & TCP_ACK)
+ {
+ if ((tcp->Flag & TCP_SYN) == 0 &&
+ (tcp->Flag & TCP_RST) == 0 &&
+ (tcp->Flag & TCP_URG) == 0)
+ {
+ if (p->PayloadSize != 0)
+ {
+ if (IsTcpPacketNcsiHttpAccess(p) == false)
+ {
+/* char tmp[4000];
+ Zero(tmp, sizeof(tmp));
+ Copy(tmp, p->Payload, p->PayloadSize);
+ Debug("HTTP: %s\n", tmp);*/
+ if (IsEmptyStr(s->FirstTimeHttpRedirectUrl) == false)
+ {
+ use_redirect_url = true;
+ StrCpy(redirect_url, sizeof(redirect_url), s->FirstTimeHttpRedirectUrl);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (use_redirect_url)
+ {
+ if (s->NormalClient)
+ {
+ // In the case of a normal VPN client (Not a local bridge, a SecureNAT, and not a virtual L3 switch),
+ // process URL redirection and discard the packet
+ ForceRedirectToUrl(hub, s, p, redirect_url);
+ }
+ else
+ {
+ // Discard packets that is sent from the sessions such as local bridge,
+ // SecureNAT, virtual L3 switch
+ }
+
+ pass = false;
+ }
+
+ return pass;
+}
+
+// Check whether the TCP packet is NCSI accessing
+bool IsTcpPacketNcsiHttpAccess(PKT *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return false;
+ }
+
+ if (p->TypeL4 != L4_TCP)
+ {
+ return false;
+ }
+
+ if (p->Payload == NULL || p->PayloadSize == 0)
+ {
+ return false;
+ }
+
+ if (SearchBin(p->Payload, 0, p->PayloadSize, "NCSI", 4) != INFINITE)
+ {
+ return true;
+ }
+
+ if (SearchBin(p->Payload, 0, p->PayloadSize, ".jpeg", 5) != INFINITE)
+ {
+ return true;
+ }
+
+ if (SearchBin(p->Payload, 0, p->PayloadSize, ".jpg", 4) != INFINITE)
+ {
+ return true;
+ }
+
+ if (SearchBin(p->Payload, 0, p->PayloadSize, ".gif", 4) != INFINITE)
+ {
+ return true;
+ }
+
+ if (SearchBin(p->Payload, 0, p->PayloadSize, ".css", 4) != INFINITE)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Set the URL to which to redirect first
+bool SetSessionFirstRedirectHttpUrl(SESSION *s, char *url)
+{
+ URL_DATA d;
+ IP ip;
+ // Validate arguments
+ if (s == NULL || url == NULL || IsEmptyStr(url))
+ {
+ return false;
+ }
+
+ if (ParseUrl(&d, url, false, NULL) == false)
+ {
+ return false;
+ }
+
+ if (StrToIP(&ip, d.HostName) == false)
+ {
+ return false;
+ }
+
+ if (IsIP4(&ip) == false)
+ {
+ return false;
+ }
+
+ s->FirstTimeHttpAccessCheckIp = IPToUINT(&ip);
+ StrCpy(s->FirstTimeHttpRedirectUrl, sizeof(s->FirstTimeHttpRedirectUrl), url);
+ s->FirstTimeHttpRedirect = true;
+
+ return true;
+}
+
+// Adding Access List
+void AddAccessList(HUB *hub, ACCESS *a)
+{
+ AddAccessListEx(hub, a, false, false);
+}
+void AddAccessListEx(HUB *hub, ACCESS *a, bool no_sort, bool no_reassign_id)
+{
+ // Validate arguments
+ if (hub == NULL || a == NULL)
+ {
+ return;
+ }
+
+ LockList(hub->AccessList);
+ {
+ ACCESS *access;
+ UINT i;
+
+ // Check the number of items
+ if (LIST_NUM(hub->AccessList) >= MAX_ACCESSLISTS)
+ {
+ UnlockList(hub->AccessList);
+ return;
+ }
+
+ access = Malloc(sizeof(ACCESS));
+ Copy(access, a, sizeof(ACCESS));
+
+ access->IsSrcUsernameIncludeOrExclude = false;
+ access->IsDestUsernameIncludeOrExclude = false;
+
+ // User name correction
+ if (IsEmptyStr(access->SrcUsername) == false)
+ {
+ if (StartWith(access->SrcUsername, ACCESS_LIST_INCLUDED_PREFIX) == false && StartWith(access->SrcUsername, ACCESS_LIST_EXCLUDED_PREFIX) == false)
+ {
+ MakeSimpleUsernameRemoveNtDomain(access->SrcUsername, sizeof(access->SrcUsername), access->SrcUsername);
+ }
+ else
+ {
+ access->IsSrcUsernameIncludeOrExclude = true;
+ }
+ }
+ if (IsEmptyStr(access->DestUsername) == false)
+ {
+ if (StartWith(access->DestUsername, ACCESS_LIST_INCLUDED_PREFIX) == false && StartWith(access->DestUsername, ACCESS_LIST_EXCLUDED_PREFIX) == false)
+ {
+ MakeSimpleUsernameRemoveNtDomain(access->DestUsername, sizeof(access->DestUsername), access->DestUsername);
+ }
+ else
+ {
+ access->IsDestUsernameIncludeOrExclude = true;
+ }
+ }
+
+ access->SrcUsernameHash = UsernameToInt64(access->SrcUsername);
+ access->DestUsernameHash = UsernameToInt64(access->DestUsername);
+
+ // Port number correction
+ if (access->SrcPortStart != 0)
+ {
+ access->SrcPortEnd = MAX(access->SrcPortEnd, access->SrcPortStart);
+ }
+ if (access->DestPortStart != 0)
+ {
+ access->DestPortEnd = MAX(access->DestPortEnd, access->DestPortStart);
+ }
+
+ // Correct delay, jitter, and packet loss
+ access->Delay = MAKESURE(access->Delay, 0, HUB_ACCESSLIST_DELAY_MAX);
+ access->Jitter = MAKESURE(access->Jitter, 0, HUB_ACCESSLIST_JITTER_MAX);
+ access->Loss = MAKESURE(access->Loss, 0, HUB_ACCESSLIST_LOSS_MAX);
+
+ if (no_sort == false)
+ {
+ Insert(hub->AccessList, access);
+ }
+ else
+ {
+ Add(hub->AccessList, access);
+ }
+
+ // Reassign the ID
+ if (no_reassign_id == false)
+ {
+ for (i = 0;i < LIST_NUM(hub->AccessList);i++)
+ {
+ ACCESS *a = LIST_DATA(hub->AccessList, i);
+ a->Id = (i + 1);
+ }
+ }
+ }
+ UnlockList(hub->AccessList);
+}
+
+// Initialize the access list
+void InitAccessList(HUB *hub)
+{
+ // Validate arguments
+ if (hub == NULL)
+ {
+ return;
+ }
+
+ hub->AccessList = NewList(CmpAccessList);
+}
+
+// Release the access list
+void FreeAccessList(HUB *hub)
+{
+ UINT i;
+ // Validate arguments
+ if (hub == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(hub->AccessList);i++)
+ {
+ ACCESS *a = LIST_DATA(hub->AccessList, i);
+ Free(a);
+ }
+
+ ReleaseList(hub->AccessList);
+ hub->AccessList = NULL;
+}
+
+// Comparison of the access list entry
+int CmpAccessList(void *p1, void *p2)
+{
+ ACCESS *a1, *a2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ a1 = *(ACCESS **)p1;
+ a2 = *(ACCESS **)p2;
+ if (a1 == NULL || a2 == NULL)
+ {
+ return 0;
+ }
+ // Sort by priority
+ if (a1->Priority > a2->Priority)
+ {
+ return 1;
+ }
+ else if (a1->Priority < a2->Priority)
+ {
+ return -1;
+ }
+ else if (a1->Discard > a2->Discard)
+ {
+ return 1;
+ }
+ else if (a1->Discard < a2->Discard)
+ {
+ return -1;
+ }
+ else
+ {
+ UINT64 size64 = ((UINT64)(&a1->UniqueId) - (UINT64)(&a1->Active));
+ UINT size32 = (UINT)size64;
+
+ return Cmp(&a1->Active, &a2->Active, size32);
+ }
+}
+
+// Generate a user name without domain name of the Windows NT
+void MakeSimpleUsernameRemoveNtDomain(char *dst, UINT dst_size, char *src)
+{
+ char tmp1[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ // Validate arguments
+ if (dst == NULL || src == NULL)
+ {
+ return;
+ }
+
+ ParseNtUsername(src, tmp1, sizeof(tmp1), tmp2, sizeof(tmp2), false);
+
+ StrCpy(dst, dst_size, tmp1);
+}
+
+// Convert the user name to UINT
+UINT64 UsernameToInt64(char *name)
+{
+ UCHAR hash[SHA1_SIZE];
+ UINT64 ret;
+ char tmp[MAX_USERNAME_LEN + 1];
+ // Validate arguments
+ if (name == 0 || IsEmptyStr(name))
+ {
+ return 0;
+ }
+
+ if (StartWith(name, ACCESS_LIST_INCLUDED_PREFIX) || StartWith(name, ACCESS_LIST_EXCLUDED_PREFIX))
+ {
+ return Rand64();
+ }
+
+ MakeSimpleUsernameRemoveNtDomain(tmp, sizeof(tmp), name);
+ Trim(tmp);
+ StrUpper(tmp);
+
+ if (StrLen(tmp) == 0)
+ {
+ return 0;
+ }
+
+ Hash(hash, tmp, StrLen(tmp), true);
+ Copy(&ret, hash, sizeof(ret));
+
+ return ret;
+}
+
+// Search the session from the session pointer
+SESSION *GetSessionByPtr(HUB *hub, void *ptr)
+{
+ // Validate arguments
+ if (hub == NULL || ptr == NULL)
+ {
+ return NULL;
+ }
+
+ LockList(hub->SessionList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(hub->SessionList);i++)
+ {
+ SESSION *s = LIST_DATA(hub->SessionList, i);
+ if (s == (SESSION *)ptr)
+ {
+ // Found
+ AddRef(s->ref);
+ UnlockList(hub->SessionList);
+ return s;
+ }
+ }
+ }
+ UnlockList(hub->SessionList);
+
+ return NULL;
+}
+
+// Search the session from the session name
+SESSION *GetSessionByName(HUB *hub, char *name)
+{
+ // Validate arguments
+ if (hub == NULL || name == NULL)
+ {
+ return NULL;
+ }
+
+ LockList(hub->SessionList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(hub->SessionList);i++)
+ {
+ SESSION *s = LIST_DATA(hub->SessionList, i);
+ if (StrCmpi(s->Name, name) == 0)
+ {
+ // Found
+ AddRef(s->ref);
+ UnlockList(hub->SessionList);
+ return s;
+ }
+ }
+ }
+ UnlockList(hub->SessionList);
+
+ return NULL;
+}
+
+// Sort of the STORM list
+int CompareStormList(void *p1, void *p2)
+{
+ STORM *s1, *s2;
+ UINT r;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ s1 = *(STORM **)p1;
+ s2 = *(STORM **)p2;
+ if (s1 == NULL || s2 == NULL)
+ {
+ return 0;
+ }
+ if (s1->StrictMode == false && s2->StrictMode == false)
+ {
+ // Normal mode
+ r = CmpIpAddr(&s1->DestIp, &s2->DestIp);
+ if (r != 0)
+ {
+ return r;
+ }
+ r = CmpIpAddr(&s1->SrcIp, &s2->SrcIp);
+ if (r != 0)
+ {
+ return r;
+ }
+ }
+ else
+ {
+ // Strict mode
+ int r1, r2;
+ r1 = CmpIpAddr(&s1->DestIp, &s2->DestIp);
+ r2 = CmpIpAddr(&s1->SrcIp, &s2->SrcIp);
+ if (r1 == 0 || r2 == 0)
+ {
+ // Either the source IP, and destination IP match
+ }
+ else
+ {
+ // Mismatch
+ if (r1 != 0)
+ {
+ return r1;
+ }
+
+ if (r2 != 0)
+ {
+ return r2;
+ }
+ }
+ }
+ r = Cmp(s1->MacAddress, s2->MacAddress, 6);
+ return r;
+}
+
+// Packet adapter initialization
+bool HubPaInit(SESSION *s)
+{
+ // Initialize the packet adapter information
+ HUB_PA *pa = ZeroMalloc(sizeof(HUB_PA));
+ pa->Cancel = NewCancel();
+ pa->PacketQueue = NewQueue();
+ pa->Now = Tick64();
+ pa->Session = s;
+ pa->StormList = NewList(CompareStormList);
+ pa->UsernameHash = UsernameToInt64(s->Username);
+ pa->GroupnameHash = UsernameToInt64(s->GroupName);
+
+ s->PacketAdapter->Param = pa;
+
+ if (s->Policy->MonitorPort)
+ {
+ // Mark this port as monitoring port
+ pa->MonitorPort = true;
+
+ // Add this session to the list of monitoring port of the HUB
+ LockList(s->Hub->MonitorList);
+ {
+ Insert(s->Hub->MonitorList, s);
+ }
+ UnlockList(s->Hub->MonitorList);
+ }
+
+ return true;
+}
+
+// Release the Packet adapter
+void HubPaFree(SESSION *s)
+{
+ HUB_PA *pa = (HUB_PA *)s->PacketAdapter->Param;
+ HUB *hub = s->Hub;
+
+ if (pa->MonitorPort)
+ {
+ // Remove the session from the list of monitor port of the HUB
+ LockList(s->Hub->MonitorList);
+ {
+ Delete(s->Hub->MonitorList, s);
+ }
+ UnlockList(s->Hub->MonitorList);
+ }
+
+ // Erase MAC address table entries that is associated with this session
+ LockList(hub->MacTable);
+ {
+ UINT i, num = LIST_NUM(hub->MacTable);
+ LIST *o = NewListFast(NULL);
+ for (i = 0;i < num;i++)
+ {
+ MAC_TABLE_ENTRY *e = (MAC_TABLE_ENTRY *)LIST_DATA(hub->MacTable, i);
+ if (e->Session == s)
+ {
+ Add(o, e);
+ }
+ }
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ MAC_TABLE_ENTRY *e = (MAC_TABLE_ENTRY *)LIST_DATA(o, i);
+ Delete(hub->MacTable, e);
+ Free(e);
+ }
+ ReleaseList(o);
+ }
+ {
+ UINT i, num = LIST_NUM(hub->IpTable);
+ LIST *o = NewListFast(NULL);
+ for (i = 0;i < num;i++)
+ {
+ IP_TABLE_ENTRY *e = LIST_DATA(hub->IpTable, i);
+ if (e->Session == s)
+ {
+ Add(o, e);
+ }
+ }
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IP_TABLE_ENTRY *e = LIST_DATA(o, i);
+ Delete(hub->IpTable, e);
+ Free(e);
+ }
+ ReleaseList(o);
+ }
+ UnlockList(hub->MacTable);
+
+ // Release the STORM list
+ LockList(pa->StormList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(pa->StormList);i++)
+ {
+ STORM *s = (STORM *)LIST_DATA(pa->StormList, i);
+ Free(s);
+ }
+ DeleteAll(pa->StormList);
+ }
+ UnlockList(pa->StormList);
+
+ ReleaseList(pa->StormList);
+
+ // Release the packets remaining in the queue
+ LockQueue(pa->PacketQueue);
+ {
+ BLOCK *b;
+
+ while (b = GetNext(pa->PacketQueue))
+ {
+ // Release the block
+ FreeBlock(b);
+ }
+ }
+ UnlockQueue(pa->PacketQueue);
+
+ // Release the queue
+ ReleaseQueue(pa->PacketQueue);
+
+ // Release the cancel object
+ ReleaseCancel(pa->Cancel);
+
+ // Release the packet adapter information
+ Free(pa);
+ s->PacketAdapter->Param = NULL;
+}
+
+// Get the cancel object
+CANCEL *HubPaGetCancel(SESSION *s)
+{
+ HUB_PA *pa = (HUB_PA *)s->PacketAdapter->Param;
+
+ AddRef(pa->Cancel->ref);
+ return pa->Cancel;
+}
+
+// Get the packet to be transmitted next
+UINT HubPaGetNextPacket(SESSION *s, void **data)
+{
+ UINT ret = 0;
+ HUB_PA *pa = (HUB_PA *)s->PacketAdapter->Param;
+
+ // Get one from the head of the queue
+ LockQueue(pa->PacketQueue);
+ {
+ BLOCK *block = GetNext(pa->PacketQueue);
+ if (block == NULL)
+ {
+ // No queue
+ ret = 0;
+ }
+ else
+ {
+ // Found
+ *data = block->Buf;
+ ret = block->Size;
+ // Release the memory of the structure of the block
+ Free(block);
+ }
+ }
+ UnlockQueue(pa->PacketQueue);
+
+ return ret;
+}
+
+// Receive a packet
+bool HubPaPutPacket(SESSION *s, void *data, UINT size)
+{
+ PKT *packet;
+ HUB_PA *pa = (HUB_PA *)s->PacketAdapter->Param;
+ bool b = false;
+ HUB *hub;
+ bool no_l3 = false;
+ bool no_http = false;
+ LIST *o = NULL;
+ UINT i;
+ UINT vlan_type_id = 0;
+ bool no_look_bpdu_bridge_id = false;
+ bool no_parse_dhcp = false;
+ bool no_correct_checksum = false;
+
+ hub = s->Hub;
+
+ pa->Now = Tick64();
+
+ // Processing of Adjust TCP MSS
+ if (hub->Option != NULL && hub->Option->DisableAdjustTcpMss == false && s != NULL)
+ {
+ UINT target_mss = (hub->Option->AdjustTcpMssValue == 0 ? INFINITE : hub->Option->AdjustTcpMssValue);
+ UINT session_mss = (s->AdjustMss == 0 ? INFINITE : s->AdjustMss);
+
+ target_mss = MIN(target_mss, session_mss);
+
+ if (s->IsUsingUdpAcceleration && s->UdpAccelMss != 0)
+ {
+ // If the link is established with UDP acceleration function, use optimum value of the UDP acceleration function
+ target_mss = MIN(target_mss, s->UdpAccelMss);
+ }
+ else if (s->IsRUDPSession && s->RUdpMss != 0)
+ {
+ // If the link with UDP acceleration is not established, use the optimum value for R-UDP in the case of using R-UDP connection
+ target_mss = MIN(target_mss, s->RUdpMss);
+ }
+
+ if (target_mss != INFINITE)
+ {
+ AdjustTcpMssL2(data, size, target_mss, hub->Option->VlanTypeId);
+ }
+ }
+
+ if (data == NULL)
+ {
+ // Check the delayed packet
+ o = NULL;
+ LockList(s->DelayedPacketList);
+ {
+ UINT i;
+ if (LIST_NUM(s->DelayedPacketList) >= 1)
+ {
+ UINT64 now = TickHighres64();
+ for (i = 0;i < LIST_NUM(s->DelayedPacketList);i++)
+ {
+ PKT *p = LIST_DATA(s->DelayedPacketList, i);
+
+ if (now >= p->DelayedForwardTick)
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Add(o, p);
+ }
+ }
+ }
+
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ PKT *p = LIST_DATA(o, i);
+
+ Delete(s->DelayedPacketList, p);
+ }
+ }
+ }
+ UnlockList(s->DelayedPacketList);
+
+ // If there is a delayed packet, store it
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ PKT *p = LIST_DATA(o, i);
+
+ StorePacket(s->Hub, s, p);
+ }
+
+ ReleaseList(o);
+ }
+
+ // Reception of all packets from this session is complete
+ CancelList(s->CancelList);
+
+ // Yield
+ if (hub->Option != NULL && hub->Option->YieldAfterStorePacket)
+ {
+ YieldCpu();
+ }
+
+ return true;
+ }
+
+ if (hub != NULL && hub->Option != NULL)
+ {
+ no_l3 = hub->Option->DisableIPParsing;
+ no_http = hub->Option->DisableHttpParsing;
+ vlan_type_id = hub->Option->VlanTypeId;
+ no_look_bpdu_bridge_id = hub->Option->NoLookBPDUBridgeId;
+ no_correct_checksum = hub->Option->DisableCorrectIpOffloadChecksum;
+ }
+
+ // Insert a VLAN tag
+ if (s->VLanId != 0)
+ {
+ VLanInsertTag(&data, &size, s->VLanId, vlan_type_id);
+ }
+
+LABEL_TRY_AGAIN:
+ // Parse the packet
+ packet = ParsePacketEx4(data, size, no_l3, vlan_type_id, !no_look_bpdu_bridge_id, no_http, !no_correct_checksum);
+
+ if (packet != NULL)
+ {
+ if (packet->InvalidSourcePacket)
+ {
+ // Packet which have illegal source
+ FreePacket(packet);
+ packet = NULL;
+ }
+ }
+
+
+ if (packet != NULL)
+ {
+ if (packet->TypeL7 == L7_DHCPV4)
+ {
+ if (packet->TypeL3 == L3_IPV4 && packet->TypeL4 == L4_UDP)
+ {
+ if (packet->L7.DHCPv4Header != NULL)
+ {
+ DHCPV4_HEADER *dhcp = packet->L7.DHCPv4Header;
+
+ if (dhcp->OpCode == 1)
+ {
+ if (NsIsMacAddressOnLocalhost(dhcp->ClientMacAddress))
+ {
+ // Filter DHCP requests sent from local kernel-mode virtual NAT
+ // not to re-enter it to the virtual HUB along the local bridge
+ FreePacket(packet);
+ packet = NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (no_parse_dhcp == false && packet != NULL)
+ {
+ if (hub->Option != NULL && hub->Option->RemoveDefGwOnDhcpForLocalhost)
+ {
+ // Remove the designation of the DHCP server from the DHCP response packet addressed to localhost
+ if (packet->TypeL7 == L7_DHCPV4)
+ {
+ if (packet->TypeL3 == L3_IPV4)
+ {
+ if (packet->TypeL4 == L4_UDP)
+ {
+ if (packet->L7.DHCPv4Header != NULL)
+ {
+ DHCPV4_HEADER *dhcp = packet->L7.DHCPv4Header;
+
+ if (dhcp->OpCode == 2)
+ {
+ if (IsMacAddressLocalFast(dhcp->ClientMacAddress))
+ {
+ BUF *new_buf;
+ DHCP_MODIFY_OPTION m;
+ WHERE;
+
+ Zero(&m, sizeof(m));
+ m.RemoveDefaultGatewayOnReply = true;
+
+ new_buf = DhcpModifyIPv4(&m, data, size);
+
+ if (new_buf != NULL)
+ {
+ Free(data);
+
+ data = new_buf->Buf;
+ size = new_buf->Size;
+
+ Free(new_buf);
+
+ no_parse_dhcp = true;
+
+ FreePacket(packet);
+
+ goto LABEL_TRY_AGAIN;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (packet != NULL)
+ {
+ // Store packet
+ StorePacket(s->Hub, s, packet);
+ }
+ else
+ {
+ // Release the packet data because it is a bad packet (not a correct MAC frame)
+ Free(data);
+ }
+
+ return true;
+}
+
+// VGS: Setting for embedding UA tag
+void VgsSetEmbTag(bool b)
+{
+ g_vgs_emb_tag = b;
+}
+
+// VGS: Setting for the User-Agent value
+void VgsSetUserAgentValue(char *str)
+{
+ // Validate arguments
+ if (str == NULL || StrLen(str) != 8)
+ {
+ Zero(vgs_ua_str, sizeof(vgs_ua_str));
+ }
+ else
+ {
+ StrCpy(vgs_ua_str, sizeof(vgs_ua_str), str);
+ }
+}
+
+// Checking algorithm to prevent broadcast-storm
+// If broadcast from a specific endpoint came frequently, filter it
+bool CheckBroadcastStorm(HUB *hub, SESSION *s, PKT *p)
+{
+ IP src_ip, dest_ip;
+ HUB_PA *pa;
+ UINT64 now = Tick64();
+ UINT limit_start_count;
+ SESSION *sess = s;
+ bool ret = true;
+ bool strict = false;
+ bool no_heavy = false;
+ // Validate arguments
+ if (s == NULL || p == NULL || hub == NULL)
+ {
+ return false;
+ }
+
+ if (s->Policy->NoBroadcastLimiter)
+ {
+ // Unlimited the number of broadcasts
+ return true;
+ }
+
+ if (hub != NULL && hub->Option != NULL)
+ {
+ strict = hub->Option->BroadcastLimiterStrictMode;
+ no_heavy = hub->Option->DoNotSaveHeavySecurityLogs;
+ }
+
+ pa = (HUB_PA *)s->PacketAdapter->Param;
+
+ Zero(&src_ip, sizeof(IP));
+ Zero(&dest_ip, sizeof(IP));
+
+ if (p->TypeL3 == L3_IPV4)
+ {
+ UINTToIP(&src_ip, p->L3.IPv4Header->SrcIP);
+ UINTToIP(&dest_ip, p->L3.IPv4Header->DstIP);
+ }
+ else if (p->TypeL3 == L3_ARPV4)
+ {
+ UINTToIP(&src_ip, p->L3.ARPv4Header->SrcIP);
+ Zero(&dest_ip, sizeof(IP));
+ }
+ else if (p->TypeL3 == L3_IPV6)
+ {
+ IPv6AddrToIP(&src_ip, &p->L3.IPv6Header->SrcAddress);
+ IPv6AddrToIP(&dest_ip, &p->L3.IPv6Header->DestAddress);
+ }
+
+ // Number of broadcast to start limitation for a single interval
+ limit_start_count = 32;
+
+ if (s->Hub != NULL && s->Hub->Option->BroadcastStormDetectionThreshold != 0)
+ {
+ limit_start_count = s->Hub->Option->BroadcastStormDetectionThreshold;
+ }
+
+ LockList(pa->StormList);
+ {
+ STORM *s;
+ UINT num;
+ s = SearchStormList(pa, p->MacAddressSrc, &src_ip, &dest_ip, strict);
+ if (s == NULL)
+ {
+ s = AddStormList(pa, p->MacAddressSrc, &src_ip, &dest_ip, strict);
+ }
+
+ s->CurrentBroadcastNum++;
+
+ if ((s->CheckStartTick + STORM_CHECK_SPAN) < now ||
+ s->CheckStartTick == 0 || s->CheckStartTick > now)
+ {
+ // Measure the number of broadcast periodically
+ UINT64 diff_time;
+ if (s->CheckStartTick < now)
+ {
+ diff_time = now - s->CheckStartTick;
+ }
+ else
+ {
+ diff_time = 0;
+ }
+ s->CheckStartTick = now;
+ num = (UINT)((UINT64)s->CurrentBroadcastNum * (UINT64)1000 / (UINT64)STORM_CHECK_SPAN);
+ s->CurrentBroadcastNum = 0;
+ if (num >= limit_start_count)
+ {
+ char ip1[64];
+ char ip2[64];
+ char mac[MAX_SIZE];
+ IPToStr(ip1, sizeof(ip1), &src_ip);
+ IPToStr(ip2, sizeof(ip2), &dest_ip);
+ ret = false;
+ if (s->DiscardValue < STORM_DISCARD_VALUE_END)
+ {
+ s->DiscardValue = MAX(s->DiscardValue, 1) * 2;
+ }
+ Debug("s->DiscardValue: %u (%u)\n", s->DiscardValue, num);
+
+ MacToStr(mac, sizeof(mac), p->MacAddressSrc);
+
+ if (no_heavy == false)
+ {
+ HLog(sess->Hub, "LH_BCAST_STORM", sess->Name, mac, ip1, ip2, num);
+ }
+ }
+ else
+ {
+ if (s->DiscardValue >= 1)
+ {
+ s->DiscardValue = (UINT)((UINT64)s->DiscardValue / MAX((UINT64)2, (UINT64)diff_time / (UINT64)STORM_CHECK_SPAN));
+ }
+ }
+ }
+
+ if (s->DiscardValue >= STORM_DISCARD_VALUE_START)
+ {
+ if (s->DiscardValue >= 128)
+ {
+ ret = false;
+ }
+ else if ((rand() % s->DiscardValue) != 0)
+ {
+ ret = false;
+ }
+ }
+
+ }
+ UnlockList(pa->StormList);
+
+ return ret;
+}
+
+// Store packet
+void StorePacket(HUB *hub, SESSION *s, PKT *packet)
+{
+ MAC_TABLE_ENTRY *entry = NULL;
+ MAC_TABLE_ENTRY t;
+ void *data;
+ UINT size;
+ bool broadcast_mode;
+ HUB_PA *dest_pa;
+ SESSION *dest_session;
+ TRAFFIC traffic;
+ UINT64 now = Tick64();
+ bool no_heavy = false;
+ // Validate arguments
+ if (hub == NULL || packet == NULL)
+ {
+ return;
+ }
+
+ if (s != NULL)
+ {
+ if (((HUB_PA *)s->PacketAdapter->Param)->MonitorPort)
+ {
+ // Not to forward packets received from the monitor port
+ Free(packet->PacketData);
+ FreePacket(packet);
+ return;
+ }
+ }
+
+ if (hub->Option != NULL)
+ {
+ no_heavy = hub->Option->DoNotSaveHeavySecurityLogs;
+ }
+
+ // Lock the entire MAC address table
+ LockList(hub->MacTable);
+ {
+ // Filtering
+ if (s != NULL && (packet->DelayedForwardTick == 0 && StorePacketFilter(s, packet) == false))
+ {
+DISCARD_PACKET:
+ // Release a packet since passing has been disallowed
+ Free(packet->PacketData);
+ FreePacket(packet);
+ }
+ else // Passing is allowed
+ {
+ bool forward_now = true;
+
+ if (packet->Loss >= 1)
+ {
+ // Cause packet loss
+ UINT r = rand() % 100;
+ if ((packet->Loss >= 100) || (r < packet->Loss))
+ {
+ // Packet loss
+ goto DISCARD_PACKET;
+ }
+ }
+
+ if (packet->Delay >= 1)
+ {
+ float delay = (float)packet->Delay;
+ float jitter;
+ UINT delay_uint;
+ bool f = Rand1();
+ if (packet->Jitter == 0)
+ {
+ jitter = 0;
+ }
+ else
+ {
+ jitter = (float)(Rand32() % (int)((float)packet->Jitter * delay / 100.0f));
+ }
+
+ delay += jitter * (f ? 1 : -1);
+ delay_uint = (UINT)delay;
+
+ if (delay_uint >= 1)
+ {
+ // Cause delay
+ forward_now = false;
+ packet->Loss = packet->Jitter = packet->Delay = 0;
+ packet->DelayedForwardTick = TickHighres64() + (UINT64)delay_uint;
+ packet->DelayedSrcSession = s;
+
+ LockList(s->DelayedPacketList);
+ {
+ Add(s->DelayedPacketList, packet);
+ }
+ UnlockList(s->DelayedPacketList);
+ }
+ }
+
+ if (forward_now)
+ {
+ if (Cmp(packet->MacAddressSrc, hub->HubMacAddr, 6) == 0)
+ {
+ if (s != NULL)
+ {
+ // Packets that this HUB itself sent is input from the outside
+ goto DISCARD_PACKET;
+ }
+ }
+ if (s != NULL && (Cmp(packet->MacAddressSrc, hub->HubMacAddr, 6) != 0))
+ {
+ // Check whether the source MAC address is registered in the table
+ Copy(t.MacAddress, packet->MacAddressSrc, 6);
+ if (hub->Option->NoManageVlanId == false)
+ {
+ t.VlanId = packet->VlanId;
+ }
+ else
+ {
+ t.VlanId = 0;
+ }
+ entry = Search(hub->MacTable, &t);
+
+ if (entry == NULL)
+ {
+ // Remove old entries
+ DeleteExpiredMacTableEntry(hub->MacTable);
+
+ // Register since it is not registered
+ if ((s->Policy->MaxMac != 0 || s->Policy->NoBridge) && (s->IsOpenVPNL3Session == false))
+ {
+ UINT i, num_mac_for_me = 0;
+ UINT limited_count;
+
+ // Examine a number of MAC addresses that are registered in this current session
+ for (i = 0;i < LIST_NUM(hub->MacTable);i++)
+ {
+ MAC_TABLE_ENTRY *e = LIST_DATA(hub->MacTable, i);
+ if (e->Session == s)
+ {
+ num_mac_for_me++;
+ }
+ }
+
+ limited_count = 0xffffffff;
+ if (s->Policy->NoBridge)
+ {
+ limited_count = MIN(limited_count, MAC_MIN_LIMIT_COUNT);
+ }
+ if (s->Policy->MaxMac != 0)
+ {
+ limited_count = MIN(limited_count, s->Policy->MaxMac);
+ }
+ limited_count = MAX(limited_count, MAC_MIN_LIMIT_COUNT);
+
+ if (num_mac_for_me >= limited_count)
+ {
+ // Number of MAC addresses that are registered already exceeds the upper limit
+ char mac_str[64];
+
+ if (s != NULL)
+ {
+ MacToStr(mac_str, sizeof(mac_str), packet->MacAddressSrc);
+ if (s->Policy->NoBridge)
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_BRIDGE_LIMIT", s->Name, mac_str, num_mac_for_me, limited_count);
+ }
+ }
+ else
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_MAC_LIMIT", s->Name, mac_str, num_mac_for_me, limited_count);
+ }
+ }
+ }
+
+ goto DISCARD_PACKET; // Drop the packet
+ }
+ }
+
+ if (LIST_NUM(hub->MacTable) >= MAX_MAC_TABLES)
+ {
+ // Delete the oldest entry because the MAC table database is
+ // exceeded the maximum number of entries
+ UINT i;
+ UINT64 old_time = 0xffffffffffffffffULL;
+ MAC_TABLE_ENTRY *old_entry = NULL;
+ for (i = 0;i < LIST_NUM(hub->MacTable);i++)
+ {
+ MAC_TABLE_ENTRY *e = LIST_DATA(hub->MacTable, i);
+ if (e->UpdatedTime <= old_time)
+ {
+ old_time = e->UpdatedTime;
+ old_entry = e;
+ }
+ }
+ if (old_entry != NULL)
+ {
+ Delete(hub->MacTable, old_entry);
+ Free(old_entry);
+ }
+ }
+
+ entry = ZeroMalloc(sizeof(MAC_TABLE_ENTRY));
+ entry->HubPa = (HUB_PA *)s->PacketAdapter->Param;
+ Copy(entry->MacAddress, packet->MacAddressSrc, 6);
+ if (hub->Option->NoManageVlanId == false)
+ {
+ entry->VlanId = packet->VlanId;
+ }
+ else
+ {
+ entry->VlanId = 0;
+ }
+ entry->Session = s;
+ entry->UpdatedTime = entry->CreatedTime = now;
+
+ Insert(hub->MacTable, entry);
+
+ if (hub->Option->NoMacAddressLog == false)
+ {
+ // Debug display
+ char mac_address[32];
+
+ if (s != NULL)
+ {
+ MacToStr(mac_address, sizeof(mac_address), packet->MacAddressSrc);
+// Debug("Register MAC Address %s to Session %X.\n", mac_address, s);
+
+ if (packet->VlanId == 0)
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_MAC_REGIST", s->Name, mac_address);
+ }
+ }
+ else
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_MAC_REGIST_VLAN", s->Name, mac_address, packet->VlanId);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (entry->Session == s)
+ {
+ // Do not do anything because it is already registered
+ entry->UpdatedTime = now;
+ }
+ else
+ {
+ // Read the value of the policy CheckMac
+ bool check_mac = s->Policy->CheckMac;
+
+ if (check_mac == false)
+ {
+ if (s->BridgeMode)
+ {
+ // Enable the CheckMac policy for the local bridge session forcibly
+ check_mac = true;
+
+ if (hub->Option != NULL && hub->Option->DisableCheckMacOnLocalBridge)
+ {
+ // Disable if DisableCheckMacOnLocalBridge option is set
+ check_mac = false;
+ }
+ }
+ }
+
+ // It's already registered and it's in another session
+ if (check_mac && (Cmp(packet->MacAddressSrc, hub->HubMacAddr, 6) != 0) &&
+ ((entry->UpdatedTime + MAC_TABLE_EXCLUSIVE_TIME) >= now))
+ {
+ UCHAR *mac = packet->MacAddressSrc;
+ if (hub->Option != NULL && hub->Option->FixForDLinkBPDU &&
+ (mac[0] == 0x00 && mac[1] == 0x80 && mac[2] == 0xc8 && mac[3] == 0x00 && mac[4] == 0x00 && mac[5] == 0x00) ||
+ (mac[0] == 0x00 && mac[1] == 0x0d && mac[2] == 0x88 && mac[3] == 0x00 && mac[4] == 0x00 && mac[5] == 0x00))
+ {
+ // Measures for D-Link. Spanning tree packet of D-Link is sent from the above address.
+ //CheckMac options for the local bridge may cause an adverse effect. So process this exceptionally.
+ UCHAR hash[MD5_SIZE];
+ UINT64 tick_diff = Tick64() - s->LastDLinkSTPPacketSendTick;
+
+ Hash(hash, packet->PacketData, packet->PacketSize, false);
+
+ if ((s->LastDLinkSTPPacketSendTick != 0) &&
+ (tick_diff < 750ULL) &&
+ (Cmp(hash, s->LastDLinkSTPPacketDataHash, MD5_SIZE) == 0))
+ {
+ // Discard if the same packet sent before 750ms ago
+ Debug("D-Link Discard %u\n", (UINT)tick_diff);
+ goto DISCARD_PACKET; // Drop the packet
+ }
+ else
+ {
+ goto UPDATE_FDB;
+ }
+ }
+ else
+ {
+ if (0)
+ {
+ // If the CheckMac policy-enabled, owning same
+ // MAC address by other sessions are prohibited
+ // (If the second byte is 0xAE, don't perform this check)
+ char mac_address[32];
+ BinToStr(mac_address, sizeof(mac_address), packet->MacAddressSrc, 6);
+ }
+ }
+
+ goto DISCARD_PACKET; // Drop the packet
+ }
+ else
+ {
+ // Rewrite the session of MAC address table and the HUB_PA
+ char mac_address[32];
+UPDATE_FDB:
+ BinToStr(mac_address, sizeof(mac_address), packet->MacAddressSrc, 6);
+
+ entry->Session = s;
+ entry->HubPa = (HUB_PA *)s->PacketAdapter->Param;
+ entry->UpdatedTime = entry->CreatedTime = now;
+
+ if (1)
+ {
+ // Debug display
+ char mac_address[32];
+
+ if (s != NULL)
+ {
+ MacToStr(mac_address, sizeof(mac_address), packet->MacHeader->SrcAddress);
+ Debug("Register MAC Address %s to Session %X.\n", mac_address, s);
+ if (packet->VlanId == 0)
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_MAC_REGIST", s->Name, mac_address);
+ }
+ }
+ else
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_MAC_REGIST_VLAN", s->Name, mac_address, packet->VlanId);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ broadcast_mode = false;
+ dest_pa = NULL;
+ dest_session = NULL;
+
+ if (packet->BroadcastPacket)
+ {
+ // Broadcast packet
+ broadcast_mode = true;
+ }
+ else
+ {
+ // Examine whether the destination MAC address is registered in the table
+ Copy(t.MacAddress, packet->MacAddressDest, 6);
+ if (hub->Option->NoManageVlanId == false)
+ {
+ t.VlanId = packet->VlanId;
+ }
+ else
+ {
+ t.VlanId = 0;
+ }
+ entry = Search(hub->MacTable, &t);
+
+ if (entry == NULL)
+ {
+ // Broadcast because the destination isn't found
+ broadcast_mode = true;
+ }
+ else
+ {
+ if (entry->Session != s)
+ {
+ // Destination is found
+ dest_pa = entry->HubPa;
+ dest_session = entry->Session;
+ }
+ else
+ {
+ // Bad packet whose destination is its own
+ goto DISCARD_PACKET;
+ }
+ }
+ }
+
+ if (s != NULL && hub->Option->NoIpTable == false)
+ {
+ if (packet->TypeL3 == L3_IPV6)
+ {
+ // IPv6 packet
+ IP ip;
+ bool b = true;
+ UINT ip_type;
+ bool dhcp_or_ra = false;
+
+ IPv6AddrToIP(&ip, &packet->L3.IPv6Header->SrcAddress);
+ ip_type = GetIPv6AddrType(&packet->L3.IPv6Header->SrcAddress);
+
+ if (!(ip_type & IPV6_ADDR_UNICAST))
+ {
+ // Multicast address
+ b = false;
+ }
+ else if ((ip_type & IPV6_ADDR_LOOPBACK) || (ip_type & IPV6_ADDR_ZERO))
+ {
+ // Loop-back address or all-zero address
+ b = false;
+ }
+
+ if (packet->TypeL4 == L4_ICMPV6)
+ {
+ if (packet->ICMPv6HeaderPacketInfo.Type == 133 ||
+ packet->ICMPv6HeaderPacketInfo.Type == 134)
+ {
+ // ICMPv6 RS/RA
+ dhcp_or_ra = true;
+ }
+ }
+ else if (packet->TypeL4 == L4_UDP)
+ {
+ if (Endian16(packet->L4.UDPHeader->DstPort) == 546 ||
+ Endian16(packet->L4.UDPHeader->DstPort) == 547)
+ {
+ // DHCPv6
+ dhcp_or_ra = true;
+ }
+ }
+
+ if (IsHubMacAddress(packet->MacAddressSrc) &&
+ IsHubIpAddress64(&packet->L3.IPv6Header->SrcAddress))
+ {
+ // The source address of the Virtual HUB for polling
+ b = false;
+ }
+
+ if (b)
+ {
+ // Other than ICMPv6 RS/RA nor DHCPv6 packet
+ IP_TABLE_ENTRY t, *e;
+
+ Copy(&t.Ip, &ip, sizeof(IP));
+
+ // Check whether it is registered to an existing table
+ e = Search(hub->IpTable, &t);
+
+ if (e == NULL)
+ {
+ // Register since it is not registered
+ if (s->Policy->NoRoutingV6 || s->Policy->MaxIPv6 != 0)
+ {
+ UINT i, num_ip_for_me = 0;
+ UINT limited_count = 0xffffffff;
+
+ for (i = 0;i < LIST_NUM(hub->IpTable);i++)
+ {
+ IP_TABLE_ENTRY *e = LIST_DATA(hub->IpTable, i);
+
+ if (e->Session == s)
+ {
+ if (IsIP6(&e->Ip))
+ {
+ num_ip_for_me++;
+ }
+ }
+ }
+
+ if (s->Policy->NoRoutingV6)
+ {
+ limited_count = MIN(limited_count, IP_LIMIT_WHEN_NO_ROUTING_V6);
+ }
+ if (s->Policy->MaxIPv6 != 0)
+ {
+ limited_count = MIN(limited_count, s->Policy->MaxIPv6);
+ }
+ limited_count = MAX(limited_count, IP_MIN_LIMIT_COUNT_V6);
+
+ if (dhcp_or_ra)
+ {
+ limited_count = 0xffffffff;
+ }
+
+ if (num_ip_for_me >= limited_count)
+ {
+ // Discard the packet because it exceeded the
+ // upper limit of the IP address that can be used
+ char tmp[64];
+ IPToStr(tmp, sizeof(tmp), &ip);
+ if (s->Policy->NoRoutingV6 == false)
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_IP_LIMIT", s->Name, tmp, num_ip_for_me, limited_count);
+ }
+ }
+ else
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_ROUTING_LIMIT", s->Name, tmp, num_ip_for_me, limited_count);
+ }
+ }
+ goto DISCARD_PACKET;
+ }
+ }
+
+ if (IsIPManagementTargetForHUB(&ip, hub))
+ {
+ // Create a entry
+ e = ZeroMalloc(sizeof(IP_TABLE_ENTRY));
+ e->CreatedTime = e->UpdatedTime = now;
+ e->DhcpAllocated = false;
+ Copy(&e->Ip, &ip, sizeof(IP));
+ Copy(e->MacAddress, packet->MacAddressSrc, 6);
+ e->Session = s;
+
+ DeleteExpiredIpTableEntry(hub->IpTable);
+
+ if (LIST_NUM(hub->IpTable) >= MAX_IP_TABLES)
+ {
+ // Delete old IP table entries
+ DeleteOldIpTableEntry(hub->IpTable);
+ }
+
+ Insert(hub->IpTable, e);
+
+ if (0)
+ {
+ char ip_address[64];
+ IPToStr(ip_address, sizeof(ip_address), &ip);
+ Debug("Registered IP Address %s to Session %X.\n",
+ ip_address, s);
+ }
+ }
+ }
+ else
+ {
+ if (e->Session == s)
+ {
+ // Do not do anything because it is self session
+ // Renew updated time
+ e->UpdatedTime = now;
+ Copy(e->MacAddress, packet->MacAddressSrc, 6);
+ }
+ else
+ {
+ // Another session was using this IP address before
+ if ((s->Policy->CheckIPv6) &&
+ ((e->UpdatedTime + IP_TABLE_EXCLUSIVE_TIME) >= now))
+ {
+ // Discard the packet because another session uses this IP address
+ char ip_address[32];
+ char mac_str[48];
+ IPToStr(ip_address, sizeof(ip_address), &ip);
+
+ Debug("IP Address %s is Already used by Session %X.\n",
+ ip_address, s);
+
+ MacToStr(mac_str, sizeof(mac_str), e->MacAddress);
+
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_IP_CONFLICT", s->Name, ip_address, e->Session->Name, mac_str,
+ e->CreatedTime, e->UpdatedTime, e->DhcpAllocated, now);
+ }
+
+ goto DISCARD_PACKET;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (
+ (s != NULL) &&
+ (hub->Option->NoIpTable == false) &&
+ (
+ (packet->TypeL3 == L3_IPV4 ||
+ (packet->TypeL3 == L3_ARPV4 && packet->L3.ARPv4Header->HardwareSize == 6 &&
+ Endian16(packet->L3.ARPv4Header->HardwareType) == ARP_HARDWARE_TYPE_ETHERNET &&
+ packet->L3.ARPv4Header->ProtocolSize == 4 &&
+ Endian16(packet->L3.ARPv4Header->ProtocolType) == 0x0800)
+ ) &&
+ (packet->TypeL7 != L7_DHCPV4)
+ )
+ ) // Other than DHCP packets
+ {
+ // In the case of the ARP response packet or the IP packet, search in the IP address table
+ IP_TABLE_ENTRY t, *e;
+ IP ip;
+ UINT uint_ip = 0;
+
+ if (packet->TypeL3 == L3_IPV4)
+ {
+ uint_ip = packet->L3.IPv4Header->SrcIP;
+ }
+ else if (packet->TypeL3 == L3_ARPV4)
+ {
+ uint_ip = packet->L3.ARPv4Header->SrcIP;
+ }
+
+ if (uint_ip != 0 && uint_ip != 0xffffffff && !(IsHubIpAddress32(uint_ip) && IsHubMacAddress(packet->MacAddressSrc)))
+ {
+ UINTToIP(&ip, uint_ip);
+ Copy(&t.Ip, &ip, sizeof(IP));
+
+ // Check whether it is registered to an existing table
+ e = Search(hub->IpTable, &t);
+
+ if (e == NULL)
+ {
+ // Register since it is not registered
+ if (s->Policy->DHCPForce)
+ {
+ char ipstr[MAX_SIZE];
+
+ // Discard the packet because this IP address isn't
+ // assigned by the DHCP server
+ IPToStr32(ipstr, sizeof(ipstr), uint_ip);
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_DHCP_FORCE", s->Name, ipstr);
+ }
+ goto DISCARD_PACKET;
+ }
+
+ // if (packet->TypeL3 == L3_ARPV4)
+ {
+ // Examine the number that are registered in this session already
+ if (s->Policy->NoRouting || s->Policy->MaxIP != 0)
+ {
+ UINT i, num_ip_for_me = 0;
+ UINT limited_count = 0xffffffff;
+
+ for (i = 0;i < LIST_NUM(hub->IpTable);i++)
+ {
+ IP_TABLE_ENTRY *e = LIST_DATA(hub->IpTable, i);
+
+ if (e->Session == s)
+ {
+ if (IsIP4(&e->Ip))
+ {
+ num_ip_for_me++;
+ }
+ }
+ }
+
+ if (s->Policy->NoRouting)
+ {
+ limited_count = MIN(limited_count, IP_MIN_LIMIT_COUNT);
+ }
+ if (s->Policy->MaxIP != 0)
+ {
+ limited_count = MIN(limited_count, s->Policy->MaxIP);
+ }
+ limited_count = MAX(limited_count, IP_MIN_LIMIT_COUNT);
+
+ if (num_ip_for_me >= limited_count)
+ {
+ // Discard the packet because it exceeded the
+ // upper limit of the IP address that can be used
+ char tmp[64];
+ IPToStr32(tmp, sizeof(tmp), uint_ip);
+ if (s->Policy->NoRouting == false)
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_IP_LIMIT", s->Name, tmp, num_ip_for_me, limited_count);
+ }
+ }
+ else
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_ROUTING_LIMIT", s->Name, tmp, num_ip_for_me, limited_count);
+ }
+ }
+ goto DISCARD_PACKET;
+ }
+ }
+
+ if (IsIPManagementTargetForHUB(&ip, hub))
+ {
+ // Create a entry
+ e = ZeroMalloc(sizeof(IP_TABLE_ENTRY));
+ e->CreatedTime = e->UpdatedTime = now;
+ e->DhcpAllocated = false;
+ Copy(&e->Ip, &ip, sizeof(IP));
+ Copy(e->MacAddress, packet->MacAddressSrc, 6);
+ e->Session = s;
+
+ DeleteExpiredIpTableEntry(hub->IpTable);
+
+ if (LIST_NUM(hub->IpTable) >= MAX_IP_TABLES)
+ {
+ // Delete old IP table entries
+ DeleteOldIpTableEntry(hub->IpTable);
+ }
+
+ Insert(hub->IpTable, e);
+
+ if (0)
+ {
+ char ip_address[64];
+ IPToStr(ip_address, sizeof(ip_address), &ip);
+ Debug("Registered IP Address %s to Session %X.\n",
+ ip_address, s);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (e->Session == s)
+ {
+ // Do not do anything because it is self session
+ // Renew update time
+ e->UpdatedTime = now;
+ Copy(e->MacAddress, packet->MacAddressSrc, 6);
+ }
+ else
+ {
+ // Another session was using this IP address before
+ if ((s->Policy->CheckIP || s->Policy->DHCPForce) &&
+ ((e->UpdatedTime + IP_TABLE_EXCLUSIVE_TIME) >= now))
+ {
+ // Discard the packet because another session uses
+ // this IP address
+ char ip_address[32];
+ char mac_str[48];
+ IPToStr(ip_address, sizeof(ip_address), &ip);
+
+ Debug("IP Address %s is Already used by Session %X.\n",
+ ip_address, s);
+
+ MacToStr(mac_str, sizeof(mac_str), e->MacAddress);
+
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_IP_CONFLICT", s->Name, ip_address, e->Session->Name, mac_str,
+ e->CreatedTime, e->UpdatedTime, e->DhcpAllocated, now);
+ }
+
+ goto DISCARD_PACKET;
+ }
+
+ if (s->Policy->DHCPForce)
+ {
+ if (e->DhcpAllocated == false)
+ {
+ char ipstr[MAX_SIZE];
+
+ // Discard the packet because this IP address
+ // isn't assigned by the DHCP server
+ IPToStr32(ipstr, sizeof(ipstr), uint_ip);
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_DHCP_FORCE", s->Name, ipstr);
+ }
+ goto DISCARD_PACKET;
+ }
+ }
+
+ // Overwrite the entry
+ e->Session = s;
+ e->UpdatedTime = now;
+ Copy(e->MacAddress, packet->MacAddressSrc, 6);
+ }
+ }
+ }
+ }
+
+ if (s != NULL && broadcast_mode)
+ {
+ // Calling Broadcast Storm avoidance algorithm
+ // in order to prevent occurrence of a broadcast packet loop
+ // or a large number of broadcast
+ if (CheckBroadcastStorm(hub, s, packet) == false)
+ {
+ goto DISCARD_PACKET;
+ }
+ }
+
+ // Adding traffic
+ Zero(&traffic, sizeof(traffic));
+ if (packet->BroadcastPacket)
+ {
+ // Broadcast
+ traffic.Send.BroadcastBytes = packet->PacketSize;
+ traffic.Send.BroadcastCount = 1;
+ }
+ else
+ {
+ // Unicast
+ traffic.Send.UnicastBytes = packet->PacketSize;
+ traffic.Send.UnicastCount = 1;
+ }
+
+ if (s != NULL)
+ {
+ AddTrafficForSession(s, &traffic);
+ }
+
+ // Invert the Recv and Send of traffic information
+ Copy(&traffic.Recv, &traffic.Send, sizeof(TRAFFIC_ENTRY));
+ Zero(&traffic.Send, sizeof(TRAFFIC_ENTRY));
+
+ // Broadcast this packet to the monitor port of the HUB
+ if (hub->MonitorList->num_item != 0)
+ {
+ LockList(hub->MonitorList);
+ {
+ UINT i;
+ void *data;
+ UINT size = packet->PacketSize;
+ for (i = 0;i < LIST_NUM(hub->MonitorList);i++)
+ {
+ SESSION *monitor_session = (SESSION *)LIST_DATA(hub->MonitorList, i);
+
+ // Flood the packet
+ if (monitor_session->PacketAdapter->Param != NULL)
+ {
+ data = MallocFast(size);
+ Copy(data, packet->PacketData, size);
+ StorePacketToHubPa((HUB_PA *)monitor_session->PacketAdapter->Param,
+ s, data, size, packet);
+ }
+ }
+ }
+ UnlockList(hub->MonitorList);
+ }
+
+ if (broadcast_mode == false)
+ {
+ if (dest_pa != NULL)
+ {
+ if (dest_session->Policy->NoIPv6DefaultRouterInRA ||
+ (dest_session->Policy->NoIPv6DefaultRouterInRAWhenIPv6 && dest_session->IPv6Session) ||
+ (hub->Option->NoIPv6DefaultRouterInRAWhenIPv6 && dest_session->IPv6Session))
+ {
+ DeleteIPv6DefaultRouterInRA(packet);
+ }
+ if (dest_session->Policy->RSandRAFilter)
+ {
+ if (packet->TypeL3 == L3_IPV6 &&
+ packet->TypeL4 == L4_ICMPV6 &&
+ (packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_SOLICIATION ||
+ packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
+ {
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+ if (dest_session->Policy->DHCPFilter)
+ {
+ if (packet->TypeL3 == L3_IPV4 &&
+ packet->TypeL4 == L4_UDP &&
+ packet->TypeL7 == L7_DHCPV4)
+ {
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+ if (dest_session->Policy->DHCPv6Filter)
+ {
+ if (packet->TypeL3 == L3_IPV6 &&
+ packet->TypeL4 == L4_UDP &&
+ (Endian16(packet->L4.UDPHeader->DstPort) == 546 || Endian16(packet->L4.UDPHeader->DstPort) == 547))
+ {
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+ if (dest_session->Policy->ArpDhcpOnly)
+ {
+ if (packet->BroadcastPacket)
+ {
+ bool b = true;
+
+ if (packet->TypeL3 == L3_IPV4 &&
+ packet->TypeL4 == L4_UDP &&
+ packet->TypeL7 == L7_DHCPV4)
+ {
+ b = false;
+ }
+ else if (packet->TypeL3 == L3_ARPV4)
+ {
+ b = false;
+ }
+ else if (packet->TypeL3 == L3_IPV6 &&
+ packet->TypeL4 == L4_UDP &&
+ (Endian16(packet->L4.UDPHeader->DstPort) == 546 || Endian16(packet->L4.UDPHeader->DstPort) == 547))
+ {
+ b = false;
+ }
+ else if (packet->TypeL3 == L3_IPV6 &&
+ packet->TypeL4 == L4_ICMPV6)
+ {
+ b = false;
+ }
+
+ if (b)
+ {
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+ }
+ if (dest_session->Policy->FilterIPv4)
+ {
+ if (packet->TypeL3 == L3_IPV4 || packet->TypeL3 == L3_ARPV4)
+ {
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+ if (dest_session->Policy->FilterIPv6)
+ {
+ if (packet->TypeL3 == L3_IPV6)
+ {
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+ if (dest_session->Policy->FilterNonIP)
+ {
+ if (packet->TypeL3 != L3_IPV4 && packet->TypeL3 != L3_ARPV4 && packet->TypeL3 != L3_IPV6)
+ {
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+
+ if (s != NULL &&
+ (packet->BroadcastPacket == false &&
+ s->Policy->PrivacyFilter &&
+ dest_session->Policy->PrivacyFilter)
+ )
+ {
+ // Privacy filter
+ if (packet->TypeL3 != L3_ARPV4)
+ {
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+
+ if (s != NULL)
+ {
+ if (Cmp(packet->MacAddressSrc, s->Hub->HubMacAddr, 6) == 0 ||
+ Cmp(packet->MacAddressDest, s->Hub->HubMacAddr, 6) == 0)
+ {
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+
+ // Take a packet log
+ if (s != NULL)
+ {
+ if (PacketLog(s->Hub, s, dest_session, packet, now) == false)
+ {
+ // The packet drops because it have exceeded the allowable amount
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+
+ // Store to the destination HUB_PA
+ StorePacketToHubPa(dest_pa, s, packet->PacketData, packet->PacketSize, packet);
+
+ // Adding traffic
+ AddTrafficForSession(dest_session, &traffic);
+ }
+ else
+ {
+DISCARD_UNICAST_PACKET:
+ Free(packet->PacketData);
+ }
+ }
+ else
+ {
+ // Take a packet log
+ if (s != NULL)
+ {
+ if (PacketLog(s->Hub, s, NULL, packet, now) == false)
+ {
+ // The packet drops because It have exceeded the allowable amount
+ goto DISCARD_BROADCAST_PACKET;
+ }
+ }
+
+ // Store for all sessions
+ LockList(hub->SessionList);
+ {
+ UINT i, num = LIST_NUM(hub->SessionList);
+ for (i = 0;i < num;i++)
+ {
+ SESSION *dest_session = LIST_DATA(hub->SessionList, i);
+ HUB_PA *dest_pa = (HUB_PA *)dest_session->PacketAdapter->Param;
+ bool discard = false;
+
+ if (dest_session != s)
+ {
+ bool delete_default_router_in_ra = false;
+
+ if (dest_session->IsMonitorMode)
+ {
+ discard = true;
+ }
+
+ if (dest_session->VLanId != 0 && packet->TypeL3 == L3_TAGVLAN &&
+ packet->VlanId != dest_session->VLanId)
+ {
+ discard = true;
+ }
+
+ if (dest_session->Policy->NoIPv6DefaultRouterInRA ||
+ (dest_session->Policy->NoIPv6DefaultRouterInRAWhenIPv6 && dest_session->IPv6Session) ||
+ (hub->Option->NoIPv6DefaultRouterInRAWhenIPv6 && dest_session->IPv6Session))
+ {
+ if (packet->TypeL3 == L3_IPV6 && packet->TypeL4 == L4_ICMPV6 &&
+ (packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
+ {
+ if (packet->ICMPv6HeaderPacketInfo.Headers.RouterAdvertisementHeader->Lifetime != 0)
+ {
+ delete_default_router_in_ra = true;
+ }
+ }
+ }
+ if (dest_session->Policy->RSandRAFilter)
+ {
+ if (packet->TypeL3 == L3_IPV6 &&
+ packet->TypeL4 == L4_ICMPV6 &&
+ (packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_SOLICIATION ||
+ packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
+ {
+ discard = true;
+ }
+ }
+
+ if (dest_session->Policy->DHCPFilter)
+ {
+ if (packet->TypeL3 == L3_IPV4 &&
+ packet->TypeL4 == L4_UDP &&
+ packet->TypeL7 == L7_DHCPV4)
+ {
+ discard = true;
+ }
+ }
+
+ if (dest_session->Policy->DHCPv6Filter)
+ {
+ if (packet->TypeL3 == L3_IPV6 &&
+ packet->TypeL4 == L4_UDP &&
+ (Endian16(packet->L4.UDPHeader->DstPort) == 546 || Endian16(packet->L4.UDPHeader->DstPort) == 547))
+ {
+ discard = true;
+ }
+ }
+
+ if (dest_session->Policy->ArpDhcpOnly)
+ {
+ if (packet->BroadcastPacket)
+ {
+ bool b = true;
+
+ if (packet->TypeL3 == L3_IPV4 &&
+ packet->TypeL4 == L4_UDP &&
+ packet->TypeL7 == L7_DHCPV4)
+ {
+ b = false;
+ }
+ else if (packet->TypeL3 == L3_ARPV4)
+ {
+ b = false;
+ }
+ else if (packet->TypeL3 == L3_IPV6 &&
+ packet->TypeL4 == L4_UDP &&
+ (Endian16(packet->L4.UDPHeader->DstPort) == 546 || Endian16(packet->L4.UDPHeader->DstPort) == 547))
+ {
+ b = false;
+ }
+ else if (packet->TypeL3 == L3_IPV6 &&
+ packet->TypeL4 == L4_ICMPV6)
+ {
+ b = false;
+ }
+
+ if (discard == false)
+ {
+ discard = b;
+ }
+ }
+ }
+
+ if (dest_session->Policy->FilterIPv4)
+ {
+ if (packet->TypeL3 == L3_IPV4 || packet->TypeL3 == L3_ARPV4)
+ {
+ discard = true;
+ }
+ }
+ if (dest_session->Policy->FilterIPv6)
+ {
+ if (packet->TypeL3 == L3_IPV6)
+ {
+ discard = true;
+ }
+ }
+ if (dest_session->Policy->FilterNonIP)
+ {
+ if (packet->TypeL3 != L3_IPV4 && packet->TypeL3 != L3_ARPV4 && packet->TypeL3 != L3_IPV6)
+ {
+ discard = true;
+ }
+ }
+
+ if (s != NULL &&
+ (packet->BroadcastPacket == false &&
+ s->Policy->PrivacyFilter &&
+ dest_session->Policy->PrivacyFilter)
+ )
+ {
+ // Privacy filter
+ if (packet->TypeL3 != L3_ARPV4)
+ {
+ discard = true;
+ }
+ }
+
+ if (s != NULL)
+ {
+ if (Cmp(packet->MacAddressSrc, s->Hub->HubMacAddr, 6) == 0 ||
+ Cmp(packet->MacAddressDest, s->Hub->HubMacAddr, 6) == 0)
+ {
+ discard = true;
+ }
+ }
+
+ if (discard == false && dest_pa != NULL)
+ {
+ // Store in session other than its own
+ data = MallocFast(packet->PacketSize);
+ Copy(data, packet->PacketData, packet->PacketSize);
+ size = packet->PacketSize;
+
+ if (delete_default_router_in_ra)
+ {
+ PKT *pkt2 = ParsePacket(data, size);
+
+ DeleteIPv6DefaultRouterInRA(pkt2);
+
+ FreePacket(pkt2);
+ }
+
+ StorePacketToHubPa(dest_pa, s, data, size, packet);
+
+ // Adding traffic
+ AddTrafficForSession(dest_session, &traffic);
+ }
+ }
+ }
+ }
+ UnlockList(hub->SessionList);
+
+DISCARD_BROADCAST_PACKET:
+ Free(packet->PacketData);
+ }
+ FreePacket(packet);
+ }
+ }
+ }
+ UnlockList(hub->MacTable);
+}
+
+// Examine the maximum number of logging target packets per minute
+bool CheckMaxLoggedPacketsPerMinute(SESSION *s, UINT max_packets, UINT64 now)
+{
+ UINT64 minute = 60 * 1000;
+ // Validate arguments
+ if (s == NULL || max_packets == 0)
+ {
+ return true;
+ }
+
+ if ((s->Policy != NULL && s->Policy->NoBroadcastLimiter) ||
+ s->SecureNATMode || s->BridgeMode || s->LinkModeServer || s->LinkModeClient ||
+ s->L3SwitchMode)
+ {
+ return true;
+ }
+
+ if (s->MaxLoggedPacketsPerMinuteStartTick == 0 ||
+ ((s->MaxLoggedPacketsPerMinuteStartTick + minute) <= now))
+ {
+ s->MaxLoggedPacketsPerMinuteStartTick = now;
+ s->CurrentNumPackets = 0;
+ }
+
+ s->CurrentNumPackets++;
+ if (s->CurrentNumPackets > max_packets)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Confirm whether the specified IP address is managed by Virtual HUB
+bool IsIPManagementTargetForHUB(IP *ip, HUB *hub)
+{
+ // Validate arguments
+ if (ip == NULL || hub == NULL)
+ {
+ return false;
+ }
+
+ if (hub->Option == NULL)
+ {
+ return true;
+ }
+
+ if (IsIP4(ip))
+ {
+ if (hub->Option->ManageOnlyPrivateIP)
+ {
+ if (IsIPPrivate(ip) == false)
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ if (hub->Option->ManageOnlyLocalUnicastIPv6)
+ {
+ UINT ip_type = GetIPAddrType6(ip);
+
+ if (!(ip_type & IPV6_ADDR_LOCAL_UNICAST))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+// Delete old IP table entries
+void DeleteOldIpTableEntry(LIST *o)
+{
+ UINT i;
+ UINT64 oldest_time = 0xffffffffffffffffULL;
+ IP_TABLE_ENTRY *old = NULL;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IP_TABLE_ENTRY *e = LIST_DATA(o, i);
+
+ if (e->UpdatedTime <= oldest_time)
+ {
+ old = e;
+ }
+ }
+
+ if (old != NULL)
+ {
+ Delete(o, old);
+ Free(old);
+ }
+}
+
+
+// Add to Storm list
+STORM *AddStormList(HUB_PA *pa, UCHAR *mac_address, IP *src_ip, IP *dest_ip, bool strict)
+{
+ STORM *s;
+ // Validate arguments
+ if (pa == NULL || mac_address == NULL)
+ {
+ return NULL;
+ }
+
+ s = ZeroMalloc(sizeof(STORM));
+ if (src_ip != NULL)
+ {
+ Copy(&s->SrcIp, src_ip, sizeof(IP));
+ }
+ if (dest_ip != NULL)
+ {
+ Copy(&s->DestIp, dest_ip, sizeof(IP));
+ }
+ Copy(s->MacAddress, mac_address, 6);
+ s->StrictMode = strict;
+
+ Insert(pa->StormList, s);
+
+ return s;
+}
+
+// Search in Storm list
+STORM *SearchStormList(HUB_PA *pa, UCHAR *mac_address, IP *src_ip, IP *dest_ip, bool strict)
+{
+ STORM t, *s;
+ // Validate arguments
+ if (pa == NULL || mac_address == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&t, sizeof(t));
+ if (src_ip != NULL)
+ {
+ Copy(&t.SrcIp, src_ip, sizeof(IP));
+ }
+ if (dest_ip != NULL)
+ {
+ Copy(&t.DestIp, dest_ip, sizeof(IP));
+ }
+ Copy(t.MacAddress, mac_address, 6);
+
+ t.StrictMode = strict;
+
+ s = Search(pa->StormList, &t);
+
+ return s;
+}
+
+// Store the packet to destination HUB_PA
+void StorePacketToHubPa(HUB_PA *dest, SESSION *src, void *data, UINT size, PKT *packet)
+{
+ BLOCK *b;
+ // Validate arguments
+ if (dest == NULL || data == NULL)
+ {
+ return;
+ }
+
+ if (size < 14)
+ {
+ Free(data);
+ return;
+ }
+
+ if (src != NULL)
+ {
+ // Apply the access list for forwarding
+ if (ApplyAccessListToForwardPacket(src->Hub, src, dest->Session, packet) == false)
+ {
+ Free(data);
+ return;
+ }
+ }
+
+ if (src != NULL)
+ {
+ if (dest->Session->Policy->MaxDownload != 0)
+ {
+ // Traffic limit
+ if (packet != NULL && IsMostHighestPriorityPacket(dest->Session, packet) == false)
+ {
+ TRAFFIC_LIMITER *tr = &dest->DownloadLimiter;
+ IntoTrafficLimiter(tr, packet);
+
+ if ((tr->Value * (UINT64)1000 / (UINT64)LIMITER_SAMPLING_SPAN) > dest->Session->Policy->MaxDownload)
+ {
+ // Limit
+ Free(data);
+ return;
+ }
+ }
+ }
+ }
+
+ if (src != NULL && src->Hub != NULL && src->Hub->Option != NULL && src->Hub->Option->FixForDLinkBPDU)
+ {
+ // Measures for D-Link bug
+ UCHAR *mac = packet->MacAddressSrc;
+ if ((mac[0] == 0x00 && mac[1] == 0x80 && mac[2] == 0xc8 && mac[3] == 0x00 && mac[4] == 0x00 && mac[5] == 0x00) ||
+ (mac[0] == 0x00 && mac[1] == 0x0d && mac[2] == 0x88 && mac[3] == 0x00 && mac[4] == 0x00 && mac[5] == 0x00))
+ {
+ SESSION *session = dest->Session;
+
+ if (session != NULL)
+ {
+ if (session->Policy != NULL && session->Policy->CheckMac)
+ {
+ UCHAR hash[MD5_SIZE];
+ Hash(hash, packet->PacketData, packet->PacketSize, false);
+
+ Copy(session->LastDLinkSTPPacketDataHash, hash, MD5_SIZE);
+ session->LastDLinkSTPPacketSendTick = Tick64();
+ }
+ }
+ }
+ }
+
+ // Remove the VLAN tag
+ if (dest->Session != NULL && dest->Session->VLanId != 0)
+ {
+ UINT vlan_tpid = 0;
+ if (src != NULL && src->Hub != NULL && src->Hub->Option != NULL)
+ {
+ vlan_tpid = src->Hub->Option->VlanTypeId;
+ }
+ if (VLanRemoveTag(&data, &size, dest->Session->VLanId, vlan_tpid) == false)
+ {
+ Free(data);
+ return;
+ }
+ }
+
+ if (dest != NULL && src != NULL && dest->Session != NULL && src->Hub != NULL && src->Hub->Option != NULL)
+ {
+ if (dest->Session->AdjustMss != 0 ||
+ (dest->Session->IsUsingUdpAcceleration && dest->Session->UdpAccelMss != 0) ||
+ (dest->Session->IsRUDPSession && dest->Session->RUdpMss != 0))
+ {
+ if (src->Hub->Option->DisableAdjustTcpMss == false)
+ {
+ UINT target_mss = INFINITE;
+
+ if (dest->Session->AdjustMss != 0)
+ {
+ target_mss = MIN(target_mss, dest->Session->AdjustMss);
+ }
+
+ if (dest->Session->IsUsingUdpAcceleration && dest->Session->UdpAccelMss != 0)
+ {
+ target_mss = MIN(target_mss, dest->Session->UdpAccelMss);
+ }
+ else if (dest->Session->IsRUDPSession && dest->Session->RUdpMss != 0)
+ {
+ target_mss = MIN(target_mss, dest->Session->RUdpMss);
+ }
+
+ // Processing of Adjust TCP MSS
+ if (target_mss != INFINITE)
+ {
+ AdjustTcpMssL2(data, size, target_mss, src->Hub->Option->VlanTypeId);
+ }
+ }
+ }
+ }
+
+ // Create a block
+ b = NewBlock(data, size, 0);
+
+ LockQueue(dest->PacketQueue);
+ {
+ // Measure the length of queue
+ if ((dest->PacketQueue->num_item < MAX_STORED_QUEUE_NUM) ||
+ (((UCHAR *)data)[12] == 'S' && ((UCHAR *)data)[13] == 'E'))
+ {
+ // Store
+ InsertQueue(dest->PacketQueue, b);
+ }
+ else
+ {
+ // Drop the packet
+ FreeBlock(b);
+ }
+ }
+ UnlockQueue(dest->PacketQueue);
+
+ // Issue of cancellation
+ if (src != NULL)
+ {
+ AddCancelList(src->CancelList, dest->Cancel);
+ }
+ else
+ {
+ Cancel(dest->Cancel);
+ }
+}
+
+// Remove the default router specification from the IPv6 router advertisement
+bool DeleteIPv6DefaultRouterInRA(PKT *p)
+{
+ if (p->TypeL3 == L3_IPV6 && p->TypeL4 == L4_ICMPV6 &&
+ (p->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
+ {
+ if (p->ICMPv6HeaderPacketInfo.Headers.RouterAdvertisementHeader->Lifetime != 0)
+ {
+ p->ICMPv6HeaderPacketInfo.Headers.RouterAdvertisementHeader->Lifetime = 0;
+
+ p->L4.ICMPHeader->Checksum = 0;
+ p->L4.ICMPHeader->Checksum =
+ CalcChecksumForIPv6(&p->L3.IPv6Header->SrcAddress,
+ &p->L3.IPv6Header->DestAddress, IP_PROTO_ICMPV6,
+ p->L4.ICMPHeader, p->IPv6HeaderPacketInfo.PayloadSize, 0);
+ }
+ }
+
+ return false;
+}
+
+// Packet filter by policy
+bool StorePacketFilterByPolicy(SESSION *s, PKT *p)
+{
+ POLICY *pol;
+ HUB *hub;
+ bool no_heavy = false;
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return false;
+ }
+
+ hub = s->Hub;
+
+ if (hub->Option != NULL)
+ {
+ no_heavy = hub->Option->DoNotSaveHeavySecurityLogs;
+ }
+
+ // Policy
+ pol = s->Policy;
+
+ // To prohibit the operation as a server
+ if (pol->NoServer)
+ {
+ if (p->TypeL3 == L3_IPV4)
+ {
+ if (p->TypeL4 == L4_TCP)
+ {
+ UCHAR flag = p->L4.TCPHeader->Flag;
+ if ((flag & TCP_SYN) && (flag & TCP_ACK))
+ {
+ char ip1[64], ip2[64];
+ // Not to send a SYN + ACK packet
+ Debug("pol->NoServer: Discard SYN+ACK Packet.\n");
+
+ IPToStr32(ip1, sizeof(ip1), p->L3.IPv4Header->SrcIP);
+ IPToStr32(ip2, sizeof(ip2), p->L3.IPv4Header->DstIP);
+
+ if (no_heavy == false)
+ {
+ HLog(s->Hub, "LH_NO_SERVER", s->Name, ip2, p->L4.TCPHeader->DstPort,
+ ip1, p->L4.TCPHeader->SrcPort);
+ }
+
+ return false;
+ }
+ }
+ }
+ }
+
+ // Prohibit the operation as a server (IPv6)
+ if (pol->NoServerV6)
+ {
+ if (p->TypeL3 == L3_IPV6)
+ {
+ if (p->TypeL4 == L4_TCP)
+ {
+ UCHAR flag = p->L4.TCPHeader->Flag;
+ if ((flag & TCP_SYN) && (flag & TCP_ACK))
+ {
+ char ip1[128], ip2[128];
+ // Not to send a SYN + ACK packet
+ Debug("pol->NoServerV6: Discard SYN+ACK Packet.\n");
+
+ IP6AddrToStr(ip1, sizeof(ip1), &p->IPv6HeaderPacketInfo.IPv6Header->SrcAddress);
+ IP6AddrToStr(ip2, sizeof(ip2), &p->IPv6HeaderPacketInfo.IPv6Header->DestAddress);
+
+ if (no_heavy == false)
+ {
+ HLog(s->Hub, "LH_NO_SERVER", s->Name, ip2, p->L4.TCPHeader->DstPort,
+ ip1, p->L4.TCPHeader->SrcPort);
+ }
+
+ return false;
+ }
+ }
+ }
+ }
+
+ // Allow broadcast only DHCP and ARP
+ if (pol->ArpDhcpOnly && p->BroadcastPacket)
+ {
+ bool ok = false;
+
+ if (p->TypeL3 == L3_ARPV4)
+ {
+ ok = true;
+ }
+ if (p->TypeL3 == L3_IPV4)
+ {
+ if (p->TypeL4 == L4_UDP)
+ {
+ if (p->TypeL7 == L7_DHCPV4)
+ {
+ ok = true;
+ }
+ }
+ }
+ if (p->TypeL3 == L3_IPV6)
+ {
+ if (p->TypeL4 == L4_ICMPV6)
+ {
+ ok = true;
+ }
+ }
+
+ if (p->TypeL3 == L3_IPV6 &&
+ p->TypeL4 == L4_UDP &&
+ (Endian16(p->L4.UDPHeader->DstPort) == 546 || Endian16(p->L4.UDPHeader->DstPort) == 547))
+ {
+ ok = true;
+ }
+
+ if (ok == false)
+ {
+ return false;
+ }
+ }
+
+ // Filter IPv4 packets
+ if (pol->FilterIPv4)
+ {
+ if (p->MacHeader != NULL)
+ {
+ USHORT proto = Endian16(p->MacHeader->Protocol);
+ if (proto == 0x0800 || proto == 0x0806)
+ {
+ return false;
+ }
+ }
+ }
+
+ // Filter IPv6 packets
+ if (pol->FilterIPv6)
+ {
+ if (p->MacHeader != NULL)
+ {
+ USHORT proto = Endian16(p->MacHeader->Protocol);
+ if (proto == 0x86dd)
+ {
+ return false;
+ }
+ }
+ }
+
+ // Filter non-IP packets
+ if (pol->FilterNonIP)
+ {
+ if (p->MacHeader != NULL)
+ {
+ USHORT proto = Endian16(p->MacHeader->Protocol);
+ if (!(proto == 0x86dd || proto == 0x0800 || proto == 0x0806))
+ {
+ return false;
+ }
+ }
+ }
+
+ // Filter DHCP packets
+ if (pol->DHCPFilter)
+ {
+ if (p->TypeL3 == L3_IPV4 &&
+ p->TypeL4 == L4_UDP &&
+ p->TypeL7 == L7_DHCPV4)
+ {
+ // Discard the DHCP packet
+ Debug("pol->DHCPFilter: Discard DHCP Packet.\n");
+
+ return false;
+ }
+ }
+
+ // DHCPv6 packet filtering
+ if (pol->DHCPv6Filter)
+ {
+ if (p->TypeL3 == L3_IPV6 &&
+ p->TypeL4 == L4_UDP)
+ {
+ if (Endian16(p->L4.UDPHeader->DstPort) == 546 ||
+ Endian16(p->L4.UDPHeader->DstPort) == 547)
+ {
+ // Discard the DHCPv6 packet
+ Debug("pol->DHCPv6Filter: Discard DHCPv6 Packet.\n");
+
+ return false;
+ }
+ }
+ }
+
+ // The behavior as a DHCP server is prohibited
+ if (pol->DHCPNoServer)
+ {
+ if (p->TypeL3 == L3_IPV4 &&
+ p->TypeL4 == L4_UDP &&
+ p->TypeL7 == L7_DHCPV4)
+ {
+ DHCPV4_HEADER *h = p->L7.DHCPv4Header;
+ if (h->OpCode == 2)
+ {
+ char ip1[64], ip2[64];
+
+ // Discard the DHCP packet
+ IPToStr32(ip1, sizeof(ip1), p->L3.IPv4Header->SrcIP);
+ IPToStr32(ip2, sizeof(ip2), p->L3.IPv4Header->DstIP);
+
+ if (no_heavy == false)
+ {
+ HLog(s->Hub, "LH_NO_DHCP", s->Name, ip1, ip2);
+ }
+
+ // Discard the DHCP response packet
+ Debug("pol->DHCPNoServer: Discard DHCP Response Packet.\n");
+ return false;
+ }
+ }
+ }
+
+ // The behavior as a DHCPv6 server is prohibited
+ if (pol->DHCPv6NoServer)
+ {
+ if (p->TypeL3 == L3_IPV6 &&
+ p->TypeL4 == L4_UDP &&
+ (Endian16(p->L4.UDPHeader->DstPort) == 546 || Endian16(p->L4.UDPHeader->SrcPort) == 547))
+ {
+ char ip1[128], ip2[128];
+
+ // Discard the DHCP packet
+ IP6AddrToStr(ip1, sizeof(ip1), &p->L3.IPv6Header->SrcAddress);
+ IP6AddrToStr(ip2, sizeof(ip2), &p->L3.IPv6Header->DestAddress);
+
+ if (no_heavy == false)
+ {
+ HLog(s->Hub, "LH_NO_DHCP", s->Name, ip1, ip2);
+ }
+
+ // Discard the DHCP response packet
+ Debug("pol->DHCPv6NoServer: Discard DHCPv6 Response Packet.\n");
+ return false;
+ }
+ }
+
+ // Filter the Router Solicitation / Advertising packet (IPv6)
+ if (pol->RSandRAFilter)
+ {
+ if (p->TypeL3 == L3_IPV6 && p->TypeL4 == L4_ICMPV6 &&
+ (p->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_SOLICIATION ||
+ p->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
+ {
+ return false;
+ }
+ }
+
+ // Filter the router advertisement packet (IPv6)
+ if (pol->RAFilter)
+ {
+ if (p->TypeL3 == L3_IPV6 && p->TypeL4 == L4_ICMPV6 &&
+ p->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT)
+ {
+ return false;
+ }
+ }
+
+ // Register to the IP table by recording the DHCP response packet
+ if (p->TypeL3 == L3_IPV4 &&
+ p->TypeL4 == L4_UDP &&
+ p->TypeL7 == L7_DHCPV4 &&
+ (s->Hub != NULL && s->Hub->Option->NoIpTable == false))
+ {
+ DHCPV4_HEADER *h = p->L7.DHCPv4Header;
+ if (h->OpCode == 2 && p->DhcpOpCode == DHCP_ACK)
+ {
+ // Register to the IP table by peeking the contents of the DHCP response packet
+ if (h->HardwareType == ARP_HARDWARE_TYPE_ETHERNET)
+ {
+ if (h->HardwareAddressSize == 6)
+ {
+ if (h->YourIP != 0 && h->YourIP != 0xffffffff)
+ {
+ UINT ip_uint = h->YourIP;
+ IP ip;
+ IP_TABLE_ENTRY *e, t;
+ MAC_TABLE_ENTRY *mac_table, mt;
+ mt.VlanId = 0;
+ Copy(&mt.MacAddress, &h->ClientMacAddress, 6);
+ mac_table = Search(hub->MacTable, &mt);
+
+ if (mac_table != NULL)
+ {
+ bool new_entry = true;
+ UINTToIP(&ip, ip_uint);
+ Copy(&t.Ip, &ip, sizeof(IP));
+
+ e = Search(hub->IpTable, &t);
+ if (e == NULL)
+ {
+ // Register as a new item
+ e = ZeroMalloc(sizeof(IP_TABLE_ENTRY));
+UPDATE_DHCP_ALLOC_ENTRY:
+ e->CreatedTime = e->UpdatedTime = Tick64();
+ e->DhcpAllocated = true;
+ Copy(&e->Ip, &ip, sizeof(IP));
+ e->Session = mac_table->Session;
+ Copy(e->MacAddress, p->MacAddressDest, 6);
+
+ if (new_entry)
+ {
+ // Delete the expired IP table entries
+ DeleteExpiredIpTableEntry(hub->IpTable);
+ if (LIST_NUM(hub->IpTable) >= MAX_IP_TABLES)
+ {
+ // Remove old entries
+ DeleteOldIpTableEntry(hub->IpTable);
+ }
+ Insert(hub->IpTable, e);
+ }
+
+ if (new_entry)
+ {
+ if ((hub->Option != NULL && hub->Option->NoDhcpPacketLogOutsideHub == false) || mac_table->Session != s)
+ {
+ char dhcp_mac_addr[64];
+ char dest_mac_addr[64];
+ char dest_ip_addr[64];
+ char server_ip_addr[64];
+ MacToStr(dhcp_mac_addr, sizeof(dhcp_mac_addr), p->MacAddressSrc);
+ MacToStr(dest_mac_addr, sizeof(dest_mac_addr), h->ClientMacAddress);
+ IPToStr(dest_ip_addr, sizeof(dest_ip_addr), &ip);
+ IPToStr32(server_ip_addr, sizeof(server_ip_addr), p->L3.IPv4Header->SrcIP);
+ Debug("DHCP Allocated; dhcp server: %s, client: %s, new_ip: %s\n",
+ dhcp_mac_addr, dest_mac_addr, dest_ip_addr);
+
+ if (no_heavy == false)
+ {
+ HLog(s->Hub, "LH_REGIST_DHCP", s->Name, dhcp_mac_addr, server_ip_addr,
+ mac_table->Session->Name, dest_mac_addr, dest_ip_addr);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Update
+ new_entry = false;
+ goto UPDATE_DHCP_ALLOC_ENTRY;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+// Delete the expired MAC table entries
+void DeleteExpiredMacTableEntry(LIST *o)
+{
+ LIST *o2;
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ o2 = NewListFast(NULL);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ MAC_TABLE_ENTRY *e = LIST_DATA(o, i);
+ if ((e->UpdatedTime + (UINT64)MAC_TABLE_EXPIRE_TIME) <= Tick64())
+ {
+ Add(o2, e);
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o2);i++)
+ {
+ MAC_TABLE_ENTRY *e = LIST_DATA(o2, i);
+ Delete(o, e);
+ Free(e);
+ }
+
+ ReleaseList(o2);
+}
+
+// Delete the expired IP table entries
+void DeleteExpiredIpTableEntry(LIST *o)
+{
+ LIST *o2;
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ o2 = NewListFast(NULL);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IP_TABLE_ENTRY *e = LIST_DATA(o, i);
+ if ((e->UpdatedTime + (UINT64)(e->DhcpAllocated ? IP_TABLE_EXPIRE_TIME_DHCP : IP_TABLE_EXPIRE_TIME)) <= Tick64())
+ {
+ Add(o2, e);
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o2);i++)
+ {
+ IP_TABLE_ENTRY *e = LIST_DATA(o2, i);
+ Delete(o, e);
+ Free(e);
+ }
+
+ ReleaseList(o2);
+}
+
+// Determine whether the packet to be handled with priority
+bool IsMostHighestPriorityPacket(SESSION *s, PKT *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return false;
+ }
+
+ if (p->TypeL3 == L3_ARPV4)
+ {
+ // ARP packets
+ return true;
+ }
+
+ if (p->TypeL3 == L3_IPV4)
+ {
+ if (p->TypeL4 == L4_ICMPV4)
+ {
+ // ICMP packets
+ return true;
+ }
+
+ if (p->TypeL4 == L4_TCP)
+ {
+ if ((p->L4.TCPHeader->Flag & TCP_SYN) || (p->L4.TCPHeader->Flag & TCP_FIN)
+ || (p->L4.TCPHeader->Flag & TCP_RST))
+ {
+ // SYN, FIN, RST packet
+ return true;
+ }
+ }
+
+ if (p->TypeL4 == L4_UDP)
+ {
+ if (p->TypeL7 == L7_DHCPV4)
+ {
+ // DHCP packets
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+// Add a packet to traffic limiter
+void IntoTrafficLimiter(TRAFFIC_LIMITER *tr, PKT *p)
+{
+ UINT64 now = Tick64();
+ // Validate arguments
+ if (tr == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (tr->LastTime == 0 || tr->LastTime > now ||
+ (tr->LastTime + LIMITER_SAMPLING_SPAN) < now)
+ {
+ // Sampling initialization
+ tr->Value = 0;
+ tr->LastTime = now;
+ }
+
+ // Value increase
+ tr->Value += (UINT64)(p->PacketSize * 8);
+}
+
+// The bandwidth reduction by traffic limiter
+bool StorePacketFilterByTrafficLimiter(SESSION *s, PKT *p)
+{
+ HUB_PA *pa;
+ TRAFFIC_LIMITER *tr;
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return false;
+ }
+
+ if (s->Policy->MaxUpload == 0)
+ {
+ // Unlimited
+ return true;
+ }
+
+ pa = (HUB_PA *)s->PacketAdapter->Param;
+ tr = &pa->UploadLimiter;
+
+ // Restrictions are not applied for priority packets
+ if (IsMostHighestPriorityPacket(s, p))
+ {
+ return true;
+ }
+
+ // Input packets to the limiter
+ IntoTrafficLimiter(tr, p);
+
+ // Compare the current bandwidth and limit value
+ if ((tr->Value * (UINT64)1000 / (UINT64)LIMITER_SAMPLING_SPAN) > s->Policy->MaxUpload)
+ {
+ // Discard the packet
+ return false;
+ }
+
+ return true;
+}
+
+// Filtering of packets to store
+bool StorePacketFilter(SESSION *s, PKT *packet)
+{
+ // Validate arguments
+ if (s == NULL || packet == NULL)
+ {
+ return false;
+ }
+
+ // The bandwidth reduction by traffic limiter
+ if (StorePacketFilterByTrafficLimiter(s, packet) == false)
+ {
+ return false;
+ }
+
+ // Packet filter by policy
+ if (StorePacketFilterByPolicy(s, packet) == false)
+ {
+ return false;
+ }
+
+ // The packet filter with Access Lists
+ if (ApplyAccessListToStoredPacket(s->Hub, s, packet) == false)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Get the packet adapter for the HUB
+PACKET_ADAPTER *GetHubPacketAdapter()
+{
+ // Hand over by creating a function list
+ PACKET_ADAPTER *pa = NewPacketAdapter(HubPaInit,
+ HubPaGetCancel, HubPaGetNextPacket, HubPaPutPacket, HubPaFree);
+
+ return pa;
+}
+
+// Stop all the SESSION of the HUB
+void StopAllSession(HUB *h)
+{
+ SESSION **s;
+ UINT i, num;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ LockList(h->SessionList);
+ {
+ num = LIST_NUM(h->SessionList);
+ s = ToArray(h->SessionList);
+ DeleteAll(h->SessionList);
+ }
+ UnlockList(h->SessionList);
+
+ for (i = 0;i < num;i++)
+ {
+ StopSession(s[i]);
+ ReleaseSession(s[i]);
+ }
+
+ Free(s);
+}
+
+// Remove the SESSION from HUB
+void DelSession(HUB *h, SESSION *s)
+{
+ // Validate arguments
+ if (h == NULL || s == NULL)
+ {
+ return;
+ }
+
+ LockList(h->SessionList);
+ {
+ if (Delete(h->SessionList, s))
+ {
+ Debug("Session %s was Deleted from %s.\n", s->Name, h->Name);
+ ReleaseSession(s);
+ }
+ }
+ UnlockList(h->SessionList);
+}
+
+// Add a SESSION to the HUB
+void AddSession(HUB *h, SESSION *s)
+{
+ // Validate arguments
+ if (h == NULL || s == NULL)
+ {
+ return;
+ }
+
+ LockList(h->SessionList);
+ {
+ Insert(h->SessionList, s);
+ AddRef(s->ref);
+ Debug("Session %s Inserted to %s.\n", s->Name, h->Name);
+
+ if (s->InProcMode)
+ {
+ s->UniqueId = GetNewUniqueId(h);
+ }
+ }
+ UnlockList(h->SessionList);
+}
+
+// Create a new unique ID of the HUB
+UINT GetNewUniqueId(HUB *h)
+{
+ UINT id;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return 0;
+ }
+
+ for (id = 1;;id++)
+ {
+ if (SearchSessionByUniqueId(h, id) == NULL)
+ {
+ return id;
+ }
+ }
+}
+
+// Search for a session by the unique session ID
+SESSION *SearchSessionByUniqueId(HUB *h, UINT id)
+{
+ UINT i;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(h->SessionList);i++)
+ {
+ SESSION *s = LIST_DATA(h->SessionList, i);
+
+ if (s->UniqueId == id)
+ {
+ return s;
+ }
+ }
+
+ return NULL;
+}
+
+// Stop the operation of the HUB
+void StopHub(HUB *h)
+{
+ bool old_status = false;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ old_status = h->Offline;
+ h->HubIsOnlineButHalting = true;
+
+ SetHubOffline(h);
+
+ if (h->Halt == false)
+ {
+ SLog(h->Cedar, "LS_HUB_STOP", h->Name);
+ h->Halt = true;
+ }
+
+ h->Offline = old_status;
+ h->HubIsOnlineButHalting = false;
+}
+
+// Online the Virtual HUB
+void SetHubOnline(HUB *h)
+{
+ bool for_cluster = false;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ if (h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ if (h->Type == HUB_TYPE_FARM_DYNAMIC)
+ {
+ for_cluster = true;
+ }
+ }
+
+ Lock(h->lock_online);
+ {
+ if (h->Offline == false)
+ {
+ Unlock(h->lock_online);
+ return;
+ }
+ HLog(h, "LH_ONLINE");
+
+ // Start all links
+ StartAllLink(h);
+
+ // Start the SecureNAT
+ if (h->EnableSecureNAT)
+ {
+ if (h->SecureNAT == NULL)
+ {
+ if (for_cluster == false)
+ {
+ h->SecureNAT = SnNewSecureNAT(h, h->SecureNATOption);
+ }
+ }
+ }
+
+ // Start all of the local bridges that is associated with this HUB
+ if (h->Type != HUB_TYPE_FARM_DYNAMIC)
+ {
+ LockList(h->Cedar->LocalBridgeList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(h->Cedar->LocalBridgeList);i++)
+ {
+ LOCALBRIDGE *br = LIST_DATA(h->Cedar->LocalBridgeList, i);
+
+ if (StrCmpi(br->HubName, h->Name) == 0)
+ {
+ if (br->Bridge == NULL)
+ {
+ br->Bridge = BrNewBridge(h, br->DeviceName, NULL, br->Local, br->Monitor,
+ br->TapMode, br->TapMacAddress, br->LimitBroadcast, br);
+ }
+ }
+ }
+ }
+ UnlockList(h->Cedar->LocalBridgeList);
+ }
+
+ h->Offline = false;
+ }
+ Unlock(h->lock_online);
+
+ if (h->Cedar->Server != NULL)
+ {
+ SiHubOnlineProc(h);
+ }
+}
+
+// Offline the Virtual HUB
+void SetHubOffline(HUB *h)
+{
+ UINT i;
+ bool for_cluster = false;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ if (h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ if (h->Type == HUB_TYPE_FARM_DYNAMIC)
+ {
+ for_cluster = true;
+ }
+ }
+
+ h->BeingOffline = true;
+
+ Lock(h->lock_online);
+ {
+ if (h->Offline || h->Halt)
+ {
+ Unlock(h->lock_online);
+ h->BeingOffline = false;
+ return;
+ }
+
+ HLog(h, "LH_OFFLINE");
+
+ // Stop all links
+ StopAllLink(h);
+
+ // Stop the SecureNAT
+ SnFreeSecureNAT(h->SecureNAT);
+ h->SecureNAT = NULL;
+
+ // Stop all the local bridges that is associated with this HUB
+ LockList(h->Cedar->LocalBridgeList);
+ {
+ for (i = 0;i < LIST_NUM(h->Cedar->LocalBridgeList);i++)
+ {
+ LOCALBRIDGE *br = LIST_DATA(h->Cedar->LocalBridgeList, i);
+
+ if (StrCmpi(br->HubName, h->Name) == 0)
+ {
+ BrFreeBridge(br->Bridge);
+ br->Bridge = NULL;
+ }
+ }
+ }
+ UnlockList(h->Cedar->LocalBridgeList);
+
+ // Offline
+ h->Offline = true;
+
+ // Disconnect all sessions
+ StopAllSession(h);
+ }
+ Unlock(h->lock_online);
+
+ h->BeingOffline = false;
+
+ if (h->Cedar->Server != NULL)
+ {
+ SiHubOfflineProc(h);
+ }
+}
+
+// Get whether a HUB which have the specified name exists
+bool IsHub(CEDAR *cedar, char *name)
+{
+ HUB *h;
+ // Validate arguments
+ if (cedar == NULL || name == NULL)
+ {
+ return false;
+ }
+
+ h = GetHub(cedar, name);
+ if (h == NULL)
+ {
+ return false;
+ }
+
+ ReleaseHub(h);
+
+ return true;
+}
+
+// Get the HUB
+HUB *GetHub(CEDAR *cedar, char *name)
+{
+ HUB *h, t;
+ // Validate arguments
+ if (cedar == NULL || name == NULL)
+ {
+ return NULL;
+ }
+
+ LockHubList(cedar);
+
+ t.Name = name;
+ h = Search(cedar->HubList, &t);
+ if (h == NULL)
+ {
+ UnlockHubList(cedar);
+ return NULL;
+ }
+
+ AddRef(h->ref);
+
+ UnlockHubList(cedar);
+
+ return h;
+}
+
+// Lock the HUB list
+void LockHubList(CEDAR *cedar)
+{
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return;
+ }
+
+ LockList(cedar->HubList);
+}
+
+// Unlock the HUB list
+void UnlockHubList(CEDAR *cedar)
+{
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return;
+ }
+
+ UnlockList(cedar->HubList);
+}
+
+// Release the HUB
+void ReleaseHub(HUB *h)
+{
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ if (Release(h->ref) == 0)
+ {
+ CleanupHub(h);
+ }
+}
+
+// Get the Radius server information
+bool GetRadiusServer(HUB *hub, char *name, UINT size, UINT *port, char *secret, UINT secret_size)
+{
+ UINT interval;
+ return GetRadiusServerEx(hub, name, size, port, secret, secret_size, &interval);
+}
+bool GetRadiusServerEx(HUB *hub, char *name, UINT size, UINT *port, char *secret, UINT secret_size, UINT *interval)
+{
+ return GetRadiusServerEx2(hub, name, size, port, secret, secret_size, interval, NULL, 0);
+}
+bool GetRadiusServerEx2(HUB *hub, char *name, UINT size, UINT *port, char *secret, UINT secret_size, UINT *interval, char *suffix_filter, UINT suffix_filter_size)
+{
+ bool ret = false;
+ // Validate arguments
+ if (hub == NULL || name == NULL || port == NULL || secret == NULL || interval == NULL)
+ {
+ return false;
+ }
+
+ Lock(hub->RadiusOptionLock);
+ {
+ if (hub->RadiusServerName != NULL)
+ {
+ char *tmp;
+ UINT tmp_size;
+ StrCpy(name, size, hub->RadiusServerName);
+ *port = hub->RadiusServerPort;
+ *interval = hub->RadiusRetryInterval;
+
+ tmp_size = hub->RadiusSecret->Size + 1;
+ tmp = ZeroMalloc(tmp_size);
+ Copy(tmp, hub->RadiusSecret->Buf, hub->RadiusSecret->Size);
+ StrCpy(secret, secret_size, tmp);
+ Free(tmp);
+
+ if (suffix_filter != NULL)
+ {
+ StrCpy(suffix_filter, suffix_filter_size, hub->RadiusSuffixFilter);
+ }
+
+ ret = true;
+ }
+ }
+ Unlock(hub->RadiusOptionLock);
+
+ return ret;
+}
+
+// Set the Radius server information
+void SetRadiusServer(HUB *hub, char *name, UINT port, char *secret)
+{
+ SetRadiusServerEx(hub, name, port, secret, RADIUS_RETRY_INTERVAL);
+}
+void SetRadiusServerEx(HUB *hub, char *name, UINT port, char *secret, UINT interval)
+{
+ // Validate arguments
+ if (hub == NULL)
+ {
+ return;
+ }
+
+ Lock(hub->RadiusOptionLock);
+ {
+ if (hub->RadiusServerName != NULL)
+ {
+ Free(hub->RadiusServerName);
+ }
+
+ if (name == NULL)
+ {
+ hub->RadiusServerName = NULL;
+ hub->RadiusServerPort = 0;
+ hub->RadiusRetryInterval = RADIUS_RETRY_INTERVAL;
+ FreeBuf(hub->RadiusSecret);
+ }
+ else
+ {
+ hub->RadiusServerName = CopyStr(name);
+ hub->RadiusServerPort = port;
+ if (interval == 0)
+ {
+ hub->RadiusRetryInterval = RADIUS_RETRY_INTERVAL;
+ }
+ else if (interval > RADIUS_RETRY_TIMEOUT)
+ {
+ hub->RadiusRetryInterval = RADIUS_RETRY_TIMEOUT;
+ }
+ else
+ {
+ hub->RadiusRetryInterval = interval;
+ }
+ FreeBuf(hub->RadiusSecret);
+
+ if (secret == NULL)
+ {
+ hub->RadiusSecret = NewBuf();
+ }
+ else
+ {
+ hub->RadiusSecret = NewBuf();
+ WriteBuf(hub->RadiusSecret, secret, StrLen(secret));
+ SeekBuf(hub->RadiusSecret, 0, 0);
+ }
+ }
+ }
+ Unlock(hub->RadiusOptionLock);
+}
+
+// Get the difference between the traffic data
+void CalcTrafficEntryDiff(TRAFFIC_ENTRY *diff, TRAFFIC_ENTRY *old, TRAFFIC_ENTRY *current)
+{
+ // Validate arguments
+ Zero(diff, sizeof(TRAFFIC_ENTRY));
+ if (old == NULL || current == NULL || diff == NULL)
+ {
+ return;
+ }
+
+ if (current->BroadcastCount >= old->BroadcastCount)
+ {
+ diff->BroadcastCount = current->BroadcastCount - old->BroadcastCount;
+ }
+ if (current->BroadcastBytes >= old->BroadcastBytes)
+ {
+ diff->BroadcastBytes = current->BroadcastBytes - old->BroadcastBytes;
+ }
+ if (current->UnicastCount >= old->UnicastCount)
+ {
+ diff->UnicastCount = current->UnicastCount - old->UnicastCount;
+ }
+ if (current->UnicastBytes >= old->UnicastBytes)
+ {
+ diff->UnicastBytes = current->UnicastBytes - old->UnicastBytes;
+ }
+}
+void CalcTrafficDiff(TRAFFIC *diff, TRAFFIC *old, TRAFFIC *current)
+{
+ Zero(diff, sizeof(TRAFFIC));
+ if (old == NULL || current == NULL || diff == NULL)
+ {
+ return;
+ }
+
+ CalcTrafficEntryDiff(&diff->Send, &old->Send, ¤t->Send);
+ CalcTrafficEntryDiff(&diff->Recv, &old->Recv, ¤t->Recv);
+}
+
+// Add the traffic information for Virtual HUB
+void IncrementHubTraffic(HUB *h)
+{
+ TRAFFIC t;
+ // Validate arguments
+ if (h == NULL || h->FarmMember == false)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+
+ Lock(h->TrafficLock);
+ {
+ t.Send.BroadcastBytes =
+ h->Traffic->Send.BroadcastBytes - h->OldTraffic->Send.BroadcastBytes;
+ t.Send.BroadcastCount =
+ h->Traffic->Send.BroadcastCount - h->OldTraffic->Send.BroadcastCount;
+ t.Send.UnicastBytes =
+ h->Traffic->Send.UnicastBytes - h->OldTraffic->Send.UnicastBytes;
+ t.Send.UnicastCount =
+ h->Traffic->Send.UnicastCount - h->OldTraffic->Send.UnicastCount;
+ t.Recv.BroadcastBytes =
+ h->Traffic->Recv.BroadcastBytes - h->OldTraffic->Recv.BroadcastBytes;
+ t.Recv.BroadcastCount =
+ h->Traffic->Recv.BroadcastCount - h->OldTraffic->Recv.BroadcastCount;
+ t.Recv.UnicastBytes =
+ h->Traffic->Recv.UnicastBytes - h->OldTraffic->Recv.UnicastBytes;
+ t.Recv.UnicastCount =
+ h->Traffic->Recv.UnicastCount - h->OldTraffic->Recv.UnicastCount;
+ Copy(h->OldTraffic, h->Traffic, sizeof(TRAFFIC));
+ }
+ Unlock(h->TrafficLock);
+
+ if (IsZero(&t, sizeof(TRAFFIC)))
+ {
+ return;
+ }
+
+ AddTrafficDiff(h, h->Name, TRAFFIC_DIFF_HUB, &t);
+}
+
+// Adding Traffic information
+void AddTrafficDiff(HUB *h, char *name, UINT type, TRAFFIC *traffic)
+{
+ TRAFFIC_DIFF *d;
+ // Validate arguments
+ if (h == NULL || h->FarmMember == false || name == NULL || traffic == NULL)
+ {
+ return;
+ }
+
+ if (LIST_NUM(h->Cedar->TrafficDiffList) > MAX_TRAFFIC_DIFF)
+ {
+ return;
+ }
+
+ d = ZeroMallocFast(sizeof(TRAFFIC_DIFF));
+ d->HubName = CopyStr(h->Name);
+ d->Name = CopyStr(name);
+ d->Type = type;
+ Copy(&d->Traffic, traffic, sizeof(TRAFFIC));
+
+ LockList(h->Cedar->TrafficDiffList);
+ {
+ Insert(h->Cedar->TrafficDiffList, d);
+ }
+ UnlockList(h->Cedar->TrafficDiffList);
+}
+
+// Cleanup of HUB
+void CleanupHub(HUB *h)
+{
+ UINT i;
+ char name[MAX_SIZE];
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ StrCpy(name, sizeof(name), h->Name);
+
+ if (h->WatchDogStarted)
+ {
+ StopHubWatchDog(h);
+ }
+
+ FreeAccessList(h);
+
+ if (h->RadiusServerName != NULL)
+ {
+ Free(h->RadiusServerName);
+ FreeBuf(h->RadiusSecret);
+ }
+ ReleaseAllLink(h);
+ DeleteHubDb(h->HubDb);
+ ReleaseCedar(h->Cedar);
+ DeleteLock(h->lock);
+ DeleteLock(h->lock_online);
+ Free(h->Name);
+ ReleaseList(h->SessionList);
+ ReleaseList(h->MacTable);
+ ReleaseList(h->IpTable);
+ ReleaseList(h->MonitorList);
+ ReleaseList(h->LinkList);
+ DeleteCounter(h->NumSessions);
+ DeleteCounter(h->NumSessionsClient);
+ DeleteCounter(h->NumSessionsBridge);
+ DeleteCounter(h->SessionCounter);
+ FreeTraffic(h->Traffic);
+ FreeTraffic(h->OldTraffic);
+ Free(h->Option);
+
+ Free(h->SecureNATOption);
+
+ DeleteLock(h->TrafficLock);
+
+ for (i = 0;i < LIST_NUM(h->TicketList);i++)
+ {
+ Free(LIST_DATA(h->TicketList, i));
+ }
+
+ ReleaseList(h->TicketList);
+
+ DeleteLock(h->RadiusOptionLock);
+
+ FreeLog(h->PacketLogger);
+ FreeLog(h->SecurityLogger);
+
+ for (i = 0;i < LIST_NUM(h->AdminOptionList);i++)
+ {
+ Free(LIST_DATA(h->AdminOptionList, i));
+ }
+ ReleaseList(h->AdminOptionList);
+
+ if (h->Msg != NULL)
+ {
+ Free(h->Msg);
+ }
+
+ FreeUserList(h->UserList);
+
+ Free(h);
+}
+
+// Comparison function of IP table entries
+int CompareIpTable(void *p1, void *p2)
+{
+ IP_TABLE_ENTRY *e1, *e2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ e1 = *(IP_TABLE_ENTRY **)p1;
+ e2 = *(IP_TABLE_ENTRY **)p2;
+ if (e1 == NULL || e2 == NULL)
+ {
+ return 0;
+ }
+ return CmpIpAddr(&e1->Ip, &e2->Ip);
+}
+
+// Comparison function of the MAC table entries
+int CompareMacTable(void *p1, void *p2)
+{
+ int r;
+ MAC_TABLE_ENTRY *e1, *e2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ e1 = *(MAC_TABLE_ENTRY **)p1;
+ e2 = *(MAC_TABLE_ENTRY **)p2;
+ if (e1 == NULL || e2 == NULL)
+ {
+ return 0;
+ }
+ r = Cmp(e1->MacAddress, e2->MacAddress, 6);
+ if (r != 0)
+ {
+ return r;
+ }
+ if (e1->VlanId > e2->VlanId)
+ {
+ return 1;
+ }
+ else if (e1->VlanId < e2->VlanId)
+ {
+ return -1;
+ }
+ return 0;
+}
+
+// Comparison function of HUB
+int CompareHub(void *p1, void *p2)
+{
+ HUB *h1, *h2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ h1 = *(HUB **)p1;
+ h2 = *(HUB **)p2;
+ if (h1 == NULL || h2 == NULL)
+ {
+ return 0;
+ }
+ return StrCmpi(h1->Name, h2->Name);
+}
+
+// Examine whether the MAC address is for the ARP polling of the Virtual HUB
+bool IsHubMacAddress(UCHAR *mac)
+{
+ // Validate arguments
+ if (mac == NULL)
+ {
+ return false;
+ }
+
+ if (mac[0] == 0x00 && mac[1] == SE_HUB_MAC_ADDR_SIGN)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Examine whether the IP address is for the ARP polling of the Virtual HUB
+bool IsHubIpAddress32(UINT ip32)
+{
+ IP ip;
+
+ UINTToIP(&ip, ip32);
+
+ return IsHubIpAddress(&ip);
+}
+bool IsHubIpAddress(IP *ip)
+{
+ // Validate arguments
+ if (ip == NULL)
+ {
+ return false;
+ }
+
+ if (ip->addr[0] == 172 && ip->addr[1] == 31)
+ {
+ if (ip->addr[2] >= 1 && ip->addr[2] <= 254)
+ {
+ if (ip->addr[3] >= 1 && ip->addr[3] <= 254)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+bool IsHubIpAddress64(IPV6_ADDR *addr)
+{
+ // Validate arguments
+ if (addr == NULL)
+ {
+ return false;
+ }
+
+ if (addr->Value[0] == 0xfe && addr->Value[1] == 0x80 &&
+ addr->Value[2] == 0 &&
+ addr->Value[3] == 0 &&
+ addr->Value[4] == 0 &&
+ addr->Value[5] == 0 &&
+ addr->Value[6] == 0 &&
+ addr->Value[7] == 0 &&
+ addr->Value[8] == 0x02 && addr->Value[9] == 0xae &&
+ addr->Value[11] == 0xff && addr->Value[12] == 0xfe)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Generate an IP address for the Virtual HUB
+void GenHubIpAddress(IP *ip, char *name)
+{
+ char tmp1[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ UCHAR hash[SHA1_SIZE];
+ // Validate arguments
+ if (ip == NULL || name == NULL)
+ {
+ return;
+ }
+
+ StrCpy(tmp1, sizeof(tmp1), name);
+ Trim(tmp1);
+ GenerateMachineUniqueHash(hash);
+ BinToStr(tmp2, sizeof(tmp2), hash, sizeof(hash));
+ StrCat(tmp2, sizeof(tmp2), tmp1);
+ StrUpper(tmp2);
+
+ Hash(hash, tmp2, StrLen(tmp2), true);
+
+ Zero(ip, sizeof(IP));
+ ip->addr[0] = 172;
+ ip->addr[1] = 31;
+ ip->addr[2] = hash[0] % 254 + 1;
+ ip->addr[3] = hash[1] % 254 + 1;
+}
+
+// Generate a MAC address for the Virtual HUB
+void GenHubMacAddress(UCHAR *mac, char *name)
+{
+ char tmp1[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ UCHAR hash[SHA1_SIZE];
+ // Validate arguments
+ if (mac == NULL || name == NULL)
+ {
+ return;
+ }
+
+ StrCpy(tmp1, sizeof(tmp1), name);
+ Trim(tmp1);
+ GenerateMachineUniqueHash(hash);
+ BinToStr(tmp2, sizeof(tmp2), hash, sizeof(hash));
+ StrCat(tmp2, sizeof(tmp2), tmp1);
+ StrUpper(tmp2);
+
+ Hash(hash, tmp2, StrLen(tmp2), true);
+
+ mac[0] = 0x00;
+ mac[1] = SE_HUB_MAC_ADDR_SIGN;
+ mac[2] = hash[0];
+ mac[3] = hash[1];
+ mac[4] = hash[2];
+ mac[5] = hash[3];
+}
+
+// Get a message from HUB
+wchar_t *GetHubMsg(HUB *h)
+{
+ wchar_t *ret = NULL;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return NULL;
+ }
+
+ Lock(h->lock);
+ {
+ if (h->Msg != NULL)
+ {
+ ret = CopyUniStr(h->Msg);
+ }
+ }
+ Unlock(h->lock);
+
+ return ret;
+}
+
+// Set a message to the HUB
+void SetHubMsg(HUB *h, wchar_t *msg)
+{
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ Lock(h->lock);
+ {
+ if (h->Msg != NULL)
+ {
+ Free(h->Msg);
+ h->Msg = NULL;
+ }
+
+ if (UniIsEmptyStr(msg) == false)
+ {
+ h->Msg = UniCopyStr(msg);
+ }
+ }
+ Unlock(h->lock);
+}
+
+// Creating a new HUB
+HUB *NewHub(CEDAR *cedar, char *HubName, HUB_OPTION *option)
+{
+ HUB *h;
+ char packet_logger_name[MAX_SIZE];
+ char tmp[MAX_SIZE];
+ char safe_hub_name[MAX_HUBNAME_LEN + 1];
+ UCHAR hash[SHA1_SIZE];
+ IP ip6;
+ // Validate arguments
+ if (cedar == NULL || option == NULL || HubName == NULL)
+ {
+ return NULL;
+ }
+
+ h = ZeroMalloc(sizeof(HUB));
+ Hash(h->HashedPassword, "", 0, true);
+ HashPassword(h->SecurePassword, ADMINISTRATOR_USERNAME, "");
+ h->lock = NewLock();
+ h->lock_online = NewLock();
+ h->ref = NewRef();
+ h->Cedar = cedar;
+ AddRef(h->Cedar->ref);
+ h->Type = HUB_TYPE_STANDALONE;
+
+ ConvertSafeFileName(safe_hub_name, sizeof(safe_hub_name), HubName);
+ h->Name = CopyStr(safe_hub_name);
+
+
+ h->AdminOptionList = NewList(CompareAdminOption);
+ AddHubAdminOptionsDefaults(h, true);
+
+ h->LastCommTime = SystemTime64();
+ h->LastLoginTime = SystemTime64();
+ h->NumLogin = 0;
+
+ h->TrafficLock = NewLock();
+
+ h->HubDb = NewHubDb();
+
+ h->SessionList = NewList(NULL);
+ h->SessionCounter = NewCounter();
+ h->NumSessions = NewCounter();
+ h->NumSessionsClient = NewCounter();
+ h->NumSessionsBridge = NewCounter();
+ h->MacTable = NewList(CompareMacTable);
+ h->IpTable = NewList(CompareIpTable);
+ h->MonitorList = NewList(NULL);
+ h->LinkList = NewList(NULL);
+
+ h->Traffic = NewTraffic();
+ h->OldTraffic = NewTraffic();
+
+ h->Option = ZeroMalloc(sizeof(HUB_OPTION));
+ Copy(h->Option, option, sizeof(HUB_OPTION));
+
+ if (h->Option->VlanTypeId == 0)
+ {
+ h->Option->VlanTypeId = MAC_PROTO_TAGVLAN;
+ }
+
+ Rand(h->HubSignature, sizeof(h->HubSignature));
+
+ // SecureNAT related
+ h->EnableSecureNAT = false;
+ h->SecureNAT = NULL;
+ h->SecureNATOption = ZeroMalloc(sizeof(VH_OPTION));
+ NiSetDefaultVhOption(NULL, h->SecureNATOption);
+
+ if (h->Cedar != NULL && h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ NiClearUnsupportedVhOptionForDynamicHub(h->SecureNATOption, true);
+ }
+
+ // Generate a temporary MAC address for the HUB
+ GenerateMachineUniqueHash(hash);
+ GenHubMacAddress(h->HubMacAddr, h->Name);
+ GenHubIpAddress(&h->HubIp, h->Name);
+
+ // IPv6 address for the HUB
+ GenerateEui64LocalAddress(&ip6, h->HubMacAddr);
+ IPToIPv6Addr(&h->HubIpV6, &ip6);
+
+ h->RadiusOptionLock = NewLock();
+ h->RadiusServerPort = RADIUS_DEFAULT_PORT;
+
+ h->TicketList = NewList(NULL);
+
+ InitAccessList(h);
+
+ // Create a user list
+ h->UserList = NewUserList();
+
+ // Default logging settings
+ h->LogSetting.SavePacketLog = h->LogSetting.SaveSecurityLog = true;
+ h->LogSetting.PacketLogConfig[PACKET_LOG_TCP_CONN] =
+ h->LogSetting.PacketLogConfig[PACKET_LOG_DHCP] = PACKET_LOG_HEADER;
+ h->LogSetting.SecurityLogSwitchType = LOG_SWITCH_DAY;
+ h->LogSetting.PacketLogSwitchType = LOG_SWITCH_DAY;
+
+ MakeDir(HUB_SECURITY_LOG_DIR_NAME);
+ MakeDir(HUB_PACKET_LOG_DIR_NAME);
+
+ // Start the packet logger
+ Format(packet_logger_name, sizeof(packet_logger_name), HUB_PACKET_LOG_FILE_NAME, h->Name);
+ h->PacketLogger = NewLog(packet_logger_name, HUB_PACKET_LOG_PREFIX, h->LogSetting.PacketLogSwitchType);
+
+ // Start the security logger
+ Format(tmp, sizeof(tmp), HUB_SECURITY_LOG_FILE_NAME, h->Name);
+ h->SecurityLogger = NewLog(tmp, HUB_SECURITY_LOG_PREFIX, h->LogSetting.SecurityLogSwitchType);
+
+ if (h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ h->FarmMember = true;
+ }
+
+ // Start the HUB
+ SetHubOnline(h);
+
+ if (h->Cedar->Bridge)
+ {
+ h->Option->NoArpPolling = true;
+ }
+
+ if (h->Option->NoArpPolling == false && h->Option->NoIpTable == false)
+ {
+ StartHubWatchDog(h);
+ h->WatchDogStarted = true;
+ }
+
+ SLog(h->Cedar, "LS_HUB_START", h->Name);
+
+ MacToStr(tmp, sizeof(tmp), h->HubMacAddr);
+ SLog(h->Cedar, "LS_HUB_MAC", h->Name, tmp);
+
+ return h;
+}
+
+// Delete the HUBDB
+void DeleteHubDb(HUBDB *d)
+{
+ // Validate arguments
+ if (d == NULL)
+ {
+ return;
+ }
+
+ LockList(d->UserList);
+ {
+ LockList(d->GroupList);
+ {
+ // Release all users and groups
+ UINT i;
+ USER **users;
+ USERGROUP **groups;
+
+ users = ToArray(d->UserList);
+ groups = ToArray(d->GroupList);
+
+ for (i = 0;i < LIST_NUM(d->UserList);i++)
+ {
+ ReleaseUser(users[i]);
+ }
+ for (i = 0;i < LIST_NUM(d->GroupList);i++)
+ {
+ ReleaseGroup(groups[i]);
+ }
+
+ Free(users);
+ Free(groups);
+ }
+ UnlockList(d->GroupList);
+ }
+ UnlockList(d->UserList);
+
+ // Release the root certificate list
+ LockList(d->RootCertList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(d->RootCertList);i++)
+ {
+ X *x = LIST_DATA(d->RootCertList, i);
+ FreeX(x);
+ }
+ }
+ UnlockList(d->RootCertList);
+
+ // Release the CRL
+ LockList(d->CrlList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(d->CrlList);i++)
+ {
+ CRL *crl = LIST_DATA(d->CrlList, i);
+ FreeCrl(crl);
+ }
+ }
+ UnlockList(d->CrlList);
+
+ // Release the AC list
+ FreeAcList(d->AcList);
+
+ ReleaseList(d->GroupList);
+ ReleaseList(d->UserList);
+ ReleaseList(d->RootCertList);
+ ReleaseList(d->CrlList);
+ Free(d);
+}
+
+// Get a log setting of the HUB
+void GetHubLogSetting(HUB *h, HUB_LOG *setting)
+{
+ // Validate arguments
+ if (setting == NULL || h == NULL)
+ {
+ return;
+ }
+
+ Copy(setting, &h->LogSetting, sizeof(HUB_LOG));
+}
+
+// Update the log settings of the HUB
+void SetHubLogSettingEx(HUB *h, HUB_LOG *setting, bool no_change_switch_type)
+{
+ UINT i1, i2;
+ // Validate arguments
+ if (setting == NULL || h == NULL)
+ {
+ return;
+ }
+
+ i1 = h->LogSetting.PacketLogSwitchType;
+ i2 = h->LogSetting.SecurityLogSwitchType;
+
+ Copy(&h->LogSetting, setting, sizeof(HUB_LOG));
+
+ if (no_change_switch_type)
+ {
+ h->LogSetting.PacketLogSwitchType = i1;
+ h->LogSetting.SecurityLogSwitchType = i2;
+ }
+
+ // Packet logger configuration
+ SetLogSwitchType(h->PacketLogger, setting->PacketLogSwitchType);
+ SetLogSwitchType(h->SecurityLogger, setting->SecurityLogSwitchType);
+}
+void SetHubLogSetting(HUB *h, HUB_LOG *setting)
+{
+ SetHubLogSettingEx(h, setting, false);
+}
+
+// Add the trusted root certificate to the HUB
+void AddRootCert(HUB *hub, X *x)
+{
+ HUBDB *db;
+ // Validate arguments
+ if (hub == NULL || x == NULL)
+ {
+ return;
+ }
+
+ db = hub->HubDb;
+ if (db != NULL)
+ {
+ LockList(db->RootCertList);
+ {
+ if (LIST_NUM(db->RootCertList) < MAX_HUB_CERTS)
+ {
+ UINT i;
+ bool ok = true;
+
+ for (i = 0;i < LIST_NUM(db->RootCertList);i++)
+ {
+ X *exist_x = LIST_DATA(db->RootCertList, i);
+ if (CompareX(exist_x, x))
+ {
+ ok = false;
+ break;
+ }
+ }
+
+ if (ok)
+ {
+ Insert(db->RootCertList, CloneX(x));
+ }
+ }
+ }
+ UnlockList(db->RootCertList);
+ }
+}
+
+// Compare the list of certificates
+int CompareCert(void *p1, void *p2)
+{
+ X *x1, *x2;
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ x1 = *(X **)p1;
+ x2 = *(X **)p2;
+ if (x1 == NULL || x2 == NULL)
+ {
+ return 0;
+ }
+
+ GetPrintNameFromX(tmp1, sizeof(tmp1), x1);
+ GetPrintNameFromX(tmp2, sizeof(tmp2), x2);
+
+ return UniStrCmpi(tmp1, tmp2);
+}
+
+// Creating a new HUBDB
+HUBDB *NewHubDb()
+{
+ HUBDB *d = ZeroMalloc(sizeof(HUBDB));
+
+ d->GroupList = NewList(CompareGroupName);
+ d->UserList = NewList(CompareUserName);
+ d->RootCertList = NewList(CompareCert);
+ d->CrlList = NewList(NULL);
+ d->AcList = NewAcList();
+
+ return d;
+}
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Hub.h b/src/Cedar/Hub.h
new file mode 100644
index 00000000..ae671d89
--- /dev/null
+++ b/src/Cedar/Hub.h
@@ -0,0 +1,598 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Hub.h
+// Header of Hub.c
+
+#ifndef HUB_H
+#define HUB_H
+
+
+// Prefix in the access list for investigating whether the user name which is contained in a particular file
+#define ACCESS_LIST_INCLUDED_PREFIX "include:" // Included
+#define ACCESS_LIST_EXCLUDED_PREFIX "exclude:" // Not included
+
+// The default value for the cache expiration of the user name reference file of the access list (in seconds)
+#define ACCESS_LIST_INCLUDE_FILE_CACHE_LIFETIME 30
+
+// The maximum length of the include file in the access list
+#define ACCESS_LIST_INCLUDE_FILE_MAX_SIZE (1024 * 1024)
+
+// tags of the URL in the access list
+#define ACCESS_LIST_URL_INFO_TAG ""
+
+
+// SoftEther link control packet
+struct SE_LINK
+{
+ UCHAR DestMacAddress[6]; // Destination MAC address
+ UCHAR SrcMacAddress[6]; // Source MAC address
+ UCHAR SignatureS; // 'S'
+ UCHAR SignatureE; // 'E'
+ UCHAR Padding[2]; // Padding
+ UINT Type; // Type
+ UCHAR HubSignature[16]; // HUB signature
+ UINT TransactionId; // Transaction ID
+ UINT Data; // Data
+ UCHAR Dummy[20]; // Dummy
+ UCHAR Checksum[SHA1_SIZE]; // Checksum
+};
+
+
+// Test packet reception record
+struct TEST_HISTORY
+{
+ SESSION *s1;
+ SESSION *s2;
+};
+
+// State machine for link test
+struct SE_TEST
+{
+ LOCK *lock; // Lock
+ UINT64 LastTestPacketSentTime; // Time that sent the test packet at the last
+ UINT NextTestPacketSendInterval; // Next test packet transmission interval
+ bool CurrentTesting; // Test by sending a test packet currently
+ UINT TransactionId; // Transaction ID
+ LIST *TestHistory; // Reception history
+};
+
+// Macro
+#define NO_ACCOUNT_DB(h) ((h)->FarmMember)
+
+// Database in the case of a stand-alone or a farm master HUB
+struct HUBDB
+{
+ LIST *UserList; // User List
+ LIST *GroupList; // Group List
+ LIST *RootCertList; // Certificate list to trust
+ LIST *CrlList; // CRL list
+ LIST *AcList; // AC List
+};
+
+// Traffic limiter
+struct TRAFFIC_LIMITER
+{
+ UINT64 LastTime; // Time of last measured
+ UINT64 Value; // The current value
+};
+
+// Record the number of broadcast of each endpoint
+struct STORM
+{
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2]; // Padding
+ IP SrcIp; // Source IP address
+ IP DestIp; // Destination IP address
+ UINT64 CheckStartTick; // Time that checking is started
+ UINT CurrentBroadcastNum; // The current number of broadcasts
+ UINT DiscardValue; // Ratio to discard the broadcast packet
+ bool StrictMode; // Strict mode
+};
+
+// Packet adapter information structure for HUB
+struct HUB_PA
+{
+ CANCEL *Cancel; // Cancel object
+ QUEUE *PacketQueue; // Packet queue
+ bool MonitorPort; // Monitor port
+ UINT64 Now; // Current time
+ TRAFFIC_LIMITER UploadLimiter; // Upload bandwidth limit
+ TRAFFIC_LIMITER DownloadLimiter; // Download bandwidth limitation
+ SESSION *Session; // Session
+ LIST *StormList; // Broadcast storm recording list
+ UINT64 UsernameHash; // User name hash
+ UINT64 UsernameHashSimple; // User name hash (simple)
+ UINT64 GroupnameHash; // Group name hash
+};
+
+// HUB options
+struct HUB_OPTION
+{
+ // Standard options
+ UINT MaxSession; // Maximum number of simultaneous connections
+ bool NoEnum; // Excluded from the enumeration
+ // Advanced options
+ bool NoArpPolling; // No ARP polling
+ bool NoIPv6AddrPolling; // No IPv6 address polling
+ bool NoIpTable; // Do not generate an IP address table
+ bool NoMacAddressLog; // Not to write the registration log of the MAC address
+ bool ManageOnlyPrivateIP; // Manage only private IP
+ bool ManageOnlyLocalUnicastIPv6; // Manage only local unicast IPv6 addresses
+ bool DisableIPParsing; // Disable the IP interpretation
+ bool YieldAfterStorePacket; // Yield after the packet is stored
+ bool NoSpinLockForPacketDelay; // Do not use the spin lock
+ UINT BroadcastStormDetectionThreshold; // Broadcast number limit threshold
+ bool FilterPPPoE; // Filtering the PPPoE (0x8863, 0x8864)
+ bool FilterOSPF; // Filtering the OSPF (ip_proto = 89)
+ bool FilterIPv4; // Filter IPv4 packets
+ bool FilterIPv6; // Filter IPv6 packets
+ bool FilterNonIP; // Filter all non-IP packets
+ bool FilterBPDU; // Filter the BPDU packets
+ UINT ClientMinimumRequiredBuild; // If the build number of the client is lower than a certain value, deny it
+ bool NoIPv6DefaultRouterInRAWhenIPv6; // Delete the default router specification from the IPv6 router advertisement (only in the case of IPv6 physical connection)
+ bool NoIPv4PacketLog; // Do not save the packet log for the IPv4 packet
+ bool NoIPv6PacketLog; // Do not save the packet log of IPv6 packets
+ bool NoLookBPDUBridgeId; // Don't look the BPDU bridge ID for switching
+ bool NoManageVlanId; // Don't manage the VLAN ID
+ UINT VlanTypeId; // Type ID of VLAN packets (usually 0x8100)
+ bool FixForDLinkBPDU; // Apply the fix for the BPDU of the strange behavior of the D-Link
+ UINT RequiredClientId; // Client ID
+ UINT AdjustTcpMssValue; // TCP MSS adjustment value
+ bool DisableAdjustTcpMss; // Completely disable the TCP MSS adjustment function
+ bool NoDhcpPacketLogOutsideHub; // Suppress DHCP unrelated log
+ bool DisableHttpParsing; // Prohibit the HTTP interpretation
+ bool DisableUdpAcceleration; // Prohibit the UDP acceleration function
+ bool DisableUdpFilterForLocalBridgeNic; // Not to perform filtering DHCP packets associated with local bridge NIC
+ bool ApplyIPv4AccessListOnArpPacket; // Apply an IPv4 access list to the ARP packet
+ bool RemoveDefGwOnDhcpForLocalhost; // Remove the designation of the DHCP server from the DHCP response packet addressed to localhost
+ UINT SecureNAT_MaxTcpSessionsPerIp; // Maximum number of TCP sessions per IP address
+ UINT SecureNAT_MaxTcpSynSentPerIp; // Maximum number of TCP sessions of SYN_SENT state per IP address
+ UINT SecureNAT_MaxUdpSessionsPerIp; // Maximum number of UDP sessions per IP address
+ UINT SecureNAT_MaxDnsSessionsPerIp; // Maximum number of DNS sessions per IP address
+ UINT SecureNAT_MaxIcmpSessionsPerIp; // Maximum number of ICMP sessions per IP address
+ UINT AccessListIncludeFileCacheLifetime; // Expiration of the access list external file (in seconds)
+ bool DisableKernelModeSecureNAT; // Disable the kernel mode NAT
+ bool DisableUserModeSecureNAT; // Disable the user mode NAT
+ bool DisableCheckMacOnLocalBridge; // Disable the MAC address verification in local bridge
+ bool DisableCorrectIpOffloadChecksum; // Disable the correction of checksum that is IP-Offloaded
+ bool BroadcastLimiterStrictMode; // Strictly broadcast packets limiting mode
+ UINT MaxLoggedPacketsPerMinute; // Maximum number of logging target packets per minute
+ bool DoNotSaveHeavySecurityLogs; // Do not take heavy security log
+};
+
+// MAC table entry
+struct MAC_TABLE_ENTRY
+{
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2];
+ UINT VlanId; // VLAN ID
+ SESSION *Session; // Session
+ HUB_PA *HubPa; // HUB packet adapter
+ UINT64 CreatedTime; // Creation date and time
+ UINT64 UpdatedTime; // Updating date
+};
+
+// IP table entry
+struct IP_TABLE_ENTRY
+{
+ IP Ip; // IP address
+ SESSION *Session; // Session
+ bool DhcpAllocated; // Assigned by DHCP
+ UINT64 CreatedTime; // Creation date and time
+ UINT64 UpdatedTime; // Updating date
+ UCHAR MacAddress[6]; // MAC address
+};
+
+// Loop List
+struct LOOP_LIST
+{
+ UINT NumSessions;
+ SESSION **Session;
+};
+
+// Access list
+struct ACCESS
+{
+ // IPv4
+ UINT Id; // ID
+ wchar_t Note[MAX_ACCESSLIST_NOTE_LEN + 1]; // Note
+
+ // --- Please add items to the bottom of here for enhancements ---
+ bool Active; // Enable flag
+ UINT Priority; // Priority
+ bool Discard; // Discard flag
+ UINT SrcIpAddress; // Source IP address
+ UINT SrcSubnetMask; // Source subnet mask
+ UINT DestIpAddress; // Destination IP address
+ UINT DestSubnetMask; // Destination subnet mask
+ UINT Protocol; // Protocol
+ UINT SrcPortStart; // Source port number starting point
+ UINT SrcPortEnd; // Source port number end point
+ UINT DestPortStart; // Destination port number starting point
+ UINT DestPortEnd; // Destination port number end point
+ UINT64 SrcUsernameHash; // Source user name hash
+ bool IsSrcUsernameIncludeOrExclude; // The source user name is formed as the "include:" or "exclude:"
+ char SrcUsername[MAX_USERNAME_LEN + 1];
+ bool IsDestUsernameIncludeOrExclude; // The destination user name is formed as "include:" or "exclude:"
+ UINT64 DestUsernameHash; // Destination user name hash
+ char DestUsername[MAX_USERNAME_LEN + 1];
+ bool CheckSrcMac; // Presence of a source MAC address setting
+ UCHAR SrcMacAddress[6]; // Source MAC address
+ UCHAR SrcMacMask[6]; // Source MAC address mask
+ bool CheckDstMac; // Whether the setting of the destination MAC address exists
+ UCHAR DstMacAddress[6]; // Destination MAC address
+ UCHAR DstMacMask[6]; // Destination MAC address mask
+ bool CheckTcpState; // The state of the TCP connection
+ bool Established; // Establieshed(TCP)
+ UINT Delay; // Delay
+ UINT Jitter; // Jitter
+ UINT Loss; // Packet loss
+ char RedirectUrl[MAX_REDIRECT_URL_LEN + 1]; // URL to redirect to
+
+ // IPv6
+ bool IsIPv6; // Whether it's an IPv6
+ IPV6_ADDR SrcIpAddress6; // The source IP address (IPv6)
+ IPV6_ADDR SrcSubnetMask6; // Source subnet mask (IPv6)
+ IPV6_ADDR DestIpAddress6; // Destination IP address (IPv6)
+ IPV6_ADDR DestSubnetMask6; // Destination subnet mask (IPv6)
+
+ // --- Please add items to the above of here for enhancements ---
+
+ // For management
+ UINT UniqueId; // Unique ID
+};
+
+// Ticket
+struct TICKET
+{
+ UINT64 CreatedTick; // Creation date and time
+ UCHAR Ticket[SHA1_SIZE]; // Ticket
+ char Username[MAX_USERNAME_LEN + 1]; // User name
+ char UsernameReal[MAX_USERNAME_LEN + 1]; // Real user name
+ char GroupName[MAX_USERNAME_LEN + 1]; // Group name
+ char SessionName[MAX_SESSION_NAME_LEN + 1]; // Session name
+ POLICY Policy; // Policy
+};
+
+// Traffic difference
+struct TRAFFIC_DIFF
+{
+ UINT Type; // Type
+ TRAFFIC Traffic; // Traffic
+ char *HubName; // HUB name
+ char *Name; // Name
+};
+
+// Administration options
+struct ADMIN_OPTION
+{
+ char Name[MAX_ADMIN_OPTION_NAME_LEN + 1]; // Name
+ UINT Value; // Data
+};
+
+// Certificate Revocation List entry
+struct CRL
+{
+ X_SERIAL *Serial; // Serial number
+ NAME *Name; // Name information
+ UCHAR DigestMD5[MD5_SIZE]; // MD5 hash
+ UCHAR DigestSHA1[SHA1_SIZE]; // SHA-1 hash
+};
+
+// Access control
+struct AC
+{
+ UINT Id; // ID
+ UINT Priority; // Priority
+ bool Deny; // Deny access
+ bool Masked; // Is masked
+ IP IpAddress; // IP address
+ IP SubnetMask; // Subnet mask
+};
+
+// User List
+struct USERLIST
+{
+ char Filename[MAX_PATH]; // File name
+ LIST *UserHashList; // Hash list of user names
+};
+
+// HUB structure
+struct HUB
+{
+ LOCK *lock; // Lock
+ LOCK *lock_online; // Lock for Online
+ REF *ref; // Reference counter
+ CEDAR *Cedar; // Cedar
+ UINT Type; // Type
+ HUBDB *HubDb; // Database
+ char *Name; // The name of the HUB
+ LOCK *RadiusOptionLock; // Lock for Radius option
+ char *RadiusServerName; // Radius server name
+ UINT RadiusServerPort; // Radius server port number
+ UINT RadiusRetryInterval; // Radius retry interval
+ BUF *RadiusSecret; // Radius shared key
+ char RadiusSuffixFilter[MAX_SIZE]; // Radius suffix filter
+ volatile bool Halt; // Halting flag
+ bool Offline; // Offline
+ bool BeingOffline; // Be Doing Offline
+ LIST *SessionList; // Session list
+ COUNTER *SessionCounter; // Session number generation counter
+ TRAFFIC *Traffic; // Traffic information
+ TRAFFIC *OldTraffic; // Old traffic information
+ LOCK *TrafficLock; // Traffic lock
+ COUNTER *NumSessions; // The current number of sessions
+ COUNTER *NumSessionsClient; // The current number of sessions (client)
+ COUNTER *NumSessionsBridge; // The current number of sessions (bridge)
+ HUB_OPTION *Option; // HUB options
+ LIST *MacTable; // MAC address table
+ LIST *IpTable; // IP address table
+ LIST *MonitorList; // Monitor port session list
+ LIST *LinkList; // Linked list
+ UCHAR HubSignature[16]; // HUB signature
+ UCHAR HubMacAddr[6]; // MAC address of the HUB
+ IP HubIp; // IP address of the HUB (IPv4)
+ IPV6_ADDR HubIpV6; // IP address of the HUB (IPv6)
+ UINT HubIP6Id; // IPv6 packet ID of the HUB
+ UCHAR Padding[2]; // Padding
+ LOCK *LoopListLock; // Lock for the loop list
+ UINT NumLoopList; // Number of loop lists
+ LOOP_LIST **LoopLists; // Loop List
+ LIST *AccessList; // Access list
+ HUB_LOG LogSetting; // Log Settings
+ LOG *PacketLogger; // Packet logger
+ LOG *SecurityLogger; // Security logger
+ UCHAR HashedPassword[SHA1_SIZE]; // Password
+ UCHAR SecurePassword[SHA1_SIZE]; // Secure password
+ LIST *TicketList; // Ticket list
+ bool FarmMember; // Farm member
+ UINT64 LastIncrementTraffic; // Traffic reporting time
+ UINT64 LastSendArpTick; // ARP transmission time of the last
+ SNAT *SecureNAT; // SecureNAT
+ bool EnableSecureNAT; // SecureNAT enable / disable flag
+ VH_OPTION *SecureNATOption; // SecureNAT Option
+ THREAD *WatchDogThread; // Watchdog thread
+ EVENT *WatchDogEvent; // Watchdog event
+ bool WatchDogStarted; // Whether the watchdog thread is used
+ volatile bool HaltWatchDog; // Stop the watchdog thread
+ LIST *AdminOptionList; // Administration options list
+ UINT64 CreatedTime; // Creation date and time
+ UINT64 LastCommTime; // Last communication date and time
+ UINT64 LastLoginTime; // Last login date and time
+ UINT NumLogin; // Number of logins
+ bool HubIsOnlineButHalting; // Virtual HUB is really online, but it is in offline state to stop
+ UINT FarmMember_MaxSessionClient; // Maximum client connection sessions for cluster members
+ UINT FarmMember_MaxSessionBridge; // Maximum bridge connection sessions for cluster members
+ bool FarmMember_MaxSessionClientBridgeApply; // Apply the FarmMember_MaxSession*
+ UINT CurrentVersion; // The current version
+ UINT LastVersion; // Version of when the update notification is issued at the last
+ wchar_t *Msg; // Message to be displayed when the client is connected
+ LIST *UserList; // Cache of the user list file
+ bool IsVgsHub; // Whether it's a VGS Virtual HUB
+};
+
+
+// Global variable
+extern ADMIN_OPTION admin_options[];
+extern UINT num_admin_options;
+
+
+// Function prototype
+HUBDB *NewHubDb();
+void DeleteHubDb(HUBDB *d);
+HUB *NewHub(CEDAR *cedar, char *HubName, HUB_OPTION *option);
+void SetHubMsg(HUB *h, wchar_t *msg);
+wchar_t *GetHubMsg(HUB *h);
+void GenHubMacAddress(UCHAR *mac, char *name);
+void GenHubIpAddress(IP *ip, char *name);
+bool IsHubIpAddress(IP *ip);
+bool IsHubIpAddress32(UINT ip32);
+bool IsHubIpAddress64(IPV6_ADDR *addr);
+bool IsHubMacAddress(UCHAR *mac);
+void ReleaseHub(HUB *h);
+void CleanupHub(HUB *h);
+int CompareHub(void *p1, void *p2);
+void LockHubList(CEDAR *cedar);
+void UnlockHubList(CEDAR *cedar);
+HUB *GetHub(CEDAR *cedar, char *name);
+bool IsHub(CEDAR *cedar, char *name);
+void StopHub(HUB *h);
+void AddSession(HUB *h, SESSION *s);
+void DelSession(HUB *h, SESSION *s);
+SESSION *SearchSessionByUniqueId(HUB *h, UINT id);
+UINT GetNewUniqueId(HUB *h);
+void StopAllSession(HUB *h);
+bool HubPaInit(SESSION *s);
+void HubPaFree(SESSION *s);
+CANCEL *HubPaGetCancel(SESSION *s);
+UINT HubPaGetNextPacket(SESSION *s, void **data);
+bool HubPaPutPacket(SESSION *s, void *data, UINT size);
+PACKET_ADAPTER *GetHubPacketAdapter();
+int CompareMacTable(void *p1, void *p2);
+void StorePacket(HUB *hub, SESSION *s, PKT *packet);
+bool StorePacketFilter(SESSION *s, PKT *packet);
+void StorePacketToHubPa(HUB_PA *dest, SESSION *src, void *data, UINT size, PKT *packet);
+void SetHubOnline(HUB *h);
+void SetHubOffline(HUB *h);
+SESSION *GetSessionByPtr(HUB *hub, void *ptr);
+SESSION *GetSessionByName(HUB *hub, char *name);
+int CompareIpTable(void *p1, void *p2);
+bool StorePacketFilterByPolicy(SESSION *s, PKT *p);
+bool DeleteIPv6DefaultRouterInRA(PKT *p);
+bool StorePacketFilterByTrafficLimiter(SESSION *s, PKT *p);
+void IntoTrafficLimiter(TRAFFIC_LIMITER *tr, PKT *p);
+bool IsMostHighestPriorityPacket(SESSION *s, PKT *p);
+bool IsPriorityPacketForQoS(PKT *p);
+int CompareStormList(void *p1, void *p2);
+STORM *SearchStormList(HUB_PA *pa, UCHAR *mac_address, IP *src_ip, IP *dest_ip, bool strict);
+STORM *AddStormList(HUB_PA *pa, UCHAR *mac_address, IP *src_ip, IP *dest_ip, bool strict);
+bool CheckBroadcastStorm(HUB *hub, SESSION *s, PKT *p);
+void AddRootCert(HUB *hub, X *x);
+int CmpAccessList(void *p1, void *p2);
+void InitAccessList(HUB *hub);
+void FreeAccessList(HUB *hub);
+void AddAccessList(HUB *hub, ACCESS *a);
+void AddAccessListEx(HUB *hub, ACCESS *a, bool no_sort, bool no_reassign_id);
+bool SetSessionFirstRedirectHttpUrl(SESSION *s, char *url);
+bool IsTcpPacketNcsiHttpAccess(PKT *p);
+UINT64 UsernameToInt64(char *name);
+void MakeSimpleUsernameRemoveNtDomain(char *dst, UINT dst_size, char *src);
+bool ApplyAccessListToStoredPacket(HUB *hub, SESSION *s, PKT *p);
+void ForceRedirectToUrl(HUB *hub, SESSION *src_session, PKT *p, char *redirect_url);
+BUF *BuildRedirectToUrlPayload(HUB *hub, SESSION *s, char *redirect_url);
+bool ApplyAccessListToForwardPacket(HUB *hub, SESSION *src_session, SESSION *dest_session, PKT *p);
+bool IsPacketMaskedByAccessList(SESSION *s, PKT *p, ACCESS *a, UINT64 dest_username, UINT64 dest_groupname, SESSION *dest_session);
+void GetAccessListStr(char *str, UINT size, ACCESS *a);
+void DeleteOldIpTableEntry(LIST *o);
+void SetRadiusServer(HUB *hub, char *name, UINT port, char *secret);
+void SetRadiusServerEx(HUB *hub, char *name, UINT port, char *secret, UINT interval);
+bool GetRadiusServer(HUB *hub, char *name, UINT size, UINT *port, char *secret, UINT secret_size);
+bool GetRadiusServerEx(HUB *hub, char *name, UINT size, UINT *port, char *secret, UINT secret_size, UINT *interval);
+bool GetRadiusServerEx2(HUB *hub, char *name, UINT size, UINT *port, char *secret, UINT secret_size, UINT *interval, char *suffix_filter, UINT suffix_filter_size);
+int CompareCert(void *p1, void *p2);
+void GetHubLogSetting(HUB *h, HUB_LOG *setting);
+void SetHubLogSetting(HUB *h, HUB_LOG *setting);
+void SetHubLogSettingEx(HUB *h, HUB_LOG *setting, bool no_change_switch_type);
+void DeleteExpiredIpTableEntry(LIST *o);
+void DeleteExpiredMacTableEntry(LIST *o);
+void AddTrafficDiff(HUB *h, char *name, UINT type, TRAFFIC *traffic);
+void IncrementHubTraffic(HUB *h);
+void EnableSecureNAT(HUB *h, bool enable);
+void EnableSecureNATEx(HUB *h, bool enable, bool no_change);
+void StartHubWatchDog(HUB *h);
+void StopHubWatchDog(HUB *h);
+void HubWatchDogThread(THREAD *t, void *param);
+int CompareAdminOption(void *p1, void *p2);
+UINT GetHubAdminOptionEx(HUB *h, char *name, UINT default_value);
+UINT GetHubAdminOption(HUB *h, char *name);
+void DeleteAllHubAdminOption(HUB *h, bool lock);
+void AddHubAdminOptionsDefaults(HUB *h, bool lock);
+bool IsCertMatchCrl(X *x, CRL *crl);
+bool IsCertMatchCrlList(X *x, LIST *o);
+wchar_t *GenerateCrlStr(CRL *crl);
+bool IsValidCertInHub(HUB *h, X *x);
+void FreeCrl(CRL *crl);
+CRL *CopyCrl(CRL *crl);
+int CmpAc(void *p1, void *p2);
+LIST *NewAcList();
+void AddAc(LIST *o, AC *ac);
+bool DelAc(LIST *o, UINT id);
+AC *GetAc(LIST *o, UINT id);
+void SetAc(LIST *o, UINT id, AC *ac);
+void DelAllAc(LIST *o);
+void SetAcList(LIST *o, LIST *src);
+void NormalizeAcList(LIST *o);
+bool IsIpMaskedByAc(IP *ip, AC *ac);
+bool IsIpDeniedByAcList(IP *ip, LIST *o);
+char *GenerateAcStr(AC *ac);
+void FreeAcList(LIST *o);
+LIST *CloneAcList(LIST *o);
+bool IsIPManagementTargetForHUB(IP *ip, HUB *hub);
+wchar_t *GetHubAdminOptionHelpString(char *name);
+void HubOptionStructToData(RPC_ADMIN_OPTION *ao, HUB_OPTION *o, char *hub_name);
+ADMIN_OPTION *NewAdminOption(char *name, UINT value);
+void DataToHubOptionStruct(HUB_OPTION *o, RPC_ADMIN_OPTION *ao);
+UINT GetHubAdminOptionData(RPC_ADMIN_OPTION *ao, char *name);
+void GetHubAdminOptionDataAndSet(RPC_ADMIN_OPTION *ao, char *name, UINT *dest);
+bool IsURLMsg(wchar_t *str, char *url, UINT url_size);
+LIST *NewUserList();
+void DeleteAllUserListCache(LIST *o);
+void FreeUserList(LIST *o);
+void FreeUserListEntry(USERLIST *u);
+int CompareUserList(void *p1, void *p2);
+USERLIST *LoadUserList(LIST *o, char *filename);
+USERLIST *FindUserList(LIST *o, char *filename);
+bool IsUserMatchInUserList(LIST *o, char *filename, UINT64 user_hash);
+bool IsUserMatchInUserListWithCacheExpires(LIST *o, char *filename, UINT64 user_hash, UINT64 lifetime);
+bool IsUserMatchInUserListWithCacheExpiresAcl(LIST *o, char *name_in_acl, UINT64 user_hash, UINT64 lifetime);
+void CalcTrafficEntryDiff(TRAFFIC_ENTRY *diff, TRAFFIC_ENTRY *old, TRAFFIC_ENTRY *current);
+void CalcTrafficDiff(TRAFFIC *diff, TRAFFIC *old, TRAFFIC *current);
+bool CheckMaxLoggedPacketsPerMinute(SESSION *s, UINT max_packets, UINT64 now);
+void VgsSetUserAgentValue(char *str);
+void VgsSetEmbTag(bool b);
+
+#endif // HUB_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec.c b/src/Cedar/IPsec.c
new file mode 100644
index 00000000..7288e0b5
--- /dev/null
+++ b/src/Cedar/IPsec.c
@@ -0,0 +1,767 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec.c
+// IPsec module
+
+#include "CedarPch.h"
+
+
+static bool ipsec_disable = false;
+
+// Disabling whole IPsec
+void IPSecSetDisable(bool b)
+{
+ ipsec_disable = b;
+}
+
+
+// Monitor the IPsec service of the OS, and stop it if it will conflict
+void IPsecOsServiceCheckThread(THREAD *t, void *p)
+{
+ UINT interval = IPSEC_CHECK_OS_SERVICE_INTERVAL_INITIAL;
+ IPSEC_SERVER *s = (IPSEC_SERVER *)p;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ s->HostIPAddressListChanged = true;
+ s->OsServiceStoped = false;
+
+ while (s->Halt == false)
+ {
+ if (IPsecCheckOsService(s))
+ {
+ interval = IPSEC_CHECK_OS_SERVICE_INTERVAL_INITIAL;
+ }
+
+ if (Wait(s->OsServiceCheckThreadEvent, interval) == false)
+ {
+ interval = MIN(interval * 2, IPSEC_CHECK_OS_SERVICE_INTERVAL_MAX);
+ }
+ else
+ {
+ interval = IPSEC_CHECK_OS_SERVICE_INTERVAL_INITIAL;
+ }
+ }
+
+ IPsecCheckOsService(s);
+}
+
+// Monitoring process main
+bool IPsecCheckOsService(IPSEC_SERVER *s)
+{
+ bool b_ipsec;
+ IPSEC_SERVICES sl;
+ bool ret = false;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ IPsecServerGetServices(s, &sl);
+
+ b_ipsec = (sl.EtherIP_IPsec || sl.L2TP_IPsec);
+
+ if (b_ipsec != s->Check_LastEnabledStatus)
+ {
+ s->Check_LastEnabledStatus = b_ipsec;
+
+ if (b_ipsec)
+ {
+ // Use of IPsec has been started
+#ifdef OS_WIN32
+ if (s->Win7 == NULL)
+ {
+ s->Win7 = IPsecWin7Init();
+ s->HostIPAddressListChanged = true;
+ }
+
+ s->OsServiceStoped = false;
+#else // OS_WIN32
+#endif // OS_WIN32
+ }
+ else
+ {
+ // Use of IPsec is stopped
+#ifdef OS_WIN32
+ if (s->Win7 != NULL)
+ {
+ IPsecWin7Free(s->Win7);
+ s->Win7 = NULL;
+ }
+
+ if (s->OsServiceStoped)
+ {
+ MsStartIPsecService();
+ s->OsServiceStoped = false;
+ }
+#else // OS_WIN32
+ UnixSetEnableKernelEspProcessing(true);
+#endif // OS_WIN32
+ }
+ }
+
+ if (b_ipsec)
+ {
+#ifdef OS_WIN32
+ if (MsStopIPsecService())
+ {
+ s->OsServiceStoped = true;
+ ret = true;
+ }
+#else // OS_WIN32
+ UnixSetEnableKernelEspProcessing(false);
+#endif // OS_WIN32
+ }
+
+#ifdef OS_WIN32
+ if (s->Win7 != NULL)
+ {
+ IPsecWin7UpdateHostIPAddressList(s->Win7);
+ s->HostIPAddressListChanged = false;
+ }
+#endif // OS_WIN32
+
+ return ret;
+}
+
+// Processing of UDP packets (one by one)
+void IPsecProcPacket(IPSEC_SERVER *s, UDPPACKET *p)
+{
+ L2TP_SERVER *l2tp;
+ IKE_SERVER *ike;
+ void *old_data_ptr;
+ UINT old_data_size;
+ bool proc_this_packet = true;
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ old_data_ptr = p->Data;
+ old_data_size = p->Size;
+
+ l2tp = s->L2TP;
+ ike = s->Ike;
+
+ // UDP decapsulation process
+ if (p->DestPort == IPSEC_PORT_IPSEC_ESP_UDP)
+ {
+#ifdef OS_WIN32
+ if (p->Size >= 12 && IsZero(p->Data, 4))
+ {
+ if (((*((UINT *)(((UCHAR *)p->Data) + sizeof(UINT) * 1))) == WFP_ESP_PACKET_TAG_1) &&
+ ((*((UINT *)(((UCHAR *)p->Data) + sizeof(UINT) * 2))) == WFP_ESP_PACKET_TAG_2))
+ {
+ // Truncate the head because the packet was modified by WFP
+ p->Data = ((UCHAR *)p->Data) + 12;
+ p->Size -= 12;
+ }
+ }
+#endif // OS_WIN32
+
+ if (p->Size >= 4 && IsZero(p->Data, 4))
+ {
+ // Truncate the Non-ESP Marker
+ p->Data = ((UCHAR *)p->Data) + 4;
+ p->Size -= 4;
+
+ p->Type = IKE_UDP_TYPE_ISAKMP;
+ }
+ else
+ {
+ p->Type = IKE_UDP_TYPE_ESP;
+ }
+ }
+ else if (p->DestPort == IPSEC_PORT_IPSEC_ISAKMP)
+ {
+ if (p->Size >= 8 && IsZero(p->Data, 8))
+ {
+ // Truncate the Non-IKE Maker
+ p->Data = ((UCHAR *)p->Data) + 8;
+ p->Size -= 8;
+
+ p->Type = IKE_UDP_TYPE_ESP;
+ }
+ else
+ {
+ p->Type = IKE_UDP_TYPE_ISAKMP;
+ }
+ }
+ else if (p->DestPort == IPSEC_PORT_IPSEC_ESP_RAW)
+ {
+ // Raw ESP
+ p->Type = IKE_UDP_TYPE_ESP;
+ }
+
+
+ if (proc_this_packet)
+ {
+ switch (p->DestPort)
+ {
+ case IPSEC_PORT_L2TP:
+ // L2TP
+ ProcL2TPPacketRecv(l2tp, p);
+ break;
+
+ case IPSEC_PORT_IPSEC_ISAKMP:
+ case IPSEC_PORT_IPSEC_ESP_UDP:
+ case IPSEC_PORT_IPSEC_ESP_RAW:
+ // IPsec
+ ProcIKEPacketRecv(ike, p);
+ break;
+ }
+ }
+
+ p->Data = old_data_ptr;
+ p->Size = old_data_size;
+}
+
+// Packet reception procedure of UDP listener
+void IPsecServerUdpPacketRecvProc(UDPLISTENER *u, LIST *packet_list)
+{
+ UINT i;
+ IPSEC_SERVER *s;
+ L2TP_SERVER *l2tp;
+ IKE_SERVER *ike;
+ UINT64 now;
+ static UCHAR zero8[8] = {0, 0, 0, 0, 0, 0, 0, 0, };
+ // Validate arguments
+ if (u == NULL || packet_list == NULL)
+ {
+ return;
+ }
+ s = (IPSEC_SERVER *)u->Param;
+ if (s == NULL)
+ {
+ return;
+ }
+
+ if (u->HostIPAddressListChanged)
+ {
+ u->HostIPAddressListChanged = false;
+
+ s->HostIPAddressListChanged = true;
+
+ Set(s->OsServiceCheckThreadEvent);
+ }
+
+ now = Tick64();
+
+ // Adjustment about L2TP server timing
+ l2tp = s->L2TP;
+
+ if (l2tp->Interrupts == NULL)
+ {
+ l2tp->Interrupts = u->Interrupts;
+ }
+
+ if (l2tp->SockEvent == NULL)
+ {
+ SetL2TPServerSockEvent(l2tp, u->Event);
+ }
+
+ l2tp->Now = now;
+
+ // Adjustment about IKE server timing
+ ike = s->Ike;
+
+ if (ike->Interrupts == NULL)
+ {
+ ike->Interrupts = u->Interrupts;
+ }
+
+ if (ike->SockEvent == NULL)
+ {
+ SetIKEServerSockEvent(ike, u->Event);
+ }
+
+ ike->Now = now;
+
+ if (ipsec_disable == false)
+ {
+ // Process the received packet
+ for (i = 0;i < LIST_NUM(packet_list);i++)
+ {
+ UDPPACKET *p = LIST_DATA(packet_list, i);
+
+ IPsecProcPacket(s, p);
+ }
+ }
+
+ // Interrupt processing of L2TP server
+ L2TPProcessInterrupts(l2tp);
+
+ // L2TP packet transmission processing
+ UdpListenerSendPackets(u, l2tp->SendPacketList);
+ DeleteAll(l2tp->SendPacketList);
+
+ // Interrupt processing of IKE server
+ ProcessIKEInterrupts(ike);
+
+ // UDP encapsulation process of IKE server packet scheduled for transmission
+ for (i = 0;i < LIST_NUM(ike->SendPacketList);i++)
+ {
+ UDPPACKET *p = LIST_DATA(ike->SendPacketList, i);
+
+ if (p->Type == IKE_UDP_TYPE_ISAKMP && p->SrcPort == IPSEC_PORT_IPSEC_ESP_UDP)
+ {
+ // Add the Non-ESP Marker
+ void *old_data = p->Data;
+
+ p->Data = AddHead(p->Data, p->Size, zero8, 4);
+ p->Size += 4;
+
+ Free(old_data);
+ }
+ else if (p->Type == IKE_UDP_TYPE_ESP && p->SrcPort == IPSEC_PORT_IPSEC_ISAKMP)
+ {
+ // Add the Non-IKE Marker
+ void *old_data = p->Data;
+
+ p->Data = AddHead(p->Data, p->Size, zero8, 8);
+ p->Size += 8;
+
+ Free(old_data);
+ }
+ }
+
+ // IKE server packet transmission processing
+ UdpListenerSendPackets(u, ike->SendPacketList);
+ DeleteAll(ike->SendPacketList);
+}
+
+// Get the service list
+void IPsecServerGetServices(IPSEC_SERVER *s, IPSEC_SERVICES *sl)
+{
+ // Validate arguments
+ if (s == NULL || sl == NULL)
+ {
+ return;
+ }
+
+ Lock(s->LockSettings);
+ {
+ IPsecNormalizeServiceSetting(s);
+
+ Copy(sl, &s->Services, sizeof(IPSEC_SERVICES));
+ }
+ Unlock(s->LockSettings);
+}
+
+// Normalize the IPsec service setttings
+void IPsecNormalizeServiceSetting(IPSEC_SERVER *s)
+{
+ CEDAR *c;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ c = s->Cedar;
+
+ Lock(s->LockSettings);
+ {
+ bool reset_hub_setting = false;
+
+ if (IsEmptyStr(s->Services.IPsec_Secret))
+ {
+ // If the secret is not set, set the default one
+ StrCpy(s->Services.IPsec_Secret, sizeof(s->Services.IPsec_Secret), IPSEC_DEFAULT_SECRET);
+ }
+
+ LockList(c->HubList);
+ {
+ if (IsEmptyStr(s->Services.L2TP_DefaultHub))
+ {
+ reset_hub_setting = true;
+ }
+ else
+ {
+ if (IsHub(c, s->Services.L2TP_DefaultHub) == false)
+ {
+ reset_hub_setting = true;
+ }
+ }
+
+ if (reset_hub_setting)
+ {
+ // Select the first Virtual HUB if there is no HUB
+ HUB *h = NULL;
+
+ if (LIST_NUM(c->HubList) >= 1)
+ {
+ h = LIST_DATA(c->HubList, 0);
+ }
+
+ if (h != NULL)
+ {
+ StrCpy(s->Services.L2TP_DefaultHub, sizeof(s->Services.L2TP_DefaultHub), h->Name);
+ }
+ else
+ {
+ StrCpy(s->Services.L2TP_DefaultHub, sizeof(s->Services.L2TP_DefaultHub), "");
+ }
+ }
+ }
+ UnlockList(c->HubList);
+ }
+ Unlock(s->LockSettings);
+}
+
+// Set the service list
+void IPsecServerSetServices(IPSEC_SERVER *s, IPSEC_SERVICES *sl)
+{
+ // Validate arguments
+ if (s == NULL || sl == NULL)
+ {
+ return;
+ }
+
+ if (IsZero(sl, sizeof(IPSEC_SERVICES)) == false)
+ {
+ if (s->NoMoreChangeSettings)
+ {
+ return;
+ }
+ }
+
+ Lock(s->LockSettings);
+ {
+ Copy(&s->Services, sl, sizeof(IPSEC_SERVICES));
+
+ if (sl->L2TP_Raw)
+ {
+ AddPortToUdpListener(s->UdpListener, IPSEC_PORT_L2TP);
+ }
+ else
+ {
+ DeletePortFromUdpListener(s->UdpListener, IPSEC_PORT_L2TP);
+ }
+
+ if (sl->L2TP_IPsec || sl->EtherIP_IPsec)
+ {
+ AddPortToUdpListener(s->UdpListener, IPSEC_PORT_IPSEC_ISAKMP);
+ AddPortToUdpListener(s->UdpListener, IPSEC_PORT_IPSEC_ESP_UDP);
+ AddPortToUdpListener(s->UdpListener, IPSEC_PORT_IPSEC_ESP_RAW);
+ AddPortToUdpListener(s->UdpListener, IPSEC_PORT_IPSEC_ESP_RAW_WPF);
+ }
+ else
+ {
+ DeletePortFromUdpListener(s->UdpListener, IPSEC_PORT_IPSEC_ISAKMP);
+ DeletePortFromUdpListener(s->UdpListener, IPSEC_PORT_IPSEC_ESP_UDP);
+ DeletePortFromUdpListener(s->UdpListener, IPSEC_PORT_IPSEC_ESP_RAW);
+ DeletePortFromUdpListener(s->UdpListener, IPSEC_PORT_IPSEC_ESP_RAW_WPF);
+ }
+
+ if (IsEmptyStr(sl->IPsec_Secret) == false)
+ {
+ StrCpy(s->Ike->Secret, sizeof(s->Ike->Secret), sl->IPsec_Secret);
+ }
+
+ IPsecNormalizeServiceSetting(s);
+ }
+ Unlock(s->LockSettings);
+
+ Set(s->OsServiceCheckThreadEvent);
+}
+
+// Add the EtherIP key
+void AddEtherIPId(IPSEC_SERVER *s, ETHERIP_ID *id)
+{
+ // Validate arguments
+ if (s == NULL || id == NULL)
+ {
+ return;
+ }
+
+ Lock(s->LockSettings);
+ {
+ // If there is the same key, remove them
+ ETHERIP_ID t, *k;
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Id, sizeof(t.Id), id->Id);
+
+ k = Search(s->EtherIPIdList, &t);
+
+ if (k != NULL)
+ {
+ Delete(s->EtherIPIdList, k);
+
+ Free(k);
+ }
+
+ // Add
+ k = Clone(id, sizeof(ETHERIP_ID));
+
+ Insert(s->EtherIPIdList, k);
+
+ s->EtherIPIdListSettingVerNo++;
+ }
+ Unlock(s->LockSettings);
+}
+
+// Delete the EtherIP key
+bool DeleteEtherIPId(IPSEC_SERVER *s, char *id_str)
+{
+ bool ret = false;
+ // Validate arguments
+ if (s == NULL || id_str == NULL)
+ {
+ return false;
+ }
+
+ Lock(s->LockSettings);
+ {
+ // If there is the same key, remove them
+ ETHERIP_ID t, *k;
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Id, sizeof(t.Id), id_str);
+
+ k = Search(s->EtherIPIdList, &t);
+
+ if (k != NULL)
+ {
+ Delete(s->EtherIPIdList, k);
+
+ Free(k);
+
+ ret = true;
+
+ s->EtherIPIdListSettingVerNo++;
+ }
+ }
+ Unlock(s->LockSettings);
+
+ return ret;
+}
+
+// Search the EtherIP key
+bool SearchEtherIPId(IPSEC_SERVER *s, ETHERIP_ID *id, char *id_str)
+{
+ bool ret = false;
+ // Validate arguments
+ if (s == NULL || id == NULL || id_str == NULL)
+ {
+ return false;
+ }
+
+ Lock(s->LockSettings);
+ {
+ ETHERIP_ID t, *k;
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Id, sizeof(t.Id), id_str);
+
+ k = Search(s->EtherIPIdList, &t);
+
+ if (k != NULL)
+ {
+ Copy(id, k, sizeof(ETHERIP_ID));
+
+ ret = true;
+ }
+ }
+ Unlock(s->LockSettings);
+
+ return ret;
+}
+
+// Comparison of key EtherIP list entries
+int CmpEtherIPId(void *p1, void *p2)
+{
+ ETHERIP_ID *k1, *k2;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ k1 = *(ETHERIP_ID **)p1;
+ k2 = *(ETHERIP_ID **)p2;
+ if (k1 == NULL || k2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(k1->Id, k2->Id);
+}
+
+// Release and stop the IPsec server
+void FreeIPsecServer(IPSEC_SERVER *s)
+{
+ UINT i;
+ IPSEC_SERVICES sl;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ s->NoMoreChangeSettings = true;
+
+ // Stopp the L2TP server
+ StopL2TPServer(s->L2TP, false);
+
+ // Stop the IKE server
+ StopIKEServer(s->Ike);
+
+ // Stop all the services explicitly
+ Zero(&sl, sizeof(sl));
+ IPsecServerSetServices(s, &sl);
+
+ // Releasing process
+ FreeUdpListener(s->UdpListener);
+
+ ReleaseCedar(s->Cedar);
+
+ FreeL2TPServer(s->L2TP);
+
+ FreeIKEServer(s->Ike);
+
+ for (i = 0;i < LIST_NUM(s->EtherIPIdList);i++)
+ {
+ ETHERIP_ID *k = LIST_DATA(s->EtherIPIdList, i);
+
+ Free(k);
+ }
+
+ ReleaseList(s->EtherIPIdList);
+
+ // Stop the OS monitoring thread
+ s->Halt = true;
+ Set(s->OsServiceCheckThreadEvent);
+ WaitThread(s->OsServiceCheckThread, INFINITE);
+ ReleaseThread(s->OsServiceCheckThread);
+ ReleaseEvent(s->OsServiceCheckThreadEvent);
+
+ DeleteLock(s->LockSettings);
+
+ Free(s);
+}
+
+// Initialize the IPsec server
+IPSEC_SERVER *NewIPsecServer(CEDAR *cedar)
+{
+ IPSEC_SERVER *s;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ s = ZeroMalloc(sizeof(IPSEC_SERVER));
+
+ s->LockSettings = NewLock();
+
+ s->Cedar = cedar;
+
+ AddRef(s->Cedar->ref);
+
+ s->L2TP = NewL2TPServer(cedar);
+
+ s->Ike = NewIKEServer(cedar, s);
+ StrCpy(s->Ike->Secret, sizeof(s->Ike->Secret), IPSEC_DEFAULT_SECRET);
+
+ s->UdpListener = NewUdpListener(IPsecServerUdpPacketRecvProc, s);
+
+ s->EtherIPIdList = NewList(CmpEtherIPId);
+
+ // Start an OS service monitoring thread
+ s->OsServiceCheckThreadEvent = NewEvent();
+ s->OsServiceCheckThread = NewThread(IPsecOsServiceCheckThread, s);
+
+ return s;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec.h b/src/Cedar/IPsec.h
new file mode 100644
index 00000000..48b297c8
--- /dev/null
+++ b/src/Cedar/IPsec.h
@@ -0,0 +1,179 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec.h
+// Header of IPsec.c
+
+#ifndef IPSEC_H
+#define IPSEC_H
+
+//// Constants
+
+// UDP port number
+#define IPSEC_PORT_L2TP 1701 // L2TP
+#define IPSEC_PORT_IPSEC_ISAKMP 500 // ISAKMP
+#define IPSEC_PORT_IPSEC_ESP_UDP 4500 // IPsec ESP over UDP
+#define IPSEC_PORT_IPSEC_ESP_RAW MAKE_SPECIAL_PORT(50) // Raw mode ESP Protocol No: 50
+#define IPSEC_PORT_IPSEC_ESP_RAW_WPF MAKE_SPECIAL_PORT(52) // Raw mode ESP Protocol No: 52 (WPF)
+#define IPSEC_PORT_L2TPV3_VIRTUAL 1000001 // L2TPv3 virtual port
+
+// IP protocol number
+#define IPSEC_IP_PROTO_ETHERIP IP_PROTO_ETHERIP // EtherIP
+#define IPSEC_IP_PROTO_L2TPV3 IP_PROTO_L2TPV3 // L2TPv3
+
+// WFP tag
+#define WFP_ESP_PACKET_TAG_1 0x19841117
+#define WFP_ESP_PACKET_TAG_2 0x1accafe1
+
+// Monitoring interval of OS service
+#define IPSEC_CHECK_OS_SERVICE_INTERVAL_INITIAL 1024
+#define IPSEC_CHECK_OS_SERVICE_INTERVAL_MAX (5 * 60 * 1000)
+
+// Default IPsec pre-shared key
+#define IPSEC_DEFAULT_SECRET "vpn"
+
+
+//// Type
+
+// List of services provided by IPsec server
+struct IPSEC_SERVICES
+{
+ bool L2TP_Raw; // Raw L2TP
+ bool L2TP_IPsec; // L2TP over IPsec
+ bool EtherIP_IPsec; // EtherIP over IPsec
+
+ char IPsec_Secret[MAX_SIZE]; // IPsec pre-shared key
+ char L2TP_DefaultHub[MAX_SIZE]; // Default Virtual HUB name for L2TP connection
+};
+
+// EtherIP key list entry
+struct ETHERIP_ID
+{
+ char Id[MAX_SIZE]; // ID
+ char HubName[MAX_HUBNAME_LEN + 1]; // Virtual HUB name
+ char UserName[MAX_USERNAME_LEN + 1]; // User name
+ char Password[MAX_USERNAME_LEN + 1]; // Password
+};
+
+// IPsec server
+struct IPSEC_SERVER
+{
+ CEDAR *Cedar;
+ UDPLISTENER *UdpListener;
+ bool Halt;
+ bool NoMoreChangeSettings;
+ LOCK *LockSettings;
+ IPSEC_SERVICES Services;
+ L2TP_SERVER *L2TP; // L2TP server
+ IKE_SERVER *Ike; // IKE server
+ LIST *EtherIPIdList; // EtherIP setting list
+ UINT EtherIPIdListSettingVerNo; // EtherIP setting list version number
+ THREAD *OsServiceCheckThread; // OS Service monitoring thread
+ EVENT *OsServiceCheckThreadEvent; // Event for OS Service monitoring thread
+ IPSEC_WIN7 *Win7; // Helper module for Windows Vista / 7
+ bool Check_LastEnabledStatus;
+ bool HostIPAddressListChanged;
+ bool OsServiceStoped;
+};
+
+
+//// Function prototype
+IPSEC_SERVER *NewIPsecServer(CEDAR *cedar);
+void FreeIPsecServer(IPSEC_SERVER *s);
+void IPsecServerUdpPacketRecvProc(UDPLISTENER *u, LIST *packet_list);
+void IPsecServerSetServices(IPSEC_SERVER *s, IPSEC_SERVICES *sl);
+void IPsecNormalizeServiceSetting(IPSEC_SERVER *s);
+void IPsecServerGetServices(IPSEC_SERVER *s, IPSEC_SERVICES *sl);
+void IPsecProcPacket(IPSEC_SERVER *s, UDPPACKET *p);
+int CmpEtherIPId(void *p1, void *p2);
+bool SearchEtherIPId(IPSEC_SERVER *s, ETHERIP_ID *id, char *id_str);
+void AddEtherIPId(IPSEC_SERVER *s, ETHERIP_ID *id);
+bool DeleteEtherIPId(IPSEC_SERVER *s, char *id_str);
+void IPsecOsServiceCheckThread(THREAD *t, void *p);
+bool IPsecCheckOsService(IPSEC_SERVER *s);
+void IPSecSetDisable(bool b);
+
+
+#endif // IPSEC_H
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_EtherIP.c b/src/Cedar/IPsec_EtherIP.c
new file mode 100644
index 00000000..632df40b
--- /dev/null
+++ b/src/Cedar/IPsec_EtherIP.c
@@ -0,0 +1,539 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_EtherIP.c
+// EtherIP protocol stack
+
+#include "CedarPch.h"
+
+// IPC connection processing thread
+void EtherIPIpcConnectThread(THREAD *t, void *p)
+{
+ ETHERIP_SERVER *s;
+ IPC *ipc = NULL;
+ UINT error_code = 0;
+ char tmp[MAX_SIZE];
+ ETHERIP_ID id;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ s = (ETHERIP_SERVER *)p;
+
+ GetHostName(tmp, sizeof(tmp), &s->ClientIP);
+
+ // Get the setting of the virtual HUB to be connected based on the client ID presented
+ if (SearchEtherIPId(s->Ike->IPsec, &id, s->ClientId) == false &&
+ SearchEtherIPId(s->Ike->IPsec, &id, "*") == false)
+ {
+ // Failed to get the settings for the virtual HUB
+ Debug("Not Found: EtherIP Settings for Client ID \"%s\".\n", s->ClientId);
+
+ EtherIPLog(s, "LE_NO_SETTING", s->ClientId);
+ }
+ else
+ {
+ UINT mss = CalcEtherIPTcpMss(s);
+ char client_name[MAX_SIZE];
+
+ if (s->L2TPv3 == false)
+ {
+ StrCpy(client_name, sizeof(client_name), ETHERIP_CLIENT_NAME);
+ }
+ else
+ {
+ if (IsEmptyStr(s->VendorName))
+ {
+ StrCpy(client_name, sizeof(client_name), ETHERIP_L2TPV3_CLIENT_NAME);
+ }
+ else
+ {
+ Format(client_name, sizeof(client_name), ETHERIP_L2TPV3_CLIENT_NAME_EX, s->VendorName);
+ }
+ }
+
+ // Execution of IPC connection process
+ EtherIPLog(s, "LE_START_IPC", id.HubName, id.UserName, mss);
+ ipc = NewIPC(s->Cedar, client_name,
+ (s->L2TPv3 ? ETHERIP_L2TPV3_POSTFIX : ETHERIP_POSTFIX),
+ id.HubName, id.UserName, id.Password,
+ &error_code,
+ &s->ClientIP, s->ClientPort,
+ &s->ServerIP, s->ServerPort,
+ tmp,
+ s->CryptName, true, mss);
+
+ if (ipc != NULL)
+ {
+ Copy(&s->CurrentEtherIPIdSetting, &id, sizeof(ETHERIP_ID));
+ EtherIPLog(s, "LE_IPC_CONNECT_OK", id.HubName);
+ }
+ else
+ {
+ EtherIPLog(s, "LE_IPC_CONNECT_ERROR", id.HubName, error_code, _E(error_code));
+ }
+ }
+
+ Lock(s->Lock);
+ {
+ // Set the results
+ ReleaseThread(s->IpcConnectThread);
+ s->IpcConnectThread = NULL;
+
+ s->Ipc = ipc;
+
+ s->LastConnectFailedTick = Tick64();
+ }
+ Unlock(s->Lock);
+
+ // Hit the event to cause interrupt
+ SetSockEvent(s->SockEvent);
+
+ // Release the EtherIP object that is hold by this thread
+ ReleaseEtherIPServer(s);
+}
+
+// Processing of the interrupt
+void EtherIPProcInterrupts(ETHERIP_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ // If EtherIP settings have been changed, and the change may effect to this connection, disconnect
+ if (s->Ipc != NULL)
+ {
+ if (s->Ike->IPsec->EtherIPIdListSettingVerNo != s->LastEtherIPSettingVerNo)
+ {
+ ETHERIP_ID id;
+ bool ok = true;
+
+ s->LastEtherIPSettingVerNo = s->Ike->IPsec->EtherIPIdListSettingVerNo;
+
+ if (SearchEtherIPId(s->IPsec, &id, s->ClientId) == false &&
+ SearchEtherIPId(s->IPsec, &id, "*") == false)
+ {
+ ok = false;
+ }
+ else
+ {
+ if (StrCmpi(s->CurrentEtherIPIdSetting.HubName, id.HubName) != 0 ||
+ StrCmpi(s->CurrentEtherIPIdSetting.UserName, id.UserName) != 0 ||
+ StrCmp(s->CurrentEtherIPIdSetting.Password, id.Password) != 0)
+ {
+ ok = false;
+ }
+ }
+
+ if (ok == false)
+ {
+ // Disconnect immediately since setting of EtherIP seems to have been changed
+ FreeIPC(s->Ipc);
+ s->Ipc = NULL;
+
+ EtherIPLog(s, "LE_RECONNECT");
+ }
+ }
+ }
+
+ // Connect if IPC connection is not completed
+ Lock(s->Lock);
+ {
+ if (s->Ipc == NULL)
+ {
+ if (s->IpcConnectThread == NULL)
+ {
+ if ((s->LastConnectFailedTick == 0) || ((s->LastConnectFailedTick + (UINT64)ETHERIP_VPN_CONNECT_RETRY_INTERVAL) <= s->Now))
+ {
+ Lock(s->IPsec->LockSettings);
+ {
+ Copy(&s->CurrentIPSecServiceSetting, &s->IPsec->Services, sizeof(IPSEC_SERVICES));
+ }
+ Unlock(s->IPsec->LockSettings);
+
+ s->IpcConnectThread = NewThread(EtherIPIpcConnectThread, s);
+ AddThreadToThreadList(s->Ike->ThreadList, s->IpcConnectThread);
+ AddRef(s->Ref);
+ }
+ }
+ }
+ }
+ Unlock(s->Lock);
+
+ if (s->Ipc != NULL)
+ {
+ // Set to get hit the SockEvent when a packet arrives via the IPC
+ IPCSetSockEventWhenRecvL2Packet(s->Ipc, s->SockEvent);
+
+ // IPC interrupt processing
+ IPCProcessInterrupts(s->Ipc);
+
+ // Receive the MAC frame which arrived via the IPC
+ while (true)
+ {
+ BLOCK *b = IPCRecvL2(s->Ipc);
+ UCHAR *dst;
+ UINT dst_size;
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ if (b->Size >= 14)
+ {
+ BLOCK *block;
+
+ // Store the arrived MAC frame by adding an EtherIP header to the reception packet queue
+
+ if (s->L2TPv3 == false)
+ {
+ dst_size = b->Size + 2;
+ dst = Malloc(dst_size);
+
+ dst[0] = 0x30;
+ dst[1] = 0x00;
+
+ Copy(dst + 2, b->Buf, b->Size);
+ }
+ else
+ {
+ dst = Clone(b->Buf, b->Size);
+ dst_size = b->Size;
+ }
+
+ block = NewBlock(dst, dst_size, 0);
+
+ Add(s->SendPacketList, block);
+ }
+
+ FreeBlock(b);
+ }
+
+ if (IsIPCConnected(s->Ipc) == false)
+ {
+ // IPC connection is disconnected
+ FreeIPC(s->Ipc);
+ s->Ipc = NULL;
+ }
+ }
+}
+
+// Process the received packet
+void EtherIPProcRecvPackets(ETHERIP_SERVER *s, BLOCK *b)
+{
+ UCHAR *src;
+ UINT src_size;
+ // Validate arguments
+ if (s == NULL || b == NULL)
+ {
+ return;
+ }
+
+ if (s->Ipc == NULL)
+ {
+ // Not connected to the Virtual HUB
+ return;
+ }
+
+ src = b->Buf;
+ src_size = b->Size;
+
+ if (s->L2TPv3 == false)
+ {
+ // EtherIP header confirmation
+ if (src_size < 2)
+ {
+ return;
+ }
+
+ if ((src[0] & 0xf0) != 0x30)
+ {
+ return;
+ }
+
+ src += 2;
+ src_size -= 2;
+ }
+
+ if (src_size < 14)
+ {
+ // The size of the MAC frame is less than 14 bytes
+ return;
+ }
+
+ // Send by IPC since a MAC frame has been received
+ IPCSendL2(s->Ipc, src, src_size);
+}
+
+// Create a new EtherIP server
+ETHERIP_SERVER *NewEtherIPServer(CEDAR *cedar, IPSEC_SERVER *ipsec, IKE_SERVER *ike,
+ IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, char *crypt_name,
+ bool is_tunnel_mode, UINT crypt_block_size,
+ char *client_id, UINT id)
+{
+ ETHERIP_SERVER *s;
+ // Validate arguments
+ if (cedar == NULL || ipsec == NULL || ike == NULL || client_ip == NULL || server_ip == NULL || client_id == NULL)
+ {
+ return NULL;
+ }
+
+ s = ZeroMalloc(sizeof(ETHERIP_SERVER));
+
+ s->Ref = NewRef();
+
+ s->Id = id;
+
+ s->Cedar = cedar;
+ AddRef(s->Cedar->ref);
+ s->IPsec = ipsec;
+ s->Ike = ike;
+ s->IsTunnelMode = is_tunnel_mode;
+
+ StrCpy(s->ClientId, sizeof(s->ClientId), client_id);
+
+ s->SendPacketList = NewList(NULL);
+
+ s->Now = Tick64();
+
+ s->Lock = NewLock();
+
+ Copy(&s->ClientIP, client_ip, sizeof(IP));
+ s->ClientPort = client_port;
+
+ Copy(&s->ServerIP, server_ip, sizeof(IP));
+ s->ServerPort = server_port;
+
+ StrCpy(s->CryptName, sizeof(s->CryptName), crypt_name);
+ s->CryptBlockSize = crypt_block_size;
+
+ EtherIPLog(s, "LE_START_MODULE");
+
+ return s;
+}
+
+// Release the EtherIP server
+void ReleaseEtherIPServer(ETHERIP_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ if (Release(s->Ref) == 0)
+ {
+ CleanupEtherIPServer(s);
+ }
+}
+void CleanupEtherIPServer(ETHERIP_SERVER *s)
+{
+ UINT i;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ EtherIPLog(s, "LE_STOP");
+
+ if (s->IpcConnectThread != NULL)
+ {
+ ReleaseThread(s->IpcConnectThread);
+ }
+
+ if (s->Ipc != NULL)
+ {
+ FreeIPC(s->Ipc);
+ }
+
+ for (i = 0;i < LIST_NUM(s->SendPacketList);i++)
+ {
+ BLOCK *b = LIST_DATA(s->SendPacketList, i);
+
+ FreeBlock(b);
+ }
+
+ ReleaseList(s->SendPacketList);
+
+ ReleaseSockEvent(s->SockEvent);
+
+ ReleaseCedar(s->Cedar);
+
+ DeleteLock(s->Lock);
+
+ Free(s);
+}
+
+
+// Set SockEvent to EtherIP server
+void SetEtherIPServerSockEvent(ETHERIP_SERVER *s, SOCK_EVENT *e)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ if (e != NULL)
+ {
+ AddRef(e->ref);
+ }
+
+ if (s->SockEvent != NULL)
+ {
+ ReleaseSockEvent(s->SockEvent);
+ s->SockEvent = NULL;
+ }
+
+ s->SockEvent = e;
+}
+
+// Calculate the proper TCP MSS in EtherIP communication
+UINT CalcEtherIPTcpMss(ETHERIP_SERVER *s)
+{
+ UINT ret = MTU_FOR_PPPOE;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return 0;
+ }
+
+ // IPv4 / IPv6
+ if (IsIP4(&s->ClientIP))
+ {
+ ret -= 20;
+ }
+ else
+ {
+ ret -= 40;
+ }
+
+ // IPsec UDP
+ ret -= 8;
+
+ // IPsec ESP
+ ret -= 20;
+ ret -= s->CryptBlockSize * 2;
+
+ // IPsec Tunnel Mode IPv4 / IPv6 Header
+ if (s->IsTunnelMode)
+ {
+ if (IsIP4(&s->ClientIP))
+ {
+ ret -= 20;
+ }
+ else
+ {
+ ret -= 40;
+ }
+ }
+
+ if (s->L2TPv3 == false)
+ {
+ // EtherIP
+ ret -= 2;
+ }
+ else
+ {
+ // L2TPv3
+ ret -= 2;
+ }
+
+ // Ethernet
+ ret -= 14;
+
+ // IPv4
+ ret -= 20;
+
+ // TCP
+ ret -= 20;
+
+ return ret;
+}
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_EtherIP.h b/src/Cedar/IPsec_EtherIP.h
new file mode 100644
index 00000000..a0be2bf5
--- /dev/null
+++ b/src/Cedar/IPsec_EtherIP.h
@@ -0,0 +1,150 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_EtherIP.h
+// Header of IPsec_EtherIP.c
+
+#ifndef IPSEC_ETHERIP_H
+#define IPSEC_ETHERIP_H
+
+//// Macro
+
+
+//// Constants
+#define ETHERIP_VPN_CONNECT_RETRY_INTERVAL (15 * 1000) // VPN connection retry interval
+#define ETHERIP_CLIENT_NAME "EtherIP Client"
+#define ETHERIP_POSTFIX "ETHERIP"
+#define ETHERIP_L2TPV3_CLIENT_NAME "L2TPv3 Client"
+#define ETHERIP_L2TPV3_CLIENT_NAME_EX "L2TPv3 Client - %s"
+#define ETHERIP_L2TPV3_POSTFIX "L2TPV3"
+
+//// Type
+
+// EtherIP server
+struct ETHERIP_SERVER
+{
+ REF *Ref;
+ CEDAR *Cedar;
+ IPSEC_SERVER *IPsec;
+ LOCK *Lock;
+ UINT Id;
+ IKE_SERVER *Ike;
+ UINT64 Now; // Current time
+ INTERRUPT_MANAGER *Interrupts; // Interrupt manager
+ SOCK_EVENT *SockEvent; // SockEvent
+ char CryptName[MAX_SIZE]; // Cipher algorithm name
+ LIST *SendPacketList; // Transmission packet list
+ UINT64 LastConnectFailedTick; // Time that it fails to connect at the last
+ IPC *Ipc; // IPC
+ THREAD *IpcConnectThread; // IPC connection thread
+ IPSEC_SERVICES CurrentIPSecServiceSetting; // Copy of the current IPsec service settings
+ IP ClientIP, ServerIP;
+ UINT ClientPort, ServerPort;
+ bool IsTunnelMode; // Whether the IPsec is in the tunnel mode
+ UINT CryptBlockSize; // Encryption block size of IPsec
+ char ClientId[MAX_SIZE]; // Client ID has been presented by the IPsec connection
+ UINT LastEtherIPSettingVerNo; // Version number of EtherIP settings last checked
+ ETHERIP_ID CurrentEtherIPIdSetting; // Current EtherIP ID settings
+ bool L2TPv3; // L2TPv3 mode
+ char VendorName[MAX_SIZE]; // Vendor name
+};
+
+
+//// Function prototype
+ETHERIP_SERVER *NewEtherIPServer(CEDAR *cedar, IPSEC_SERVER *ipsec, IKE_SERVER *ike,
+ IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, char *crypt_name,
+ bool is_tunnel_mode, UINT crypt_block_size,
+ char *client_id, UINT id);
+void ReleaseEtherIPServer(ETHERIP_SERVER *s);
+void CleanupEtherIPServer(ETHERIP_SERVER *s);
+void SetEtherIPServerSockEvent(ETHERIP_SERVER *s, SOCK_EVENT *e);
+void EtherIPProcInterrupts(ETHERIP_SERVER *s);
+void EtherIPProcRecvPackets(ETHERIP_SERVER *s, BLOCK *b);
+void EtherIPIpcConnectThread(THREAD *t, void *p);
+UINT CalcEtherIPTcpMss(ETHERIP_SERVER *s);
+
+
+#endif // IPSEC_ETHERIP_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_IKE.c b/src/Cedar/IPsec_IKE.c
new file mode 100644
index 00000000..7156b735
--- /dev/null
+++ b/src/Cedar/IPsec_IKE.c
@@ -0,0 +1,5947 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_IKE.c
+// IKE (ISAKMP) and ESP protocol stack
+
+#include "CedarPch.h"
+
+
+// Processing of IKE received packet
+void ProcIKEPacketRecv(IKE_SERVER *ike, UDPPACKET *p)
+{
+ // Validate arguments
+ if (ike == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (p->Type == IKE_UDP_TYPE_ISAKMP)
+ {
+ // ISAKMP (IKE) packet
+ IKE_PACKET *header;
+
+ header = ParseIKEPacketHeader(p);
+ if (header == NULL)
+ {
+ return;
+ }
+
+ //Debug("InitiatorCookie: %I64u, ResponderCookie: %I64u\n", header->InitiatorCookie, header->ResponderCookie);
+
+ switch (header->ExchangeType)
+ {
+ case IKE_EXCHANGE_TYPE_MAIN: // Main mode
+ ProcIkeMainModePacketRecv(ike, p, header);
+ break;
+
+ case IKE_EXCHANGE_TYPE_AGGRESSIVE: // Aggressive mode
+ ProcIkeAggressiveModePacketRecv(ike, p, header);
+ break;
+
+ case IKE_EXCHANGE_TYPE_QUICK: // Quick mode
+ ProcIkeQuickModePacketRecv(ike, p, header);
+ break;
+
+ case IKE_EXCHANGE_TYPE_INFORMATION: // Information exchange
+ ProcIkeInformationalExchangePacketRecv(ike, p, header);
+ break;
+ }
+
+ IkeFree(header);
+ }
+ else if (p->Type == IKE_UDP_TYPE_ESP)
+ {
+ // ESP packet
+ ProcIPsecEspPacketRecv(ike, p);
+ }
+}
+
+// Send a packet via IPsec
+void IPsecSendPacketByIPsecSa(IKE_SERVER *ike, IPSECSA *sa, UCHAR *data, UINT data_size, UCHAR protocol_id)
+{
+ bool is_tunnel_mode;
+ IKE_CLIENT *c;
+ // Validate arguments
+ if (ike == NULL || sa == NULL || data == NULL || data_size == 0)
+ {
+ return;
+ }
+
+ is_tunnel_mode = IsIPsecSaTunnelMode(sa);
+
+ c = sa->IkeClient;
+
+ if (c == NULL)
+ {
+ return;
+ }
+
+ if (is_tunnel_mode)
+ {
+ // Add an IPv4 / IPv6 header in the case of tunnel mode
+ if (IsZeroIP(&c->TunnelModeClientIP) == false || IsZeroIP(&c->TunnelModeServerIP) == false)
+ {
+ BUF *b;
+ UCHAR esp_proto_id;
+
+ b = NewBuf();
+
+ if (IsIP4(&c->TunnelModeClientIP))
+ {
+ // IPv4 header
+ IPV4_HEADER h;
+
+ h.VersionAndHeaderLength = 0;
+ h.TypeOfService = 0;
+ IPV4_SET_VERSION(&h, 4);
+ IPV4_SET_HEADER_LEN(&h, sizeof(IPV4_HEADER) / 4);
+ h.TotalLength = Endian16((USHORT)(data_size + sizeof(IPV4_HEADER)));
+ h.Identification = Endian16(c->TunnelSendIpId++);
+ h.FlagsAndFlagmentOffset[0] = h.FlagsAndFlagmentOffset[1] = 0;
+ h.TimeToLive = DEFAULT_IP_TTL;
+ h.Protocol = protocol_id;
+ h.SrcIP = IPToUINT(&c->TunnelModeServerIP);
+ h.DstIP = IPToUINT(&c->TunnelModeClientIP);
+ h.Checksum = 0;
+ h.Checksum = IpChecksum(&h, sizeof(IPV4_HEADER));
+
+ WriteBuf(b, &h, sizeof(IPV4_HEADER));
+
+ esp_proto_id = IKE_PROTOCOL_ID_IPV4;
+ }
+ else
+ {
+ // IPv6 header
+ IPV6_HEADER h;
+
+ Zero(&h, sizeof(h));
+ h.VersionAndTrafficClass1 = 0;
+ IPV6_SET_VERSION(&h, 6);
+ h.TrafficClass2AndFlowLabel1 = 0;
+ h.FlowLabel2 = h.FlowLabel3 = 0;
+ h.PayloadLength = Endian16(data_size);
+ h.NextHeader = protocol_id;
+ h.HopLimit = 64;
+ Copy(h.SrcAddress.Value, c->TunnelModeServerIP.ipv6_addr, 16);
+ Copy(h.DestAddress.Value, c->TunnelModeClientIP.ipv6_addr, 16);
+
+ WriteBuf(b, &h, sizeof(IPV6_HEADER));
+
+ esp_proto_id = IKE_PROTOCOL_ID_IPV6;
+ }
+
+ WriteBuf(b, data, data_size);
+
+ IPsecSendPacketByIPsecSaInner(ike, sa, b->Buf, b->Size, esp_proto_id);
+
+ FreeBuf(b);
+ }
+ }
+ else
+ {
+ // Send as it is in the case of transport mode
+ IPsecSendPacketByIPsecSaInner(ike, sa, data, data_size, protocol_id);
+ }
+}
+void IPsecSendPacketByIPsecSaInner(IKE_SERVER *ike, IPSECSA *sa, UCHAR *data, UINT data_size, UCHAR protocol_id)
+{
+ UINT esp_size;
+ UINT encrypted_payload_size;
+ UCHAR *esp;
+ UINT i;
+ UINT size_of_padding;
+ IKE_CRYPTO_PARAM cp;
+ BUF *enc;
+ IKE_CLIENT *c;
+ // Validate arguments
+ if (ike == NULL || sa == NULL || data == NULL || data_size == 0)
+ {
+ return;
+ }
+
+ c = sa->IkeClient;
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Calculate the payload size after encryption
+ encrypted_payload_size = data_size + 2;
+ if ((encrypted_payload_size % sa->TransformSetting.Crypto->BlockSize) != 0)
+ {
+ encrypted_payload_size = ((encrypted_payload_size / sa->TransformSetting.Crypto->BlockSize) + 1) * sa->TransformSetting.Crypto->BlockSize;
+ }
+ size_of_padding = encrypted_payload_size - data_size - 2;
+
+ // Calculate the size of the ESP packet
+ esp_size = sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize + encrypted_payload_size + IKE_ESP_HASH_SIZE;
+
+ // Build the ESP packet
+ esp = Malloc(esp_size + IKE_MAX_HASH_SIZE);
+
+ // SPI
+ WRITE_UINT(esp, sa->Spi);
+
+ // Sequence number
+ sa->CurrentSeqNo++;
+ WRITE_UINT(esp + sizeof(UINT), sa->CurrentSeqNo);
+
+ // IV
+ Copy(esp + sizeof(UINT) * 2, sa->EspIv, sa->TransformSetting.Crypto->BlockSize);
+
+ // Payload data
+ Copy(esp + sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize, data, data_size);
+
+ // Padding
+ for (i = 0;i < size_of_padding;i++)
+ {
+ esp[sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize + data_size + i] = (UCHAR)(i + 1);
+ }
+
+ // Padding length
+ esp[sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize + data_size + size_of_padding] = (UCHAR)size_of_padding;
+
+ // Next header number
+ esp[sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize + data_size + size_of_padding + 1] = protocol_id;
+
+ // Encryption
+ Copy(cp.Iv, sa->EspIv, sa->TransformSetting.Crypto->BlockSize);
+ cp.Key = sa->CryptoKey;
+
+ enc = IkeEncrypt(esp + sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize, encrypted_payload_size, &cp);
+ if (enc != NULL)
+ {
+ bool start_qm = false;
+ UINT server_port = c->ServerPort;
+ UINT client_port = c->ClientPort;
+
+ // Overwrite the encrypted result
+ Copy(esp + sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize, enc->Buf, encrypted_payload_size);
+
+ FreeBuf(enc);
+
+ // Calculate the HMAC
+ IkeHMac(sa->TransformSetting.Hash,
+ esp + sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize + encrypted_payload_size,
+ sa->HashKey,
+ sa->TransformSetting.Hash->HashSize,
+ esp,
+ sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize + encrypted_payload_size);
+
+ //*(UCHAR *)(esp + sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize + encrypted_payload_size) = 0xff;
+
+ if (sa->TransformSetting.CapsuleMode == IKE_P2_CAPSULE_TRANSPORT ||
+ sa->TransformSetting.CapsuleMode == IKE_P2_CAPSULE_TUNNEL)
+ {
+ server_port = client_port = IPSEC_PORT_IPSEC_ESP_RAW;
+ }
+
+ // Add the completed packet to the transmission list
+ IkeSendUdpPacket(ike, IKE_UDP_TYPE_ESP, &c->ServerIP, server_port, &c->ClientIP, client_port,
+ esp, esp_size);
+
+ // Feedback the IV
+ Copy(sa->EspIv, cp.NextIv, sa->TransformSetting.Crypto->BlockSize);
+
+ sa->TotalSize += esp_size;
+
+ if (sa->CurrentSeqNo >= 0xf0000000)
+ {
+ start_qm = true;
+ }
+
+ if (sa->TransformSetting.LifeKilobytes != 0)
+ {
+ UINT64 hard_size = (UINT64)sa->TransformSetting.LifeKilobytes * (UINT64)1000;
+ UINT64 soft_size = hard_size * (UINT64)2 / (UINT64)3;
+
+ if (sa->TotalSize >= soft_size)
+ {
+ start_qm = true;
+ }
+ }
+
+ if (start_qm)
+ {
+ if (sa->StartQM_FlagSet == false)
+ {
+ sa->StartQM_FlagSet = true;
+ c->StartQuickModeAsSoon = true;
+ }
+ }
+ }
+ else
+ {
+ // Encryption failure
+ Free(esp);
+ }
+}
+void IPsecSendPacketByIkeClient(IKE_SERVER *ike, IKE_CLIENT *c, UCHAR *data, UINT data_size, UCHAR protocol_id)
+{
+ // Validate arguments
+ if (ike == NULL || c == NULL || data == NULL || data_size == 0)
+ {
+ return;
+ }
+
+ if (c->CurrentIpSecSaSend == NULL)
+ {
+ return;
+ }
+
+ IPsecSendPacketByIPsecSa(ike, c->CurrentIpSecSaSend, data, data_size, protocol_id);
+}
+
+// Send an UDP packet via IPsec
+void IPsecSendUdpPacket(IKE_SERVER *ike, IKE_CLIENT *c, UINT src_port, UINT dst_port, UCHAR *data, UINT data_size)
+{
+ UCHAR *udp;
+ UINT udp_size;
+ UDP_HEADER *u;
+ UCHAR tmp1600[1600];
+ bool no_free = false;
+ // Validate arguments
+ if (ike == NULL || c == NULL || data == NULL || data_size == 0)
+ {
+ return;
+ }
+
+ // Build an UDP packet
+ udp_size = sizeof(UDP_HEADER) + data_size;
+
+ if (udp_size > sizeof(tmp1600))
+ {
+ udp = Malloc(udp_size);
+ }
+ else
+ {
+ udp = tmp1600;
+ no_free = true;
+ }
+
+ // UDP header
+ u = (UDP_HEADER *)udp;
+ u->SrcPort = Endian16(src_port);
+ u->DstPort = Endian16(dst_port);
+ u->PacketLength = Endian16(udp_size);
+ u->Checksum = 0;
+
+ //Debug("IPsec UDP Send: %u -> %u %u\n", src_port, dst_port, data_size);
+#ifdef RAW_DEBUG
+ IPsecIkeSendUdpForDebug(IPSEC_PORT_L2TP, 1, data, data_size);
+#endif // RAW_DEBUG
+
+ // Payload
+ Copy(udp + sizeof(UDP_HEADER), data, data_size);
+
+ if (IsIP6(&c->ClientIP))
+ {
+ if (IsIPsecSaTunnelMode(c->CurrentIpSecSaSend) == false)
+ {
+ u->Checksum = CalcChecksumForIPv6((IPV6_ADDR *)c->TransportModeServerIP.ipv6_addr,
+ (IPV6_ADDR *)c->TransportModeClientIP.ipv6_addr,
+ IP_PROTO_UDP,
+ u,
+ udp_size, 0);
+ }
+ else
+ {
+ u->Checksum = CalcChecksumForIPv6((IPV6_ADDR *)c->TunnelModeServerIP.ipv6_addr,
+ (IPV6_ADDR *)c->TunnelModeClientIP.ipv6_addr,
+ IP_PROTO_UDP,
+ u,
+ udp_size, 0);
+ }
+ }
+
+ IPsecSendPacketByIkeClient(ike, c, udp, udp_size, IP_PROTO_UDP);
+
+ if (no_free == false)
+ {
+ Free(udp);
+ }
+}
+
+// Get whether the specified IPsec SA is in tunnel mode
+bool IsIPsecSaTunnelMode(IPSECSA *sa)
+{
+ // Validate arguments
+ if (sa == NULL)
+ {
+ return false;
+ }
+
+ if (sa->TransformSetting.CapsuleMode == IKE_P2_CAPSULE_TUNNEL ||
+ sa->TransformSetting.CapsuleMode == IKE_P2_CAPSULE_NAT_TUNNEL_1 ||
+ sa->TransformSetting.CapsuleMode == IKE_P2_CAPSULE_NAT_TUNNEL_2)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Reception process of ESP packet
+void ProcIPsecEspPacketRecv(IKE_SERVER *ike, UDPPACKET *p)
+{
+ UCHAR *src;
+ UINT src_size;
+ UINT spi;
+ UINT seq;
+ IPSECSA *ipsec_sa;
+ IKE_CLIENT *c;
+ UINT block_size;
+ UINT hash_size;
+ bool update_status = false;
+ UCHAR *iv;
+ UCHAR *hash;
+ UCHAR *encrypted_payload_data;
+ UINT size_of_payload_data;
+ IKE_CRYPTO_PARAM cp;
+ BUF *dec;
+ UCHAR calced_hash[IKE_MAX_HASH_SIZE];
+ bool is_tunnel_mode = false;
+ // Validate arguments
+ if (ike == NULL || p == NULL)
+ {
+ return;
+ }
+
+ src = (UCHAR *)p->Data;
+ src_size = p->Size;
+
+ if (p->DestPort == IPSEC_PORT_IPSEC_ESP_RAW)
+ {
+ if (IsIP4(&p->DstIP))
+ {
+ // Skip the IP header when received in Raw mode (only in the case of IPv4)
+ UINT ip_header_size = GetIpHeaderSize(src, src_size);
+
+ src += ip_header_size;
+ src_size -= ip_header_size;
+ }
+ }
+
+ // Get the SPI
+ if (src_size < sizeof(UINT))
+ {
+ return;
+ }
+
+ spi = READ_UINT(src + 0);
+ if (spi == 0)
+ {
+ return;
+ }
+
+ // Get the sequence number
+ if (src_size < (sizeof(UINT) * 2))
+ {
+ return;
+ }
+ seq = READ_UINT(src + sizeof(UINT));
+
+ // Search and retrieve the IPsec SA from SPI
+ ipsec_sa = SearchClientToServerIPsecSaBySpi(ike, spi);
+ if (ipsec_sa == NULL)
+ {
+ // Invalid SPI
+ UINT64 init_cookie = Rand64();
+ UINT64 resp_cookie = 0;
+ IKE_CLIENT *c = NULL;
+ IKE_CLIENT t;
+
+
+ Copy(&t.ClientIP, &p->SrcIP, sizeof(IP));
+ t.ClientPort = p->SrcPort;
+ Copy(&t.ServerIP, &p->DstIP, sizeof(IP));
+ t.ServerPort = p->DestPort;
+ t.CurrentIkeSa = NULL;
+
+ if (p->DestPort == IPSEC_PORT_IPSEC_ESP_RAW)
+ {
+ t.ClientPort = t.ServerPort = IPSEC_PORT_IPSEC_ISAKMP;
+ }
+
+ c = Search(ike->ClientList, &t);
+
+ if (c != NULL && c->CurrentIkeSa != NULL)
+ {
+ init_cookie = c->CurrentIkeSa->InitiatorCookie;
+ resp_cookie = c->CurrentIkeSa->ResponderCookie;
+ }
+
+ SendInformationalExchangePacketEx(ike, (c == NULL ? &t : c), IkeNewNoticeErrorInvalidSpiPayload(spi), false,
+ init_cookie, resp_cookie);
+
+ SendDeleteIPsecSaPacket(ike, (c == NULL ? &t : c), spi);
+ return;
+ }
+
+ is_tunnel_mode = IsIPsecSaTunnelMode(ipsec_sa);
+
+ c = ipsec_sa->IkeClient;
+ if (c == NULL)
+ {
+ return;
+ }
+
+ block_size = ipsec_sa->TransformSetting.Crypto->BlockSize;
+ hash_size = IKE_ESP_HASH_SIZE;
+
+ // Get the IV
+ if (src_size < (sizeof(UINT) * 2 + block_size + hash_size + block_size))
+ {
+ return;
+ }
+ iv = src + sizeof(UINT) * 2;
+
+ // Get the hash
+ hash = src + src_size - hash_size;
+
+ // Inspect the HMAC
+ IkeHMac(ipsec_sa->TransformSetting.Hash, calced_hash, ipsec_sa->HashKey,
+ ipsec_sa->TransformSetting.Hash->HashSize, src, src_size - hash_size);
+
+ if (Cmp(calced_hash, hash, hash_size) != 0)
+ {
+ //Debug("IPsec SA 0x%X: Invalid HMAC Value.\n", ipsec_sa->Spi);
+ return;
+ }
+
+ // Get the payload data
+ encrypted_payload_data = src + sizeof(UINT) * 2 + block_size;
+ size_of_payload_data = src_size - hash_size - block_size - sizeof(UINT) * 2;
+ if (size_of_payload_data == 0 || (size_of_payload_data % block_size) != 0)
+ {
+ // Payload data don't exist or is not a multiple of block size
+ return;
+ }
+
+ // Decrypt the payload data
+ cp.Key = ipsec_sa->CryptoKey;
+ Copy(&cp.Iv, iv, block_size);
+
+ dec = IkeDecrypt(encrypted_payload_data, size_of_payload_data, &cp);
+ if (dec != NULL)
+ {
+ UCHAR *dec_data = dec->Buf;
+ UINT dec_size = dec->Size;
+ UCHAR size_of_padding = dec_data[dec_size - 2];
+ UCHAR next_header = dec_data[dec_size - 1];
+ if ((dec_size - 2) >= size_of_padding)
+ {
+ UINT orig_size = dec_size - 2 - size_of_padding;
+
+ ipsec_sa->TotalSize += dec_size;
+
+ if (is_tunnel_mode)
+ {
+ // Tunnel Mode
+ if (next_header == IKE_PROTOCOL_ID_IPV4 || next_header == IKE_PROTOCOL_ID_IPV6)
+ {
+ // Check the contents by parsing the IPv4 / IPv6 header in the case of tunnel mode
+ BUF *b = NewBuf();
+ static UCHAR src_mac_dummy[6] = {0, 0, 0, 0, 0, 0, };
+ static UCHAR dst_mac_dummy[6] = {0, 0, 0, 0, 0, 0, };
+ USHORT tpid = Endian16(next_header == IKE_PROTOCOL_ID_IPV4 ? MAC_PROTO_IPV4 : MAC_PROTO_IPV6);
+ PKT *pkt;
+
+ WriteBuf(b, src_mac_dummy, sizeof(src_mac_dummy));
+ WriteBuf(b, dst_mac_dummy, sizeof(dst_mac_dummy));
+ WriteBuf(b, &tpid, sizeof(tpid));
+
+ WriteBuf(b, dec_data, dec_size);
+
+ // Parse
+ pkt = ParsePacket(b->Buf, b->Size);
+
+#ifdef RAW_DEBUG
+ IPsecIkeSendUdpForDebug(IPSEC_PORT_L2TP, 1, b->Buf, b->Size);
+#endif // RAW_DEBUG
+
+ if (pkt == NULL)
+ {
+ // Parsing failure
+ dec_data = NULL;
+ dec_size = 0;
+ }
+ else
+ {
+ // Parsing success
+ switch (pkt->TypeL3)
+ {
+ case L3_IPV4:
+ // Save the internal IP address information
+ UINTToIP(&c->TunnelModeServerIP, pkt->L3.IPv4Header->DstIP);
+ UINTToIP(&c->TunnelModeClientIP, pkt->L3.IPv4Header->SrcIP);
+
+ if (IPV4_GET_OFFSET(pkt->L3.IPv4Header) == 0)
+ {
+ if ((IPV4_GET_FLAGS(pkt->L3.IPv4Header) & 0x01) == 0)
+ {
+ if (pkt->L3.IPv4Header->Protocol == IPSEC_IP_PROTO_ETHERIP)
+ {
+ // EtherIP
+ if (ike->IPsec->Services.EtherIP_IPsec)
+ {
+ // An EtherIP packet has been received
+ ProcIPsecEtherIPPacketRecv(ike, c, pkt->IPv4PayloadData, pkt->IPv4PayloadSize, true);
+ }
+ }
+ else if (pkt->L3.IPv4Header->Protocol == IPSEC_IP_PROTO_L2TPV3)
+ {
+ // L2TPv3
+ if (ike->IPsec->Services.EtherIP_IPsec)
+ {
+ // A L2TPv3 packet has been received
+ ProcL2TPv3PacketRecv(ike, c, pkt->IPv4PayloadData, pkt->IPv4PayloadSize, true);
+ }
+ }
+ }
+ }
+ break;
+
+ case L3_IPV6:
+ // Save the internal IP address information
+ SetIP6(&c->TunnelModeServerIP, pkt->IPv6HeaderPacketInfo.IPv6Header->DestAddress.Value);
+ SetIP6(&c->TunnelModeClientIP, pkt->IPv6HeaderPacketInfo.IPv6Header->SrcAddress.Value);
+
+ if (pkt->IPv6HeaderPacketInfo.IsFragment == false)
+ {
+ if (pkt->IPv6HeaderPacketInfo.FragmentHeader == NULL || (IPV6_GET_FLAGS(pkt->IPv6HeaderPacketInfo.FragmentHeader) & IPV6_FRAGMENT_HEADER_FLAG_MORE_FRAGMENTS) == 0)
+ {
+ if (pkt->IPv6HeaderPacketInfo.Protocol == IPSEC_IP_PROTO_ETHERIP)
+ {
+ // EtherIP
+ if (ike->IPsec->Services.EtherIP_IPsec)
+ {
+ // An EtherIP packet has been received
+ ProcIPsecEtherIPPacketRecv(ike, c, pkt->IPv6HeaderPacketInfo.Payload, pkt->IPv6HeaderPacketInfo.PayloadSize, true);
+ }
+ }
+ else if (pkt->IPv6HeaderPacketInfo.Protocol == IPSEC_IP_PROTO_L2TPV3)
+ {
+ // L2TPv3
+ if (ike->IPsec->Services.EtherIP_IPsec)
+ {
+ // A L2TPv3 packet has been received
+ ProcL2TPv3PacketRecv(ike, c, pkt->IPv6HeaderPacketInfo.Payload, pkt->IPv6HeaderPacketInfo.PayloadSize, true);
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ FreePacket(pkt);
+ }
+
+ FreeBuf(b);
+ }
+ }
+ else
+ {
+ // Transport mode
+ if (next_header == IP_PROTO_UDP)
+ {
+ if (ike->IPsec->Services.L2TP_IPsec)
+ {
+ // An UDP packet has been received
+ ProcIPsecUdpPacketRecv(ike, c, dec_data, dec_size);
+ }
+ }
+ else if (next_header == IPSEC_IP_PROTO_ETHERIP)
+ {
+ if (ike->IPsec->Services.EtherIP_IPsec)
+ {
+ // An EtherIP packet has been received
+ ProcIPsecEtherIPPacketRecv(ike, c, dec_data, dec_size, false);
+ }
+ }
+ else if (next_header == IPSEC_IP_PROTO_L2TPV3)
+ {
+ if (ike->IPsec->Services.EtherIP_IPsec)
+ {
+ // A L2TPv3 packet has been received
+ ProcL2TPv3PacketRecv(ike, c, dec_data, dec_size, false);
+ }
+ }
+ }
+
+ update_status = true;
+ }
+
+ FreeBuf(dec);
+ }
+
+ if (update_status)
+ {
+ bool start_qm = false;
+ // Update the status of the client
+ c->CurrentIpSecSaRecv = ipsec_sa;
+ if (ipsec_sa->PairIPsecSa != NULL)
+ {
+ c->CurrentIpSecSaSend = ipsec_sa->PairIPsecSa;
+ }
+ c->LastCommTick = ike->Now;
+ ipsec_sa->LastCommTick = ike->Now;
+ if (ipsec_sa->PairIPsecSa != NULL)
+ {
+ ipsec_sa->PairIPsecSa->LastCommTick = ike->Now;
+ }
+
+ SetIkeClientEndpoint(ike, c, &p->SrcIP, p->SrcPort, &p->DstIP, p->DestPort);
+
+ if (seq >= 0xf0000000)
+ {
+ // Execute a QuickMode forcibly since sequence number is going to exhaust
+ start_qm = true;
+ }
+
+ if (ipsec_sa->TransformSetting.LifeKilobytes != 0)
+ {
+ UINT64 hard_size = (UINT64)ipsec_sa->TransformSetting.LifeKilobytes * (UINT64)1000;
+ UINT64 soft_size = hard_size * (UINT64)2 / (UINT64)3;
+
+ if (ipsec_sa->TotalSize >= soft_size)
+ {
+ // Execute a QuickMode forcibly because the capacity limit is going to exceed
+ start_qm = true;
+ }
+ }
+
+ if (start_qm)
+ {
+ if (ipsec_sa->StartQM_FlagSet == false)
+ {
+ c->StartQuickModeAsSoon = true;
+ ipsec_sa->StartQM_FlagSet = true;
+ }
+ }
+ }
+}
+
+// Received the L2TPv3 packet via the IPsec tunnel
+void ProcL2TPv3PacketRecv(IKE_SERVER *ike, IKE_CLIENT *c, UCHAR *data, UINT data_size, bool is_tunnel_mode)
+{
+ UDPPACKET p;
+ // Validate arguments
+ if (ike == NULL || c == NULL || data == NULL || data_size == 0)
+ {
+ return;
+ }
+
+ c->IsL2TPOnIPsecTunnelMode = is_tunnel_mode;
+
+ IPsecIkeClientManageL2TPServer(ike, c);
+
+ // Pass the received packet to the L2TP server
+ p.Type = 0;
+ p.Data = data;
+ p.DestPort = IPSEC_PORT_L2TPV3_VIRTUAL;
+ p.Size = data_size;
+
+ if (is_tunnel_mode)
+ {
+ Copy(&p.DstIP, &c->TunnelModeServerIP, sizeof(IP));
+ Copy(&p.SrcIP, &c->TunnelModeClientIP, sizeof(IP));
+ }
+ else
+ {
+ Copy(&p.DstIP, &c->L2TPServerIP, sizeof(IP));
+ Copy(&p.SrcIP, &c->L2TPClientIP, sizeof(IP));
+ }
+ p.SrcPort = IPSEC_PORT_L2TPV3_VIRTUAL;
+
+#ifdef RAW_DEBUG
+ IPsecIkeSendUdpForDebug(IPSEC_PORT_L2TP, 1, ((UCHAR *)p.Data) + 4, p.Size - 4);
+#endif // RAW_DEBUG
+
+ ProcL2TPPacketRecv(c->L2TP, &p);
+}
+
+// An EtherIP packet has been received via an IPsec tunnel
+void ProcIPsecEtherIPPacketRecv(IKE_SERVER *ike, IKE_CLIENT *c, UCHAR *data, UINT data_size, bool is_tunnel_mode)
+{
+ BLOCK *b;
+ // Validate arguments
+ if (ike == NULL || c == NULL || data == NULL || data_size == 0)
+ {
+ return;
+ }
+
+ c->IsEtherIPOnIPsecTunnelMode = is_tunnel_mode;
+
+ IPsecIkeClientManageEtherIPServer(ike, c);
+
+ b = NewBlock(data, data_size, 0);
+
+ EtherIPProcRecvPackets(c->EtherIP, b);
+
+ Free(b);
+}
+
+// An UDP packet has been received via the IPsec tunnel
+void ProcIPsecUdpPacketRecv(IKE_SERVER *ike, IKE_CLIENT *c, UCHAR *data, UINT data_size)
+{
+ UDP_HEADER *u;
+ UINT payload_size;
+ UINT src_port, dst_port;
+ UINT packet_length;
+ // Validate arguments
+ if (ike == NULL || c == NULL || data == NULL || data_size == 0)
+ {
+ return;
+ }
+
+ if (data_size <= sizeof(UDP_HEADER))
+ {
+ // There is no UDP header or the data is 0 bytes
+ return;
+ }
+
+ // UDP header
+ u = (UDP_HEADER *)data;
+
+ packet_length = Endian16(u->PacketLength);
+
+ if (packet_length <= sizeof(UDP_HEADER))
+ {
+ return;
+ }
+
+ payload_size = packet_length - sizeof(UDP_HEADER);
+
+ if (payload_size == 0)
+ {
+ // No data
+ return;
+ }
+
+ if (data_size < (sizeof(UDP_HEADER) + payload_size))
+ {
+ // Data is not followed
+ return;
+ }
+
+ src_port = Endian16(u->SrcPort);
+ dst_port = Endian16(u->DstPort);
+
+ if (dst_port == IPSEC_PORT_L2TP)
+ {
+ UDPPACKET p;
+ // A L2TP packet has been received
+ IPsecIkeClientManageL2TPServer(ike, c);
+
+ // Update Port number
+ c->L2TPClientPort = src_port;
+
+ // Pass the received packet to the L2TP server
+ p.Type = 0;
+ p.Data = data + sizeof(UDP_HEADER);
+ p.DestPort = IPSEC_PORT_L2TP;
+ Copy(&p.DstIP, &c->L2TPServerIP, sizeof(IP));
+ p.Size = payload_size;
+ Copy(&p.SrcIP, &c->L2TPClientIP, sizeof(IP));
+ p.SrcPort = IPSEC_PORT_L2TP;
+
+ ProcL2TPPacketRecv(c->L2TP, &p);
+
+ //Debug("IPsec UDP Recv: %u <= %u %u\n", dst_port, src_port, p.Size);
+
+#ifdef RAW_DEBUG
+ IPsecIkeSendUdpForDebug(IPSEC_PORT_L2TP, 1, p.Data, p.Size);
+#endif // RAW_DEBUG
+ }
+}
+
+// Send a raw packet for debugging
+void IPsecIkeSendUdpForDebug(UINT dst_port, UINT dst_ip, void *data, UINT size)
+{
+ SOCK *s = NewUDP(0);
+ IP d;
+
+ SetIP(&d, dst_ip, dst_ip, dst_ip, dst_ip);
+
+ SendTo(s, &d, dst_port, data, size);
+
+ ReleaseSock(s);
+}
+
+// L2TP packet transmission (via IPsec SA tunnel)
+void IPsecIkeClientSendL2TPPackets(IKE_SERVER *ike, IKE_CLIENT *c, L2TP_SERVER *l2tp)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL || c == NULL || l2tp == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(l2tp->SendPacketList);i++)
+ {
+ UDPPACKET *u = LIST_DATA(l2tp->SendPacketList, i);
+
+ if (u->SrcPort != IPSEC_PORT_L2TPV3_VIRTUAL)
+ {
+ // L2TP UDP packet transmission
+ IPsecSendUdpPacket(ike, c, IPSEC_PORT_L2TP, c->L2TPClientPort,
+ u->Data, u->Size);
+ }
+ else
+ {
+ // L2TPv3 special IP packet transmission
+ IPsecSendPacketByIkeClient(ike, c, u->Data, u->Size, IPSEC_IP_PROTO_L2TPV3);
+
+#ifdef RAW_DEBUG
+ IPsecIkeSendUdpForDebug(IPSEC_PORT_L2TP, 1, ((UCHAR *)u->Data) + 4, u->Size - 4);
+#endif // RAW_DEBUG
+ }
+
+ FreeUdpPacket(u);
+ }
+
+ DeleteAll(l2tp->SendPacketList);
+}
+
+// Manage the L2TP server that is associated with the IKE_CLIENT
+void IPsecIkeClientManageL2TPServer(IKE_SERVER *ike, IKE_CLIENT *c)
+{
+ L2TP_SERVER *l2tp;
+ // Validate arguments
+ if (ike == NULL || c == NULL)
+ {
+ return;
+ }
+
+ if (c->L2TP == NULL)
+ {
+ UINT crypt_block_size = IKE_MAX_BLOCK_SIZE;
+
+ if (c->CurrentIpSecSaRecv != NULL)
+ {
+ crypt_block_size = c->CurrentIpSecSaRecv->TransformSetting.Crypto->BlockSize;
+ }
+
+ c->L2TP = NewL2TPServerEx(ike->Cedar, ike, IsIP6(&c->ClientIP), crypt_block_size);
+ c->L2TP->IkeClient = c;
+
+ Copy(&c->L2TPServerIP, &c->ServerIP, sizeof(IP));
+ Copy(&c->L2TPClientIP, &c->ClientIP, sizeof(IP));
+
+ if (c->CurrentIpSecSaRecv != NULL)
+ {
+ Format(c->L2TP->CryptName, sizeof(c->L2TP->CryptName),
+ "IPsec - %s (%u bits)",
+ c->CurrentIpSecSaRecv->TransformSetting.Crypto->Name,
+ c->CurrentIpSecSaRecv->TransformSetting.CryptoKeySize * 8);
+ }
+
+ Debug("IKE_CLIENT 0x%X: L2TP Server Started.\n", c);
+
+ IPsecLog(ike, c, NULL, NULL, "LI_L2TP_SERVER_STARTED");
+ }
+
+ l2tp = c->L2TP;
+
+ if (l2tp->Interrupts == NULL)
+ {
+ l2tp->Interrupts = ike->Interrupts;
+ }
+
+ if (l2tp->SockEvent == NULL)
+ {
+ SetL2TPServerSockEvent(l2tp, ike->SockEvent);
+ }
+
+ l2tp->Now = ike->Now;
+}
+
+// Manage the EtherIP server that is associated with the IKE_CLIENT
+void IPsecIkeClientManageEtherIPServer(IKE_SERVER *ike, IKE_CLIENT *c)
+{
+ ETHERIP_SERVER *s;
+ // Validate arguments
+ if (ike == NULL || c == NULL)
+ {
+ return;
+ }
+
+ if (c->EtherIP == NULL)
+ {
+ char crypt_name[MAX_SIZE];
+ UINT crypt_block_size = IKE_MAX_BLOCK_SIZE;
+
+ Zero(crypt_name, sizeof(crypt_name));
+
+ if (c->CurrentIpSecSaRecv != NULL)
+ {
+ Format(crypt_name, sizeof(crypt_name),
+ "IPsec - %s (%u bits)",
+ c->CurrentIpSecSaRecv->TransformSetting.Crypto->Name,
+ c->CurrentIpSecSaRecv->TransformSetting.CryptoKeySize * 8);
+
+ crypt_block_size = c->CurrentIpSecSaRecv->TransformSetting.Crypto->BlockSize;
+ }
+
+ c->EtherIP = NewEtherIPServer(ike->Cedar, ike->IPsec, ike,
+ &c->ClientIP, c->ClientPort,
+ &c->ServerIP, c->ServerPort, crypt_name,
+ c->IsEtherIPOnIPsecTunnelMode, crypt_block_size, c->ClientId,
+ ++ike->CurrentEtherId);
+
+ Debug("IKE_CLIENT 0x%X: EtherIP Server Started.\n", c);
+
+ IPsecLog(ike, c, NULL, NULL, NULL, "LI_ETHERIP_SERVER_STARTED", ike->CurrentEtherId);
+ }
+ else
+ {
+ StrCpy(c->EtherIP->ClientId, sizeof(c->EtherIP->ClientId), c->ClientId);
+ }
+
+ s = c->EtherIP;
+
+ if (s->Interrupts == NULL)
+ {
+ s->Interrupts = ike->Interrupts;
+ }
+
+ if (s->SockEvent == NULL)
+ {
+ SetEtherIPServerSockEvent(s, ike->SockEvent);
+ }
+
+ s->Now = ike->Now;
+}
+
+// EtherIP packet transmission (via IPsec SA tunnel)
+void IPsecIkeClientSendEtherIPPackets(IKE_SERVER *ike, IKE_CLIENT *c, ETHERIP_SERVER *s)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL || c == NULL || s == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(s->SendPacketList);i++)
+ {
+ BLOCK *b = LIST_DATA(s->SendPacketList, i);
+
+ // Packet transmission
+ IPsecSendPacketByIkeClient(ike, c, b->Buf, b->Size, IPSEC_IP_PROTO_ETHERIP);
+
+ FreeBlock(b);
+ }
+
+ DeleteAll(s->SendPacketList);
+}
+
+// Handle the deletion payload
+void ProcDeletePayload(IKE_SERVER *ike, IKE_CLIENT *c, IKE_PACKET_DELETE_PAYLOAD *d)
+{
+ // Validate arguments
+ if (ike == NULL || c == NULL || d == NULL)
+ {
+ return;
+ }
+
+ if (d->ProtocolId == IKE_PROTOCOL_ID_IPSEC_ESP)
+ {
+ UINT i;
+ // Remove the IPsec SA
+ for (i = 0;i < LIST_NUM(d->SpiList);i++)
+ {
+ BUF *b = LIST_DATA(d->SpiList, i);
+
+ if (b->Size == 4)
+ {
+ UINT spi = READ_UINT(b->Buf);
+ MarkIPsecSaAsDeleted(ike, SearchIPsecSaBySpi(ike, c, spi));
+ }
+ }
+ }
+ else if (d->ProtocolId == IKE_PROTOCOL_ID_IKE)
+ {
+ UINT i;
+ // Remove the IKE SA
+ for (i = 0;i < LIST_NUM(d->SpiList);i++)
+ {
+ BUF *b = LIST_DATA(d->SpiList, i);
+
+ if (b->Size == 16)
+ {
+ UINT64 v1 = READ_UINT64(((UCHAR *)b->Buf) + 0);
+ UINT64 v2 = READ_UINT64(((UCHAR *)b->Buf) + 8);
+
+ IKE_SA *sa = FindIkeSaByResponderCookie(ike, v2);
+
+ if (sa != NULL && sa->IkeClient == c)
+ {
+ MarkIkeSaAsDeleted(ike, sa);
+ }
+ }
+ }
+ }
+}
+
+// Mark the IKE_CLIENT for deletion
+void MarkIkeClientAsDeleted(IKE_SERVER *ike, IKE_CLIENT *c)
+{
+ char client_ip_str[MAX_SIZE];
+ char server_ip_str[MAX_SIZE];
+ // Validate arguments
+ if (ike == NULL || c == NULL)
+ {
+ return;
+ }
+
+ if (c->Deleting)
+ {
+ return;
+ }
+
+ ike->StateHasChanged = true;
+
+ c->Deleting = true;
+
+ IPToStr(client_ip_str, sizeof(client_ip_str), &c->ClientIP);
+ IPToStr(server_ip_str, sizeof(server_ip_str), &c->ServerIP);
+
+ Debug("Deleting IKE_CLIENT: %p: %s:%u -> %s:%u\n", c, client_ip_str, c->ClientPort, server_ip_str, c->ServerPort);
+
+ IPsecLog(ike, c, NULL, NULL, "LI_DELETE_IKE_CLIENT");
+}
+
+// Mark the IKE SA for deletion
+void MarkIkeSaAsDeleted(IKE_SERVER *ike, IKE_SA *sa)
+{
+ // Validate arguments
+ if (ike == NULL || sa == NULL)
+ {
+ return;
+ }
+
+ if (sa->Deleting)
+ {
+ return;
+ }
+
+ ike->StateHasChanged = true;
+
+ sa->Deleting = true;
+
+ Debug("IKE SA %I64u - %I64u has been marked as being deleted.\n", sa->InitiatorCookie, sa->ResponderCookie);
+
+ SendDeleteIkeSaPacket(ike, sa->IkeClient, sa->InitiatorCookie, sa->ResponderCookie);
+
+ IPsecLog(ike, NULL, sa, NULL, "LI_DELETE_IKE_SA");
+}
+
+// Mark the IPsec SA for deletion
+void MarkIPsecSaAsDeleted(IKE_SERVER *ike, IPSECSA *sa)
+{
+ // Validate arguments
+ if (ike == NULL || sa == NULL)
+ {
+ return;
+ }
+
+ if (sa->Deleting)
+ {
+ return;
+ }
+
+ ike->StateHasChanged = true;
+
+ sa->Deleting = true;
+
+ Debug("IPsec SA 0x%X has been marked as being deleted.\n", sa->Spi);
+
+ SendDeleteIPsecSaPacket(ike, sa->IkeClient, sa->Spi);
+
+ IPsecLog(ike, NULL, NULL, sa, "LI_DELETE_IPSEC_SA");
+}
+
+// IPsec SA Deletion packet transmission process
+void SendDeleteIPsecSaPacket(IKE_SERVER *ike, IKE_CLIENT *c, UINT spi)
+{
+ IKE_PACKET_PAYLOAD *payload;
+ BUF *buf;
+ // Validate arguments
+ if (ike == NULL || c == NULL || spi == 0)
+ {
+ return;
+ }
+
+ buf = NewBuf();
+ WriteBufInt(buf, spi);
+
+ payload = IkeNewDeletePayload(IKE_PROTOCOL_ID_IPSEC_ESP, NewListSingle(buf));
+
+ SendInformationalExchangePacket(ike, c, payload);
+}
+
+// IKE SA deletion packet transmission process
+void SendDeleteIkeSaPacket(IKE_SERVER *ike, IKE_CLIENT *c, UINT64 init_cookie, UINT64 resp_cookie)
+{
+ IKE_PACKET_PAYLOAD *payload;
+ BUF *buf;
+ // Validate arguments
+ if (ike == NULL || c == NULL)
+ {
+ return;
+ }
+
+ buf = NewBuf();
+ WriteBufInt64(buf, init_cookie);
+ WriteBufInt64(buf, resp_cookie);
+
+ payload = IkeNewDeletePayload(IKE_PROTOCOL_ID_IKE, NewListSingle(buf));
+
+ SendInformationalExchangePacket(ike, c, payload);
+}
+
+// Information exchange packet transmission process
+void SendInformationalExchangePacket(IKE_SERVER *ike, IKE_CLIENT *c, IKE_PACKET_PAYLOAD *payload)
+{
+ SendInformationalExchangePacketEx(ike, c, payload, false, 0, 0);
+}
+void SendInformationalExchangePacketEx(IKE_SERVER *ike, IKE_CLIENT *c, IKE_PACKET_PAYLOAD *payload, bool force_plain, UINT64 init_cookie, UINT64 resp_cookie)
+{
+ IKE_SA *sa;
+ IKE_PACKET *ps;
+ LIST *payload_list;
+ UCHAR dummy_hash_data[IKE_MAX_HASH_SIZE];
+ IKE_PACKET_PAYLOAD *hash_payload;
+ BUF *ps_buf;
+ UINT after_hash_offset, after_hash_size;
+ BUF *ps_buf_after_hash;
+ BUF *tmp_buf;
+ UCHAR hash[IKE_MAX_HASH_SIZE];
+ IKE_CRYPTO_PARAM cp;
+ bool plain = false;
+ // Validate arguments
+ if (ike == NULL || c == NULL || payload == NULL)
+ {
+ IkeFreePayload(payload);
+ return;
+ }
+
+ sa = c->CurrentIkeSa;
+ if (sa == NULL)
+ {
+ plain = true;
+ }
+
+ if (force_plain)
+ {
+ plain = true;
+ }
+
+ if (plain && (init_cookie == 0 && resp_cookie == 0))
+ {
+ init_cookie = Rand64();
+ resp_cookie = 0;
+ }
+
+ payload_list = NewListFast(NULL);
+
+ Zero(dummy_hash_data, sizeof(dummy_hash_data));
+
+ // Hash payload
+ if (plain == false)
+ {
+ hash_payload = IkeNewDataPayload(IKE_PAYLOAD_HASH, dummy_hash_data, sa->HashSize);
+ Add(payload_list, hash_payload);
+ }
+
+ // Body
+ Add(payload_list, payload);
+
+ // Packet creation
+ ps = IkeNew((plain ? init_cookie : sa->InitiatorCookie), (plain ? resp_cookie : sa->ResponderCookie),
+ IKE_EXCHANGE_TYPE_INFORMATION, false, false, false,
+ GenerateNewMessageId(ike), payload_list);
+
+ if (plain == false)
+ {
+ // Build a temporary packet
+ ps_buf = IkeBuild(ps, NULL);
+
+ // Get the payload after the hash part
+ after_hash_offset = sizeof(IKE_HEADER) + hash_payload->BitArray->Size + sizeof(IKE_COMMON_HEADER);
+ after_hash_size = ((ps_buf->Size > after_hash_offset) ? (ps_buf->Size - after_hash_offset) : 0);
+
+ ps_buf_after_hash = MemToBuf(((UCHAR *)ps_buf->Buf) + after_hash_offset, after_hash_size);
+ FreeBuf(ps_buf);
+
+ // Calculate the hash
+ tmp_buf = NewBuf();
+ WriteBufInt(tmp_buf, ps->MessageId);
+ WriteBufBuf(tmp_buf, ps_buf_after_hash);
+ IkeHMac(sa->TransformSetting.Hash, hash, sa->SKEYID_a, sa->HashSize, tmp_buf->Buf, tmp_buf->Size);
+ FreeBuf(tmp_buf);
+
+ // Overwrite the hash
+ Copy(hash_payload->Payload.Hash.Data->Buf, hash, sa->HashSize);
+
+ ps->FlagEncrypted = true;
+ FreeBuf(ps_buf_after_hash);
+ }
+
+ // Packet reply
+ Zero(&cp, sizeof(cp));
+
+ if (plain == false)
+ {
+ cp.Key = sa->CryptoKey;
+ IkeCalcPhase2InitialIv(cp.Iv, sa, ps->MessageId);
+ }
+
+ ps_buf = IkeBuild(ps, &cp);
+
+ IkeSendUdpPacket(ike, IKE_UDP_TYPE_ISAKMP, &c->ServerIP, c->ServerPort,
+ &c->ClientIP, c->ClientPort,
+ ps_buf->Buf, ps_buf->Size);
+
+#ifdef RAW_DEBUG
+ IkeDebugUdpSendRawPacket(ps);
+#endif // RAW_DEBUG
+
+ Free(ps_buf);
+
+ IkeFree(ps);
+}
+
+// Information exchange packet reception process
+void ProcIkeInformationalExchangePacketRecv(IKE_SERVER *ike, UDPPACKET *p, IKE_PACKET *header)
+{
+ IKE_CLIENT *c;
+ IKE_SA *ike_sa;
+ // Validate arguments
+ if (ike == NULL || p == NULL || header == NULL || header->InitiatorCookie == 0 || header->ResponderCookie == 0
+ || header->MessageId == 0 || header->FlagEncrypted == false)
+ {
+ return;
+ }
+
+ c = SearchOrCreateNewIkeClientForIkePacket(ike, &p->SrcIP, p->SrcPort, &p->DstIP, p->DestPort, header);
+
+ if (c == NULL)
+ {
+ return;
+ }
+
+ ike_sa = FindIkeSaByResponderCookieAndClient(ike, header->ResponderCookie, c);
+
+ if (ike_sa != NULL && ike_sa->Established)
+ {
+ IKE_PACKET *pr;
+ IKE_CRYPTO_PARAM cp;
+
+ // Packet decoding
+ Zero(&cp, sizeof(cp));
+ cp.Key = ike_sa->CryptoKey;
+ IkeCalcPhase2InitialIv(cp.Iv, ike_sa, header->MessageId);
+
+ pr = IkeParse(p->Data, p->Size, &cp);
+#ifdef RAW_DEBUG
+ IkeDebugUdpSendRawPacket(pr);
+#endif // RAW_DEBUG
+ if (pr != NULL)
+ {
+ // Get the hash payload
+ IKE_PACKET_PAYLOAD *hash_payload;
+
+ hash_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_HASH, 0);
+ if (hash_payload != NULL)
+ {
+ // Get the payload after the hash
+ UINT header_and_hash_size = sizeof(IKE_COMMON_HEADER) + hash_payload->BitArray->Size;
+ void *after_hash_data = ((UCHAR *)pr->DecryptedPayload->Buf) + header_and_hash_size;
+ if (pr->DecryptedPayload->Size > header_and_hash_size)
+ {
+ UINT after_hash_size = pr->DecryptedPayload->Size - header_and_hash_size;
+ UCHAR hash1[IKE_MAX_HASH_SIZE];
+ BUF *hash1_buf;
+
+ hash1_buf = NewBuf();
+ WriteBufInt(hash1_buf, header->MessageId);
+ WriteBuf(hash1_buf, after_hash_data, after_hash_size);
+
+ IkeHMac(ike_sa->TransformSetting.Hash, hash1, ike_sa->SKEYID_a, ike_sa->HashSize,
+ hash1_buf->Buf, hash1_buf->Size);
+
+ // Compare the hash value
+ if (IkeCompareHash(hash_payload, hash1, ike_sa->HashSize))
+ {
+ UINT i, num;
+ // Handle the deletion payload
+ num = IkeGetPayloadNum(pr->PayloadList, IKE_PAYLOAD_DELETE);
+ for (i = 0;i < num;i++)
+ {
+ IKE_PACKET_PAYLOAD *payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_DELETE, i);
+ IKE_PACKET_DELETE_PAYLOAD *del = &payload->Payload.Delete;
+
+ ProcDeletePayload(ike, c, del);
+ }
+ num = IkeGetPayloadNum(pr->PayloadList, IKE_PAYLOAD_NOTICE);
+ // Handle the notification payload
+ for (i = 0;i < num;i++)
+ {
+ IKE_PACKET_PAYLOAD *payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NOTICE, i);
+ IKE_PACKET_NOTICE_PAYLOAD *n = &payload->Payload.Notice;
+
+ if (n->MessageType == IKE_NOTICE_DPD_REQUEST || n->MessageType == IKE_NOTICE_DPD_RESPONSE)
+ {
+ if (n->MessageData != NULL && n->MessageData->Size == sizeof(UINT))
+ {
+ UINT seq_no = READ_UINT(n->MessageData->Buf);
+
+ if (n->Spi->Size == (sizeof(UINT64) * 2))
+ {
+ UINT64 init_cookie = READ_UINT64(((UCHAR *)n->Spi->Buf));
+ UINT64 resp_cookie = READ_UINT64(((UCHAR *)n->Spi->Buf) + sizeof(UINT64));
+
+ if (init_cookie != 0 && resp_cookie != 0)
+ {
+ IKE_SA *found_ike_sa = SearchIkeSaByCookie(ike, init_cookie, resp_cookie);
+
+ if (found_ike_sa != NULL && found_ike_sa->IkeClient == c)
+ {
+ if (n->MessageType == IKE_NOTICE_DPD_REQUEST)
+ {
+ // Return the DPD Response (ACK) for the DPD Request
+ SendInformationalExchangePacket(ike, c,
+ IkeNewNoticeDpdPayload(true, init_cookie, resp_cookie,
+ seq_no));
+ }
+
+ // Update the status of the IKE SA
+ found_ike_sa->LastCommTick = ike->Now;
+ ike_sa->LastCommTick = ike->Now;
+ found_ike_sa->IkeClient->LastCommTick = ike->Now;
+ ike_sa->IkeClient->LastCommTick = ike->Now;
+ ike_sa->IkeClient->CurrentIkeSa = ike_sa;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ FreeBuf(hash1_buf);
+ }
+ }
+
+ IkeFree(pr);
+ }
+ }
+}
+
+// Create a new message ID
+UINT GenerateNewMessageId(IKE_SERVER *ike)
+{
+ UINT ret;
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return 0;
+ }
+
+ while (true)
+ {
+ ret = Rand32();
+
+ if (ret != 0 && ret != 0xffffffff)
+ {
+ UINT i;
+ bool ok = true;
+
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+
+ if (sa->MessageId == ret)
+ {
+ ok = false;
+ break;
+ }
+ }
+
+ if (ok)
+ {
+ return ret;
+ }
+ }
+ }
+}
+
+// Start the quick mode
+void StartQuickMode(IKE_SERVER *ike, IKE_CLIENT *c)
+{
+ IPSEC_SA_TRANSFORM_SETTING setting;
+ IKE_SA *ike_sa;
+ UINT message_id;
+ UCHAR iv[IKE_MAX_BLOCK_SIZE];
+ // Validate arguments
+ if (ike == NULL || c == NULL)
+ {
+ return;
+ }
+
+ if (IsZero(&c->CachedTransformSetting, sizeof(IPSEC_SA_TRANSFORM_SETTING)))
+ {
+ // Cached transform setting does not exist
+ Debug("Error: c->CachedTransformSetting is not existing.\n");
+ return;
+ }
+
+ ike_sa = c->CurrentIkeSa;
+ if (ike_sa == NULL)
+ {
+ return;
+ }
+
+ IPsecLog(ike, NULL, ike_sa, NULL, "LI_START_QM_FROM_SERVER");
+
+ Copy(&setting, &c->CachedTransformSetting, sizeof(IPSEC_SA_TRANSFORM_SETTING));
+
+ message_id = GenerateNewMessageId(ike);
+
+ IkeCalcPhase2InitialIv(iv, ike_sa, message_id);
+
+#ifdef FORCE_LIFETIME_QM
+ setting.LifeSeconds = FORCE_LIFETIME_QM;
+#endif // FORCE_LIFETIME_QM
+
+ if (true)
+ {
+ IKE_PACKET *ps;
+ LIST *payload_list;
+ IKE_PACKET_PAYLOAD *send_hash_payload;
+ IKE_PACKET_PAYLOAD *send_sa_payload;
+ IKE_PACKET_PAYLOAD *send_proposal_payload;
+ IKE_PACKET_PAYLOAD *send_transform_payload;
+ IKE_PACKET_PAYLOAD *send_rand_payload;
+ IKE_PACKET_PAYLOAD *send_key_payload = NULL;
+ IKE_PACKET_PAYLOAD *send_id_1 = NULL, *send_id_2 = NULL;
+ UINT shared_key_size = 0;
+ UCHAR *shared_key = NULL;
+ BUF *initiator_rand;
+ IPSECSA *ipsec_sa_s_c, *ipsec_sa_c_s;
+ BUF *ps_buf;
+ UINT after_hash_offset, after_hash_size;
+ BUF *ps_buf_after_hash;
+ BUF *tmp_buf;
+ UINT spi;
+ UINT spi_be;
+ UCHAR hash1[IKE_MAX_HASH_SIZE];
+ UCHAR zero = 0;
+ DH_CTX *dh = NULL;
+ UCHAR dummy_hash_data[IKE_MAX_HASH_SIZE];
+
+ initiator_rand = RandBuf(IKE_SA_RAND_SIZE);
+
+ if (setting.Dh != NULL)
+ {
+ // Generate DH
+ dh = IkeDhNewCtx(setting.Dh);
+
+ if (dh != NULL)
+ {
+ send_key_payload = IkeNewDataPayload(IKE_PAYLOAD_KEY_EXCHANGE,
+ dh->MyPublicKey->Buf, dh->MyPublicKey->Size);
+ }
+ }
+
+ Zero(dummy_hash_data, sizeof(dummy_hash_data));
+
+ // Dummy hash value
+ payload_list = NewListFast(NULL);
+ send_hash_payload = IkeNewDataPayload(IKE_PAYLOAD_HASH, dummy_hash_data, ike_sa->HashSize);
+ Add(payload_list, send_hash_payload);
+
+ // Determine the SPI
+ spi = GenerateNewIPsecSaSpi(ike, 0);
+ spi_be = Endian32(spi);
+
+ // SA
+ send_transform_payload = TransformSettingToTransformPayloadForIPsec(ike, &setting);
+ send_proposal_payload = IkeNewProposalPayload(1, IKE_PROTOCOL_ID_IPSEC_ESP, &spi_be, sizeof(spi_be),
+ NewListSingle(send_transform_payload));
+ send_sa_payload = IkeNewSaPayload(NewListSingle(send_proposal_payload));
+ Add(payload_list, send_sa_payload);
+
+ // Random number
+ send_rand_payload = IkeNewDataPayload(IKE_PAYLOAD_RAND, initiator_rand->Buf, initiator_rand->Size);
+ Add(payload_list, send_rand_payload);
+
+ // Key exchange
+ if (send_key_payload != NULL)
+ {
+ Add(payload_list, send_key_payload);
+ }
+
+ if (c->SendID1andID2)
+ {
+ // Add the ID payload
+ if (setting.CapsuleMode == IKE_P2_CAPSULE_NAT_TUNNEL_1 || setting.CapsuleMode == IKE_P2_CAPSULE_NAT_TUNNEL_2)
+ {
+ UCHAR zero[32];
+
+ Zero(zero, sizeof(zero));
+
+ // Tunnel Mode
+ send_id_1 = IkeNewIdPayload((IsIP4(&c->ServerIP) ? IKE_ID_IPV4_ADDR_SUBNET : IKE_ID_IPV6_ADDR_SUBNET),
+ 0, 0,
+ zero, (IsIP4(&c->ServerIP) ? 8 : 32));
+
+ send_id_2 = IkeNewIdPayload(c->SendID1_Type,
+ c->SendID1_Protocol, c->SendID1_Port,
+ c->SendID1_Buf->Buf, c->SendID1_Buf->Size);
+ }
+ else
+ {
+ // Transport mode
+ // Specify in the reverse order in which the client has been specified
+ send_id_2 = IkeNewIdPayload(c->SendID1_Type,
+ c->SendID1_Protocol, c->SendID1_Port,
+ c->SendID1_Buf->Buf, c->SendID1_Buf->Size);
+
+ send_id_1 = IkeNewIdPayload(c->SendID2_Type,
+ c->SendID2_Protocol, c->SendID2_Port,
+ c->SendID2_Buf->Buf, c->SendID2_Buf->Size);
+ }
+
+ Add(payload_list, send_id_1);
+ Add(payload_list, send_id_2);
+ }
+
+ if (true)
+ {
+ // NAT-OA payload
+ if (c->SendNatOaDraft1)
+ {
+ Add(payload_list, IkeNewNatOaPayload(IKE_PAYLOAD_NAT_OA_DRAFT, &c->ServerIP));
+ }
+
+ if (c->SendNatOaDraft2)
+ {
+ Add(payload_list, IkeNewNatOaPayload(IKE_PAYLOAD_NAT_OA_DRAFT_2, &c->ServerIP));
+ }
+
+ if (c->SendNatOaRfc)
+ {
+ Add(payload_list, IkeNewNatOaPayload(IKE_PAYLOAD_NAT_OA, &c->ClientIP));
+ Add(payload_list, IkeNewNatOaPayload(IKE_PAYLOAD_NAT_OA, &c->ServerIP));
+ }
+ }
+
+ // Build a packet
+ ps = IkeNew(ike_sa->InitiatorCookie, ike_sa->ResponderCookie, IKE_EXCHANGE_TYPE_QUICK,
+ false, false, false, message_id, payload_list);
+
+ // Build a temporary packet
+ ps_buf = IkeBuild(ps, NULL);
+
+ // Get the payload after the hash part
+ after_hash_offset = sizeof(IKE_HEADER) + send_hash_payload->BitArray->Size + sizeof(IKE_COMMON_HEADER);
+ after_hash_size = ((ps_buf->Size > after_hash_offset) ? (ps_buf->Size - after_hash_offset) : 0);
+
+ ps_buf_after_hash = MemToBuf(((UCHAR *)ps_buf->Buf) + after_hash_offset, after_hash_size);
+ FreeBuf(ps_buf);
+
+ // Calculate the hash #1
+ tmp_buf = NewBuf();
+ WriteBufInt(tmp_buf, message_id);
+ WriteBufBuf(tmp_buf, ps_buf_after_hash);
+ IkeHMac(ike_sa->TransformSetting.Hash, hash1, ike_sa->SKEYID_a, ike_sa->HashSize, tmp_buf->Buf, tmp_buf->Size);
+ FreeBuf(tmp_buf);
+
+ // Overwrite hash #1
+ Copy(send_hash_payload->Payload.Hash.Data->Buf, hash1, ike_sa->HashSize);
+
+ // Create an IPsec SA
+ ipsec_sa_c_s = NewIPsecSa(ike, c, ike_sa, true, message_id, false, iv, spi,
+ initiator_rand->Buf, initiator_rand->Size, NULL, 0,
+ &setting, shared_key, shared_key_size);
+
+ ipsec_sa_s_c = NewIPsecSa(ike, c, ike_sa, true, message_id, true, iv, 0,
+ initiator_rand->Buf, initiator_rand->Size, NULL, 0,
+ &setting, shared_key, shared_key_size);
+
+ ipsec_sa_c_s->PairIPsecSa = ipsec_sa_s_c;
+ ipsec_sa_s_c->PairIPsecSa = ipsec_sa_c_s;
+
+ ipsec_sa_s_c->Dh = dh;
+
+ Insert(ike->IPsecSaList, ipsec_sa_c_s);
+ Insert(ike->IPsecSaList, ipsec_sa_s_c);
+
+ // Packet transmission
+ ps->FlagEncrypted = true;
+ IPsecSaSendPacket(ike, ipsec_sa_s_c, ps);
+ ipsec_sa_s_c->NumResends = 3;
+#ifdef RAW_DEBUG
+ IkeDebugUdpSendRawPacket(ps);
+#endif // RAW_DEBUG
+
+ IkeFree(ps);
+ Free(shared_key);
+ FreeBuf(ps_buf_after_hash);
+ FreeBuf(initiator_rand);
+ }
+}
+
+// Process the quick mode received packet
+void ProcIkeQuickModePacketRecv(IKE_SERVER *ike, UDPPACKET *p, IKE_PACKET *header)
+{
+ IKE_CLIENT *c;
+ IKE_SA *ike_sa;
+ // Validate arguments
+ if (ike == NULL || p == NULL || header == NULL || header->InitiatorCookie == 0 || header->ResponderCookie == 0
+ || header->MessageId == 0 || header->FlagEncrypted == false)
+ {
+ return;
+ }
+
+ c = SearchOrCreateNewIkeClientForIkePacket(ike, &p->SrcIP, p->SrcPort, &p->DstIP, p->DestPort, header);
+
+ if (c == NULL)
+ {
+ return;
+ }
+
+ ike_sa = FindIkeSaByResponderCookieAndClient(ike, header->ResponderCookie, c);
+
+ if (ike_sa == NULL)
+ {
+ // IKE SA does not exist
+ SendInformationalExchangePacketEx(ike, c, IkeNewNoticeErrorInvalidCookiePayload(header->InitiatorCookie,
+ header->ResponderCookie), true, header->InitiatorCookie, header->ResponderCookie);
+ }
+
+ if (ike_sa != NULL && ike_sa->Established)
+ {
+ // Update the status of the IKE SA
+ ike_sa->LastCommTick = ike->Now;
+ ike_sa->IkeClient->LastCommTick = ike->Now;
+ ike_sa->IkeClient->CurrentIkeSa = ike_sa;
+
+ // Search whether the Message ID is already in the database
+ if (SearchIPsecSaByMessageId(ike, c, header->MessageId) == NULL)
+ {
+ IKE_PACKET *pr;
+ IKE_CRYPTO_PARAM cp;
+
+ // Message ID does not exist. Start a new Quick Mode session
+ Zero(&cp, sizeof(cp));
+ cp.Key = ike_sa->CryptoKey;
+ IkeCalcPhase2InitialIv(cp.Iv, ike_sa, header->MessageId);
+
+ pr = IkeParse(p->Data, p->Size, &cp);
+#ifdef RAW_DEBUG
+ IkeDebugUdpSendRawPacket(pr);
+#endif // RAW_DEBUG
+ if (pr != NULL)
+ {
+ // Get the hash payload
+ IKE_PACKET_PAYLOAD *hash_payload;
+
+ hash_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_HASH, 0);
+ if (hash_payload != NULL)
+ {
+ // Get the payload after the hash
+ UINT header_and_hash_size = sizeof(IKE_COMMON_HEADER) + hash_payload->BitArray->Size;
+ void *after_hash_data = ((UCHAR *)pr->DecryptedPayload->Buf) + header_and_hash_size;
+ if (pr->DecryptedPayload->Size > header_and_hash_size)
+ {
+ UINT after_hash_size = pr->DecryptedPayload->Size - header_and_hash_size;
+ UCHAR hash1[IKE_MAX_HASH_SIZE];
+ BUF *hash1_buf;
+
+ hash1_buf = NewBuf();
+ WriteBufInt(hash1_buf, header->MessageId);
+ WriteBuf(hash1_buf, after_hash_data, after_hash_size);
+
+ IkeHMac(ike_sa->TransformSetting.Hash, hash1, ike_sa->SKEYID_a, ike_sa->HashSize,
+ hash1_buf->Buf, hash1_buf->Size);
+
+ // Compare the hash value
+ if (IkeCompareHash(hash_payload, hash1, ike_sa->HashSize))
+ {
+ IKE_PACKET_PAYLOAD *sa_payload, *rand_payload, *key_payload, *id_payload_1, *id_payload_2;
+
+ // Get the payload of other
+ sa_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_SA, 0);
+ rand_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_RAND, 0);
+ key_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_KEY_EXCHANGE, 0);
+ id_payload_1 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_ID, 0);
+ id_payload_2 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_ID, 1);
+
+ if (sa_payload != NULL && rand_payload != NULL)
+ {
+ IPSEC_SA_TRANSFORM_SETTING setting;
+
+ Zero(&setting, sizeof(setting));
+
+ // Interpret the SA payload
+ if (GetBestTransformSettingForIPsecSa(ike, pr, &setting, &p->DstIP) && (GetNumberOfIPsecSaOfIkeClient(ike, c) <= IKE_QUOTA_MAX_SA_PER_CLIENT))
+ {
+ // Appropriate transform setting is selected
+ Debug("P2 Transform: %s %s %s(%u) %u %u\n",
+ (setting.Dh == NULL ? NULL : setting.Dh->Name), setting.Hash->Name, setting.Crypto->Name, setting.CryptoKeySize,
+ setting.LifeKilobytes, setting.LifeSeconds);
+
+#ifdef FORCE_LIFETIME_QM
+ setting.LifeSeconds = FORCE_LIFETIME_QM;
+#endif // FORCE_LIFETIME_QM
+
+ // Cache the transform attribute value
+ Copy(&c->CachedTransformSetting, &setting, sizeof(IPSEC_SA_TRANSFORM_SETTING));
+
+ // Check the key exchange payload if the PFS is specified
+ if (setting.Dh == NULL || (setting.Dh != NULL && key_payload != NULL &&
+ key_payload->Payload.KeyExchange.Data->Size <= setting.Dh->KeySize))
+ {
+ // Create a payload for response
+ IKE_PACKET *ps;
+ LIST *payload_list;
+ IKE_PACKET_PAYLOAD *send_hash_payload;
+ IKE_PACKET_PAYLOAD *send_sa_payload;
+ IKE_PACKET_PAYLOAD *send_proposal_payload;
+ IKE_PACKET_PAYLOAD *send_transform_payload;
+ IKE_PACKET_PAYLOAD *send_rand_payload;
+ IKE_PACKET_PAYLOAD *send_key_payload = NULL;
+ IKE_PACKET_PAYLOAD *send_id_1 = NULL, *send_id_2 = NULL;
+ UCHAR dummy_hash_data[IKE_MAX_HASH_SIZE];
+ DH_CTX *dh = NULL;
+ UINT shared_key_size = 0;
+ UCHAR *shared_key = NULL;
+ BUF *initiator_rand, *responder_rand;
+ IPSECSA *ipsec_sa_s_c, *ipsec_sa_c_s;
+ BUF *ps_buf;
+ UINT after_hash_offset, after_hash_size;
+ BUF *ps_buf_after_hash;
+ BUF *tmp_buf;
+ UINT spi;
+ UINT spi_be;
+ UCHAR hash2[IKE_MAX_HASH_SIZE];
+ UCHAR hash3[IKE_MAX_HASH_SIZE];
+ UCHAR zero = 0;
+
+ IPsecLog(ike, NULL, ike_sa, NULL, "LI_START_QM_FROM_CLIENT");
+
+ initiator_rand = CloneBuf(rand_payload->Payload.Rand.Data);
+ responder_rand = RandBuf(IKE_SA_RAND_SIZE);
+
+ if (setting.Dh != NULL)
+ {
+ // Calculate DH
+ dh = IkeDhNewCtx(setting.Dh);
+ shared_key_size = (dh == NULL ? 0 : dh->Size);
+ shared_key = ZeroMalloc(shared_key_size);
+
+ if (DhCompute(dh, shared_key, key_payload->Payload.KeyExchange.Data->Buf, key_payload->Payload.KeyExchange.Data->Size))
+ {
+ // DH calculation success
+ Debug("P2 DH Ok.\n");
+
+ send_key_payload = IkeNewDataPayload(IKE_PAYLOAD_KEY_EXCHANGE,
+ dh->MyPublicKey->Buf, dh->MyPublicKey->Size);
+
+ IkeDhFreeCtx(dh);
+ }
+ else
+ {
+ // DH calculation failure
+ Debug("P2 DhCompute failed.\n");
+
+ shared_key = NULL;
+ Free(shared_key);
+ shared_key_size = 0;
+
+ IPsecLog(ike, NULL, ike_sa, NULL, "LI_QM_DH_ERROR");
+ }
+ }
+
+ Zero(dummy_hash_data, sizeof(dummy_hash_data));
+
+ // Dummy hash value
+ payload_list = NewListFast(NULL);
+ send_hash_payload = IkeNewDataPayload(IKE_PAYLOAD_HASH, dummy_hash_data, ike_sa->HashSize);
+ Add(payload_list, send_hash_payload);
+
+ // Determine the SPI
+ spi = GenerateNewIPsecSaSpi(ike, setting.SpiServerToClient);
+ spi_be = Endian32(spi);
+
+ // SA
+ send_transform_payload = TransformSettingToTransformPayloadForIPsec(ike, &setting);
+ send_proposal_payload = IkeNewProposalPayload(1, IKE_PROTOCOL_ID_IPSEC_ESP, &spi_be, sizeof(spi_be),
+ NewListSingle(send_transform_payload));
+ send_sa_payload = IkeNewSaPayload(NewListSingle(send_proposal_payload));
+ Add(payload_list, send_sa_payload);
+
+ // Random number
+ send_rand_payload = IkeNewDataPayload(IKE_PAYLOAD_RAND, responder_rand->Buf, responder_rand->Size);
+ Add(payload_list, send_rand_payload);
+
+ // Key exchange
+ if (send_key_payload != NULL)
+ {
+ Add(payload_list, send_key_payload);
+ }
+
+ // ID
+ if (id_payload_1 != NULL && id_payload_2 != NULL)
+ {
+ send_id_1 = IkeNewIdPayload(id_payload_1->Payload.Id.Type,
+ id_payload_1->Payload.Id.ProtocolId, id_payload_1->Payload.Id.Port,
+ id_payload_1->Payload.Id.IdData->Buf, id_payload_1->Payload.Id.IdData->Size);
+
+ send_id_2 = IkeNewIdPayload(id_payload_2->Payload.Id.Type,
+ id_payload_2->Payload.Id.ProtocolId, id_payload_2->Payload.Id.Port,
+ id_payload_2->Payload.Id.IdData->Buf, id_payload_2->Payload.Id.IdData->Size);
+
+ Add(payload_list, send_id_1);
+ Add(payload_list, send_id_2);
+
+ if (c->SendID1_Buf != NULL)
+ {
+ FreeBuf(c->SendID1_Buf);
+ }
+
+ if (c->SendID2_Buf != NULL)
+ {
+ FreeBuf(c->SendID2_Buf);
+ }
+
+ c->SendID1_Type = id_payload_1->Payload.Id.Type;
+ c->SendID1_Protocol = id_payload_1->Payload.Id.ProtocolId;
+ c->SendID1_Port = id_payload_1->Payload.Id.Port;
+ c->SendID1_Buf = CloneBuf(id_payload_1->Payload.Id.IdData);
+
+ c->SendID2_Type = id_payload_2->Payload.Id.Type;
+ c->SendID2_Protocol = id_payload_2->Payload.Id.ProtocolId;
+ c->SendID2_Port = id_payload_2->Payload.Id.Port;
+ c->SendID2_Buf = CloneBuf(id_payload_2->Payload.Id.IdData);
+
+ c->SendID1andID2 = true;
+ }
+ else
+ {
+ c->SendID1andID2 = false;
+ }
+
+ if (true)
+ {
+ // Reply if NAT-OA payload is presented by the client
+ IKE_PACKET_PAYLOAD *nat_oa_draft1 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_OA_DRAFT, 0);
+ IKE_PACKET_PAYLOAD *nat_oa_draft2 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_OA_DRAFT_2, 0);
+ IKE_PACKET_PAYLOAD *nat_oa_rfc_0 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_OA, 0);
+ IKE_PACKET_PAYLOAD *nat_oa_rfc_1 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_OA, 1);
+
+ c->SendNatOaDraft1 = c->SendNatOaDraft2 = c->SendNatOaRfc = false;
+
+ c->ShouldCalcChecksumForUDP = false;
+
+ if (nat_oa_draft1 != NULL)
+ {
+ Add(payload_list, IkeNewNatOaPayload(IKE_PAYLOAD_NAT_OA_DRAFT, &c->ServerIP));
+ c->SendNatOaDraft1 = true;
+
+ if (IsIP4(&nat_oa_draft1->Payload.NatOa.IpAddress) == IsIP4(&c->ServerIP))
+ {
+ Copy(&c->TransportModeClientIP, &nat_oa_draft1->Payload.NatOa.IpAddress, sizeof(IP));
+ Copy(&c->TransportModeServerIP, &c->ServerIP, sizeof(IP));
+
+ c->ShouldCalcChecksumForUDP = true;
+ }
+ }
+
+ if (nat_oa_draft2 != NULL)
+ {
+ Add(payload_list, IkeNewNatOaPayload(IKE_PAYLOAD_NAT_OA_DRAFT_2, &c->ServerIP));
+ c->SendNatOaDraft2 = true;
+
+ if (IsIP4(&nat_oa_draft2->Payload.NatOa.IpAddress) == IsIP4(&c->ServerIP))
+ {
+ Copy(&c->TransportModeClientIP, &nat_oa_draft2->Payload.NatOa.IpAddress, sizeof(IP));
+ Copy(&c->TransportModeServerIP, &c->ServerIP, sizeof(IP));
+
+ c->ShouldCalcChecksumForUDP = true;
+ }
+ }
+
+ if (nat_oa_rfc_0 != NULL && nat_oa_rfc_1 != NULL)
+ {
+ Add(payload_list, IkeNewNatOaPayload(IKE_PAYLOAD_NAT_OA, &c->ClientIP));
+ Add(payload_list, IkeNewNatOaPayload(IKE_PAYLOAD_NAT_OA, &c->ServerIP));
+ c->SendNatOaRfc = true;
+
+ if (IsIP4(&nat_oa_rfc_0->Payload.NatOa.IpAddress) == IsIP4(&c->ServerIP))
+ {
+ Copy(&c->TransportModeClientIP, &nat_oa_rfc_0->Payload.NatOa.IpAddress, sizeof(IP));
+ Copy(&c->TransportModeServerIP, &c->ServerIP, sizeof(IP));
+
+ c->ShouldCalcChecksumForUDP = true;
+ }
+ }
+ }
+
+ // Build a packet
+ ps = IkeNew(ike_sa->InitiatorCookie, ike_sa->ResponderCookie, IKE_EXCHANGE_TYPE_QUICK,
+ false, false, false, header->MessageId, payload_list);
+
+ // Build a temporary packet
+ ps_buf = IkeBuild(ps, NULL);
+
+ // Get the payload after the hash part
+ after_hash_offset = sizeof(IKE_HEADER) + send_hash_payload->BitArray->Size + sizeof(IKE_COMMON_HEADER);
+ after_hash_size = ((ps_buf->Size > after_hash_offset) ? (ps_buf->Size - after_hash_offset) : 0);
+
+ ps_buf_after_hash = MemToBuf(((UCHAR *)ps_buf->Buf) + after_hash_offset, after_hash_size);
+ FreeBuf(ps_buf);
+
+ // Calculate the hash #2
+ tmp_buf = NewBuf();
+ WriteBufInt(tmp_buf, header->MessageId);
+ WriteBufBuf(tmp_buf, initiator_rand);
+ WriteBufBuf(tmp_buf, ps_buf_after_hash);
+ IkeHMac(ike_sa->TransformSetting.Hash, hash2, ike_sa->SKEYID_a, ike_sa->HashSize, tmp_buf->Buf, tmp_buf->Size);
+ FreeBuf(tmp_buf);
+
+ // Calculate the hash #3
+ tmp_buf = NewBuf();
+ WriteBuf(tmp_buf, &zero, 1);
+ WriteBufInt(tmp_buf, header->MessageId);
+ WriteBufBuf(tmp_buf, initiator_rand);
+ WriteBufBuf(tmp_buf, responder_rand);
+ IkeHMac(ike_sa->TransformSetting.Hash, hash3, ike_sa->SKEYID_a, ike_sa->HashSize, tmp_buf->Buf, tmp_buf->Size);
+ FreeBuf(tmp_buf);
+
+ // Create an IPsec SA
+ ipsec_sa_c_s = NewIPsecSa(ike, c, ike_sa, false, header->MessageId, false, cp.NextIv, spi,
+ initiator_rand->Buf, initiator_rand->Size, responder_rand->Buf, responder_rand->Size,
+ &setting, shared_key, shared_key_size);
+ ipsec_sa_s_c = NewIPsecSa(ike, c, ike_sa, false, header->MessageId, true, cp.NextIv, setting.SpiServerToClient,
+ initiator_rand->Buf, initiator_rand->Size, responder_rand->Buf, responder_rand->Size,
+ &setting, shared_key, shared_key_size);
+
+ ipsec_sa_c_s->PairIPsecSa = ipsec_sa_s_c;
+ ipsec_sa_s_c->PairIPsecSa = ipsec_sa_c_s;
+
+ Insert(ike->IPsecSaList, ipsec_sa_c_s);
+ Insert(ike->IPsecSaList, ipsec_sa_s_c);
+
+ Copy(ipsec_sa_c_s->Hash3, hash3, ike_sa->HashSize);
+
+ // Overwrite hash #2
+ Copy(send_hash_payload->Payload.Hash.Data->Buf, hash2, ike_sa->HashSize);
+
+ // Packet reply
+ ps->FlagEncrypted = true;
+ IPsecSaSendPacket(ike, ipsec_sa_s_c, ps);
+ IkeSaSendPacket(ike, ike_sa, NULL);
+
+#ifdef RAW_DEBUG
+ IkeDebugUdpSendRawPacket(ps);
+#endif // RAW_DEBUG
+
+ IkeFree(ps);
+ Free(shared_key);
+ FreeBuf(ps_buf_after_hash);
+ FreeBuf(initiator_rand);
+ FreeBuf(responder_rand);
+ }
+ }
+ else
+ {
+ // No appropriate transform setting
+ Debug("No Appropriate Transform was Found.\n");
+
+ IPsecLog(ike, NULL, ike_sa, NULL, "LI_IPSEC_NO_TRANSFORM");
+
+ SendInformationalExchangePacket(ike, c, IkeNewNoticeErrorNoProposalChosenPayload(true, header->InitiatorCookie, header->ResponderCookie));
+ }
+ }
+ }
+ else
+ {
+ Debug("QM-1: Hash 1 is invalid.\n");
+ }
+
+ FreeBuf(hash1_buf);
+ }
+ }
+
+ IkeFree(pr);
+ }
+ }
+ else
+ {
+ // Get the IPsec SA
+ IPSECSA *ipsec_sa_cs = SearchIPsecSaByMessageId(ike, c, header->MessageId);
+ if (ipsec_sa_cs != NULL)
+ {
+ IPSECSA *ipsec_sa_sc = ipsec_sa_cs->PairIPsecSa;
+ if (ipsec_sa_sc != NULL)
+ {
+ if (ipsec_sa_sc->Established == false && ipsec_sa_cs->Established == false)
+ {
+ IKE_PACKET *pr = IPsecSaRecvPacket(ike, ipsec_sa_cs, p->Data, p->Size);
+
+#ifdef RAW_DEBUG
+ IkeDebugUdpSendRawPacket(pr);
+#endif // RAW_DEBUG
+
+ if (pr != NULL)
+ {
+ if (ipsec_sa_cs->Initiated == false)
+ {
+ // Initiator is client-side
+ // Check hash3 payload
+ IKE_PACKET_PAYLOAD *hash_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_HASH, 0);
+
+ if (hash_payload != NULL)
+ {
+ BUF *hash_buf = hash_payload->Payload.Hash.Data;
+ if (hash_buf != NULL)
+ {
+ if (hash_buf->Size == ipsec_sa_cs->IkeSa->HashSize)
+ {
+ if (Cmp(hash_buf->Buf, ipsec_sa_cs->Hash3, hash_buf->Size) == 0)
+ {
+ ipsec_sa_cs->Established = ipsec_sa_sc->Established = true;
+ ipsec_sa_cs->EstablishedTick = ipsec_sa_sc->EstablishedTick = ike->Now;
+ ipsec_sa_cs->LastCommTick = ipsec_sa_sc->LastCommTick = ike->Now;
+
+ c->CurrentIpSecSaRecv = ipsec_sa_cs;
+ c->CurrentIpSecSaSend = ipsec_sa_sc;
+
+ Debug("IPsec SA 0x%X & 0x%X Established.\n",
+ ipsec_sa_cs->Spi,
+ ipsec_sa_sc->Spi);
+
+ IPsecLog(ike, NULL, NULL, ipsec_sa_sc, "LI_IPSEC_SA_ESTABLISHED");
+
+ IPsecSaSendPacket(ike, ipsec_sa_sc, NULL);
+ }
+ else
+ {
+ Debug("QM-3: Hash 3 is invalid.\n");
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Initiator is server-side
+ // Get hash payload
+ IKE_PACKET_PAYLOAD *hash_payload;
+
+ hash_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_HASH, 0);
+ if (hash_payload != NULL && ipsec_sa_sc->InitiatorRand != NULL)
+ {
+ // Get the payload after the hash
+ UINT header_and_hash_size = sizeof(IKE_COMMON_HEADER) + hash_payload->BitArray->Size;
+ void *after_hash_data = ((UCHAR *)pr->DecryptedPayload->Buf) + header_and_hash_size;
+ if (pr->DecryptedPayload->Size > header_and_hash_size)
+ {
+ UINT after_hash_size = pr->DecryptedPayload->Size - header_and_hash_size;
+ UCHAR hash2[IKE_MAX_HASH_SIZE];
+ BUF *hash2_buf;
+
+ hash2_buf = NewBuf();
+ WriteBufInt(hash2_buf, header->MessageId);
+ WriteBufBuf(hash2_buf, ipsec_sa_sc->InitiatorRand);
+ WriteBuf(hash2_buf, after_hash_data, after_hash_size);
+
+ IkeHMac(ipsec_sa_sc->SKEYID_Hash, hash2, ipsec_sa_sc->SKEYID_a, ipsec_sa_sc->SKEYID_Hash->HashSize,
+ hash2_buf->Buf, hash2_buf->Size);
+
+ FreeBuf(hash2_buf);
+
+ // Compare the hash value
+ if (IkeCompareHash(hash_payload, hash2, ike_sa->HashSize))
+ {
+ IKE_PACKET_PAYLOAD *sa_payload, *rand_payload, *key_payload, *id_payload_1, *id_payload_2;
+
+ // Get the payload of other
+ sa_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_SA, 0);
+ rand_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_RAND, 0);
+ key_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_KEY_EXCHANGE, 0);
+ id_payload_1 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_ID, 0);
+ id_payload_2 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_ID, 1);
+
+ if (sa_payload != NULL && rand_payload != NULL)
+ {
+ IPSEC_SA_TRANSFORM_SETTING setting;
+
+ // Interpret the SA payload
+ if (GetBestTransformSettingForIPsecSa(ike, pr, &setting, &p->DstIP))
+ {
+ // Appropriate transform setting is selected
+ Debug("P2 Transform: %s %s %s(%u) %u %u\n",
+ (setting.Dh == NULL ? NULL : setting.Dh->Name), setting.Hash->Name, setting.Crypto->Name, setting.CryptoKeySize,
+ setting.LifeKilobytes, setting.LifeSeconds);
+
+#ifdef FORCE_LIFETIME_QM
+ setting.LifeSeconds = FORCE_LIFETIME_QM;
+#endif // FORCE_LIFETIME_QM
+
+ // Check the key exchange payload if the PFS is specified
+ if (setting.Dh == NULL || (setting.Dh != NULL && key_payload != NULL && ipsec_sa_sc->Dh != NULL &&
+ key_payload->Payload.KeyExchange.Data->Size <= setting.Dh->KeySize))
+ {
+ IKE_PACKET *ps;
+ LIST *payload_list;
+ IKE_PACKET_PAYLOAD *send_hash_payload;
+ IKE_PACKET_PAYLOAD *send_key_payload = NULL;
+ IKE_PACKET_PAYLOAD *send_id_1 = NULL, *send_id_2 = NULL;
+ DH_CTX *dh = NULL;
+ UINT shared_key_size = 0;
+ UCHAR *shared_key = NULL;
+ BUF *initiator_rand, *responder_rand;
+ BUF *tmp_buf;
+ UCHAR hash3[IKE_MAX_HASH_SIZE];
+ char tmp[MAX_SIZE];
+ UCHAR zero = 0;
+
+ initiator_rand = ipsec_sa_sc->InitiatorRand;
+ responder_rand = CloneBuf(rand_payload->Payload.Rand.Data);
+
+ if (setting.Dh != NULL)
+ {
+ // Calculate DH
+ DH_CTX *dh = ipsec_sa_sc->Dh;
+
+ shared_key_size = (dh == NULL ? 0 : dh->Size);
+ shared_key = ZeroMalloc(shared_key_size);
+
+ if (DhCompute(dh, shared_key, key_payload->Payload.KeyExchange.Data->Buf, key_payload->Payload.KeyExchange.Data->Size))
+ {
+ // DH calculation success
+ Debug("P2 DH Ok.\n");
+ }
+ else
+ {
+ // DH calculation failure
+ Debug("P2 DhCompute failed.\n");
+
+ shared_key = NULL;
+ Free(shared_key);
+ shared_key_size = 0;
+
+ IPsecLog(ike, NULL, ike_sa, NULL, "LI_QM_DH_ERROR");
+ }
+ }
+
+ // Update the information of IPsec SA
+ if (shared_key != NULL)
+ {
+ ipsec_sa_sc->SharedKey = NewBuf(shared_key, shared_key_size);
+ ipsec_sa_cs->SharedKey = NewBuf(shared_key, shared_key_size);
+ }
+
+ ipsec_sa_sc->Spi = setting.SpiServerToClient;
+ IPsecLog(ike, NULL, NULL, ipsec_sa_sc, "LI_IPSEC_SA_SPI_SET", ipsec_sa_sc->Spi);
+ ike->IPsecSaList->sorted = false;
+
+ ipsec_sa_sc->ResponderRand = CloneBuf(responder_rand);
+ ipsec_sa_cs->ResponderRand = CloneBuf(responder_rand);
+
+ Copy(&ipsec_sa_sc->TransformSetting, &setting, sizeof(IPSEC_SA_TRANSFORM_SETTING));
+ Copy(&ipsec_sa_cs->TransformSetting, &setting, sizeof(IPSEC_SA_TRANSFORM_SETTING));
+
+ ipsec_sa_sc->Established = true;
+ ipsec_sa_cs->Established = true;
+
+ IPsecLog(ike, NULL, NULL, ipsec_sa_sc, "LI_IPSEC_SA_ESTABLISHED");
+
+ ipsec_sa_sc->LastCommTick = ike->Now;
+ ipsec_sa_cs->LastCommTick = ike->Now;
+
+ c->CurrentIpSecSaRecv = ipsec_sa_cs;
+ c->CurrentIpSecSaSend = ipsec_sa_sc;
+
+ // Calculate the KEYMAT
+ IPsecCalcKeymat(ike, ipsec_sa_sc->SKEYID_Hash, ipsec_sa_sc->KeyMat, sizeof(ipsec_sa_sc->KeyMat),
+ ipsec_sa_sc->SKEYID_d, ipsec_sa_sc->SKEYID_Hash->HashSize, IKE_PROTOCOL_ID_IPSEC_ESP,
+ ipsec_sa_sc->Spi, initiator_rand->Buf, initiator_rand->Size,
+ responder_rand->Buf, responder_rand->Size,
+ shared_key, shared_key_size);
+
+ IPsecCalcKeymat(ike, ipsec_sa_cs->SKEYID_Hash, ipsec_sa_cs->KeyMat, sizeof(ipsec_sa_cs->KeyMat),
+ ipsec_sa_cs->SKEYID_d, ipsec_sa_cs->SKEYID_Hash->HashSize, IKE_PROTOCOL_ID_IPSEC_ESP,
+ ipsec_sa_cs->Spi, initiator_rand->Buf, initiator_rand->Size,
+ responder_rand->Buf, responder_rand->Size,
+ shared_key, shared_key_size);
+
+ IkeFreeKey(ipsec_sa_sc->CryptoKey);
+ IkeFreeKey(ipsec_sa_cs->CryptoKey);
+
+ ipsec_sa_sc->CryptoKey = IkeNewKey(setting.Crypto, ipsec_sa_sc->KeyMat, setting.CryptoKeySize);
+ ipsec_sa_cs->CryptoKey = IkeNewKey(setting.Crypto, ipsec_sa_cs->KeyMat, setting.CryptoKeySize);
+
+ Copy(ipsec_sa_sc->HashKey, ipsec_sa_sc->KeyMat + setting.CryptoKeySize, setting.Hash->HashSize);
+ Copy(ipsec_sa_cs->HashKey, ipsec_sa_cs->KeyMat + setting.CryptoKeySize, setting.Hash->HashSize);
+
+ BinToStrEx(tmp, sizeof(tmp), ipsec_sa_sc->KeyMat, ipsec_sa_sc->TransformSetting.CryptoKeySize);
+ Debug(" KEYMAT (SC): %s\n", tmp);
+
+ BinToStrEx(tmp, sizeof(tmp), ipsec_sa_cs->KeyMat, ipsec_sa_cs->TransformSetting.CryptoKeySize);
+ Debug(" KEYMAT (CS): %s\n", tmp);
+
+ Debug("IPsec SA 0x%X & 0x%X Established (Server is Initiator).\n",
+ ipsec_sa_cs->Spi,
+ ipsec_sa_sc->Spi);
+
+ // Calculate the hash #3
+ tmp_buf = NewBuf();
+ WriteBuf(tmp_buf, &zero, 1);
+ WriteBufInt(tmp_buf, header->MessageId);
+ WriteBufBuf(tmp_buf, initiator_rand);
+ WriteBufBuf(tmp_buf, responder_rand);
+ IkeHMac(ipsec_sa_cs->SKEYID_Hash, hash3, ipsec_sa_cs->SKEYID_a, ipsec_sa_cs->SKEYID_Hash->HashSize, tmp_buf->Buf, tmp_buf->Size);
+ FreeBuf(tmp_buf);
+
+ // Return the hash #3
+ send_hash_payload = IkeNewDataPayload(IKE_PAYLOAD_HASH, hash3, ipsec_sa_cs->SKEYID_Hash->HashSize);
+
+ payload_list = NewListSingle(send_hash_payload);
+ ps = IkeNew(ike_sa->InitiatorCookie, ike_sa->ResponderCookie,
+ IKE_EXCHANGE_TYPE_QUICK, true, false, false, header->MessageId, payload_list);
+
+ IPsecSaSendPacket(ike, ipsec_sa_sc, ps);
+#ifdef RAW_DEBUG
+ IkeDebugUdpSendRawPacket(ps);
+#endif // RAW_DEBUG
+ ipsec_sa_sc->NumResends = 3;
+
+ if (false)
+ {
+ UINT i;
+
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+
+ if (sa != ipsec_sa_sc && sa != ipsec_sa_cs)
+ {
+ MarkIPsecSaAsDeleted(ike, sa);
+ }
+ }
+ }
+
+ IkeFree(ps);
+
+ // Release the memory
+ FreeBuf(responder_rand);
+ }
+ }
+ else
+ {
+ // No appropriate transform setting
+ Debug("No Appropriate Transform was Found.\n");
+
+ IPsecLog(ike, NULL, ike_sa, NULL, "LI_IPSEC_NO_TRANSFORM");
+
+ SendInformationalExchangePacket(ike, c, IkeNewNoticeErrorNoProposalChosenPayload(true, header->InitiatorCookie, header->ResponderCookie));
+ }
+ }
+ }
+ }
+ }
+ }
+ IkeFree(pr);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// Calculate the KEYMAT
+void IPsecCalcKeymat(IKE_SERVER *ike, IKE_HASH *h, void *dst, UINT dst_size, void *skeyid_d_data, UINT skeyid_d_size, UCHAR protocol, UINT spi, void *rand_init_data, UINT rand_init_size,
+ void *rand_resp_data, UINT rand_resp_size, void *df_key_data, UINT df_key_size)
+{
+ BUF *k;
+ BUF *ret;
+ // Validate arguments
+ if (ike == NULL || dst == NULL || h == NULL || rand_init_data == NULL || rand_resp_data == NULL||
+ (df_key_size != 0 && df_key_data == NULL))
+ {
+ return;
+ }
+
+ ret = NewBuf();
+
+ k = NULL;
+
+ while (true)
+ {
+ BUF *tmp = NewBuf();
+ UCHAR hash[IKE_MAX_HASH_SIZE];
+
+ if (k != NULL)
+ {
+ WriteBufBuf(tmp, k);
+ }
+
+ if (df_key_data != NULL)
+ {
+ WriteBuf(tmp, df_key_data, df_key_size);
+ }
+
+ WriteBuf(tmp, &protocol, 1);
+
+ WriteBufInt(tmp, spi);
+
+ WriteBuf(tmp, rand_init_data, rand_init_size);
+ WriteBuf(tmp, rand_resp_data, rand_resp_size);
+
+ if (k != NULL)
+ {
+ FreeBuf(k);
+ }
+
+ IkeHMac(h, hash, skeyid_d_data, skeyid_d_size, tmp->Buf, tmp->Size);
+
+ FreeBuf(tmp);
+
+ k = MemToBuf(hash, h->HashSize);
+
+ WriteBufBuf(ret, k);
+
+ if (ret->Size >= dst_size)
+ {
+ break;
+ }
+ }
+
+ Copy(dst, ret->Buf, dst_size);
+
+ FreeBuf(ret);
+ FreeBuf(k);
+}
+
+// Search for IPsec SA from Message ID
+IPSECSA *SearchIPsecSaByMessageId(IKE_SERVER *ike, IKE_CLIENT *c, UINT message_id)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL || c == NULL || message_id == 0)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+
+ if (sa->IkeClient == c)
+ {
+ if (sa->MessageId == message_id)
+ {
+ if (sa->ServerToClient == false)
+ {
+ if (sa->Established == false)
+ {
+ return sa;
+ }
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+// Search for IPsec SA from SPI value
+IPSECSA *SearchClientToServerIPsecSaBySpi(IKE_SERVER *ike, UINT spi)
+{
+ IPSECSA t;
+ // Validate arguments
+ if (ike == NULL || spi == 0)
+ {
+ return NULL;
+ }
+
+ t.ServerToClient = false;
+ t.Spi = spi;
+
+ return Search(ike->IPsecSaList, &t);
+}
+IPSECSA *SearchIPsecSaBySpi(IKE_SERVER *ike, IKE_CLIENT *c, UINT spi)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL || c == NULL || spi == 0)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+
+ if (sa->Spi == spi)
+ {
+ if (sa->IkeClient == c)
+ {
+ return sa;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+// Search an IKE SA from the value of the Cookie
+IKE_SA *SearchIkeSaByCookie(IKE_SERVER *ike, UINT64 init_cookie, UINT64 resp_cookie)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+
+ if (sa->InitiatorCookie == init_cookie && sa->ResponderCookie == resp_cookie)
+ {
+ return sa;
+ }
+ }
+
+ return NULL;
+}
+
+// Generate the SPI value of new IPsec SA
+UINT GenerateNewIPsecSaSpi(IKE_SERVER *ike, UINT counterpart_spi)
+{
+ UINT ret;
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return 0;
+ }
+
+ while (true)
+ {
+ ret = Rand32();
+
+ if (ret != counterpart_spi)
+ {
+ if (ret >= 4096 && ret != INFINITE)
+ {
+ if (SearchClientToServerIPsecSaBySpi(ike, ret) == NULL)
+ {
+ return ret;
+ }
+ }
+ }
+ }
+}
+
+// Calculate the initial IV for Phase 2
+void IkeCalcPhase2InitialIv(void *iv, IKE_SA *sa, UINT message_id)
+{
+ BUF *b;
+ UCHAR hash[IKE_MAX_HASH_SIZE];
+ // Validate arguments
+ if (iv == NULL || sa == NULL)
+ {
+ return;
+ }
+
+ message_id = Endian32(message_id);
+
+ b = NewBuf();
+ WriteBuf(b, sa->Iv, sa->BlockSize);
+ WriteBuf(b, &message_id, sizeof(UINT));
+
+ IkeHash(sa->TransformSetting.Hash, hash, b->Buf, b->Size);
+
+ Copy(iv, hash, sa->TransformSetting.Crypto->BlockSize);
+
+ FreeBuf(b);
+}
+
+// Create a new IPsec SA
+IPSECSA *NewIPsecSa(IKE_SERVER *ike, IKE_CLIENT *c, IKE_SA *ike_sa, bool initiate, UINT message_id, bool server_to_client, void *iv, UINT spi, void *init_rand_data, UINT init_rand_size, void *res_rand_data, UINT res_rand_size, IPSEC_SA_TRANSFORM_SETTING *setting, void *shared_key_data, UINT shared_key_size)
+{
+ IPSECSA *sa;
+ char tmp[MAX_SIZE];
+ UINT total_key_size;
+ // Validate arguments
+ if (ike == NULL || c == NULL || ike_sa == NULL || message_id == 0 || iv == NULL || setting == NULL ||
+ (shared_key_data == NULL && shared_key_size != 0))
+ {
+ return NULL;
+ }
+
+ sa = ZeroMalloc(sizeof(IPSECSA));
+
+ if (server_to_client == false)
+ {
+ ike->CurrentIPsecSaId++;
+ }
+ sa->Id = ike->CurrentIPsecSaId;
+
+ sa->IkeClient = c;
+ sa->IkeSa = ike_sa;
+
+ sa->MessageId = message_id;
+ sa->FirstCommTick = ike->Now;
+ sa->LastCommTick = ike->Now;
+ sa->Initiated = initiate;
+
+ sa->ServerToClient = server_to_client;
+
+ sa->Spi = spi;
+
+ sa->SKEYID_Hash = ike_sa->TransformSetting.Hash;
+ Copy(sa->SKEYID_a, ike_sa->SKEYID_a, sa->SKEYID_Hash->HashSize);
+ Copy(sa->SKEYID_d, ike_sa->SKEYID_d, sa->SKEYID_Hash->HashSize);
+
+ sa->InitiatorRand = MemToBuf(init_rand_data, init_rand_size);
+
+ if (initiate == false)
+ {
+ sa->ResponderRand = MemToBuf(res_rand_data, res_rand_size);
+ }
+
+ Copy(sa->Iv, iv, ike_sa->BlockSize);
+
+ Copy(&sa->TransformSetting, setting, sizeof(IPSEC_SA_TRANSFORM_SETTING));
+
+ if (shared_key_data != NULL)
+ {
+ sa->SharedKey = MemToBuf(shared_key_data, shared_key_size);
+ }
+
+ total_key_size = sa->TransformSetting.CryptoKeySize + sa->TransformSetting.Hash->HashSize;
+
+ if (initiate == false)
+ {
+ IPsecCalcKeymat(ike, ike_sa->TransformSetting.Hash, sa->KeyMat, total_key_size,
+ ike_sa->SKEYID_d, ike_sa->HashSize, IKE_PROTOCOL_ID_IPSEC_ESP, spi, sa->InitiatorRand->Buf,
+ sa->InitiatorRand->Size, sa->ResponderRand->Buf, sa->ResponderRand->Size,
+ shared_key_data, shared_key_size);
+
+ sa->CryptoKey = IkeNewKey(sa->TransformSetting.Crypto, sa->KeyMat, sa->TransformSetting.CryptoKeySize);
+
+ Copy(sa->HashKey, sa->KeyMat + sa->TransformSetting.CryptoKeySize, sa->TransformSetting.Hash->HashSize);
+ }
+
+ Debug("New IPsec SA (StoC = %u): 0x%X 0x%X (%s %s %s(%u) %u %u)\n",
+ sa->ServerToClient,
+ sa->MessageId,
+ sa->Spi,
+ (setting->Dh == NULL ? NULL : setting->Dh->Name), setting->Hash->Name, setting->Crypto->Name, setting->CryptoKeySize,
+ setting->LifeKilobytes, setting->LifeSeconds);
+
+ IPsecLog(ike, c, NULL, sa, "LI_NEW_IPSEC_SA",
+ (sa->ServerToClient ? _UU("LI_TAG_SERVER_TO_CLIENT") : _UU("LI_TAG_CLIENT_TO_SERVER")),
+ sa->Spi,
+ (setting->Dh == NULL ? NULL : setting->Dh->Name), setting->Hash->Name, setting->Crypto->Name, setting->CryptoKeySize * 8,
+ setting->LifeKilobytes, setting->LifeSeconds);
+
+ Rand(sa->EspIv, sizeof(sa->EspIv));
+
+ if (initiate == false)
+ {
+ BinToStrEx(tmp, sizeof(tmp), sa->KeyMat, sa->TransformSetting.CryptoKeySize);
+ Debug(" KEYMAT: %s\n", tmp);
+ }
+
+ // Set the expiration time
+ if (setting->LifeSeconds != 0)
+ {
+ UINT64 span = (UINT64)(setting->LifeSeconds * 1000) + (UINT64)IKE_SOFT_EXPIRES_MARGIN;
+ sa->ExpiresHardTick = ike->Now + span;
+ sa->ExpiresSoftTick = ike->Now + span;
+ //sa->ExpiresSoftTick = ike->Now + (UINT64)5000;
+
+ AddInterrupt(ike->Interrupts, sa->ExpiresSoftTick);
+ }
+
+ return sa;
+}
+
+// Treat aggressive mode packet reception
+void ProcIkeAggressiveModePacketRecv(IKE_SERVER *ike, UDPPACKET *p, IKE_PACKET *header)
+{
+ IKE_CLIENT *c;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (ike == NULL || p == NULL || header == NULL || header->InitiatorCookie == 0)
+ {
+ return;
+ }
+
+ c = SearchOrCreateNewIkeClientForIkePacket(ike, &p->SrcIP, p->SrcPort, &p->DstIP, p->DestPort, header);
+
+ if (c == NULL)
+ {
+ return;
+ }
+
+ if (header->ResponderCookie == 0)
+ {
+ // Start process of the state 1
+ IKE_CAPS caps;
+ IKE_SA *sa;
+ IKE_PACKET *pr = IkeParse(p->Data, p->Size, NULL);
+
+ if (pr != NULL)
+ {
+ // Determine the CAPS
+ IkeCheckCaps(&caps, pr);
+ if (caps.MS_L2TPIPSecVPNClient || caps.MS_NT5_ISAKMP_OAKLEY || caps.MS_Vid_InitialContact)
+ {
+ c->IsMicrosoft = true;
+ }
+
+ if ((caps.NatTraversalDraftIetf || caps.NatTraversalRfc3947) || (IsUdpPortOpened(ike->IPsec->UdpListener, &p->DstIP, IPSEC_PORT_IPSEC_ESP_RAW)))
+ {
+ sa = FindIkeSaByEndPointAndInitiatorCookie(ike, &p->DstIP, p->DestPort, &p->SrcIP, p->SrcPort, header->InitiatorCookie, IKE_SA_AGRESSIVE_MODE);
+
+ if (sa == NULL)
+ {
+ // Check whether there is acceptable SA parameters by analyzing proposed parameters
+ IKE_SA_TRANSFORM_SETTING setting;
+
+ if (GetBestTransformSettingForIkeSa(ike, pr, &setting) && (GetNumberOfIkeSaOfIkeClient(ike, c) <= IKE_QUOTA_MAX_SA_PER_CLIENT))
+ {
+ IKE_PACKET_PAYLOAD *tp;
+ IKE_PACKET_PAYLOAD *pp;
+ IKE_PACKET_PAYLOAD *sap;
+ IKE_PACKET_PAYLOAD *client_sa_payload;
+ IKE_PACKET_PAYLOAD *your_key_payload;
+ IKE_PACKET_PAYLOAD *your_rand_payload;
+ IKE_PACKET_PAYLOAD *your_id_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_ID, 0);
+
+ // Appropriate transform setting is selected
+ Debug("P1 Transform: %s %s %s(%u) %u %u\n",
+ setting.Dh->Name, setting.Hash->Name, setting.Crypto->Name, setting.CryptoKeySize,
+ setting.LifeKilobytes, setting.LifeSeconds);
+
+ // Receive a key exchange packet
+ your_key_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_KEY_EXCHANGE, 0);
+ your_rand_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_RAND, 0);
+ if (your_key_payload != NULL && your_rand_payload != NULL && your_id_payload != NULL)
+ {
+ // Check the key payload
+ BUF *your_key_buf = your_key_payload->Payload.KeyExchange.Data;
+ BUF *your_rand_buf = your_rand_payload->Payload.Rand.Data;
+
+ // DH generation
+ DH_CTX *dh = IkeDhNewCtx(setting.Dh);
+ UINT shared_key_size = (dh == NULL ? 0 : dh->Size);
+ UCHAR *shared_key = ZeroMalloc(shared_key_size);
+
+ // DH calculation
+ if (DhCompute(dh, shared_key, your_key_buf->Buf, your_key_buf->Size))
+ {
+ IKE_PACKET *ps;
+ LIST *payload_list;
+ IKE_PACKET_PAYLOAD *my_key_payload;
+ IKE_PACKET_PAYLOAD *my_rand_payload;
+ BUF *nat_buf1, *nat_buf2;
+ BUF *iv_buf;
+ UCHAR iv_hashed_data[IKE_MAX_HASH_SIZE];
+ UCHAR initiator_hash[IKE_MAX_HASH_SIZE];
+ BUF *b;
+ IKE_PACKET_PAYLOAD *my_id_payload, *my_hash_payload;
+ UCHAR responder_hash[IKE_MAX_HASH_SIZE];
+ BUF *idir_b;
+ IKE_PACKET_PAYLOAD *your_nat_d_1 = NULL;
+ IKE_PACKET_PAYLOAD *your_nat_d_2 = NULL;
+
+ // Create an IKE SA
+ sa = NewIkeSa(ike, c, header->InitiatorCookie, IKE_SA_AGRESSIVE_MODE, &setting);
+ Copy(&sa->Caps, &caps, sizeof(IKE_CAPS));
+ sa->State= IKE_SA_AM_STATE_1_SA;
+ Insert(ike->IkeSaList, sa);
+
+ sa->HashSize = sa->TransformSetting.Hash->HashSize;
+ sa->KeySize = sa->TransformSetting.CryptoKeySize;
+ sa->BlockSize = sa->TransformSetting.Crypto->BlockSize;
+
+ // Get the Caps additionally
+ if (sa->Caps.NatTraversalRfc3947)
+ {
+ sa->Caps.UsingNatTraversalRfc3947 = true;
+
+ your_nat_d_1 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_D, 0);
+ your_nat_d_2 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_D, 1);
+ }
+ else if (sa->Caps.NatTraversalDraftIetf)
+ {
+ sa->Caps.UsingNatTraversalDraftIetf = true;
+
+ your_nat_d_1 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_D_DRAFT, 0);
+ your_nat_d_2 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_D_DRAFT, 1);
+ }
+
+ // Calculation success
+ sa->DhSharedKey = MemToBuf(shared_key, shared_key_size);
+ sa->InitiatorRand = RandBuf(IKE_SA_RAND_SIZE);
+ sa->ResponderRand = CloneBuf(your_rand_buf);
+
+ // Save a bit array of SA payload presented by the client
+ client_sa_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_SA, 0);
+ sa->SAi_b = CloneBuf(client_sa_payload->BitArray);
+
+ // Save the ID payload presented by the client
+ sa->YourIDPayloadForAM = CloneBuf(your_id_payload->BitArray);
+
+ //// Assemble the SA payload
+ // Construct transform payload
+ tp = TransformSettingToTransformPayloadForIke(ike, &setting);
+
+ // Build a proposal payload
+ pp = IkeNewProposalPayload(1, IKE_PROTOCOL_ID_IKE, NULL, 0, NewListSingle(tp));
+
+ // Build the SA payload
+ sap = IkeNewSaPayload(NewListSingle(pp));
+
+ payload_list = NewListSingle(sap);
+
+ // Send a key exchange packet
+ my_key_payload = IkeNewDataPayload(IKE_PAYLOAD_KEY_EXCHANGE, dh->MyPublicKey->Buf, dh->MyPublicKey->Size);
+ my_rand_payload = IkeNewDataPayload(IKE_PAYLOAD_RAND, sa->InitiatorRand->Buf, sa->InitiatorRand->Size);
+
+ Add(payload_list, my_key_payload);
+ Add(payload_list, my_rand_payload);
+
+ // NAT-D Packet
+ // Address of the opponent. Randomize in order to be forced to use NAT
+ nat_buf1 = IkeCalcNatDetectHash(ike, sa->TransformSetting.Hash, Rand64(), Rand64(), &c->ClientIP, Rand16());
+
+ // My address
+ if (c->IsMicrosoft == false || (your_nat_d_1 == NULL || your_nat_d_2 == NULL || your_nat_d_1->BitArray == NULL))
+ {
+ // Calculate exactly
+ nat_buf2 = IkeCalcNatDetectHash(ike, sa->TransformSetting.Hash,
+ sa->InitiatorCookie, sa->ResponderCookie, &c->ServerIP, c->ServerPort);
+ }
+ else
+ {
+ // Parrot the NAT_D payload indicating myself I got from
+ // the other if it has connected from a Microsoft VPN Client
+ nat_buf2 = CloneBuf(your_nat_d_1->BitArray);
+ }
+
+ // Save DH information
+ sa->GXi = CloneBuf(your_key_buf);
+ sa->GXr = CloneBuf(dh->MyPublicKey);
+
+ // Calculate the key set
+ IkeCalcSaKeySet(ike, sa, NULL);
+
+ // Calculate the initiator side hash value
+ b = NewBuf();
+ WriteBufBuf(b, sa->GXi);
+ WriteBufBuf(b, sa->GXr);
+ WriteBufInt64(b, sa->InitiatorCookie);
+ WriteBufInt64(b, sa->ResponderCookie);
+ WriteBufBuf(b, sa->SAi_b);
+ WriteBufBuf(b, sa->YourIDPayloadForAM);
+
+ IkeHMac(sa->TransformSetting.Hash, initiator_hash, sa->SKEYID, sa->HashSize,
+ b->Buf, b->Size);
+
+ FreeBuf(b);
+
+ Copy(sa->InitiatorHashForAM, initiator_hash, sa->HashSize);
+
+ // Prepare the response ID payload
+ // Generate the ID payload
+ if (IsIP6(&sa->IkeClient->ServerIP))
+ {
+ // IPv6 address
+ my_id_payload = IkeNewIdPayload(IKE_ID_IPV6_ADDR, 0, 0, sa->IkeClient->ServerIP.ipv6_addr, 16);
+ }
+ else
+ {
+ // IPv4 address
+ my_id_payload = IkeNewIdPayload(IKE_ID_IPV4_ADDR, 0, 0, sa->IkeClient->ServerIP.addr, 4);
+ }
+
+ // Build the ID payload tentatively
+ idir_b = IkeBuildIdPayload(&my_id_payload->Payload.Id);
+
+ b = NewBuf();
+ WriteBufBuf(b, sa->GXr);
+ WriteBufBuf(b, sa->GXi);
+ WriteBufInt64(b, sa->ResponderCookie);
+ WriteBufInt64(b, sa->InitiatorCookie);
+ WriteBufBuf(b, sa->SAi_b);
+ WriteBufBuf(b, idir_b);
+
+ IkeHMac(sa->TransformSetting.Hash, responder_hash, sa->SKEYID, sa->HashSize,
+ b->Buf, b->Size);
+
+ FreeBuf(b);
+ FreeBuf(idir_b);
+
+ my_hash_payload = IkeNewDataPayload(IKE_PAYLOAD_HASH, responder_hash, sa->HashSize);
+
+ Add(payload_list, my_id_payload);
+ Add(payload_list, my_hash_payload);
+
+ ps = IkeNew(sa->InitiatorCookie, sa->ResponderCookie, IKE_EXCHANGE_TYPE_AGGRESSIVE,
+ false, false, false, 0, payload_list);
+
+ // Add the vendor ID
+ IkeAddVendorIdPayloads(ps);
+
+ // NAT-D related
+ if (sa->Caps.UsingNatTraversalRfc3947)
+ {
+ // RFC-compliant
+ Add(payload_list, IkeNewDataPayload(IKE_PAYLOAD_NAT_D, nat_buf1->Buf, nat_buf1->Size));
+ Add(payload_list, IkeNewDataPayload(IKE_PAYLOAD_NAT_D, nat_buf2->Buf, nat_buf2->Size));
+ }
+
+ if (sa->Caps.UsingNatTraversalDraftIetf)
+ {
+ // Draft compliant
+ Add(payload_list, IkeNewDataPayload(IKE_PAYLOAD_NAT_D_DRAFT, nat_buf1->Buf, nat_buf1->Size));
+ Add(payload_list, IkeNewDataPayload(IKE_PAYLOAD_NAT_D_DRAFT, nat_buf2->Buf, nat_buf2->Size));
+ }
+
+ FreeBuf(nat_buf1);
+ FreeBuf(nat_buf2);
+
+ StrCpy(c->ClientId, sizeof(c->ClientId), your_id_payload->Payload.Id.StrData);
+ Debug("Client ID = %s\n", c->ClientId);
+
+ IPsecLog(ike, c, NULL, NULL, NULL, "LI_SET_CLIENT_ID", c->ClientId);
+
+ // Initial IV setting
+ iv_buf = NewBuf();
+ WriteBuf(iv_buf, your_key_buf->Buf, your_key_buf->Size);
+ WriteBuf(iv_buf, dh->MyPublicKey->Buf, dh->MyPublicKey->Size);
+ IkeHash(sa->TransformSetting.Hash, iv_hashed_data, iv_buf->Buf, iv_buf->Size);
+
+ BinToStrEx(tmp, sizeof(tmp), iv_hashed_data, sa->BlockSize);
+ Debug("Initial IV: %s\n", tmp);
+
+ IkeSaUpdateIv(sa, iv_hashed_data, sa->HashSize);
+
+ FreeBuf(iv_buf);
+
+ // Transmission
+ IkeSaSendPacket(ike, sa, ps);
+
+ IkeFree(ps);
+ }
+ else
+ {
+ // DH calculation failure
+ Debug("DhCompute failed.\n");
+ }
+
+ Free(shared_key);
+ DhFree(dh);
+ }
+ }
+ else
+ {
+ // No appropriate transform setting
+ Debug("No Appropriate Transform was Found.\n");
+
+ IPsecLog(ike, c, NULL, NULL, "LI_IKE_NO_TRANSFORM");
+
+ SendInformationalExchangePacket(ike, c, IkeNewNoticeErrorNoProposalChosenPayload(false, header->InitiatorCookie, header->ResponderCookie));
+ }
+ }
+ }
+ else
+ {
+ // Client does not support NAT Traversal
+ Debug("Client doesn't support NAT-T.\n");
+
+ IPsecLog(ike, c, NULL, NULL, "LI_IKE_NO_NAT_T");
+ }
+
+ IkeFree(pr);
+ }
+ }
+ else
+ {
+ // Process of state 2
+ IKE_SA *sa;
+
+ sa = FindIkeSaByResponderCookieAndClient(ike, header->ResponderCookie, c);
+
+ if (sa == NULL)
+ {
+ SendInformationalExchangePacketEx(ike, c, IkeNewNoticeErrorInvalidCookiePayload(header->InitiatorCookie,
+ header->ResponderCookie), true, header->InitiatorCookie, header->ResponderCookie);
+ }
+
+ if (sa != NULL && sa->Mode == IKE_SA_AGRESSIVE_MODE)
+ {
+ IKE_PACKET *pr = NULL;
+
+ sa->LastCommTick = ike->Now;
+
+ switch (sa->State)
+ {
+ case IKE_SA_AM_STATE_1_SA:
+ pr = IkeSaRecvPacket(ike, sa, p->Data, p->Size);
+ if (pr != NULL)
+ {
+ IKE_PACKET_PAYLOAD *your_hash_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_HASH, 0);
+
+ if (your_hash_payload != NULL)
+ {
+ // Compare the hash
+ if (IkeCompareHash(your_hash_payload, sa->InitiatorHashForAM, sa->HashSize))
+ {
+ // Transit to the established state
+ Debug("IKE SA 0x%X Established.\n", sa);
+ sa->State = IKE_SA_AM_STATE_2_ESTABLISHED;
+ sa->EstablishedTick = ike->Now;
+ sa->Established = true;
+ c->CurrentIkeSa = sa;
+ c->NextDpdSendTick = ike->Now + (UINT64)IKE_INTERVAL_DPD_KEEPALIVE;
+ StrCpy(c->Secret, sizeof(c->Secret), sa->Secret);
+
+ IPsecLog(ike, NULL, sa, NULL, "LI_IKE_SA_ESTABLISHED");
+
+ IkeSaSendPacket(ike, sa, NULL);
+ }
+ else
+ {
+ Debug("IKE SA 0x%X Invalid Hash.\n", sa);
+ }
+ }
+ }
+ break;
+ }
+
+ if (pr != NULL)
+ {
+ IkeFree(pr);
+ }
+ }
+ }
+}
+
+// Process of the main mode packet reception
+void ProcIkeMainModePacketRecv(IKE_SERVER *ike, UDPPACKET *p, IKE_PACKET *header)
+{
+ IKE_CLIENT *c;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (ike == NULL || p == NULL || header == NULL || header->InitiatorCookie == 0)
+ {
+ return;
+ }
+
+ c = SearchOrCreateNewIkeClientForIkePacket(ike, &p->SrcIP, p->SrcPort, &p->DstIP, p->DestPort, header);
+
+ if (c == NULL)
+ {
+ return;
+ }
+
+ if (header->ResponderCookie == 0)
+ {
+ // Start process of the state 1
+ IKE_CAPS caps;
+ IKE_SA *sa;
+ IKE_PACKET *pr = IkeParse(p->Data, p->Size, NULL);
+
+ if (pr != NULL)
+ {
+ // Determine the CAPS
+ IkeCheckCaps(&caps, pr);
+ if (caps.MS_L2TPIPSecVPNClient || caps.MS_NT5_ISAKMP_OAKLEY || caps.MS_Vid_InitialContact)
+ {
+ c->IsMicrosoft = true;
+ }
+
+ if ((caps.NatTraversalDraftIetf || caps.NatTraversalRfc3947) || (IsUdpPortOpened(ike->IPsec->UdpListener, &p->DstIP, IPSEC_PORT_IPSEC_ESP_RAW)))
+ {
+ sa = FindIkeSaByEndPointAndInitiatorCookie(ike, &p->DstIP, p->DestPort, &p->SrcIP, p->SrcPort, header->InitiatorCookie, IKE_SA_MAIN_MODE);
+
+ if (sa == NULL)
+ {
+ // Check whether there is acceptable SA parameters by analyzing proposed parameters
+ IKE_SA_TRANSFORM_SETTING setting;
+
+ if (GetBestTransformSettingForIkeSa(ike, pr, &setting) && (GetNumberOfIkeSaOfIkeClient(ike, c) <= IKE_QUOTA_MAX_SA_PER_CLIENT))
+ {
+ IKE_PACKET *ps;
+ IKE_PACKET_PAYLOAD *tp;
+ IKE_PACKET_PAYLOAD *pp;
+ IKE_PACKET_PAYLOAD *sap;
+ LIST *payload_list;
+ IKE_PACKET_PAYLOAD *client_sa_payload;
+
+ // Appropriate transform setting is selected
+ Debug("P1 Transform: %s %s %s(%u) %u %u\n",
+ setting.Dh->Name, setting.Hash->Name, setting.Crypto->Name, setting.CryptoKeySize,
+ setting.LifeKilobytes, setting.LifeSeconds);
+
+#ifdef FORCE_LIFETIME_MM
+ setting.LifeSeconds = FORCE_LIFETIME_MM;
+#endif // FORCE_LIFETIME_MM
+
+ // Create an IKE SA
+ sa = NewIkeSa(ike, c, header->InitiatorCookie, IKE_SA_MAIN_MODE, &setting);
+
+ Copy(&sa->Caps, &caps, sizeof(IKE_CAPS));
+
+ Insert(ike->IkeSaList, sa);
+
+ // Answer the SA parameter selection results
+ sa->State = IKE_SA_MM_STATE_1_SA;
+
+ // Save a bit array of SA payload presented by the client
+ client_sa_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_SA, 0);
+ sa->SAi_b = CloneBuf(client_sa_payload->BitArray);
+
+ //// Assemble the SA payload
+ // Construct a transform payload
+ tp = TransformSettingToTransformPayloadForIke(ike, &setting);
+
+ // Build a proposal payload
+ pp = IkeNewProposalPayload(1, IKE_PROTOCOL_ID_IKE, NULL, 0, NewListSingle(tp));
+
+ // Build a SA payload
+ sap = IkeNewSaPayload(NewListSingle(pp));
+
+ payload_list = NewListSingle(sap);
+
+ ps = IkeNew(sa->InitiatorCookie, sa->ResponderCookie, IKE_EXCHANGE_TYPE_MAIN,
+ false, false, false, 0, payload_list);
+
+ // Add the vendor ID payload
+ IkeAddVendorIdPayloads(ps);
+
+ IkeSaSendPacket(ike, sa, ps);
+
+ sa->HashSize = sa->TransformSetting.Hash->HashSize;
+ sa->KeySize = sa->TransformSetting.CryptoKeySize;
+ sa->BlockSize = sa->TransformSetting.Crypto->BlockSize;
+
+ IkeFree(ps);
+ }
+ else
+ {
+ // No appropriate transform setting
+ Debug("No Appropriate Transform was Found.\n");
+
+ IPsecLog(ike, c, NULL, NULL, "LI_IKE_NO_TRANSFORM");
+
+ SendInformationalExchangePacket(ike, c, IkeNewNoticeErrorNoProposalChosenPayload(false, header->InitiatorCookie, header->ResponderCookie));
+ }
+ }
+ else
+ {
+ // Ignore for IKE SA which already exists (Because it's likely to be a re-transmission)
+ }
+ }
+ else
+ {
+ // It does not support NAT Traversal
+ Debug("Client doesn't support NAT-T.\n");
+
+ IPsecLog(ike, c, NULL, NULL, "LI_IKE_NO_NAT_T");
+ }
+ IkeFree(pr);
+ }
+ }
+ else
+ {
+ // Process of state 2 or later
+ IKE_SA *sa;
+
+ sa = FindIkeSaByResponderCookieAndClient(ike, header->ResponderCookie, c);
+
+ if (sa == NULL)
+ {
+ SendInformationalExchangePacketEx(ike, c, IkeNewNoticeErrorInvalidCookiePayload(header->InitiatorCookie,
+ header->ResponderCookie), true, header->InitiatorCookie, header->ResponderCookie);
+ }
+
+ if (sa != NULL && sa->Mode == IKE_SA_MAIN_MODE)
+ {
+ IKE_PACKET *pr = NULL;
+
+ sa->LastCommTick = ike->Now;
+
+ switch (sa->State)
+ {
+ case IKE_SA_MM_STATE_1_SA:
+ pr = IkeSaRecvPacket(ike, sa, p->Data, p->Size);
+ if (pr != NULL)
+ {
+ // Receive a key exchange packet
+ IKE_PACKET_PAYLOAD *your_key_payload;
+ IKE_PACKET_PAYLOAD *your_rand_payload;
+ IKE_PACKET_PAYLOAD *your_nat_d_1 = NULL;
+ IKE_PACKET_PAYLOAD *your_nat_d_2 = NULL;
+
+ your_key_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_KEY_EXCHANGE, 0);
+ your_rand_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_RAND, 0);
+
+ if (IkeGetPayloadNum(pr->PayloadList, IKE_PAYLOAD_NAT_D) != 0)
+ {
+ sa->Caps.UsingNatTraversalRfc3947 = true;
+
+ your_nat_d_1 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_D, 0);
+ your_nat_d_2 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_D, 1);
+ }
+
+ if (IkeGetPayloadNum(pr->PayloadList, IKE_PAYLOAD_NAT_D_DRAFT) != 0)
+ {
+ sa->Caps.UsingNatTraversalDraftIetf = true;
+
+ your_nat_d_1 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_D_DRAFT, 0);
+ your_nat_d_2 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_D_DRAFT, 1);
+ }
+
+ if (your_key_payload != NULL && your_rand_payload != NULL)
+ {
+ // Check the key payload
+ BUF *your_key_buf = your_key_payload->Payload.KeyExchange.Data;
+ BUF *your_rand_buf = your_rand_payload->Payload.Rand.Data;
+
+ // DH generation
+ DH_CTX *dh = IkeDhNewCtx(sa->TransformSetting.Dh);
+ UINT shared_key_size = (dh == NULL ? 0 : dh->Size);
+ UCHAR *shared_key = ZeroMalloc(shared_key_size);
+
+ // DH calculation
+ if (DhCompute(dh, shared_key, your_key_buf->Buf, your_key_buf->Size))
+ {
+ IKE_PACKET *ps;
+ LIST *payload_list;
+ IKE_PACKET_PAYLOAD *my_key_payload;
+ IKE_PACKET_PAYLOAD *my_rand_payload;
+ BUF *nat_buf1, *nat_buf2;
+ BUF *iv_buf;
+ UCHAR iv_hashed_data[IKE_MAX_HASH_SIZE];
+
+ // Calculation success
+ sa->DhSharedKey = MemToBuf(shared_key, shared_key_size);
+ sa->InitiatorRand = RandBuf(IKE_SA_RAND_SIZE);
+ sa->ResponderRand = CloneBuf(your_rand_buf);
+
+ // Send a key exchange packet
+ my_key_payload = IkeNewDataPayload(IKE_PAYLOAD_KEY_EXCHANGE, dh->MyPublicKey->Buf, dh->MyPublicKey->Size);
+ my_rand_payload = IkeNewDataPayload(IKE_PAYLOAD_RAND, sa->InitiatorRand->Buf, sa->InitiatorRand->Size);
+
+ payload_list = NewListSingle(my_key_payload);
+ Add(payload_list, my_rand_payload);
+
+ // NAT-D packet
+ // Address of the opponent. Randomize in order to be forced to use NAT
+ nat_buf1 = IkeCalcNatDetectHash(ike, sa->TransformSetting.Hash, Rand64(), Rand64(), &c->ClientIP, Rand16());
+ //nat_buf1 = IkeCalcNatDetectHash(ike, sa->TransformSetting.Hash, sa->InitiatorCookie, sa->ResponderCookie, &c->ClientIP, c->ClientPort);
+ // My address
+
+ if (c->IsMicrosoft == false || (your_nat_d_1 == NULL || your_nat_d_2 == NULL || your_nat_d_1->BitArray == NULL))
+ {
+ // Calculate exactly
+ nat_buf2 = IkeCalcNatDetectHash(ike, sa->TransformSetting.Hash,
+ sa->InitiatorCookie, sa->ResponderCookie, &c->ServerIP, c->ServerPort);
+ }
+ else
+ {
+ // Parrot the NAT_D payload indicating myself I got from
+ // the other if it has connected from a Microsoft VPN Client
+ nat_buf2 = CloneBuf(your_nat_d_1->BitArray);
+ }
+
+ if (sa->Caps.UsingNatTraversalRfc3947)
+ {
+ // RFC-compliant
+ Add(payload_list, IkeNewDataPayload(IKE_PAYLOAD_NAT_D, nat_buf1->Buf, nat_buf1->Size));
+ Add(payload_list, IkeNewDataPayload(IKE_PAYLOAD_NAT_D, nat_buf2->Buf, nat_buf2->Size));
+ }
+
+ if (sa->Caps.UsingNatTraversalDraftIetf)
+ {
+ // Draft compliant
+ Add(payload_list, IkeNewDataPayload(IKE_PAYLOAD_NAT_D_DRAFT, nat_buf1->Buf, nat_buf1->Size));
+ Add(payload_list, IkeNewDataPayload(IKE_PAYLOAD_NAT_D_DRAFT, nat_buf2->Buf, nat_buf2->Size));
+ }
+
+ FreeBuf(nat_buf1);
+ FreeBuf(nat_buf2);
+
+ ps = IkeNew(sa->InitiatorCookie, sa->ResponderCookie, IKE_EXCHANGE_TYPE_MAIN,
+ false, false, false, 0, payload_list);
+
+ // Initial IV setting
+ iv_buf = NewBuf();
+ WriteBuf(iv_buf, your_key_buf->Buf, your_key_buf->Size);
+ WriteBuf(iv_buf, dh->MyPublicKey->Buf, dh->MyPublicKey->Size);
+ IkeHash(sa->TransformSetting.Hash, iv_hashed_data, iv_buf->Buf, iv_buf->Size);
+
+ BinToStrEx(tmp, sizeof(tmp), iv_hashed_data, sa->BlockSize);
+ Debug("Initial IV: %s\n", tmp);
+
+ IkeSaUpdateIv(sa, iv_hashed_data, sa->HashSize);
+
+ FreeBuf(iv_buf);
+
+ // Save the DH information
+ sa->GXi = CloneBuf(your_key_buf);
+ sa->GXr = CloneBuf(dh->MyPublicKey);
+
+ // Transmission
+ IkeSaSendPacket(ike, sa, ps);
+
+ IkeFree(ps);
+
+ // Calculate the key set
+ IkeCalcSaKeySet(ike, sa, NULL);
+
+ sa->State = IKE_SA_MM_STATE_2_KEY;
+ }
+ else
+ {
+ // DH calculation failure
+ Debug("DhCompute failed.\n");
+ }
+
+ Free(shared_key);
+ DhFree(dh);
+ }
+ }
+ break;
+
+ case IKE_SA_MM_STATE_2_KEY:
+ pr = IkeSaRecvPacket(ike, sa, p->Data, p->Size);
+ if (pr != NULL && pr->FlagEncrypted)
+ {
+ // Receive an ID exchange packet
+ IKE_PACKET_PAYLOAD *your_id_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_ID, 0);
+ IKE_PACKET_PAYLOAD *your_hash_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_HASH, 0);
+
+ if (your_id_payload && your_hash_payload)
+ {
+ UCHAR initiator_hash[IKE_MAX_HASH_SIZE];
+ BUF *b;
+
+ // Calculate the initiator side hash value
+ b = NewBuf();
+ WriteBufBuf(b, sa->GXi);
+ WriteBufBuf(b, sa->GXr);
+ WriteBufInt64(b, sa->InitiatorCookie);
+ WriteBufInt64(b, sa->ResponderCookie);
+ WriteBufBuf(b, sa->SAi_b);
+ WriteBufBuf(b, your_id_payload->BitArray);
+
+ StrCpy(c->ClientId, sizeof(c->ClientId), your_id_payload->Payload.Id.StrData);
+ Debug("Client ID = %s\n", c->ClientId);
+ IPsecLog(ike, c, NULL, NULL, NULL, "LI_SET_CLIENT_ID", c->ClientId);
+
+ IkeHMac(sa->TransformSetting.Hash, initiator_hash, sa->SKEYID, sa->HashSize,
+ b->Buf, b->Size);
+
+ FreeBuf(b);
+
+ // Hash comparison
+ if (IkeCompareHash(your_hash_payload, initiator_hash, sa->HashSize))
+ {
+ // Generate a response packet
+ IKE_PACKET *ps;
+ LIST *payload_list = NewListFast(NULL);
+ IKE_PACKET_PAYLOAD *my_id_payload, *my_hash_payload;
+ UCHAR responder_hash[IKE_MAX_HASH_SIZE];
+ BUF *idir_b;
+
+ // Generate an ID payload
+ if (IsIP6(&sa->IkeClient->ServerIP))
+ {
+ // IPv6 address
+ my_id_payload = IkeNewIdPayload(IKE_ID_IPV6_ADDR, 0, 0, sa->IkeClient->ServerIP.ipv6_addr, 16);
+ }
+ else
+ {
+ // IPv4 address
+ my_id_payload = IkeNewIdPayload(IKE_ID_IPV4_ADDR, 0, 0, sa->IkeClient->ServerIP.addr, 4);
+ }
+
+ // Build the ID payload tentatively
+ idir_b = IkeBuildIdPayload(&my_id_payload->Payload.Id);
+
+ // Generate the hash payload
+ b = NewBuf();
+ WriteBufBuf(b, sa->GXr);
+ WriteBufBuf(b, sa->GXi);
+ WriteBufInt64(b, sa->ResponderCookie);
+ WriteBufInt64(b, sa->InitiatorCookie);
+ WriteBufBuf(b, sa->SAi_b);
+ WriteBufBuf(b, idir_b);
+
+ IkeHMac(sa->TransformSetting.Hash, responder_hash, sa->SKEYID, sa->HashSize,
+ b->Buf, b->Size);
+
+ FreeBuf(b);
+ FreeBuf(idir_b);
+
+ my_hash_payload = IkeNewDataPayload(IKE_PAYLOAD_HASH, responder_hash, sa->HashSize);
+
+ Add(payload_list, my_id_payload);
+ Add(payload_list, my_hash_payload);
+
+ ps = IkeNew(sa->InitiatorCookie, sa->ResponderCookie, IKE_EXCHANGE_TYPE_MAIN, true, false,
+ false, 0, payload_list);
+
+ // Transmission
+ IkeSaSendPacket(ike, sa, ps);
+ sa->NumResends = 3;
+
+ IkeFree(ps);
+
+ StrCpy(c->ClientId, sizeof(c->ClientId), your_id_payload->Payload.Id.StrData);
+
+ // Transit to the established state
+ Debug("IKE SA 0x%X Established. Client ID=%s\n", sa, c->ClientId);
+ sa->State = IKE_SA_MM_STATE_3_ESTABLISHED;
+ sa->EstablishedTick = ike->Now;
+ c->CurrentIkeSa = sa;
+ c->NextDpdSendTick = ike->Now + (UINT64)IKE_INTERVAL_DPD_KEEPALIVE;
+ StrCpy(c->Secret, sizeof(c->Secret), sa->Secret);
+ sa->Established = true;
+
+ IPsecLog(ike, NULL, sa, NULL, "LI_IKE_SA_ESTABLISHED");
+ }
+ else
+ {
+ Debug("IKE SA 0x%X Invalid Hash.\n", sa);
+ }
+ }
+ }
+ break;
+ }
+
+ if (pr != NULL)
+ {
+ IkeFree(pr);
+ }
+ }
+ }
+}
+
+// Update the IV of IPsec SA
+void IPsecSaUpdateIv(IPSECSA *sa, void *iv, UINT iv_size)
+{
+ // Validate arguments
+ if (sa == NULL || iv == NULL)
+ {
+ return;
+ }
+
+ Copy(sa->Iv, iv, MIN(sa->IkeSa->BlockSize, iv_size));
+
+ if (iv_size < sa->IkeSa->BlockSize)
+ {
+ Zero(sa->Iv + sa->IkeSa->BlockSize, sa->IkeSa->BlockSize - iv_size);
+ }
+
+ sa->IsIvExisting = true;
+}
+
+// Update the IV of the IKE SA
+void IkeSaUpdateIv(IKE_SA *sa, void *iv, UINT iv_size)
+{
+ // Validate arguments
+ if (sa == NULL || iv == NULL)
+ {
+ return;
+ }
+
+ Copy(sa->Iv, iv, MIN(sa->BlockSize, iv_size));
+
+ if (iv_size < sa->BlockSize)
+ {
+ Zero(sa->Iv + sa->BlockSize, sa->BlockSize - iv_size);
+ }
+
+ sa->IsIvExisting = true;
+}
+
+// Calculate the key set of the IKE SA
+void IkeCalcSaKeySet(IKE_SERVER *ike, IKE_SA *sa, char *secret)
+{
+ BUF *secret_buf;
+ BUF *rand_buf;
+ BUF *d_buf, *a_buf, *e_buf;
+ UCHAR u;
+ IKE_HASH *h;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (ike == NULL || sa == NULL)
+ {
+ return;
+ }
+
+ h = sa->TransformSetting.Hash;
+
+ // Calculation of SKEYID
+ StrCpy(sa->Secret, sizeof(sa->Secret), secret == NULL ? ike->Secret : secret);
+ secret_buf = IkeStrToPassword(sa->Secret);
+ rand_buf = CloneBuf(sa->ResponderRand);
+ SeekBufToEnd(rand_buf);
+ BinToStrEx(tmp, sizeof(tmp), rand_buf->Buf, rand_buf->Size);
+ Debug("ResponderRand: %s\n", tmp);
+ BinToStrEx(tmp, sizeof(tmp), sa->InitiatorRand->Buf, sa->InitiatorRand->Size);
+ Debug("InitiatorRand: %s\n", tmp);
+
+ WriteBufBuf(rand_buf, sa->InitiatorRand);
+
+ IkeHMacBuf(h, sa->SKEYID, secret_buf, rand_buf);
+
+ BinToStrEx(tmp, sizeof(tmp), sa->SKEYID, sa->HashSize);
+ Debug("SKEYID: %s\n", tmp);
+
+ // SKEYID_d
+ d_buf = CloneBuf(sa->DhSharedKey);
+ SeekBufToEnd(d_buf);
+ WriteBufInt64(d_buf, sa->InitiatorCookie);
+ WriteBufInt64(d_buf, sa->ResponderCookie);
+ u = 0;
+ WriteBuf(d_buf, &u, 1);
+ IkeHMac(h, sa->SKEYID_d, sa->SKEYID, sa->HashSize, d_buf->Buf, d_buf->Size);
+
+ BinToStrEx(tmp, sizeof(tmp), sa->SKEYID_d, sa->HashSize);
+ Debug("SKEYID_d: %s\n", tmp);
+
+ // SKEYID_a
+ a_buf = MemToBuf(sa->SKEYID_d, sa->HashSize);
+ SeekBufToEnd(a_buf);
+ WriteBufBuf(a_buf, sa->DhSharedKey);
+ WriteBufInt64(a_buf, sa->InitiatorCookie);
+ WriteBufInt64(a_buf, sa->ResponderCookie);
+ u = 1;
+ WriteBuf(a_buf, &u, 1);
+ IkeHMac(h, sa->SKEYID_a, sa->SKEYID, sa->HashSize, a_buf->Buf, a_buf->Size);
+
+ BinToStrEx(tmp, sizeof(tmp), sa->SKEYID_a, sa->HashSize);
+ Debug("SKEYID_a: %s\n", tmp);
+
+ // SKEYID_e
+ e_buf = MemToBuf(sa->SKEYID_a, sa->HashSize);
+ SeekBufToEnd(e_buf);
+ WriteBufBuf(e_buf, sa->DhSharedKey);
+ WriteBufInt64(e_buf, sa->InitiatorCookie);
+ WriteBufInt64(e_buf, sa->ResponderCookie);
+ u = 2;
+ WriteBuf(e_buf, &u, 1);
+ IkeHMac(h, sa->SKEYID_e, sa->SKEYID, sa->HashSize, e_buf->Buf, e_buf->Size);
+
+ BinToStrEx(tmp, sizeof(tmp), sa->SKEYID_e, sa->HashSize);
+ Debug("SKEYID_e: %s\n", tmp);
+
+ if (sa->CryptoKey != NULL)
+ {
+ IkeFreeKey(sa->CryptoKey);
+ }
+
+ sa->CryptoKey = IkeNewCryptoKeyFromK(ike, sa->SKEYID_e, sa->HashSize, sa->TransformSetting.Hash,
+ sa->TransformSetting.Crypto, sa->TransformSetting.CryptoKeySize);
+
+ // Release the memory
+ FreeBuf(secret_buf);
+ FreeBuf(rand_buf);
+ FreeBuf(d_buf);
+ FreeBuf(a_buf);
+ FreeBuf(e_buf);
+}
+
+// Extend the key size
+BUF *IkeExpandKeySize(IKE_HASH *h, void *k, UINT k_size, UINT target_size)
+{
+ BUF *b1, *b2;
+ UCHAR tmp[IKE_MAX_HASH_SIZE];
+ UINT tmp_size;
+ // Validate arguments
+ if (h == NULL || k == NULL || k_size == 0)
+ {
+ return NULL;
+ }
+
+ if (k_size >= target_size)
+ {
+ return MemToBuf(k, target_size);
+ }
+
+ tmp[0] = 0;
+ tmp_size = 1;
+ b1 = NewBuf();
+
+ do
+ {
+ IkeHMac(h, tmp, k, k_size, tmp, tmp_size);
+ WriteBuf(b1, tmp, h->HashSize);
+
+ tmp_size = h->HashSize;
+ }
+ while (b1->Size < target_size);
+
+ b2 = MemToBuf(b1->Buf, target_size);
+
+ FreeBuf(b1);
+
+ return b2;
+}
+
+// Generate a key from K
+IKE_CRYPTO_KEY *IkeNewCryptoKeyFromK(IKE_SERVER *ike, void *k, UINT k_size, IKE_HASH *h, IKE_CRYPTO *c, UINT crypto_key_size)
+{
+ BUF *key_buf;
+ IKE_CRYPTO_KEY *ret;
+ // Validate arguments
+ if (ike == NULL || k == NULL || k_size == 0 || h == NULL || c == NULL || crypto_key_size == 0)
+ {
+ return NULL;
+ }
+
+ key_buf = IkeExpandKeySize(h, k, k_size, crypto_key_size);
+ if (key_buf == NULL)
+ {
+ return NULL;
+ }
+
+ ret = IkeNewKey(c, key_buf->Buf, key_buf->Size);
+
+ FreeBuf(key_buf);
+
+ return ret;
+}
+
+// Generate a hash for NAT detection
+BUF *IkeCalcNatDetectHash(IKE_SERVER *ike, IKE_HASH *hash, UINT64 initiator_cookie, UINT64 responder_cookie, IP *ip, UINT port)
+{
+ BUF *b;
+ USHORT us;
+ USHORT hash_data[IKE_MAX_HASH_SIZE];
+ // Validate arguments
+ if (ike == NULL || ip == NULL || hash == NULL)
+ {
+ return NewBuf();
+ }
+
+ b = NewBuf();
+
+ WriteBufInt64(b, initiator_cookie);
+ WriteBufInt64(b, responder_cookie);
+
+ if (IsIP6(ip))
+ {
+ WriteBuf(b, ip->ipv6_addr, sizeof(ip->ipv6_addr));
+ }
+ else
+ {
+ WriteBuf(b, ip->addr, sizeof(ip->addr));
+ }
+
+ us = Endian16((USHORT)port);
+
+ WriteBuf(b, &us, sizeof(USHORT));
+
+ IkeHash(hash, hash_data, b->Buf, b->Size);
+
+ FreeBuf(b);
+
+ return MemToBuf(hash_data, hash->HashSize);
+}
+
+// Check the capacity of the opposite IPsec client
+void IkeCheckCaps(IKE_CAPS *caps, IKE_PACKET *p)
+{
+ // Validate arguments
+ if (caps == NULL || p == NULL)
+ {
+ Zero(caps, sizeof(IKE_CAPS));
+ return;
+ }
+
+ Zero(caps, sizeof(IKE_CAPS));
+
+ caps->NatTraversalRfc3947 = IkeIsVendorIdExists(p, IKE_VENDOR_ID_RFC3947_NAT_T);
+
+ caps->NatTraversalDraftIetf = IkeIsVendorIdExists(p, IKE_VENDOR_ID_IPSEC_NAT_T_IKE_03) ||
+ IkeIsVendorIdExists(p, IKE_VENDOR_ID_IPSEC_NAT_T_IKE_02) ||
+ IkeIsVendorIdExists(p, IKE_VENDOR_ID_IPSEC_NAT_T_IKE_02_2) ||
+ IkeIsVendorIdExists(p, IKE_VENDOR_ID_IPSEC_NAT_T_IKE_00);
+
+ caps->DpdRfc3706 = IkeIsVendorIdExists(p, IKE_VENDOR_ID_RFC3706_DPD);
+
+ caps->MS_L2TPIPSecVPNClient = IkeIsVendorIdExists(p, IKE_VENDOR_ID_MICROSOFT_L2TP);
+ caps->MS_NT5_ISAKMP_OAKLEY = IkeIsVendorIdExists(p, IKE_VENDOR_ID_MS_NT5_ISAKMPOAKLEY);
+ caps->MS_Vid_InitialContact = IkeIsVendorIdExists(p, IKE_VENDOR_ID_MS_VID_INITIALCONTACT);
+}
+
+// Check whether the specified vendor ID is contained in the packet
+bool IkeIsVendorIdExists(IKE_PACKET *p, char *str)
+{
+ BUF *buf;
+ UINT i, num;
+ bool ok = false;
+ // Validate arguments
+ if (p == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ buf = IkeStrToVendorId(str);
+ if (buf == NULL)
+ {
+ return false;
+ }
+
+ num = IkeGetPayloadNum(p->PayloadList, IKE_PAYLOAD_VENDOR_ID);
+ for (i = 0;i < num;i++)
+ {
+ IKE_PACKET_PAYLOAD *payload = IkeGetPayload(p->PayloadList, IKE_PAYLOAD_VENDOR_ID, i);
+
+ if (CompareBuf(payload->Payload.VendorId.Data, buf))
+ {
+ ok = true;
+ }
+ else
+ {
+ if (payload->Payload.VendorId.Data != NULL)
+ {
+ if (payload->Payload.VendorId.Data->Size >= buf->Size)
+ {
+ if (Cmp(payload->Payload.VendorId.Data->Buf, buf->Buf, buf->Size) == 0)
+ {
+ ok = true;
+ }
+ }
+ }
+ }
+ }
+
+ FreeBuf(buf);
+
+ return ok;
+}
+
+// Add the vendor ID payload list
+void IkeAddVendorIdPayloads(IKE_PACKET *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ IkeAddVendorId(p, IKE_VENDOR_ID_RFC3947_NAT_T);
+ IkeAddVendorId(p, IKE_VENDOR_ID_IPSEC_NAT_T_IKE_03);
+ IkeAddVendorId(p, IKE_VENDOR_ID_IPSEC_NAT_T_IKE_02);
+ IkeAddVendorId(p, IKE_VENDOR_ID_IPSEC_NAT_T_IKE_02_2);
+ IkeAddVendorId(p, IKE_VENDOR_ID_IPSEC_NAT_T_IKE_00);
+ IkeAddVendorId(p, IKE_VENDOR_ID_RFC3706_DPD);
+}
+
+// Add the vendor ID payload
+void IkeAddVendorId(IKE_PACKET *p, char *str)
+{
+ BUF *buf;
+ IKE_PACKET_PAYLOAD *payload;
+ // Validate arguments
+ if (p == NULL || str == NULL)
+ {
+ return;
+ }
+
+ buf = IkeStrToVendorId(str);
+ if (buf == NULL)
+ {
+ return;
+ }
+
+ payload = IkeNewDataPayload(IKE_PAYLOAD_VENDOR_ID, buf->Buf, buf->Size);
+
+ Add(p->PayloadList, payload);
+
+ FreeBuf(buf);
+}
+
+// Convert string to the vendor ID
+BUF *IkeStrToVendorId(char *str)
+{
+ // Validate arguments
+ if (IsEmptyStr(str))
+ {
+ return NULL;
+ }
+
+ if (StartWith(str, "0x"))
+ {
+ BUF *buf = StrToBin(str + 2);
+
+ if (buf == NULL || buf->Size == 0)
+ {
+ FreeBuf(buf);
+ return NULL;
+ }
+
+ return buf;
+ }
+ else
+ {
+ BUF *buf;
+ UCHAR hash[MD5_SIZE];
+
+ Hash(hash, str, StrLen(str), false);
+
+ buf = MemToBuf(hash, sizeof(hash));
+
+ return buf;
+ }
+}
+
+// Receive a packet using the IKE SA
+IKE_PACKET *IkeSaRecvPacket(IKE_SERVER *ike, IKE_SA *sa, void *data, UINT size)
+{
+ IKE_PACKET *ret;
+ // Validate arguments
+ if (ike == NULL || sa == NULL || (size != 0 && data == NULL))
+ {
+ return NULL;
+ }
+
+ if (sa->IsIvExisting == false || sa->CryptoKey == NULL)
+ {
+ ret = IkeParse(data, size, NULL);
+ }
+ else
+ {
+ IKE_CRYPTO_PARAM cp;
+
+ Copy(&cp.Iv, sa->Iv, sa->BlockSize);
+ cp.Key = sa->CryptoKey;
+
+ ret = IkeParse(data, size, &cp);
+
+ if (ret->FlagEncrypted)
+ {
+ IkeSaUpdateIv(sa, cp.NextIv, sa->BlockSize);
+ }
+ }
+
+ return ret;
+}
+
+// Receive a packet using IPsec SA (Quick Mode received)
+IKE_PACKET *IPsecSaRecvPacket(IKE_SERVER *ike, IPSECSA *sa, void *data, UINT size)
+{
+ IKE_PACKET *ret;
+ // Validate arguments
+ if (ike == NULL || sa == NULL || (size != 0 && data == NULL))
+ {
+ return NULL;
+ }
+
+ if (sa->IsIvExisting == false || sa->IkeSa->CryptoKey == NULL)
+ {
+ ret = IkeParse(data, size, NULL);
+ }
+ else
+ {
+ IKE_CRYPTO_PARAM cp;
+
+ Copy(&cp.Iv, sa->Iv, sa->IkeSa->BlockSize);
+ cp.Key = sa->IkeSa->CryptoKey;
+
+ ret = IkeParse(data, size, &cp);
+
+ if (ret->FlagEncrypted)
+ {
+ IPsecSaUpdateIv(sa, cp.NextIv, sa->IkeSa->BlockSize);
+ IPsecSaUpdateIv(sa->PairIPsecSa, cp.NextIv, sa->IkeSa->BlockSize);
+ }
+ }
+
+ return ret;
+}
+
+// Send a packet using IPsec SA (Quick Mode transmission)
+void IPsecSaSendPacket(IKE_SERVER *ike, IPSECSA *sa, IKE_PACKET *p)
+{
+ BUF *buf;
+ // Validate arguments
+ if (ike == NULL || sa == NULL)
+ {
+ return;
+ }
+
+ if (p == NULL)
+ {
+ FreeBuf(sa->SendBuffer);
+ sa->SendBuffer = NULL;
+ sa->NextSendTick = 0;
+ return;
+ }
+
+ // Build a packet
+ if (p->FlagEncrypted == false)
+ {
+ buf = IkeBuild(p, NULL);
+ }
+ else
+ {
+ IKE_CRYPTO_PARAM cp;
+
+ Copy(cp.Iv, sa->Iv, sa->IkeSa->BlockSize);
+ cp.Key = sa->IkeSa->CryptoKey;
+
+ buf = IkeBuild(p, &cp);
+
+ IPsecSaUpdateIv(sa, cp.NextIv, sa->IkeSa->BlockSize);
+ IPsecSaUpdateIv(sa->PairIPsecSa, cp.NextIv, sa->IkeSa->BlockSize);
+ }
+
+ if (buf == NULL)
+ {
+ return;
+ }
+
+ // Register the last packet to re-transmit
+ if (sa->SendBuffer != NULL)
+ {
+ FreeBuf(sa->SendBuffer);
+ }
+
+ sa->SendBuffer = CloneBuf(buf);
+ sa->NextSendTick = ike->Now + (UINT64)(IKE_SA_RESEND_INTERVAL);
+ AddInterrupt(ike->Interrupts, sa->NextSendTick);
+
+ IkeSendUdpPacket(ike, IKE_UDP_TYPE_ISAKMP, &sa->IkeClient->ServerIP, sa->IkeClient->ServerPort,
+ &sa->IkeClient->ClientIP, sa->IkeClient->ClientPort,
+ buf->Buf, buf->Size);
+
+ Free(buf);
+}
+
+// Send a packet using the IKE SA
+void IkeSaSendPacket(IKE_SERVER *ike, IKE_SA *sa, IKE_PACKET *p)
+{
+ BUF *buf;
+ // Validate arguments
+ if (ike == NULL || sa == NULL)
+ {
+ return;
+ }
+
+ if (p == NULL)
+ {
+ FreeBuf(sa->SendBuffer);
+ sa->SendBuffer = NULL;
+ sa->NextSendTick = 0;
+ return;
+ }
+
+ // Build a packet
+ if (p->FlagEncrypted == false)
+ {
+ buf = IkeBuild(p, NULL);
+ }
+ else
+ {
+ IKE_CRYPTO_PARAM cp;
+
+ Copy(cp.Iv, sa->Iv, sa->BlockSize);
+ cp.Key = sa->CryptoKey;
+
+ buf = IkeBuild(p, &cp);
+
+ IkeSaUpdateIv(sa, cp.NextIv, sa->BlockSize);
+ }
+
+ if (buf == NULL)
+ {
+ return;
+ }
+
+ if (p->ExchangeType != IKE_EXCHANGE_TYPE_INFORMATION)
+ {
+ // Register the last packet to re-transmit
+ if (sa->SendBuffer != NULL)
+ {
+ FreeBuf(sa->SendBuffer);
+ }
+
+ sa->SendBuffer = CloneBuf(buf);
+ sa->NextSendTick = ike->Now + (UINT64)(IKE_SA_RESEND_INTERVAL);
+ AddInterrupt(ike->Interrupts, sa->NextSendTick);
+ }
+
+ IkeSendUdpPacket(ike, IKE_UDP_TYPE_ISAKMP, &sa->IkeClient->ServerIP, sa->IkeClient->ServerPort,
+ &sa->IkeClient->ClientIP, sa->IkeClient->ClientPort,
+ buf->Buf, buf->Size);
+
+ Free(buf);
+}
+
+// Send an UDP packet
+void IkeSendUdpPacket(IKE_SERVER *ike, UINT type, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, void *data, UINT size)
+{
+ UDPPACKET *p;
+ // Validate arguments
+ if (ike == NULL || server_ip == NULL || client_ip == NULL || server_port == 0 || client_port == 0 || data == NULL || size == 0)
+ {
+ return;
+ }
+
+ p = NewUdpPacket(server_ip, server_port, client_ip, client_port, data, size);
+
+ p->Type = type;
+
+ Add(ike->SendPacketList, p);
+}
+
+// Create an IKE SA
+IKE_SA *NewIkeSa(IKE_SERVER *ike, IKE_CLIENT *c, UINT64 init_cookie, UINT mode, IKE_SA_TRANSFORM_SETTING *setting)
+{
+ IKE_SA *sa;
+ // Validate arguments
+ if (ike == NULL || c == NULL || init_cookie == 0 || setting == NULL)
+ {
+ return NULL;
+ }
+
+ sa = ZeroMalloc(sizeof(IKE_SA));
+
+ sa->Id = ++ike->CurrentIkeSaId;
+
+ sa->IkeClient = c;
+ sa->InitiatorCookie = init_cookie;
+ sa->ResponderCookie = GenerateNewResponserCookie(ike);
+ sa->Mode = mode;
+ sa->FirstCommTick = sa->LastCommTick = ike->Now;
+ Copy(&sa->TransformSetting, setting, sizeof(IKE_SA_TRANSFORM_SETTING));
+
+ Debug("New IKE SA (Mode = %u): %I64u <--> %I64u (%s %s %s(%u) %u %u)\n",
+ mode,
+ sa->InitiatorCookie,
+ sa->ResponderCookie,
+ setting->Dh->Name, setting->Hash->Name, setting->Crypto->Name, setting->CryptoKeySize,
+ setting->LifeKilobytes, setting->LifeSeconds);
+
+ IPsecLog(ike, NULL, sa, NULL, "LI_NEW_IKE_SA",
+ (mode == IKE_SA_MAIN_MODE ? _UU("LI_TAG_MAINMODE") : _UU("LI_TAG_AGGRESSIVE")),
+ sa->InitiatorCookie, sa->ResponderCookie,
+ setting->Dh->Name, setting->Hash->Name, setting->Crypto->Name, setting->CryptoKeySize * 8,
+ setting->LifeKilobytes, setting->LifeSeconds);
+
+ return sa;
+}
+
+// Search an IKE SA from the Responder Cookie
+IKE_SA *FindIkeSaByResponderCookie(IKE_SERVER *ike, UINT64 responder_cookie)
+{
+ IKE_SA t;
+ // Validate arguments
+ if (ike == NULL || responder_cookie == 0)
+ {
+ return NULL;
+ }
+
+ t.ResponderCookie = responder_cookie;
+
+ return Search(ike->IkeSaList, &t);
+}
+
+// Search an IKE SA from the Responder Cookie and the IKE_CLIENT
+IKE_SA *FindIkeSaByResponderCookieAndClient(IKE_SERVER *ike, UINT64 responder_cookie, IKE_CLIENT *c)
+{
+ IKE_SA *sa;
+ // Validate arguments
+ if (ike == NULL || responder_cookie == 0 || c == NULL)
+ {
+ return NULL;
+ }
+
+ sa = FindIkeSaByResponderCookie(ike, responder_cookie);
+ if (sa == NULL)
+ {
+ return NULL;
+ }
+
+ if (sa->IkeClient != c)
+ {
+ return NULL;
+ }
+
+ return sa;
+}
+
+// Search an IKE SA from the endpoint and the Initiator Cookie
+IKE_SA *FindIkeSaByEndPointAndInitiatorCookie(IKE_SERVER *ike, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, UINT64 init_cookie, UINT mode)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL || client_ip == NULL || server_ip == NULL || client_port == 0 || server_port == 0 || init_cookie == 0)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+ IKE_CLIENT *c;
+
+ c = sa->IkeClient;
+
+ if (CmpIpAddr(&c->ClientIP, client_ip) == 0 &&
+ CmpIpAddr(&c->ServerIP, server_ip) == 0 &&
+ c->ClientPort == client_port &&
+ c->ServerPort == server_port &&
+ sa->InitiatorCookie == init_cookie &&
+ sa->Mode == mode)
+ {
+ return sa;
+ }
+ }
+
+ return NULL;
+}
+
+// Get the number of IPsec SA that is associated with the IKE_CLIENT
+UINT GetNumberOfIPsecSaOfIkeClient(IKE_SERVER *ike, IKE_CLIENT *c)
+{
+ UINT num = 0, i;
+ // Validate arguments
+ if (ike == NULL || c == NULL)
+ {
+ return 0;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+
+ if (sa->IkeClient == c)
+ {
+ num++;
+ }
+ }
+
+ return num;
+}
+
+// Get the number of IKE SA that is associated with the IKE_CLIENT
+UINT GetNumberOfIkeSaOfIkeClient(IKE_SERVER *ike, IKE_CLIENT *c)
+{
+ UINT num = 0, i;
+ // Validate arguments
+ if (ike == NULL || c == NULL)
+ {
+ return 0;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+
+ if (sa->IkeClient == c)
+ {
+ num++;
+ }
+ }
+
+ return num;
+}
+
+// Get the number of clients that are connected from the specified IP address
+UINT GetNumberOfIkeClientsFromIP(IKE_SERVER *ike, IP *client_ip)
+{
+ UINT i, num;
+ // Validate arguments
+ if (ike == NULL || client_ip == NULL)
+ {
+ return 0;
+ }
+
+ num = 0;
+
+ for (i = 0;i < LIST_NUM(ike->ClientList);i++)
+ {
+ IKE_CLIENT *c = LIST_DATA(ike->ClientList, i);
+
+ if (CmpIpAddr(&c->ClientIP, client_ip) == 0)
+ {
+ num++;
+ }
+ }
+
+ return num;
+}
+
+// Find the appropriate IKE client. Create if it is absent
+IKE_CLIENT *SearchOrCreateNewIkeClientForIkePacket(IKE_SERVER *ike, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, IKE_PACKET *pr)
+{
+ IKE_CLIENT *c;
+ // Validate arguments
+ if (ike == NULL || pr == NULL || client_ip == NULL || server_ip == NULL || client_port == 0 || server_port == 0 || pr == NULL)
+ {
+ return NULL;
+ }
+
+ c = SearchIkeClientForIkePacket(ike, client_ip, client_port, server_ip, server_port, pr);
+ if (c == NULL)
+ {
+ if (GetNumberOfIkeClientsFromIP(ike, client_ip) > IKE_QUOTA_MAX_NUM_CLIENTS_PER_IP ||
+ LIST_NUM(ike->ClientList) > IKE_QUOTA_MAX_NUM_CLIENTS)
+ {
+ return NULL;
+ }
+
+
+ c = NewIkeClient(ike, client_ip, client_port, server_ip, server_port);
+
+ Insert(ike->ClientList, c);
+ }
+
+ return SetIkeClientEndpoint(ike, c, client_ip, client_port, server_ip, server_port);
+}
+
+// Create an IKE client
+IKE_CLIENT *NewIkeClient(IKE_SERVER *ike, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port)
+{
+ IKE_CLIENT *c;
+ char client_ip_str[MAX_SIZE];
+ char server_ip_str[MAX_SIZE];
+ // Validate arguments
+ if (ike == NULL || client_ip == NULL || server_ip == NULL || client_port == 0 || server_port == 0)
+ {
+ return NULL;
+ }
+
+ c = ZeroMalloc(sizeof(IKE_CLIENT));
+
+ c->Id = ++ike->CurrentIkeClientId;
+
+ Copy(&c->ClientIP, client_ip, sizeof(IP));
+ c->ClientPort = client_port;
+
+ Copy(&c->ServerIP, server_ip, sizeof(IP));
+ Copy(&c->TransportModeServerIP, server_ip, sizeof(IP));
+ Copy(&c->TransportModeClientIP, client_ip, sizeof(IP));
+ c->ServerPort = server_port;
+
+ c->LastCommTick = ike->Now;
+ c->FirstCommTick = ike->Now;
+
+ IPToStr(client_ip_str, sizeof(client_ip_str), client_ip);
+ IPToStr(server_ip_str, sizeof(server_ip_str), server_ip);
+
+ Debug("New IKE_CLIENT: %p: %s:%u -> %s:%u\n", c, client_ip_str, client_port, server_ip_str, server_port);
+
+ IPsecLog(ike, c, NULL, NULL, "LI_NEW_IKE_CLIENT");
+
+ return c;
+}
+
+// Search for the best associated IKE client when an IKE packet has been received
+IKE_CLIENT *SearchIkeClientForIkePacket(IKE_SERVER *ike, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, IKE_PACKET *pr)
+{
+ IKE_CLIENT t;
+ IKE_CLIENT *c = NULL;
+ // Validate arguments
+ if (ike == NULL || pr == NULL || client_ip == NULL || server_ip == NULL || client_port == 0 || server_port == 0)
+ {
+ return NULL;
+ }
+
+ if (true)
+ {
+ UINT i;
+
+ if (pr->InitiatorCookie != 0 && pr->ResponderCookie != 0)
+ {
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+
+ // Extract what Cookie matches exactly
+ if (sa->InitiatorCookie == pr->InitiatorCookie && sa->ResponderCookie == pr->ResponderCookie)
+ {
+ IKE_CLIENT *cc = sa->IkeClient;
+
+ if (CmpIpAddr(&cc->ServerIP, server_ip) == 0 &&
+ CmpIpAddr(&cc->ClientIP, client_ip) == 0)
+ {
+ c = cc;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (c == NULL)
+ {
+ // Search by a pair of IP address and port number
+ Copy(&t.ClientIP, client_ip, sizeof(IP));
+ t.ClientPort = client_port;
+ Copy(&t.ServerIP, server_ip, sizeof(IP));
+ t.ServerPort = server_port;
+
+ c = Search(ike->ClientList, &t);
+
+ if (c != NULL)// && server_port == IPSEC_PORT_IPSEC_ISAKMP)
+ {
+ // Search that the IKE_SA that points to this IKE_CLIENT exists and match the Cookie
+ bool ok = false;
+ UINT i;
+
+ if (server_port == IPSEC_PORT_IPSEC_ESP_UDP)
+ {
+ // Regard as OK if the port number exactly match in the case of connecting to a server-side 4500
+ ok = true;
+ }
+ else
+ {
+ if (c->CurrentIkeSa != NULL &&
+ c->CurrentIkeSa->InitiatorCookie == pr->InitiatorCookie &&
+ c->CurrentIkeSa->ResponderCookie == pr->ResponderCookie)
+ {
+ ok = true;
+ }
+ else
+ {
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+
+ if (sa->IkeClient == c)
+ {
+ if (sa->InitiatorCookie == pr->InitiatorCookie &&
+ sa->ResponderCookie == pr->ResponderCookie)
+ {
+ ok = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (ok == false)
+ {
+ // Not found
+ c = NULL;
+ }
+ }
+ }
+
+ return c;
+}
+
+// Comparison of IPsec SA
+int CmpIPsecSa(void *p1, void *p2)
+{
+ IPSECSA *sa1, *sa2;
+ int r;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ sa1 = *(IPSECSA **)p1;
+ sa2 = *(IPSECSA **)p2;
+ if (sa1 == NULL || sa2 == NULL)
+ {
+ return 0;
+ }
+
+ r = COMPARE_RET(sa1->ServerToClient, sa2->ServerToClient);
+ if (r != 0)
+ {
+ return r;
+ }
+
+ r = COMPARE_RET(sa1->Spi, sa2->Spi);
+
+ return r;
+}
+
+// Comparison of IKE_SA
+int CmpIkeSa(void *p1, void *p2)
+{
+ IKE_SA *sa1, *sa2;
+ int r;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ sa1 = *(IKE_SA **)p1;
+ sa2 = *(IKE_SA **)p2;
+ if (sa1 == NULL || sa2 == NULL)
+ {
+ return 0;
+ }
+
+ r = COMPARE_RET(sa1->ResponderCookie, sa2->ResponderCookie);
+
+ return r;
+}
+
+// Comparison of IKE_CLIENT
+int CmpIkeClient(void *p1, void *p2)
+{
+ IKE_CLIENT *c1, *c2;
+ int r;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ c1 = *(IKE_CLIENT **)p1;
+ c2 = *(IKE_CLIENT **)p2;
+ if (c1 == NULL || c2 == NULL)
+ {
+ return 0;
+ }
+
+ r = CmpIpAddr(&c1->ClientIP, &c2->ClientIP);
+ if (r != 0)
+ {
+ return r;
+ }
+
+ r = CmpIpAddr(&c1->ServerIP, &c2->ServerIP);
+ if (r != 0)
+ {
+ return r;
+ }
+
+ r = COMPARE_RET(c1->ClientPort, c2->ClientPort);
+ if (r != 0)
+ {
+ return r;
+ }
+
+ r = COMPARE_RET(c1->ServerPort, c2->ServerPort);
+ if (r != 0)
+ {
+ return r;
+ }
+
+ return 0;
+}
+
+// Update the endpoint information of IKE_CLIENT
+IKE_CLIENT *SetIkeClientEndpoint(IKE_SERVER *ike, IKE_CLIENT *c, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port)
+{
+ char client_ip_str[MAX_SIZE];
+ char server_ip_str[MAX_SIZE];
+ IKE_CLIENT *ret = c;
+ IKE_CLIENT *cc;
+ IKE_CLIENT t;
+ // Validate arguments
+ if (ike == NULL || c == NULL || client_ip == NULL || client_port == 0 || server_ip == NULL || server_port == 0)
+ {
+ return NULL;
+ }
+
+ if (CmpIpAddr(&c->ClientIP, client_ip) == 0 &&
+ CmpIpAddr(&c->ServerIP, server_ip) == 0 &&
+ c->ClientPort == client_port &&
+ c->ServerPort == server_port)
+ {
+ // No change
+ return ret;
+ }
+
+ if (IS_SPECIAL_PORT(client_port) || IS_SPECIAL_PORT(server_port))
+ {
+ // Don't change in the case of Raw socket
+ return ret;
+ }
+
+ // Search for an existing IKE_CLIENT which exactly matches to combination of the new IP address and the port number
+ Copy(&t.ClientIP, client_ip, sizeof(IP));
+ t.ClientPort = client_port;
+ Copy(&t.ServerIP, server_ip, sizeof(IP));
+ t.ServerPort = server_port;
+
+ cc = Search(ike->ClientList, &t);
+ if (cc != NULL && c != cc && cc->Deleting == false && c->L2TP == NULL)
+ {
+ UINT i;
+ // Merge into this existing IKE_CLIENT since it found
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+
+ if (sa->IkeClient == c)
+ {
+ sa->IkeClient = cc;
+ }
+ }
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+
+ if (sa->IkeClient == c)
+ {
+ sa->IkeClient = cc;
+ }
+ }
+
+ if (cc->LastCommTick < c->LastCommTick)
+ {
+ StrCpy(cc->ClientId, sizeof(cc->ClientId), c->ClientId);
+ }
+
+ cc->FirstCommTick = MIN(cc->FirstCommTick, c->FirstCommTick);
+ cc->LastCommTick = MAX(cc->LastCommTick, c->LastCommTick);
+
+ ret = cc;
+
+ IPToStr(client_ip_str, sizeof(client_ip_str), client_ip);
+ IPToStr(server_ip_str, sizeof(server_ip_str), server_ip);
+
+ Debug("Merge IKE_CLIENT: %p->%p: %s:%u -> %s:%u\n", c, cc, client_ip_str, client_port, server_ip_str, server_port);
+
+ IPsecLog(ike, c, NULL, NULL, "LI_CLIENT_MERGE", c->Id, cc->Id, cc->Id);
+
+ // Remove old IKE_CLIENT from the list and free
+ Delete(ike->ClientList, c);
+ FreeIkeClient(ike, c);
+ }
+ else
+ {
+ // Rewrite the end point information of this IKE_CLIENT because not found
+ Copy(&c->ClientIP, client_ip, sizeof(IP));
+ Copy(&c->ServerIP, server_ip, sizeof(IP));
+ c->ClientPort = client_port;
+ c->ServerPort = server_port;
+
+ IPToStr(client_ip_str, sizeof(client_ip_str), client_ip);
+ IPToStr(server_ip_str, sizeof(server_ip_str), server_ip);
+
+ Debug("Update IKE_CLIENT: %p: %s:%u -> %s:%u\n", c, client_ip_str, client_port, server_ip_str, server_port);
+
+ IPsecLog(ike, c, NULL, NULL, "LI_CLIENT_UPDATE");
+
+ ike->ClientList->sorted = false;
+ }
+
+ return ret;
+}
+
+// Select the optimal transform setting for IPsec SA
+bool GetBestTransformSettingForIPsecSa(IKE_SERVER *ike, IKE_PACKET *pr, IPSEC_SA_TRANSFORM_SETTING *setting, IP *server_ip)
+{
+ IKE_PACKET_PAYLOAD *sa_payload;
+ IKE_PACKET_SA_PAYLOAD *sa;
+ UINT i, num;
+ bool ocmii_flag = false;
+ // Validate arguments
+ if (ike == NULL || pr == NULL || setting == NULL || server_ip == NULL)
+ {
+ return false;
+ }
+
+ Zero(setting, sizeof(IPSEC_SA_TRANSFORM_SETTING));
+
+ // Get the SA payload
+ sa_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_SA, 0);
+ if (sa_payload == NULL)
+ {
+ return false;
+ }
+
+ sa = &sa_payload->Payload.Sa;
+
+ // Scan all proposal payloads
+ num = IkeGetPayloadNum(sa->PayloadList, IKE_PAYLOAD_PROPOSAL);
+ for (i = 0;i < num;i++)
+ {
+ IKE_PACKET_PAYLOAD *proposal_payload = IkeGetPayload(sa->PayloadList, IKE_PAYLOAD_PROPOSAL, i);
+
+ if (proposal_payload != NULL)
+ {
+ IKE_PACKET_PROPOSAL_PAYLOAD *proposal = &proposal_payload->Payload.Proposal;
+
+ // Examine the contents of the proposal payload
+ if (proposal->ProtocolId == IKE_PROTOCOL_ID_IPSEC_ESP && proposal->Spi->Size == 4)
+ {
+ // Scan all transform payloads
+ UINT j, num2;
+
+ num2 = IkeGetPayloadNum(proposal->PayloadList, IKE_PAYLOAD_TRANSFORM);
+ for (j = 0;j < num2;j++)
+ {
+ IKE_PACKET_PAYLOAD *transform_payload = IkeGetPayload(proposal->PayloadList, IKE_PAYLOAD_TRANSFORM, j);
+ if (transform_payload != NULL)
+ {
+ IKE_PACKET_TRANSFORM_PAYLOAD *transform = &transform_payload->Payload.Transform;
+ IPSEC_SA_TRANSFORM_SETTING set;
+
+ if (TransformPayloadToTransformSettingForIPsecSa(ike, transform, &set, server_ip))
+ {
+ Copy(setting, &set, sizeof(IPSEC_SA_TRANSFORM_SETTING));
+
+ setting->SpiServerToClient = READ_UINT(proposal->Spi->Buf);
+
+ return true;
+ }
+ else
+ {
+ if (set.OnlyCapsuleModeIsInvalid)
+ {
+ if (ocmii_flag == false)
+ {
+ Copy(setting, &set, sizeof(IPSEC_SA_TRANSFORM_SETTING));
+ ocmii_flag = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+// Select the optimal transform settings for the IKE SA
+bool GetBestTransformSettingForIkeSa(IKE_SERVER *ike, IKE_PACKET *pr, IKE_SA_TRANSFORM_SETTING *setting)
+{
+ IKE_PACKET_PAYLOAD *sa_payload;
+ IKE_PACKET_SA_PAYLOAD *sa;
+ UINT i, num;
+ // Validate arguments
+ if (ike == NULL || pr == NULL || setting == NULL)
+ {
+ return false;
+ }
+
+ // Get the SA payload
+ sa_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_SA, 0);
+ if (sa_payload == NULL)
+ {
+ return false;
+ }
+
+ sa = &sa_payload->Payload.Sa;
+
+ // Scan all proposal payloads
+ num = IkeGetPayloadNum(sa->PayloadList, IKE_PAYLOAD_PROPOSAL);
+ for (i = 0;i < num;i++)
+ {
+ IKE_PACKET_PAYLOAD *proposal_payload = IkeGetPayload(sa->PayloadList, IKE_PAYLOAD_PROPOSAL, i);
+
+ if (proposal_payload != NULL)
+ {
+ IKE_PACKET_PROPOSAL_PAYLOAD *proposal = &proposal_payload->Payload.Proposal;
+
+ // Examine the contents of the proposal payload
+ if (proposal->ProtocolId == IKE_PROTOCOL_ID_IKE)
+ {
+ // Scan all transform payloads
+ UINT j, num2;
+
+ num2 = IkeGetPayloadNum(proposal->PayloadList, IKE_PAYLOAD_TRANSFORM);
+ for (j = 0;j < num2;j++)
+ {
+ IKE_PACKET_PAYLOAD *transform_payload = IkeGetPayload(proposal->PayloadList, IKE_PAYLOAD_TRANSFORM, j);
+ if (transform_payload != NULL)
+ {
+ IKE_PACKET_TRANSFORM_PAYLOAD *transform = &transform_payload->Payload.Transform;
+
+ if (transform->TransformId == IKE_TRANSFORM_ID_P1_KEY_IKE)
+ {
+ IKE_SA_TRANSFORM_SETTING set;
+
+ if (TransformPayloadToTransformSettingForIkeSa(ike, transform, &set))
+ {
+ Copy(setting, &set, sizeof(IKE_SA_TRANSFORM_SETTING));
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+// Convert a structure to the transform payload (for IPsec SA)
+IKE_PACKET_PAYLOAD *TransformSettingToTransformPayloadForIPsec(IKE_SERVER *ike, IPSEC_SA_TRANSFORM_SETTING *setting)
+{
+ LIST *value_list;
+ // Validate arguments
+ if (ike == NULL || setting == NULL)
+ {
+ return NULL;
+ }
+
+ value_list = NewListFast(NULL);
+
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P2_HMAC, setting->HashId));
+
+ if (setting->Dh != NULL)
+ {
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P2_DH_GROUP, setting->DhId));
+ }
+
+ if (setting->LifeSeconds != INFINITE)
+ {
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P2_LIFE_TYPE, IKE_P2_LIFE_TYPE_SECONDS));
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P2_LIFE_VALUE, setting->LifeSeconds));
+ }
+
+ if (setting->LifeKilobytes != INFINITE)
+ {
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P2_LIFE_TYPE, IKE_P2_LIFE_TYPE_KILOBYTES));
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P2_LIFE_VALUE, setting->LifeKilobytes));
+ }
+
+ if (setting->Crypto->VariableKeySize)
+ {
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P2_KEY_SIZE, setting->CryptoKeySize * 8));
+ }
+
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P2_CAPSULE, setting->CapsuleMode));
+
+ return IkeNewTransformPayload(1, setting->CryptoId, value_list);
+}
+
+// Convert a structure to the transform payload (for IKE SA)
+IKE_PACKET_PAYLOAD *TransformSettingToTransformPayloadForIke(IKE_SERVER *ike, IKE_SA_TRANSFORM_SETTING *setting)
+{
+ LIST *value_list;
+ // Validate arguments
+ if (ike == NULL || setting == NULL)
+ {
+ return NULL;
+ }
+
+ value_list = NewListFast(NULL);
+
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P1_CRYPTO, setting->CryptoId));
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P1_HASH, setting->HashId));
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P1_AUTH_METHOD, IKE_P1_AUTH_METHOD_PRESHAREDKEY));
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P1_DH_GROUP, setting->DhId));
+
+ if (setting->LifeSeconds != INFINITE)
+ {
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P1_LIFE_TYPE, IKE_P1_LIFE_TYPE_SECONDS));
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P1_LIFE_VALUE, setting->LifeSeconds));
+ }
+
+ if (setting->LifeKilobytes != INFINITE)
+ {
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P1_LIFE_TYPE, IKE_P1_LIFE_TYPE_KILOBYTES));
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P1_LIFE_VALUE, setting->LifeKilobytes));
+ }
+
+ if (setting->Crypto->VariableKeySize)
+ {
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P1_KET_SIZE, setting->CryptoKeySize * 8));
+ }
+
+ return IkeNewTransformPayload(1, IKE_TRANSFORM_ID_P1_KEY_IKE, value_list);
+}
+
+// Convert a transform payload to a structure (for IPsec SA)
+bool TransformPayloadToTransformSettingForIPsecSa(IKE_SERVER *ike, IKE_PACKET_TRANSFORM_PAYLOAD *transform, IPSEC_SA_TRANSFORM_SETTING *setting, IP *server_ip)
+{
+ UINT i;
+ UINT capsule_mode;
+ bool is_esp_supported;
+ // Validate arguments
+ if (ike == NULL || transform == NULL || setting == NULL || server_ip == NULL)
+ {
+ return false;
+ }
+
+ is_esp_supported = IsUdpPortOpened(ike->IPsec->UdpListener, server_ip, IPSEC_PORT_IPSEC_ESP_RAW);
+
+ Zero(setting, sizeof(IPSEC_SA_TRANSFORM_SETTING));
+
+ setting->CryptoId = transform->TransformId;
+ setting->HashId = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P2_HMAC, 0);
+
+ setting->DhId = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P2_DH_GROUP, 0);
+
+ setting->LifeKilobytes = INFINITE;
+ setting->LifeSeconds = INFINITE;
+
+ for (i = 0;i < IkeGetTransformValueNum(transform, IKE_TRANSFORM_VALUE_P2_LIFE_TYPE);i++)
+ {
+ UINT life_type = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P2_LIFE_TYPE, i);
+
+ switch (life_type)
+ {
+ case IKE_P2_LIFE_TYPE_SECONDS: // Number of seconds
+ setting->LifeSeconds = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P2_LIFE_VALUE, i);
+ break;
+
+ case IKE_P2_LIFE_TYPE_KILOBYTES: // Kilobytes
+ setting->LifeKilobytes = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P2_LIFE_VALUE, i);
+ break;
+
+ default:
+ // Unsupported expiration type
+ return false;
+ }
+ }
+
+ setting->Crypto = GetIkeCrypto(ike->Engine, true, setting->CryptoId);
+ setting->Hash = GetIkeHash(ike->Engine, true, setting->HashId);
+ setting->Dh = GetIkeDh(ike->Engine, true, setting->DhId);
+
+ if (setting->Crypto == NULL || setting->Hash == NULL)
+ {
+ // Unsupported algorithm
+ return false;
+ }
+
+ if (setting->Crypto->VariableKeySize)
+ {
+ // Get the actual key size in the case of variable key size
+ setting->CryptoKeySize = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P2_KEY_SIZE, 0);
+
+ // bits -> bytes
+ setting->CryptoKeySize = setting->CryptoKeySize / 8;
+
+ if (setting->CryptoKeySize == 0 || IkeCheckKeySize(setting->Crypto, setting->CryptoKeySize) == false)
+ {
+ // The key size is not specified or inappropriate
+ return false;
+ }
+ }
+ else
+ {
+ // Get a fixed key length for fixed key size
+ setting->CryptoKeySize = setting->Crypto->KeySizes[0];
+ }
+
+ capsule_mode = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P2_CAPSULE, 0);
+ if (capsule_mode != IKE_P2_CAPSULE_NAT_TUNNEL_1 && capsule_mode != IKE_P2_CAPSULE_NAT_TUNNEL_2 &&
+ capsule_mode != IKE_P2_CAPSULE_NAT_TRANSPORT_1 && capsule_mode != IKE_P2_CAPSULE_NAT_TRANSPORT_2)
+ {
+ // No support for UDP encapsulation mode except for the NAT-Traversal
+ if (capsule_mode == IKE_P2_CAPSULE_TRANSPORT || capsule_mode == IKE_P2_CAPSULE_TUNNEL)
+ {
+ if (is_esp_supported == false)
+ {
+ setting->OnlyCapsuleModeIsInvalid = true;
+ return false;
+ }
+ else
+ {
+ // It is an environment that can send and receive ESP packets
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ setting->CapsuleMode = capsule_mode;
+
+ return true;
+}
+
+// Convert a transform payload to a structure (for IKE SA)
+bool TransformPayloadToTransformSettingForIkeSa(IKE_SERVER *ike, IKE_PACKET_TRANSFORM_PAYLOAD *transform, IKE_SA_TRANSFORM_SETTING *setting)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL || transform == NULL || setting == NULL)
+ {
+ return false;
+ }
+
+ Zero(setting, sizeof(IKE_SA_TRANSFORM_SETTING));
+
+ setting->CryptoId = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P1_CRYPTO, 0);
+ setting->HashId = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P1_HASH, 0);
+
+ if (IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P1_AUTH_METHOD, 0) != IKE_P1_AUTH_METHOD_PRESHAREDKEY)
+ {
+ // Only PSK authentication method is supported
+ return false;
+ }
+
+ setting->DhId = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P1_DH_GROUP, 0);
+
+ setting->LifeKilobytes = INFINITE;
+ setting->LifeSeconds = INFINITE;
+
+ for (i = 0;i < IkeGetTransformValueNum(transform, IKE_TRANSFORM_VALUE_P1_LIFE_TYPE);i++)
+ {
+ UINT life_type = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P1_LIFE_TYPE, i);
+
+ switch (life_type)
+ {
+ case IKE_P1_LIFE_TYPE_SECONDS: // Number of seconds
+ setting->LifeSeconds = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P1_LIFE_VALUE, i);
+ break;
+
+ case IKE_P1_LIFE_TYPE_KILOBYTES: // Kilobytes
+ setting->LifeKilobytes = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P1_LIFE_VALUE, i);
+ break;
+
+ default:
+ // Unsupported expiration type
+ return false;
+ }
+ }
+
+ setting->Crypto = GetIkeCrypto(ike->Engine, false, setting->CryptoId);
+ setting->Hash = GetIkeHash(ike->Engine, false, setting->HashId);
+ setting->Dh = GetIkeDh(ike->Engine, false, setting->DhId);
+
+ if (setting->Crypto == NULL || setting->Hash == NULL || setting->Dh == NULL)
+ {
+ // Unsupported algorithm
+ return false;
+ }
+
+ if (setting->Crypto->VariableKeySize)
+ {
+ // Get the actual key size in the case of variable key size
+ setting->CryptoKeySize = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P1_KET_SIZE, 0);
+
+ // bits -> bytes
+ setting->CryptoKeySize = setting->CryptoKeySize / 8;
+
+ if (setting->CryptoKeySize == 0 || IkeCheckKeySize(setting->Crypto, setting->CryptoKeySize) == false)
+ {
+ // The key size is not specified or inappropriate
+ return false;
+ }
+ }
+ else
+ {
+ // Get a fixed key length for fixed key size
+ setting->CryptoKeySize = setting->Crypto->KeySizes[0];
+ }
+
+ return true;
+}
+
+// Creating a new Responder Cookie
+UINT64 GenerateNewResponserCookie(IKE_SERVER *ike)
+{
+ UINT64 c;
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return 0;
+ }
+
+ while (true)
+ {
+ bool b = false;
+ UINT i;
+
+ c = Rand64();
+
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+
+ if (sa->ResponderCookie == c)
+ {
+ b = true;
+ break;
+ }
+ }
+
+ if (b == false)
+ {
+ return c;
+ }
+ }
+}
+
+// Parse the IKE packet header
+IKE_PACKET *ParseIKEPacketHeader(UDPPACKET *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ return IkeParseHeader(p->Data, p->Size, NULL);
+}
+
+// Search for another IPsec SA belonging to the IKE_CLIENT which have same conditions to the specified IPsec SA
+IPSECSA *GetOtherLatestIPsecSa(IKE_SERVER *ike, IPSECSA *sa)
+{
+ UINT i;
+ UINT64 min_value = 0;
+ IPSECSA *max_sa = NULL;
+ // Validate arguments
+ if (ike == NULL || sa == NULL)
+ {
+ return NULL;
+ }
+
+ if (sa->IkeClient == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa2 = LIST_DATA(ike->IPsecSaList, i);
+
+ if (sa2 != sa)
+ {
+ if (sa2->IkeClient == sa->IkeClient)
+ {
+ if (sa2->ServerToClient == sa->ServerToClient)
+ {
+ if (sa2->Deleting == false)
+ {
+ if (sa2->Established)
+ {
+ UINT64 last_comm_tick = sa2->LastCommTick;
+
+ if (sa2->ServerToClient)
+ {
+ if (sa2->PairIPsecSa != NULL)
+ {
+ last_comm_tick = sa2->PairIPsecSa->LastCommTick;
+ }
+ }
+
+ if (min_value < last_comm_tick)
+ {
+ min_value = last_comm_tick;
+
+ max_sa = sa2;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return max_sa;
+}
+
+// Search for another IKE_SA belonging to the IKE_CLIENT which have same conditions to the specified IKE_SA
+IKE_SA *GetOtherLatestIkeSa(IKE_SERVER *ike, IKE_SA *sa)
+{
+ UINT i;
+ UINT64 min_value = 0;
+ IKE_SA *max_sa = NULL;
+ // Validate arguments
+ if (ike == NULL || sa == NULL)
+ {
+ return NULL;
+ }
+
+ if (sa->IkeClient == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa2 = LIST_DATA(ike->IkeSaList, i);
+
+ if (sa2 != sa)
+ {
+ if (sa2->IkeClient == sa->IkeClient)
+ {
+ if (sa2->Deleting == false)
+ {
+ if (sa2->Established)
+ {
+ if (min_value < sa2->LastCommTick)
+ {
+ min_value = sa2->LastCommTick;
+
+ max_sa = sa2;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return max_sa;
+}
+
+// Purge the IPsec SA
+void PurgeIPsecSa(IKE_SERVER *ike, IPSECSA *sa)
+{
+ UINT i;
+ IPSECSA *other_sa;
+ // Validate arguments
+ if (ike == NULL || sa == NULL)
+ {
+ return;
+ }
+
+ other_sa = GetOtherLatestIPsecSa(ike, sa);
+
+ // Rewrite the pairing partner by looking for IPsec SA that are paired
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa2 = LIST_DATA(ike->IPsecSaList, i);
+
+ if (sa2->PairIPsecSa == sa)
+ {
+ sa2->PairIPsecSa = other_sa;
+ }
+ }
+
+ // Rewrite the IKE_CLIENT using this IPsec SA to use alternate
+ for (i = 0;i < LIST_NUM(ike->ClientList);i++)
+ {
+ IKE_CLIENT *c = LIST_DATA(ike->ClientList, i);
+
+ if (c->CurrentIpSecSaRecv == sa)
+ {
+ c->CurrentIpSecSaRecv = other_sa;
+ }
+
+ if (c->CurrentIpSecSaSend == sa)
+ {
+ c->CurrentIpSecSaSend = other_sa;
+ }
+ }
+
+ Delete(ike->IPsecSaList, sa);
+ FreeIPsecSa(sa);
+}
+
+// Remove the IKE SA
+void PurgeIkeSa(IKE_SERVER *ike, IKE_SA *sa)
+{
+ IKE_SA *other_sa;
+ UINT i;
+ // Validate arguments
+ if (ike == NULL || sa == NULL)
+ {
+ return;
+ }
+
+ Debug("Purging IKE SA %I64u-%I64u\n", sa->InitiatorCookie, sa->ResponderCookie);
+
+ // Rewrite to alternative IKE_SA of all IPsec SA that are using this IKE_SA
+ other_sa = GetOtherLatestIkeSa(ike, sa);
+
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *ipsec_sa = LIST_DATA(ike->IPsecSaList, i);
+
+ if (ipsec_sa->IkeSa == sa)
+ {
+ if (other_sa == NULL)
+ {
+ // Remove this IPsec SA because there is no alternative IKE_SA
+ Debug(" Deleting IPsec SA 0x%X of this IKE SA (no alternatives)\n", ipsec_sa->Spi);
+ MarkIPsecSaAsDeleted(ike, ipsec_sa);
+ ipsec_sa->IkeSa = NULL;
+ }
+ else
+ {
+ // Replace to the alternative IKE_SA
+ Debug(" Replacing IKE SA of IPsec SA 0x%X from %I64u-%I64u to %I64u-%I64u\n", ipsec_sa->Spi,
+ sa->InitiatorCookie, sa->ResponderCookie,
+ other_sa->InitiatorCookie, other_sa->ResponderCookie);
+ ipsec_sa->IkeSa = other_sa;
+ }
+ }
+ }
+
+ // Substitute the IKE_SA of all IKE_CLIENT that are using this IKE_SA with alternative
+ for (i = 0;i < LIST_NUM(ike->ClientList);i++)
+ {
+ IKE_CLIENT *c = LIST_DATA(ike->ClientList, i);
+
+ if (c->CurrentIkeSa == sa)
+ {
+ c->CurrentIkeSa = other_sa;
+ }
+ }
+
+ Delete(ike->IkeSaList, sa);
+ FreeIkeSa(sa);
+}
+
+// Purge the IKE_CLIENT
+void PurgeIkeClient(IKE_SERVER *ike, IKE_CLIENT *c)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL || c == NULL)
+ {
+ return;
+ }
+
+ // Delete all of IPsec SA and IKE SA that belong to this IKE Client
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+
+ if (sa->IkeClient == c)
+ {
+ MarkIkeSaAsDeleted(ike, sa);
+ }
+ }
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+
+ if (sa->IkeClient == c)
+ {
+ MarkIPsecSaAsDeleted(ike, sa);
+ }
+ }
+
+ Delete(ike->ClientList, c);
+ FreeIkeClient(ike, c);
+}
+
+// Remove the SA that has been marked to delete
+void PurgeDeletingSAsAndClients(IKE_SERVER *ike)
+{
+ UINT i;
+ LIST *o = NULL;
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+ if (sa->Deleting)
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Add(o, sa);
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IKE_SA *sa = LIST_DATA(o, i);
+
+ PurgeIkeSa(ike, sa);
+ }
+
+ ReleaseList(o);
+
+ o = NULL;
+
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+ if (sa->Deleting)
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Add(o, sa);
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IPSECSA *sa = LIST_DATA(o, i);
+
+ PurgeIPsecSa(ike, sa);
+ }
+
+ ReleaseList(o);
+
+ o = NULL;
+
+ for (i = 0;i < LIST_NUM(ike->ClientList);i++)
+ {
+ IKE_CLIENT *c = LIST_DATA(ike->ClientList, i);
+ if (c->Deleting)
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Add(o, c);
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IKE_CLIENT *c = LIST_DATA(o, i);
+
+ PurgeIkeClient(ike, c);
+ }
+
+ ReleaseList(o);
+}
+
+// IKE interrupt process
+void ProcessIKEInterrupts(IKE_SERVER *ike)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->ClientList);i++)
+ {
+ IKE_CLIENT *c = LIST_DATA(ike->ClientList, i);
+
+ c->CurrentExpiresSoftTick_CtoS = 0;
+ c->CurrentExpiresSoftTick_StoC = 0;
+ c->CurrentNumEstablishedIPsecSA_CtoS = 0;
+ c->CurrentNumEstablishedIPsecSA_StoC = 0;
+ c->CurrentNumHealtyIPsecSA_CtoS = 0;
+ c->CurrentNumHealtyIPsecSA_StoC = 0;
+ }
+
+ // Packet retransmission by scanning all IKE SA
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+
+ if (sa->SendBuffer != NULL)
+ {
+ if (ike->Now >= sa->NextSendTick)
+ {
+ IKE_CLIENT *c = sa->IkeClient;
+
+ IkeSendUdpPacket(ike, IKE_UDP_TYPE_ISAKMP, &c->ServerIP, c->ServerPort, &c->ClientIP, c->ClientPort,
+ Clone(sa->SendBuffer->Buf, sa->SendBuffer->Size), sa->SendBuffer->Size);
+
+ sa->NextSendTick += (UINT64)(IKE_SA_RESEND_INTERVAL);
+
+ AddInterrupt(ike->Interrupts, sa->NextSendTick);
+
+ if (sa->NumResends != 0)
+ {
+ sa->NumResends--;
+ if (sa->NumResends == 0)
+ {
+ sa->NextSendTick = 0;
+ FreeBuf(sa->SendBuffer);
+ sa->SendBuffer = NULL;
+ }
+ }
+ }
+ }
+
+ // Remove those of non-communication
+ if (sa->IkeClient == NULL || (sa->IkeClient->CurrentIkeSa != sa))
+ {
+ // When the IKE_CLIENT don't point this
+ if (sa->Established == false)
+ {
+ // Make time-out in a short time when it is not established
+ if ((sa->LastCommTick + (UINT64)IKE_TIMEOUT_FOR_IKE_CLIENT_FOR_NOT_ESTABLISHED) <= ike->Now)
+ {
+ WHERE;
+ MarkIkeSaAsDeleted(ike, sa);
+ }
+ }
+ else
+ {
+ // Timeout in a long time in the case of established
+ if ((sa->LastCommTick + (UINT64)IKE_TIMEOUT_FOR_IKE_CLIENT) <= ike->Now)
+ {
+ WHERE;
+ MarkIkeSaAsDeleted(ike, sa);
+ }
+ }
+ }
+ }
+
+ // Packet retransmission by scanning all IPsec SA
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+ IKE_CLIENT *c = sa->IkeClient;
+
+ if (sa->SendBuffer != NULL)
+ {
+ if (ike->Now >= sa->NextSendTick)
+ {
+ IKE_CLIENT *c = sa->IkeClient;
+
+ IkeSendUdpPacket(ike, IKE_UDP_TYPE_ISAKMP, &c->ServerIP, c->ServerPort, &c->ClientIP, c->ClientPort,
+ Clone(sa->SendBuffer->Buf, sa->SendBuffer->Size), sa->SendBuffer->Size);
+
+ sa->NextSendTick += (UINT64)(IKE_SA_RESEND_INTERVAL);
+
+ AddInterrupt(ike->Interrupts, sa->NextSendTick);
+
+ if (sa->NumResends != 0)
+ {
+ sa->NumResends--;
+
+ if (sa->NumResends == 0)
+ {
+ sa->NextSendTick = 0;
+ FreeBuf(sa->SendBuffer);
+ sa->SendBuffer = NULL;
+ }
+ }
+ }
+ }
+
+ if (sa->Established && sa->Deleting == false && c != NULL)
+ {
+ // Get the flexible expiration date of SA for each IKE_CLIENT
+ if (sa->ServerToClient)
+ {
+ c->CurrentExpiresSoftTick_StoC = MAX(c->CurrentExpiresSoftTick_StoC, sa->ExpiresSoftTick);
+ c->CurrentNumEstablishedIPsecSA_StoC++;
+
+ if (sa->ExpiresSoftTick == 0 || sa->ExpiresSoftTick > ike->Now)
+ {
+ c->CurrentNumHealtyIPsecSA_StoC++;
+ }
+ }
+ else
+ {
+ c->CurrentExpiresSoftTick_CtoS = MAX(c->CurrentExpiresSoftTick_CtoS, sa->ExpiresSoftTick);
+ c->CurrentNumEstablishedIPsecSA_CtoS++;
+
+ if (sa->ExpiresSoftTick == 0 || sa->ExpiresSoftTick > ike->Now)
+ {
+ c->CurrentNumHealtyIPsecSA_CtoS++;
+ }
+ }
+ }
+
+ // Remove those of non-communication
+ if (sa->IkeClient == NULL || (sa->IkeClient->CurrentIpSecSaRecv != sa && sa->IkeClient->CurrentIpSecSaSend != sa))
+ {
+ // When the IKE_CLIENT don't point this
+ UINT64 last_comm_tick = sa->LastCommTick;
+
+ if (sa->ServerToClient && sa->PairIPsecSa != NULL)
+ {
+ last_comm_tick = sa->PairIPsecSa->LastCommTick;
+ }
+
+ if (sa->Established == false)
+ {
+ // Make time-out in a short time when it is not established
+ if ((last_comm_tick + (UINT64)IKE_TIMEOUT_FOR_IKE_CLIENT_FOR_NOT_ESTABLISHED) <= ike->Now)
+ {
+ WHERE;
+ MarkIPsecSaAsDeleted(ike, sa);
+ }
+ }
+ else
+ {
+ // Timeout in a long time in the case of established
+ if ((last_comm_tick + (UINT64)IKE_TIMEOUT_FOR_IKE_CLIENT) <= ike->Now)
+ {
+ WHERE;
+ MarkIPsecSaAsDeleted(ike, sa);
+ }
+ }
+ }
+ }
+
+ // IKE_CLIENT scanning process
+ for (i = 0;i < LIST_NUM(ike->ClientList);i++)
+ {
+ IKE_CLIENT *c = LIST_DATA(ike->ClientList, i);
+ UINT64 tick;
+ UCHAR data[1];
+ bool need_qm = false;
+ bool need_qm_hard = false;
+ UINT64 qm_soft_tick = 0;
+
+ // Determine whether it is necessary to start a new Quick Mode
+ if (c->CurrentExpiresSoftTick_StoC != 0 && ike->Now >= c->CurrentExpiresSoftTick_StoC)
+ {
+ need_qm = true;
+ qm_soft_tick = MAX(qm_soft_tick, c->CurrentExpiresSoftTick_StoC);
+ }
+
+ if (c->CurrentExpiresSoftTick_CtoS != 0 && ike->Now >= c->CurrentExpiresSoftTick_CtoS)
+ {
+ need_qm = true;
+ qm_soft_tick = MAX(qm_soft_tick, c->CurrentExpiresSoftTick_StoC);
+ }
+
+ if (c->CurrentNumHealtyIPsecSA_CtoS == 0 || c->CurrentNumHealtyIPsecSA_StoC == 0)
+ {
+ need_qm = true;
+ need_qm_hard = true;
+ }
+
+ if (c->StartQuickModeAsSoon)
+ {
+ need_qm = true;
+ need_qm_hard = true;
+ }
+
+ if (c->Deleting || c->CurrentIkeSa == NULL || c->CurrentIkeSa->Deleting)
+ {
+ need_qm = false;
+ need_qm_hard = true;
+ }
+
+ if (need_qm)
+ {
+ if (c->StartQuickModeAsSoon || ((c->LastQuickModeStartTick + (UINT64)IKE_QUICKMODE_START_INTERVAL) <= ike->Now))
+ {
+ // Start the Quick Mode
+ Debug("IKE_CLIENT 0x%X: Begin QuickMode\n", c);
+ c->StartQuickModeAsSoon = false;
+ c->LastQuickModeStartTick = ike->Now;
+
+ AddInterrupt(ike->Interrupts, c->LastQuickModeStartTick + (UINT64)IKE_QUICKMODE_START_INTERVAL);
+
+ StartQuickMode(ike, c);
+ }
+ }
+
+ if (need_qm_hard)
+ {
+ if (c->NeedQmBeginTick == 0)
+ {
+ c->NeedQmBeginTick = ike->Now;
+ }
+ }
+ else
+ {
+ c->NeedQmBeginTick = 0;
+ }
+
+ if (((c->LastCommTick + (UINT64)IKE_TIMEOUT_FOR_IKE_CLIENT) <= ike->Now) ||
+ ((c->CurrentIkeSa == NULL && c->CurrentIpSecSaRecv == NULL && c->CurrentIpSecSaSend == NULL) && (c->LastCommTick + (UINT64)IKE_TIMEOUT_FOR_IKE_CLIENT_FOR_NOT_ESTABLISHED) <= ike->Now) ||
+ (c->NeedQmBeginTick != 0 && ((c->NeedQmBeginTick + (UINT64)IKE_QUICKMODE_FAILED_TIMEOUT) <= ike->Now)))
+ {
+ // Remove IKE_CLIENT not communicating for a certain period of time
+ WHERE;
+ MarkIkeClientAsDeleted(ike, c);
+ }
+
+ // L2TP processing
+ if (c->L2TP != NULL)
+ {
+ IPsecIkeClientManageL2TPServer(ike, c);
+
+ // Interrupt processing occurs
+ L2TPProcessInterrupts(c->L2TP);
+
+ // Packet transmission
+ IPsecIkeClientSendL2TPPackets(ike, c, c->L2TP);
+ }
+
+ // EtherIP processing
+ if (c->EtherIP != NULL)
+ {
+ IPsecIkeClientManageEtherIPServer(ike, c);
+
+ // Interrupt processing occurs
+ EtherIPProcInterrupts(c->EtherIP);
+
+ // Packet transmission
+ IPsecIkeClientSendEtherIPPackets(ike, c, c->EtherIP);
+ }
+
+ // KeepAlive transmission
+ tick = MAX(c->LastCommTick + (UINT64)IKE_INTERVAL_UDP_KEEPALIVE, c->NextKeepAliveSendTick);
+
+ if (tick <= ike->Now && c->ServerPort == IPSEC_PORT_IPSEC_ESP_UDP)
+ {
+ c->NextKeepAliveSendTick = ike->Now + (UINT64)IKE_INTERVAL_UDP_KEEPALIVE;
+
+ AddInterrupt(ike->Interrupts, c->NextKeepAliveSendTick);
+
+ Zero(data, sizeof(data));
+ data[0] = 0xff;
+
+ IkeSendUdpPacket(ike, IKE_UDP_KEEPALIVE, &c->ServerIP, c->ServerPort, &c->ClientIP, c->ClientPort, Clone(data, sizeof(data)), sizeof(data));
+ }
+
+ // DPD transmission
+ if (c->NextDpdSendTick == 0 || c->NextDpdSendTick <= ike->Now)
+ {
+ if (c->CurrentIkeSa != NULL && c->CurrentIkeSa->Established)
+ {
+ if (c->CurrentIkeSa->Caps.DpdRfc3706)
+ {
+ c->NextDpdSendTick = ike->Now + (UINT64)IKE_INTERVAL_DPD_KEEPALIVE;
+
+ AddInterrupt(ike->Interrupts, c->NextDpdSendTick);
+
+ SendInformationalExchangePacket(ike, c,
+ IkeNewNoticeDpdPayload(false, c->CurrentIkeSa->InitiatorCookie, c->CurrentIkeSa->ResponderCookie,
+ c->DpdSeqNo++));
+ }
+ }
+ }
+ }
+
+ do
+ {
+ ike->StateHasChanged = false;
+
+ // Deletion process
+ PurgeDeletingSAsAndClients(ike);
+ }
+ while (ike->StateHasChanged);
+
+ // Maintenance of the thread list
+ MainteThreadList(ike->ThreadList);
+ /*Debug("ike->ThreadList: %u\n", LIST_NUM(ike->ThreadList));
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(ike->ThreadList);i++)
+ {
+ THREAD *t = LIST_DATA(ike->ThreadList, i);
+
+ Debug(" Thread %u: 0x%p ID: %u Stop: %u Ref: %u\n", i, t, t->ThreadId, t->Stopped, t->ref->c->c);
+ }
+ }*/
+}
+
+// Stop the IKE server
+void StopIKEServer(IKE_SERVER *ike)
+{
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return;
+ }
+}
+
+// Set the socket events in IKE server
+void SetIKEServerSockEvent(IKE_SERVER *ike, SOCK_EVENT *e)
+{
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return;
+ }
+
+ if (e != NULL)
+ {
+ AddRef(e->ref);
+ }
+
+ if (ike->SockEvent != NULL)
+ {
+ ReleaseSockEvent(ike->SockEvent);
+ }
+
+ ike->SockEvent = e;
+}
+
+// Release the IKE client
+void FreeIkeClient(IKE_SERVER *ike, IKE_CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL || ike == NULL)
+ {
+ return;
+ }
+
+ if (c->L2TP != NULL)
+ {
+ StopL2TPServer(c->L2TP, true);
+ FreeL2TPServer(c->L2TP);
+ }
+
+ if (c->EtherIP != NULL)
+ {
+ ReleaseEtherIPServer(c->EtherIP);
+ }
+
+ FreeBuf(c->SendID1_Buf);
+ FreeBuf(c->SendID2_Buf);
+
+ Free(c);
+}
+
+// Release the IPsec SA
+void FreeIPsecSa(IPSECSA *sa)
+{
+ // Validate arguments
+ if (sa == NULL)
+ {
+ return;
+ }
+
+ IkeFreeKey(sa->CryptoKey);
+
+ FreeBuf(sa->SendBuffer);
+
+ FreeBuf(sa->InitiatorRand);
+ FreeBuf(sa->ResponderRand);
+
+ FreeBuf(sa->SharedKey);
+
+ IkeDhFreeCtx(sa->Dh);
+
+ Free(sa);
+}
+
+// Release the IKE SA
+void FreeIkeSa(IKE_SA *sa)
+{
+ // Validate arguments
+ if (sa == NULL)
+ {
+ return;
+ }
+
+ FreeBuf(sa->SendBuffer);
+
+ FreeBuf(sa->InitiatorRand);
+ FreeBuf(sa->ResponderRand);
+ FreeBuf(sa->DhSharedKey);
+ FreeBuf(sa->YourIDPayloadForAM);
+
+ FreeBuf(sa->GXi);
+ FreeBuf(sa->GXr);
+
+ FreeBuf(sa->SAi_b);
+
+ IkeFreeKey(sa->CryptoKey);
+
+ Free(sa);
+}
+
+// Release the IKE server
+void FreeIKEServer(IKE_SERVER *ike)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return;
+ }
+
+ IPsecLog(ike, NULL, NULL, NULL, "LI_STOPPING");
+
+ for (i = 0;i < LIST_NUM(ike->SendPacketList);i++)
+ {
+ UDPPACKET *udp = LIST_DATA(ike->SendPacketList, i);
+
+ FreeUdpPacket(udp);
+ }
+
+ ReleaseList(ike->SendPacketList);
+
+ Debug("Num of IPsec SAs: %u\n", LIST_NUM(ike->IPsecSaList));
+ IPsecLog(ike, NULL, NULL, NULL, "LI_NUM_IPSEC_SA", LIST_NUM(ike->IPsecSaList));
+
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+
+ FreeIPsecSa(sa);
+ }
+
+ ReleaseList(ike->IPsecSaList);
+
+ Debug("Num of IKE SAs: %u\n", LIST_NUM(ike->IkeSaList));
+ IPsecLog(ike, NULL, NULL, NULL, "LI_NUM_IKE_SA", LIST_NUM(ike->IkeSaList));
+
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+
+ FreeIkeSa(sa);
+ }
+
+ ReleaseList(ike->IkeSaList);
+
+ Debug("Num of IKE_CLIENTs: %u\n", LIST_NUM(ike->ClientList));
+ IPsecLog(ike, NULL, NULL, NULL, "LI_NUM_IKE_CLIENTS", LIST_NUM(ike->ClientList));
+
+ for (i = 0;i < LIST_NUM(ike->ClientList);i++)
+ {
+ IKE_CLIENT *c = LIST_DATA(ike->ClientList, i);
+
+ FreeIkeClient(ike, c);
+ }
+
+ ReleaseList(ike->ClientList);
+
+ ReleaseSockEvent(ike->SockEvent);
+
+ IPsecLog(ike, NULL, NULL, NULL, "LI_STOP");
+
+ ReleaseCedar(ike->Cedar);
+
+ FreeIkeEngine(ike->Engine);
+
+ Debug("FreeThreadList()...\n");
+ FreeThreadList(ike->ThreadList);
+ Debug("FreeThreadList() Done.\n");
+
+ Free(ike);
+}
+
+// Create a new IKE server
+IKE_SERVER *NewIKEServer(CEDAR *cedar, IPSEC_SERVER *ipsec)
+{
+ IKE_SERVER *ike;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ ike = ZeroMalloc(sizeof(IKE_SERVER));
+
+ ike->Cedar = cedar;
+ AddRef(cedar->ref);
+
+ ike->IPsec = ipsec;
+
+ ike->Now = Tick64();
+
+ ike->SendPacketList = NewList(NULL);
+
+ ike->IkeSaList = NewList(CmpIkeSa);
+
+ ike->IPsecSaList = NewList(CmpIPsecSa);
+
+ ike->ClientList = NewList(CmpIkeClient);
+
+ ike->Engine = NewIkeEngine();
+
+ ike->ThreadList = NewThreadList();
+
+ IPsecLog(ike, NULL, NULL, NULL, "LI_START");
+
+ return ike;
+}
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_IKE.h b/src/Cedar/IPsec_IKE.h
new file mode 100644
index 00000000..85e319b1
--- /dev/null
+++ b/src/Cedar/IPsec_IKE.h
@@ -0,0 +1,450 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_IKE.h
+// Header of IPsec_IKE.c
+
+#ifndef IPSEC_IKE_H
+#define IPSEC_IKE_H
+
+//// Macro
+
+//// Constants
+
+// State
+#define IKE_SA_MAIN_MODE 0 // Main mode
+#define IKE_SA_AGRESSIVE_MODE 1 // Aggressive mode
+
+#define IKE_SA_MM_STATE_1_SA 0 // Main mode state 1 (SA exchange is complete. Wait for key exchange)
+#define IKE_SA_MM_STATE_2_KEY 1 // Main mode state 2 (Key exchange is complete. Wait for exchange ID)
+#define IKE_SA_MM_STATE_3_ESTABLISHED 2 // Main mode state 3 (ID exchange is complete. Established)
+
+#define IKE_SA_AM_STATE_1_SA 0 // Aggressive mode state 1 (SA exchange is completed. Wait for hash)
+#define IKE_SA_AM_STATE_2_ESTABLISHED 1 // Aggressive mode state 2 (Hash exchange is completed. Established)
+
+#define IKE_SA_RESEND_INTERVAL (2 * 1000) // IKE SA packet retransmission interval
+#define IKE_SA_RAND_SIZE 16 // Size of the random number
+
+// ESP
+#define IKE_ESP_HASH_SIZE 12 // The hash size for the ESP packet
+
+// Type of UDP packet
+#define IKE_UDP_TYPE_ISAKMP 0 // ISAKMP packet (destination 500)
+#define IKE_UDP_TYPE_ESP 1 // ESP packet (destination 4500)
+#define IKE_UDP_KEEPALIVE 2 // KeepAlive packet
+#define IKE_UDP_SPECIAL 3 // Special packet
+
+// String for Vendor ID
+#define IKE_VENDOR_ID_RFC3947_NAT_T "0x4a131c81070358455c5728f20e95452f"
+#define IKE_VENDOR_ID_IPSEC_NAT_T_IKE_03 "0x7d9419a65310ca6f2c179d9215529d56"
+#define IKE_VENDOR_ID_IPSEC_NAT_T_IKE_02 "0x90cb80913ebb696e086381b5ec427b1f"
+#define IKE_VENDOR_ID_IPSEC_NAT_T_IKE_02_2 "0xcd60464335df21f87cfdb2fc68b6a448"
+#define IKE_VENDOR_ID_IPSEC_NAT_T_IKE_00 "0x4485152d18b6bbcd0be8a8469579ddcc"
+#define IKE_VENDOR_ID_RFC3706_DPD "0xafcad71368a1f1c96b8696fc77570100"
+#define IKE_VENDOR_ID_MICROSOFT_L2TP "0x4048b7d56ebce88525e7de7f00d6c2d3"
+#define IKE_VENDOR_ID_MS_NT5_ISAKMPOAKLEY "0x1e2b516905991c7d7c96fcbfb587e461"
+#define IKE_VENDOR_ID_MS_VID_INITIALCONTACT "0x26244d38eddb61b3172a36e3d0cfb819"
+
+// Quota
+#define IKE_QUOTA_MAX_NUM_CLIENTS_PER_IP 1000 // The number of IKE_CLIENT per IP address
+#define IKE_QUOTA_MAX_NUM_CLIENTS 30000 // Limit number of IKE_CLIENT
+#define IKE_QUOTA_MAX_SA_PER_CLIENT 100 // The limit number of SA for each IKE_CLIENT
+
+// Time-out
+#define IKE_TIMEOUT_FOR_IKE_CLIENT 150000 // IKE_CLIENT non-communication disconnect time
+#define IKE_TIMEOUT_FOR_IKE_CLIENT_FOR_NOT_ESTABLISHED 10000 // IKE_CLIENT non-communication disconnect time (connection incomplete)
+#define IKE_INTERVAL_UDP_KEEPALIVE 5000 // UDP KeepAlive transmission interval
+#define IKE_QUICKMODE_START_INTERVAL 2000 // QuickMode start interval
+#define IKE_QUICKMODE_FAILED_TIMEOUT 10000 // Maximum time to tolerant that to fail to establish a QuickMode
+#define IKE_INTERVAL_DPD_KEEPALIVE 10000 // DPD KeepAlive transmission interval
+
+// Expiration margin
+#define IKE_SOFT_EXPIRES_MARGIN 1000 // Expiration margin
+
+
+//// Type
+
+// IKE SA transform data
+struct IKE_SA_TRANSFORM_SETTING
+{
+ IKE_CRYPTO *Crypto;
+ UINT CryptoKeySize;
+ IKE_HASH *Hash;
+ IKE_DH *Dh;
+ UINT CryptoId;
+ UINT HashId;
+ UINT DhId;
+ UINT LifeKilobytes;
+ UINT LifeSeconds;
+};
+
+// IPsec SA transforms data
+struct IPSEC_SA_TRANSFORM_SETTING
+{
+ IKE_CRYPTO *Crypto;
+ UINT CryptoKeySize;
+ IKE_HASH *Hash;
+ IKE_DH *Dh;
+ UINT CryptoId;
+ UINT HashId;
+ UINT DhId;
+ UINT LifeKilobytes;
+ UINT LifeSeconds;
+ UINT SpiServerToClient;
+ UINT CapsuleMode;
+ bool OnlyCapsuleModeIsInvalid;
+};
+
+// Function support information
+struct IKE_CAPS
+{
+ // Support Information
+ bool NatTraversalRfc3947; // RFC 3947 Negotiation of NAT-Traversal in the IKE
+ bool NatTraversalDraftIetf; // draft-ietf-ipsec-nat-t-ike
+ bool DpdRfc3706; // RFC 3706 A Traffic-Based Method of Detecting Dead Internet Key Exchange (IKE) Peers
+ bool MS_L2TPIPSecVPNClient; // Vendor ID: Microsoft L2TP/IPSec VPN Client
+ bool MS_NT5_ISAKMP_OAKLEY; // Vendor ID: MS NT5 ISAKMPOAKLEY
+ bool MS_Vid_InitialContact; // Vendor ID: Microsoft Vid-Initial-Contact
+
+ // Use information
+ bool UsingNatTraversalRfc3947;
+ bool UsingNatTraversalDraftIetf;
+};
+
+// IKE / IPsec client
+struct IKE_CLIENT
+{
+ UINT Id;
+ IP ClientIP;
+ UINT ClientPort;
+ IP ServerIP;
+ UINT ServerPort;
+ IKE_SA *CurrentIkeSa; // IKE SA to be used currently
+ IPSECSA *CurrentIpSecSaRecv; // IPsec SA to be used currently (receive direction)
+ IPSECSA *CurrentIpSecSaSend; // IPsec SA to be currently in use (transmit direction)
+ UINT64 FirstCommTick; // Time the first data communication
+ UINT64 LastCommTick; // Time that made the last communication (received data) time
+ bool Deleting; // Deleting
+ UINT64 NextKeepAliveSendTick; // Time to send the next KeepAlive
+ UINT64 NextDpdSendTick; // Time to send the next DPD
+ UINT DpdSeqNo; // DPD sequence number
+ char ClientId[128]; // ID presented by the client
+ char Secret[MAX_SIZE]; // Secret value of the authentication is successful
+
+ bool IsMicrosoft; // Whether the client is Microsoft's
+
+ IPSEC_SA_TRANSFORM_SETTING CachedTransformSetting; // Cached transform attribute value
+ UINT64 CurrentExpiresSoftTick_StoC; // The maximum value of the flexible expiration date of the current (server -> client)
+ UINT64 CurrentExpiresSoftTick_CtoS; // The maximum value of the flexible expiration date of the current (client -> server)
+ UINT CurrentNumEstablishedIPsecSA_StoC; // The number of IPsec SA currently active (server -> client)
+ UINT CurrentNumEstablishedIPsecSA_CtoS; // The number of IPsec SA currently active (client -> server)
+ UINT CurrentNumHealtyIPsecSA_CtoS; // The number of currently available IPsec SA which expiration well within (client -> server)
+ UINT CurrentNumHealtyIPsecSA_StoC; // The number of currently available IPsec SA which expiration well within (server -> client)
+ bool SendID1andID2; // Whether to send the ID in QM
+ UCHAR SendID1_Type, SendID2_Type;
+ UCHAR SendID1_Protocol, SendID2_Protocol;
+ USHORT SendID1_Port, SendID2_Port;
+ BUF *SendID1_Buf, *SendID2_Buf;
+ bool SendNatOaDraft1, SendNatOaDraft2, SendNatOaRfc; // Whether to send the NAT-OA in QM
+ bool StartQuickModeAsSoon; // Flag to indicate to the start of the Quick Mode as soon as possible
+ UINT64 LastQuickModeStartTick; // Time which the last QuickMode started
+ UINT64 NeedQmBeginTick; // Time which a start-up of QuickMode is required
+
+ // L2TP related
+ L2TP_SERVER *L2TP; // L2TP server
+ UINT L2TPClientPort; // Client-side port number of L2TP
+ IP L2TPServerIP, L2TPClientIP; // IP address used by the L2TP processing
+ bool IsL2TPOnIPsecTunnelMode; // Whether the L2TP is working on IPsec tunnel mode
+
+ // EtherIP related
+ ETHERIP_SERVER *EtherIP; // EtherIP server
+ bool IsEtherIPOnIPsecTunnelMode; // Whether the EtherIP is working on IPsec tunnel mode
+
+ // Transport mode related
+ IP TransportModeServerIP;
+ IP TransportModeClientIP;
+ bool ShouldCalcChecksumForUDP; // Flag to calculate the checksum for the UDP packet
+
+ // Tunnel mode related
+ IP TunnelModeServerIP; // Server-side internal IP address
+ IP TunnelModeClientIP; // Client-side internal IP address
+ USHORT TunnelSendIpId; // ID of the transmission IP header
+};
+
+// IKE SA
+struct IKE_SA
+{
+ UINT Id;
+ IKE_CLIENT *IkeClient; // Pointer to the IKE client
+ UINT64 InitiatorCookie, ResponderCookie; // Cookie
+ UINT Mode; // Mode
+ UINT State; // State
+ BUF *SendBuffer; // Buffer during transmission
+ UINT64 NextSendTick; // Next transmission time
+ UINT64 FirstCommTick; // Time that the first data communication
+ UINT64 EstablishedTick; // Time that the SA has been established
+ UINT64 LastCommTick; // Time that made the last communication (received data) time
+ IKE_SA_TRANSFORM_SETTING TransformSetting; // Transform Configuration
+ IKE_CAPS Caps; // IKE Caps
+ BUF *InitiatorRand, *ResponderRand; // Random number
+ BUF *DhSharedKey; // DH common key
+ BUF *GXi, *GXr; // DH exchange data
+ BUF *SAi_b; // Data needed for authentication
+ BUF *YourIDPayloadForAM; // Copy the ID payload of the client-side
+ UCHAR SKEYID[IKE_MAX_HASH_SIZE]; // Key set
+ UCHAR SKEYID_d[IKE_MAX_HASH_SIZE];
+ UCHAR SKEYID_a[IKE_MAX_HASH_SIZE];
+ UCHAR SKEYID_e[IKE_MAX_HASH_SIZE];
+ UCHAR InitiatorHashForAM[IKE_MAX_HASH_SIZE];
+ IKE_CRYPTO_KEY *CryptoKey; // Common encryption key
+ UINT HashSize; // Hash size
+ UINT KeySize; // Key size
+ UINT BlockSize; // Block size
+ UCHAR Iv[IKE_MAX_BLOCK_SIZE]; // IV
+ bool IsIvExisting; // Whether an IV exists
+ bool Established; // Established flag
+ bool Deleting; // Deleting
+ UINT NumResends; // The number of retransmissions
+ char Secret[MAX_SIZE]; // Secret value of the authentication is successful
+};
+
+// IPsec SA
+struct IPSECSA
+{
+ UINT Id;
+ IKE_CLIENT *IkeClient; // Pointer to the IKE client
+ IKE_SA *IkeSa; // Pointer to IKE_SA to use for transmission
+ UCHAR Iv[IKE_MAX_BLOCK_SIZE]; // IV used in the Quick Mode exchange
+ bool IsIvExisting; // Whether the IV exists
+ UINT MessageId; // Message ID used in Quick Mode exchange
+ UINT Spi; // SPI
+ UINT CurrentSeqNo; // Send sequence number
+ BUF *SendBuffer; // Buffer during transmission
+ UINT NumResends; // The number of retransmissions
+ UINT64 NextSendTick; // Next transmission date and time
+ UINT64 FirstCommTick; // Time the last data sent
+ UINT64 EstablishedTick; // Time that the SA has been established
+ UINT64 LastCommTick; // Time that made the last communication (received data) time
+ UINT64 ExpiresHardTick; // Exact expiration time
+ UINT64 ExpiresSoftTick; // Flexible expiration time
+ UINT64 TotalSize; // Size sent to and received
+ IPSEC_SA_TRANSFORM_SETTING TransformSetting; // Transform Configuration
+ bool ServerToClient; // Whether is upload direction
+ IPSECSA *PairIPsecSa; // IPsec SA that are paired
+ bool Established; // Established flag
+ BUF *InitiatorRand, *ResponderRand; // Random number
+ BUF *SharedKey; // PFS shared key
+ UCHAR Hash3[IKE_MAX_HASH_SIZE]; // Hash 3
+ UCHAR KeyMat[IKE_MAX_KEY_SIZE + IKE_MAX_HASH_SIZE]; // Encryption key
+ UCHAR HashKey[IKE_MAX_HASH_SIZE]; // Hash key
+ IKE_CRYPTO_KEY *CryptoKey; // Key data
+ bool Deleting; // Deleting
+ UCHAR EspIv[IKE_MAX_BLOCK_SIZE]; // IV for ESP communication
+ bool Initiated; // The server-side is initiator
+ DH_CTX *Dh; // DH (only if the server-side is initiator)
+ bool StartQM_FlagSet; // Whether the flag to indicate to do the QM is set to the IKE_CLIENT
+ UCHAR SKEYID_d[IKE_MAX_HASH_SIZE];
+ UCHAR SKEYID_a[IKE_MAX_HASH_SIZE];
+ IKE_HASH *SKEYID_Hash;
+};
+
+// IKE server
+struct IKE_SERVER
+{
+ CEDAR *Cedar;
+ IPSEC_SERVER *IPsec;
+ UINT64 Now; // Current time
+ LIST *SendPacketList; // Transmission packet
+ INTERRUPT_MANAGER *Interrupts; // Interrupt manager
+ SOCK_EVENT *SockEvent; // SockEvent
+ IKE_ENGINE *Engine; // Encryption engine
+ LIST *ClientList; // Client list
+ LIST *IkeSaList; // SA list
+ LIST *IPsecSaList; // IPsec SA list
+ LIST *ThreadList; // L2TP thread list
+ bool StateHasChanged; // Flag whether the state has changed
+ UINT CurrentIkeSaId, CurrentIPsecSaId, CurrentIkeClientId, CurrentEtherId; // Serial number ID
+
+ // Setting data
+ char Secret[MAX_SIZE]; // Pre-shared key
+};
+
+
+//// Function prototype
+IKE_SERVER *NewIKEServer(CEDAR *cedar, IPSEC_SERVER *ipsec);
+void FreeIKEServer(IKE_SERVER *ike);
+void SetIKEServerSockEvent(IKE_SERVER *ike, SOCK_EVENT *e);
+void ProcIKEPacketRecv(IKE_SERVER *ike, UDPPACKET *p);
+void StopIKEServer(IKE_SERVER *ike);
+void ProcessIKEInterrupts(IKE_SERVER *ike);
+IKE_PACKET *ParseIKEPacketHeader(UDPPACKET *p);
+void ProcIkeMainModePacketRecv(IKE_SERVER *ike, UDPPACKET *p, IKE_PACKET *header);
+void ProcIkeQuickModePacketRecv(IKE_SERVER *ike, UDPPACKET *p, IKE_PACKET *header);
+void ProcIkeAggressiveModePacketRecv(IKE_SERVER *ike, UDPPACKET *p, IKE_PACKET *header);
+void ProcIkeInformationalExchangePacketRecv(IKE_SERVER *ike, UDPPACKET *p, IKE_PACKET *header);
+void FreeIkeSa(IKE_SA *sa);
+void FreeIkeClient(IKE_SERVER *ike, IKE_CLIENT *c);
+UINT64 GenerateNewResponserCookie(IKE_SERVER *ike);
+bool GetBestTransformSettingForIkeSa(IKE_SERVER *ike, IKE_PACKET *pr, IKE_SA_TRANSFORM_SETTING *setting);
+bool TransformPayloadToTransformSettingForIkeSa(IKE_SERVER *ike, IKE_PACKET_TRANSFORM_PAYLOAD *transform, IKE_SA_TRANSFORM_SETTING *setting);
+IKE_CLIENT *SearchIkeClientForIkePacket(IKE_SERVER *ike, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, IKE_PACKET *pr);
+IKE_CLIENT *SearchOrCreateNewIkeClientForIkePacket(IKE_SERVER *ike, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, IKE_PACKET *pr);
+UINT GetNumberOfIkeClientsFromIP(IKE_SERVER *ike, IP *client_ip);
+UINT GetNumberOfIPsecSaOfIkeClient(IKE_SERVER *ike, IKE_CLIENT *c);
+UINT GetNumberOfIkeSaOfIkeClient(IKE_SERVER *ike, IKE_CLIENT *c);
+int CmpIkeClient(void *p1, void *p2);
+int CmpIkeSa(void *p1, void *p2);
+int CmpIPsecSa(void *p1, void *p2);
+IKE_SA *FindIkeSaByEndPointAndInitiatorCookie(IKE_SERVER *ike, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, UINT64 init_cookie, UINT mode);
+IKE_SA *FindIkeSaByResponderCookie(IKE_SERVER *ike, UINT64 responder_cookie);
+IKE_SA *FindIkeSaByResponderCookieAndClient(IKE_SERVER *ike, UINT64 responder_cookie, IKE_CLIENT *c);
+IKE_CLIENT *NewIkeClient(IKE_SERVER *ike, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port);
+IKE_CLIENT *SetIkeClientEndpoint(IKE_SERVER *ike, IKE_CLIENT *c, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port);
+IKE_SA *NewIkeSa(IKE_SERVER *ike, IKE_CLIENT *c, UINT64 init_cookie, UINT mode, IKE_SA_TRANSFORM_SETTING *setting);
+IKE_PACKET_PAYLOAD *TransformSettingToTransformPayloadForIke(IKE_SERVER *ike, IKE_SA_TRANSFORM_SETTING *setting);
+void IkeSaSendPacket(IKE_SERVER *ike, IKE_SA *sa, IKE_PACKET *p);
+IKE_PACKET *IkeSaRecvPacket(IKE_SERVER *ike, IKE_SA *sa, void *data, UINT size);
+void IkeSendUdpPacket(IKE_SERVER *ike, UINT type, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, void *data, UINT size);
+void IkeAddVendorIdPayloads(IKE_PACKET *p);
+BUF *IkeStrToVendorId(char *str);
+void IkeAddVendorId(IKE_PACKET *p, char *str);
+bool IkeIsVendorIdExists(IKE_PACKET *p, char *str);
+void IkeCheckCaps(IKE_CAPS *caps, IKE_PACKET *p);
+BUF *IkeCalcNatDetectHash(IKE_SERVER *ike, IKE_HASH *hash, UINT64 initiator_cookie, UINT64 responder_cookie, IP *ip, UINT port);
+void IkeCalcSaKeySet(IKE_SERVER *ike, IKE_SA *sa, char *secret);
+IKE_CRYPTO_KEY *IkeNewCryptoKeyFromK(IKE_SERVER *ike, void *k, UINT k_size, IKE_HASH *h, IKE_CRYPTO *c, UINT crypto_key_size);
+BUF *IkeExpandKeySize(IKE_HASH *h, void *k, UINT k_size, UINT target_size);
+void IkeSaUpdateIv(IKE_SA *sa, void *iv, UINT iv_size);
+IPSECSA *NewIPsecSa(IKE_SERVER *ike, IKE_CLIENT *c, IKE_SA *ike_sa, bool initiate, UINT message_id, bool server_to_client, void *iv, UINT spi, void *init_rand_data, UINT init_rand_size, void *res_rand_data, UINT res_rand_size, IPSEC_SA_TRANSFORM_SETTING *setting, void *shared_key_data, UINT shared_key_size);
+void IkeCalcPhase2InitialIv(void *iv, IKE_SA *sa, UINT message_id);
+bool GetBestTransformSettingForIPsecSa(IKE_SERVER *ike, IKE_PACKET *pr, IPSEC_SA_TRANSFORM_SETTING *setting, IP *server_ip);
+bool TransformPayloadToTransformSettingForIPsecSa(IKE_SERVER *ike, IKE_PACKET_TRANSFORM_PAYLOAD *transform, IPSEC_SA_TRANSFORM_SETTING *setting, IP *server_ip);
+IKE_PACKET_PAYLOAD *TransformSettingToTransformPayloadForIPsec(IKE_SERVER *ike, IPSEC_SA_TRANSFORM_SETTING *setting);
+UINT GenerateNewIPsecSaSpi(IKE_SERVER *ike, UINT counterpart_spi);
+IPSECSA *SearchClientToServerIPsecSaBySpi(IKE_SERVER *ike, UINT spi);
+IPSECSA *SearchIPsecSaBySpi(IKE_SERVER *ike, IKE_CLIENT *c, UINT spi);
+IPSECSA *SearchIPsecSaByMessageId(IKE_SERVER *ike, IKE_CLIENT *c, UINT message_id);
+void IPsecSaSendPacket(IKE_SERVER *ike, IPSECSA *sa, IKE_PACKET *p);
+IKE_PACKET *IPsecSaRecvPacket(IKE_SERVER *ike, IPSECSA *sa, void *data, UINT size);
+void IPsecSaUpdateIv(IPSECSA *sa, void *iv, UINT iv_size);
+void ProcDeletePayload(IKE_SERVER *ike, IKE_CLIENT *c, IKE_PACKET_DELETE_PAYLOAD *d);
+void MarkIPsecSaAsDeleted(IKE_SERVER *ike, IPSECSA *sa);
+void MarkIkeSaAsDeleted(IKE_SERVER *ike, IKE_SA *sa);
+void PurgeDeletingSAsAndClients(IKE_SERVER *ike);
+void PurgeIPsecSa(IKE_SERVER *ike, IPSECSA *sa);
+void PurgeIkeSa(IKE_SERVER *ike, IKE_SA *sa);
+void PurgeIkeClient(IKE_SERVER *ike, IKE_CLIENT *c);
+void FreeIPsecSa(IPSECSA *sa);
+void MarkIkeClientAsDeleted(IKE_SERVER *ike, IKE_CLIENT *c);
+IKE_SA *GetOtherLatestIkeSa(IKE_SERVER *ike, IKE_SA *sa);
+IPSECSA *GetOtherLatestIPsecSa(IKE_SERVER *ike, IPSECSA *sa);
+void SendInformationalExchangePacket(IKE_SERVER *ike, IKE_CLIENT *c, IKE_PACKET_PAYLOAD *payload);
+void SendInformationalExchangePacketEx(IKE_SERVER *ike, IKE_CLIENT *c, IKE_PACKET_PAYLOAD *payload, bool force_plain, UINT64 init_cookie, UINT64 resp_cookie);
+void SendDeleteIkeSaPacket(IKE_SERVER *ike, IKE_CLIENT *c, UINT64 init_cookie, UINT64 resp_cookie);
+void SendDeleteIPsecSaPacket(IKE_SERVER *ike, IKE_CLIENT *c, UINT spi);
+void IPsecCalcKeymat(IKE_SERVER *ike, IKE_HASH *h, void *dst, UINT dst_size, void *skeyid_d_data, UINT skeyid_d_size, UCHAR protocol, UINT spi, void *rand_init_data, UINT rand_init_size,
+ void *rand_resp_data, UINT rand_resp_size, void *df_key_data, UINT df_key_size);
+
+void ProcIPsecEspPacketRecv(IKE_SERVER *ike, UDPPACKET *p);
+void ProcIPsecUdpPacketRecv(IKE_SERVER *ike, IKE_CLIENT *c, UCHAR *data, UINT data_size);
+void IPsecSendPacketByIPsecSa(IKE_SERVER *ike, IPSECSA *sa, UCHAR *data, UINT data_size, UCHAR protocol_id);
+void IPsecSendPacketByIPsecSaInner(IKE_SERVER *ike, IPSECSA *sa, UCHAR *data, UINT data_size, UCHAR protocol_id);
+void IPsecSendPacketByIkeClient(IKE_SERVER *ike, IKE_CLIENT *c, UCHAR *data, UINT data_size, UCHAR protocol_id);
+void IPsecSendUdpPacket(IKE_SERVER *ike, IKE_CLIENT *c, UINT src_port, UINT dst_port, UCHAR *data, UINT data_size);
+void IPsecIkeClientManageL2TPServer(IKE_SERVER *ike, IKE_CLIENT *c);
+void IPsecIkeClientSendL2TPPackets(IKE_SERVER *ike, IKE_CLIENT *c, L2TP_SERVER *l2tp);
+void IPsecIkeSendUdpForDebug(UINT dst_port, UINT dst_ip, void *data, UINT size);
+void StartQuickMode(IKE_SERVER *ike, IKE_CLIENT *c);
+UINT GenerateNewMessageId(IKE_SERVER *ike);
+
+void IPsecIkeClientManageEtherIPServer(IKE_SERVER *ike, IKE_CLIENT *c);
+void IPsecIkeClientSendEtherIPPackets(IKE_SERVER *ike, IKE_CLIENT *c, ETHERIP_SERVER *s);
+void ProcIPsecEtherIPPacketRecv(IKE_SERVER *ike, IKE_CLIENT *c, UCHAR *data, UINT data_size, bool is_tunnel_mode);
+bool IsIPsecSaTunnelMode(IPSECSA *sa);
+void ProcL2TPv3PacketRecv(IKE_SERVER *ike, IKE_CLIENT *c, UCHAR *data, UINT data_size, bool is_tunnel_mode);
+
+IKE_SA *SearchIkeSaByCookie(IKE_SERVER *ike, UINT64 init_cookie, UINT64 resp_cookie);
+
+#endif // IPSEC_IKE_H
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_IPC.c b/src/Cedar/IPsec_IPC.c
new file mode 100644
index 00000000..de883ade
--- /dev/null
+++ b/src/Cedar/IPsec_IPC.c
@@ -0,0 +1,2028 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_IPC.c
+// In-process VPN client module
+
+#include "CedarPch.h"
+
+// Extract the MS-CHAP v2 authentication information by parsing the password string
+bool ParseAndExtractMsChapV2InfoFromPassword(IPC_MSCHAP_V2_AUTHINFO *d, char *password)
+{
+ TOKEN_LIST *t;
+ bool ret = false;
+ // Validate arguments
+ if (d == NULL || password == NULL)
+ {
+ return false;
+ }
+
+ Zero(d, sizeof(IPC_MSCHAP_V2_AUTHINFO));
+
+ if (StartWith(password, IPC_PASSWORD_MSCHAPV2_TAG) == false)
+ {
+ return false;
+ }
+
+ t = ParseTokenWithNullStr(password, ":");
+
+ if (t->NumTokens == 5)
+ {
+ BUF *b1, *b2, *b3;
+
+ b1 = StrToBin(t->Token[2]);
+ b2 = StrToBin(t->Token[3]);
+ b3 = StrToBin(t->Token[4]);
+
+ if (IsEmptyStr(t->Token[1]) == false && b1->Size == 16 && b2->Size == 16 && b3->Size == 24)
+ {
+ StrCpy(d->MsChapV2_PPPUsername, sizeof(d->MsChapV2_PPPUsername), t->Token[1]);
+ Copy(d->MsChapV2_ServerChallenge, b1->Buf, 16);
+ Copy(d->MsChapV2_ClientChallenge, b2->Buf, 16);
+ Copy(d->MsChapV2_ClientResponse, b3->Buf, 24);
+
+ ret = true;
+ }
+
+ FreeBuf(b1);
+ FreeBuf(b2);
+ FreeBuf(b3);
+ }
+
+ FreeToken(t);
+
+ return ret;
+}
+
+// Start an IPC connection asynchronously
+IPC_ASYNC *NewIPCAsync(CEDAR *cedar, IPC_PARAM *param, SOCK_EVENT *sock_event)
+{
+ IPC_ASYNC *a;
+ // Validate arguments
+ if (cedar == NULL || param == NULL)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(IPC_ASYNC));
+
+ a->TubeForDisconnect = NewTube(0);
+
+ a->Cedar = cedar;
+ AddRef(a->Cedar->ref);
+
+ Copy(&a->Param, param, sizeof(IPC_PARAM));
+
+ if (sock_event != NULL)
+ {
+ a->SockEvent = sock_event;
+ AddRef(a->SockEvent->ref);
+ }
+
+ a->Thread = NewThread(IPCAsyncThreadProc, a);
+
+ return a;
+}
+
+// asynchronous IPC connection creation thread
+void IPCAsyncThreadProc(THREAD *thread, void *param)
+{
+ IPC_ASYNC *a;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ a = (IPC_ASYNC *)param;
+
+ // Attempt to connect
+ a->Ipc = NewIPCByParam(a->Cedar, &a->Param, &a->ErrorCode);
+
+ if (a->Ipc != NULL)
+ {
+ if (a->Param.IsL3Mode)
+ {
+ DHCP_OPTION_LIST cao;
+
+ Zero(&cao, sizeof(cao));
+
+ // Get an IP address from the DHCP server in the case of L3 mode
+ Debug("IPCDhcpAllocateIPEx() start...\n");
+ if (IPCDhcpAllocateIPEx(a->Ipc, &cao, a->TubeForDisconnect, a->Param.IsOpenVPN))
+ {
+ UINT t;
+ IP ip, subnet, gw;
+
+ Debug("IPCDhcpAllocateIPEx() Ok.\n");
+
+ // Calculate the DHCP update interval
+ t = cao.LeaseTime;
+ if (t == 0)
+ {
+ t = 600;
+ }
+
+ t = t / 3;
+
+ if (t == 0)
+ {
+ t = 1;
+ }
+
+ // Save the options list
+ Copy(&a->L3ClientAddressOption, &cao, sizeof(DHCP_OPTION_LIST));
+ a->L3DhcpRenewInterval = t * 1000;
+
+ // Set the obtained IP address parameters to the IPC virtual host
+ UINTToIP(&ip, cao.ClientAddress);
+ UINTToIP(&subnet, cao.SubnetMask);
+ UINTToIP(&gw, cao.Gateway);
+
+ IPCSetIPv4Parameters(a->Ipc, &ip, &subnet, &gw);
+
+ a->L3NextDhcpRenewTick = Tick64() + a->L3DhcpRenewInterval;
+ }
+ else
+ {
+ Debug("IPCDhcpAllocateIPEx() Error.\n");
+
+ a->DhcpAllocFailed = true;
+
+ FreeIPC(a->Ipc);
+ a->Ipc = NULL;
+ }
+ }
+ }
+
+ // Procedure complete
+ a->Done = true;
+
+ if (a->SockEvent != NULL)
+ {
+ SetSockEvent(a->SockEvent);
+ }
+}
+
+// Release the IPC asynchronous connection object
+void FreeIPCAsync(IPC_ASYNC *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ TubeDisconnect(a->TubeForDisconnect);
+ WaitThread(a->Thread, INFINITE);
+ ReleaseThread(a->Thread);
+
+ if (a->Ipc != NULL)
+ {
+ FreeIPC(a->Ipc);
+ a->Ipc = NULL;
+ }
+
+ if (a->SockEvent != NULL)
+ {
+ ReleaseSockEvent(a->SockEvent);
+ }
+
+ ReleaseCedar(a->Cedar);
+
+ ReleaseTube(a->TubeForDisconnect);
+ Free(a);
+}
+
+// Start a new IPC connection by specifying the parameter structure
+IPC *NewIPCByParam(CEDAR *cedar, IPC_PARAM *param, UINT *error_code)
+{
+ IPC *ipc;
+ // Validate arguments
+ if (cedar == NULL || param == NULL)
+ {
+ return NULL;
+ }
+
+ ipc = NewIPC(cedar, param->ClientName, param->Postfix, param->HubName,
+ param->UserName, param->Password, error_code, ¶m->ClientIp,
+ param->ClientPort, ¶m->ServerIp, param->ServerPort,
+ param->ClientHostname, param->CryptName,
+ param->BridgeMode, param->Mss);
+
+ return ipc;
+}
+
+// Start a new IPC connection
+IPC *NewIPC(CEDAR *cedar, char *client_name, char *postfix, char *hubname, char *username, char *password,
+ UINT *error_code, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port,
+ char *client_hostname, char *crypt_name,
+ bool bridge_mode, UINT mss)
+{
+ IPC *ipc;
+ UINT dummy_int = 0;
+ SOCK *a;
+ SOCK *s;
+ PACK *p;
+ UINT err = ERR_INTERNAL_ERROR;
+ char server_str[MAX_SIZE];
+ char macstr[30];
+ UINT server_ver, server_build;
+ UCHAR unique[SHA1_SIZE];
+ NODE_INFO info;
+ BUF *b;
+ UCHAR mschap_v2_server_response_20[20];
+ // Validate arguments
+ if (cedar == NULL || username == NULL || password == NULL || client_hostname == NULL)
+ {
+ return NULL;
+ }
+ if (IsEmptyStr(client_name))
+ {
+ client_name = "InProc VPN Connection";
+ }
+ if (IsEmptyStr(crypt_name))
+ {
+ crypt_name = "";
+ }
+ if (error_code == NULL)
+ {
+ error_code = &dummy_int;
+ }
+
+ Zero(mschap_v2_server_response_20, sizeof(mschap_v2_server_response_20));
+
+ err = *error_code = ERR_INTERNAL_ERROR;
+
+ a = GetInProcListeningSock(cedar);
+ if (a == NULL)
+ {
+ return NULL;
+ }
+
+ ipc = ZeroMalloc(sizeof(IPC));
+
+ ipc->Cedar = cedar;
+ AddRef(cedar->ref);
+
+ ipc->FlushList = NewTubeFlushList();
+
+ StrCpy(ipc->ClientHostname, sizeof(ipc->ClientHostname), client_hostname);
+ StrCpy(ipc->HubName, sizeof(ipc->HubName), hubname);
+ StrCpy(ipc->UserName, sizeof(ipc->UserName), username);
+ StrCpy(ipc->Password, sizeof(ipc->Password), password);
+
+ // Connect the in-process socket
+ s = ConnectInProc(a, client_ip, client_port, server_ip, server_port);
+ if (s == NULL)
+ {
+ goto LABEL_ERROR;
+ }
+
+ // Protocol initialization process
+ if (ClientUploadSignature(s) == false)
+ {
+ err = ERR_DISCONNECTED;
+ goto LABEL_ERROR;
+ }
+
+ p = HttpClientRecv(s);
+ if (p == NULL)
+ {
+ err = ERR_DISCONNECTED;
+ goto LABEL_ERROR;
+ }
+
+ err = GetErrorFromPack(p);
+ if (err != ERR_NO_ERROR)
+ {
+ FreePack(p);
+ goto LABEL_ERROR;
+ }
+
+ if (GetHello(p, ipc->random, &server_ver, &server_build, server_str, sizeof(server_str)) == false)
+ {
+ FreePack(p);
+ err = ERR_DISCONNECTED;
+ goto LABEL_ERROR;
+ }
+
+ FreePack(p);
+
+ // Upload the authentication data
+ p = PackLoginWithPlainPassword(hubname, username, password);
+ PackAddInt64(p, "timestamp", SystemTime64());
+ PackAddStr(p, "hello", client_name);
+ PackAddInt(p, "client_ver", cedar->Version);
+ PackAddInt(p, "client_build", cedar->Build);
+ PackAddInt(p, "max_connection", 1);
+ PackAddInt(p, "use_encrypt", 0);
+ PackAddInt(p, "use_compress", 0);
+ PackAddInt(p, "half_connection", 0);
+ PackAddInt(p, "adjust_mss", mss);
+ PackAddBool(p, "require_bridge_routing_mode", bridge_mode);
+ PackAddBool(p, "require_monitor_mode", false);
+ PackAddBool(p, "qos", false);
+
+ // Unique ID is determined by the sum of the connecting client IP address and the client_name
+ b = NewBuf();
+ WriteBuf(b, client_ip, sizeof(IP));
+ WriteBufStr(b, client_name);
+ WriteBufStr(b, crypt_name);
+
+ HashSha1(unique, b->Buf, b->Size);
+
+ FreeBuf(b);
+
+ PackAddData(p, "unique_id", unique, SHA1_SIZE);
+
+ PackAddStr(p, "inproc_postfix", postfix);
+ PackAddStr(p, "inproc_cryptname", crypt_name);
+
+ // Node information
+ Zero(&info, sizeof(info));
+ StrCpy(info.ClientProductName, sizeof(info.ClientProductName), client_name);
+ info.ClientProductVer = Endian32(cedar->Version);
+ info.ClientProductBuild = Endian32(cedar->Build);
+ StrCpy(info.ServerProductName, sizeof(info.ServerProductName), server_str);
+ info.ServerProductVer = Endian32(server_ver);
+ info.ServerProductBuild = Endian32(server_build);
+ StrCpy(info.ClientOsName, sizeof(info.ClientOsName), client_name);
+ StrCpy(info.ClientOsVer, sizeof(info.ClientOsVer), "-");
+ StrCpy(info.ClientOsProductId, sizeof(info.ClientOsProductId), "-");
+ info.ClientIpAddress = IPToUINT(&s->LocalIP);
+ info.ClientPort = Endian32(s->LocalPort);
+ StrCpy(info.ClientHostname, sizeof(info.ClientHostname), ipc->ClientHostname);
+ IPToStr(info.ServerHostname, sizeof(info.ServerHostname), &s->RemoteIP);
+ info.ServerIpAddress = IPToUINT(&s->RemoteIP);
+ info.ServerPort = Endian32(s->RemotePort);
+ StrCpy(info.HubName, sizeof(info.HubName), hubname);
+ Copy(info.UniqueId, unique, 16);
+ if (IsIP6(&s->LocalIP))
+ {
+ Copy(info.ClientIpAddress6, s->LocalIP.ipv6_addr, 16);
+ }
+ if (IsIP6(&s->RemoteIP))
+ {
+ Copy(info.ServerIpAddress6, s->RemoteIP.ipv6_addr, 16);
+ }
+ OutRpcNodeInfo(p, &info);
+
+ if (HttpClientSend(s, p) == false)
+ {
+ FreePack(p);
+ err = ERR_DISCONNECTED;
+ goto LABEL_ERROR;
+ }
+
+ FreePack(p);
+
+ // Receive a Welcome packet
+ p = HttpClientRecv(s);
+ if (p == NULL)
+ {
+ err = ERR_DISCONNECTED;
+ goto LABEL_ERROR;
+ }
+
+ err = GetErrorFromPack(p);
+ if (err != ERR_NO_ERROR)
+ {
+ FreePack(p);
+ goto LABEL_ERROR;
+ }
+
+ if (ParseWelcomeFromPack(p, ipc->SessionName, sizeof(ipc->SessionName),
+ ipc->ConnectionName, sizeof(ipc->ConnectionName), &ipc->Policy) == false)
+ {
+ err = ERR_PROTOCOL_ERROR;
+ FreePack(p);
+ goto LABEL_ERROR;
+ }
+
+ if (PackGetData2(p, "IpcMacAddress", ipc->MacAddress, 6) == false || IsZero(ipc->MacAddress, 6))
+ {
+ err = ERR_PROTOCOL_ERROR;
+ FreePack(p);
+ goto LABEL_ERROR;
+ }
+
+ if (PackGetData2(p, "IpcMsChapV2ServerResponse", mschap_v2_server_response_20, sizeof(mschap_v2_server_response_20)))
+ {
+ Copy(ipc->MsChapV2_ServerResponse, mschap_v2_server_response_20, sizeof(mschap_v2_server_response_20));
+ }
+
+ PackGetStr(p, "IpcHubName", ipc->HubName, sizeof(ipc->HubName));
+ Debug("IPC Hub Name: %s\n", ipc->HubName);
+
+ MacToStr(macstr, sizeof(macstr), ipc->MacAddress);
+
+ Debug("IPC: Session = %s, Connection = %s, Mac = %s\n", ipc->SessionName, ipc->ConnectionName, macstr);
+
+ FreePack(p);
+
+ ReleaseSock(a);
+ ipc->Sock = s;
+
+ Debug("NewIPC() Succeed.\n");
+
+ ipc->Interrupt = NewInterruptManager();
+
+ // Create an ARP table
+ ipc->ArpTable = NewList(IPCCmpArpTable);
+
+ // Create an IPv4 reception queue
+ ipc->IPv4RecviedQueue = NewQueue();
+
+ return ipc;
+
+LABEL_ERROR:
+ Debug("NewIPC() Failed: Err = %u\n", err);
+ Disconnect(s);
+ ReleaseSock(s);
+ ReleaseSock(a);
+ FreeIPC(ipc);
+ *error_code = err;
+ return NULL;
+}
+
+// Create a new IPC based on SOCK
+IPC *NewIPCBySock(CEDAR *cedar, SOCK *s, void *mac_address)
+{
+ IPC *ipc;
+ // Validate arguments
+ if (cedar == NULL || mac_address == NULL || s == NULL)
+ {
+ return NULL;
+ }
+
+ ipc = ZeroMalloc(sizeof(IPC));
+
+ ipc->Cedar = cedar;
+ AddRef(cedar->ref);
+
+ ipc->Sock = s;
+ AddRef(s->ref);
+
+ Copy(ipc->MacAddress, mac_address, 6);
+
+ ipc->Interrupt = NewInterruptManager();
+
+ // Create an ARP table
+ ipc->ArpTable = NewList(IPCCmpArpTable);
+
+ // Create an IPv4 reception queue
+ ipc->IPv4RecviedQueue = NewQueue();
+
+ ipc->FlushList = NewTubeFlushList();
+
+ return ipc;
+}
+
+// Get whether the IPC is connected
+bool IsIPCConnected(IPC *ipc)
+{
+ // Validate arguments
+ if (ipc == NULL)
+ {
+ return false;
+ }
+
+ if (IsTubeConnected(ipc->Sock->RecvTube) == false || IsTubeConnected(ipc->Sock->SendTube) == false)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Get to hit the SOCK_EVENT when a new data has arrived in the IPC
+void IPCSetSockEventWhenRecvL2Packet(IPC *ipc, SOCK_EVENT *e)
+{
+ // Validate arguments
+ if (ipc == NULL || e == NULL)
+ {
+ return;
+ }
+
+ JoinSockToSockEvent(ipc->Sock, e);
+}
+
+// End of IPC connection
+void FreeIPC(IPC *ipc)
+{
+ UINT i;
+ // Validate arguments
+ if (ipc == NULL)
+ {
+ return;
+ }
+
+ FreeTubeFlushList(ipc->FlushList);
+
+ Disconnect(ipc->Sock);
+ ReleaseSock(ipc->Sock);
+
+ if (ipc->Policy != NULL)
+ {
+ Free(ipc->Policy);
+ }
+
+ ReleaseCedar(ipc->Cedar);
+
+ FreeInterruptManager(ipc->Interrupt);
+
+ for (i = 0;i < LIST_NUM(ipc->ArpTable);i++)
+ {
+ IPC_ARP *a = LIST_DATA(ipc->ArpTable, i);
+ IPCFreeARP(a);
+ }
+
+ ReleaseList(ipc->ArpTable);
+
+ while (true)
+ {
+ BLOCK *b = GetNext(ipc->IPv4RecviedQueue);
+ if (b == NULL)
+ {
+ break;
+ }
+
+ FreeBlock(b);
+ }
+
+ ReleaseQueue(ipc->IPv4RecviedQueue);
+
+ Free(ipc);
+}
+
+// Release the IP address from the DHCP server
+void IPCDhcpFreeIP(IPC *ipc, IP *dhcp_server)
+{
+ DHCP_OPTION_LIST req;
+ UINT tran_id = Rand32();
+ // Validate arguments
+ if (ipc == NULL || dhcp_server == NULL)
+ {
+ return;
+ }
+
+ Zero(&req, sizeof(req));
+ req.Opcode = DHCP_RELEASE;
+ req.ServerAddress = IPToUINT(dhcp_server);
+
+ FreeDHCPv4Data(IPCSendDhcpRequest(ipc, NULL, tran_id, &req, 0, 0, NULL));
+}
+
+// Update the IP address using the DHCP
+void IPCDhcpRenewIP(IPC *ipc, IP *dhcp_server)
+{
+ DHCP_OPTION_LIST req;
+ UINT tran_id = Rand32();
+ // Validate arguments
+ if (ipc == NULL || dhcp_server == NULL)
+ {
+ return;
+ }
+
+ // Send a DHCP Request
+ Zero(&req, sizeof(req));
+ req.Opcode = DHCP_REQUEST;
+ StrCpy(req.Hostname, sizeof(req.Hostname), ipc->ClientHostname);
+ req.RequestedIp = IPToUINT(&ipc->ClientIPAddress);
+
+ FreeDHCPv4Data(IPCSendDhcpRequest(ipc, dhcp_server, tran_id, &req, 0, 0, NULL));
+}
+
+// Get the information other than the IP address with using DHCP
+bool IPCDhcpRequestInformIP(IPC *ipc, DHCP_OPTION_LIST *opt, TUBE *discon_poll_tube, IP *client_ip)
+{
+ DHCP_OPTION_LIST req;
+ DHCPV4_DATA *d;
+ UINT tran_id = Rand32();
+ bool ok;
+ // Validate arguments
+ if (ipc == NULL || opt == NULL || client_ip == NULL)
+ {
+ return false;
+ }
+
+ // Send a DHCP Inform
+ Zero(&req, sizeof(req));
+ req.Opcode = DHCP_INFORM;
+ req.ClientAddress = IPToUINT(client_ip);
+ StrCpy(req.Hostname, sizeof(req.Hostname), ipc->ClientHostname);
+
+ d = IPCSendDhcpRequest(ipc, NULL, tran_id, &req, DHCP_ACK, IPC_DHCP_TIMEOUT, discon_poll_tube);
+ if (d == NULL)
+ {
+ return false;
+ }
+
+ // Analyze the DHCP Ack
+ ok = true;
+ if (d->ParsedOptionList->SubnetMask == 0)
+ {
+ ok = false;
+ }
+
+ if (ok == false)
+ {
+ FreeDHCPv4Data(d);
+ return false;
+ }
+
+ Copy(opt, d->ParsedOptionList, sizeof(DHCP_OPTION_LIST));
+
+ FreeDHCPv4Data(d);
+
+ return true;
+}
+
+// Make a request for IP addresses using DHCP
+bool IPCDhcpAllocateIP(IPC *ipc, DHCP_OPTION_LIST *opt, TUBE *discon_poll_tube)
+{
+ return IPCDhcpAllocateIPEx(ipc, opt, discon_poll_tube, false);
+}
+bool IPCDhcpAllocateIPEx(IPC *ipc, DHCP_OPTION_LIST *opt, TUBE *discon_poll_tube, bool openvpn_compatible)
+{
+ DHCP_OPTION_LIST req;
+ DHCPV4_DATA *d, *d2;
+ UINT tran_id = Rand32();
+ bool ok;
+ UINT request_ip = 0;
+ IP current_scanning_ip;
+ UCHAR current_scanning_addr8;
+ UCHAR begin_scanning_addr8;
+ UINT64 giveup = Tick64() + (UINT64)IPC_DHCP_TIMEOUT_TOTAL_GIVEUP;
+ LIST *release_list;
+ bool ret = false;
+ // Validate arguments
+ if (ipc == NULL || opt == NULL)
+ {
+ return false;
+ }
+
+ release_list = NewListFast(NULL);
+
+ Zero(¤t_scanning_ip, sizeof(current_scanning_ip));
+ current_scanning_addr8 = 0;
+ begin_scanning_addr8 = 0;
+
+LABEL_RETRY_FOR_OPENVPN:
+ tran_id = Rand32();
+ // Send a DHCP Discover
+ Zero(&req, sizeof(req));
+ req.RequestedIp = request_ip;
+ req.Opcode = DHCP_DISCOVER;
+ StrCpy(req.Hostname, sizeof(req.Hostname), ipc->ClientHostname);
+
+ d = IPCSendDhcpRequest(ipc, NULL, tran_id, &req, DHCP_OFFER, IPC_DHCP_TIMEOUT, discon_poll_tube);
+ if (d == NULL)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ // Analyze the DHCP Offer
+ ok = true;
+ if (IsValidUnicastIPAddressUINT4(d->ParsedOptionList->ClientAddress) == false)
+ {
+ ok = false;
+ }
+ if (IsValidUnicastIPAddressUINT4(d->ParsedOptionList->ServerAddress) == false)
+ {
+ ok = false;
+ }
+ if (d->ParsedOptionList->SubnetMask == 0)
+ {
+ ok = false;
+ }
+ if (d->ParsedOptionList->LeaseTime == 0)
+ {
+ d->ParsedOptionList->LeaseTime = IPC_DHCP_DEFAULT_LEASE;
+ }
+ if (d->ParsedOptionList->LeaseTime <= IPC_DHCP_MIN_LEASE)
+ {
+ d->ParsedOptionList->LeaseTime = IPC_DHCP_MIN_LEASE;
+ }
+
+ if (ok == false)
+ {
+ FreeDHCPv4Data(d);
+ goto LABEL_CLEANUP;
+ }
+
+ if (openvpn_compatible)
+ {
+ UINT ip = d->ParsedOptionList->ClientAddress;
+
+ if (OvsIsCompatibleL3IP(ip) == false)
+ {
+ char tmp[64];
+
+ DHCP_OPTION_LIST req;
+ IPC_DHCP_RELESAE_QUEUE *q;
+
+ // If the offered IP address is not used, place the address
+ // in release memo list to release at the end of this function
+ Zero(&req, sizeof(req));
+ req.Opcode = DHCP_RELEASE;
+ req.ServerAddress = d->ParsedOptionList->ServerAddress;
+
+ q = ZeroMalloc(sizeof(IPC_DHCP_RELESAE_QUEUE));
+ Copy(&q->Req, &req, sizeof(DHCP_OPTION_LIST));
+ q->TranId = tran_id;
+ Copy(q->MacAddress, ipc->MacAddress, 6);
+
+ Add(release_list, q);
+
+ FreeDHCPv4Data(d);
+
+ if (Tick64() >= giveup)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ if (IsZero(¤t_scanning_ip, sizeof(IP)))
+ {
+ UINTToIP(¤t_scanning_ip, ip);
+ current_scanning_addr8 = current_scanning_ip.addr[3];
+
+ if ((current_scanning_addr8 % 4) != 1)
+ {
+ current_scanning_addr8 = (UCHAR)(((((UINT)current_scanning_addr8 - 1) / 4) + 1) * 4 + 1);
+ }
+
+ begin_scanning_addr8 = current_scanning_addr8;
+ }
+ else
+ {
+ current_scanning_addr8 += 4;
+
+ if (current_scanning_addr8 == begin_scanning_addr8)
+ {
+ goto LABEL_CLEANUP;
+ }
+ }
+
+ current_scanning_ip.addr[3] = current_scanning_addr8;
+
+ request_ip = IPToUINT(¤t_scanning_ip);
+
+ IPToStr32(tmp, sizeof(tmp), request_ip);
+
+ // Generate another MAC address
+ ipc->MacAddress[5]++;
+
+ Debug("Trying Allocating IP for OpenVPN: %s\n", tmp);
+
+ goto LABEL_RETRY_FOR_OPENVPN;
+ }
+ }
+
+ // Send a DHCP Request
+ Zero(&req, sizeof(req));
+ req.Opcode = DHCP_REQUEST;
+ StrCpy(req.Hostname, sizeof(req.Hostname), ipc->ClientHostname);
+ req.ServerAddress = d->ParsedOptionList->ServerAddress;
+ req.RequestedIp = d->ParsedOptionList->ClientAddress;
+
+ d2 = IPCSendDhcpRequest(ipc, NULL, tran_id, &req, DHCP_ACK, IPC_DHCP_TIMEOUT, discon_poll_tube);
+ if (d2 == NULL)
+ {
+ FreeDHCPv4Data(d);
+ goto LABEL_CLEANUP;
+ }
+
+ // Analyze the DHCP Ack
+ ok = true;
+ if (IsValidUnicastIPAddressUINT4(d2->ParsedOptionList->ClientAddress) == false)
+ {
+ ok = false;
+ }
+ if (IsValidUnicastIPAddressUINT4(d2->ParsedOptionList->ServerAddress) == false)
+ {
+ ok = false;
+ }
+ if (d2->ParsedOptionList->SubnetMask == 0)
+ {
+ ok = false;
+ }
+ if (d2->ParsedOptionList->LeaseTime == 0)
+ {
+ d2->ParsedOptionList->LeaseTime = IPC_DHCP_DEFAULT_LEASE;
+ }
+ if (d2->ParsedOptionList->LeaseTime <= IPC_DHCP_MIN_LEASE)
+ {
+ d2->ParsedOptionList->LeaseTime = IPC_DHCP_MIN_LEASE;
+ }
+
+ if (ok == false)
+ {
+ FreeDHCPv4Data(d);
+ FreeDHCPv4Data(d2);
+ goto LABEL_CLEANUP;
+ }
+
+ Copy(opt, d2->ParsedOptionList, sizeof(DHCP_OPTION_LIST));
+
+ FreeDHCPv4Data(d);
+ FreeDHCPv4Data(d2);
+
+ ret = true;
+
+LABEL_CLEANUP:
+ if (release_list != NULL)
+ {
+ // Release the IP address that was acquired from the DHCP server to no avail on the way
+ UINT i;
+ UCHAR mac_backup[6];
+
+ Copy(mac_backup, ipc->MacAddress, 6);
+
+ for (i = 0;i < LIST_NUM(release_list);i++)
+ {
+ IPC_DHCP_RELESAE_QUEUE *q = LIST_DATA(release_list, i);
+
+ Copy(ipc->MacAddress, q->MacAddress, 6);
+ FreeDHCPv4Data(IPCSendDhcpRequest(ipc, NULL, q->TranId, &q->Req, 0, 0, NULL));
+
+ IPCProcessInterrupts(ipc);
+
+ Free(q);
+ }
+
+ Copy(ipc->MacAddress, mac_backup, 6);
+
+ ReleaseList(release_list);
+ }
+ return ret;
+}
+
+// Send out a DHCP request, and wait for a corresponding response
+DHCPV4_DATA *IPCSendDhcpRequest(IPC *ipc, IP *dest_ip, UINT tran_id, DHCP_OPTION_LIST *opt, UINT expecting_code, UINT timeout, TUBE *discon_poll_tube)
+{
+ UINT resend_interval;
+ UINT64 giveup_time;
+ UINT64 next_send_time = 0;
+ TUBE *tubes[3];
+ UINT num_tubes = 0;
+ // Validate arguments
+ if (ipc == NULL || opt == NULL || (expecting_code != 0 && timeout == 0))
+ {
+ return NULL;
+ }
+
+ // Retransmission interval
+ resend_interval = MAX(1, (timeout / 3) - 100);
+
+ // Time-out time
+ giveup_time = Tick64() + (UINT64)timeout;
+
+ AddInterrupt(ipc->Interrupt, giveup_time);
+
+ tubes[num_tubes++] = ipc->Sock->RecvTube;
+ tubes[num_tubes++] = ipc->Sock->SendTube;
+
+ if (discon_poll_tube != NULL)
+ {
+ tubes[num_tubes++] = discon_poll_tube;
+ }
+
+ while (true)
+ {
+ UINT64 now = Tick64();
+ BUF *dhcp_packet;
+
+ IPCFlushArpTable(ipc);
+
+ // Time-out inspection
+ if ((expecting_code != 0) && (now >= giveup_time))
+ {
+ return NULL;
+ }
+
+ // Send by building a DHCP packet periodically
+ if (next_send_time == 0 || next_send_time <= now)
+ {
+ dhcp_packet = IPCBuildDhcpRequest(ipc, dest_ip, tran_id, opt);
+ if (dhcp_packet == NULL)
+ {
+ return NULL;
+ }
+
+ IPCSendIPv4(ipc, dhcp_packet->Buf, dhcp_packet->Size);
+
+ FreeBuf(dhcp_packet);
+
+ if (expecting_code == 0)
+ {
+ return NULL;
+ }
+
+ next_send_time = now + (UINT64)resend_interval;
+
+ AddInterrupt(ipc->Interrupt, next_send_time);
+ }
+
+ // Happy processing
+ IPCProcessL3Events(ipc);
+
+ while (true)
+ {
+ // Receive a packet
+ BLOCK *b = IPCRecvIPv4(ipc);
+ PKT *pkt;
+ DHCPV4_DATA *dhcp;
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ // Parse the packet
+ pkt = ParsePacketIPv4WithDummyMacHeader(b->Buf, b->Size);
+
+ dhcp = ParseDHCPv4Data(pkt);
+
+ if (dhcp != NULL)
+ {
+ if (Endian32(dhcp->Header->TransactionId) == tran_id && dhcp->OpCode == expecting_code)
+ {
+ // Expected operation code and transaction ID are returned
+ FreePacketWithData(pkt);
+ FreeBlock(b);
+
+ return dhcp;
+ }
+
+ FreeDHCPv4Data(dhcp);
+ }
+
+ FreePacketWithData(pkt);
+
+ FreeBlock(b);
+ }
+
+ if (IsTubeConnected(ipc->Sock->RecvTube) == false || IsTubeConnected(ipc->Sock->SendTube) == false ||
+ (discon_poll_tube != NULL && IsTubeConnected(discon_poll_tube) == false))
+ {
+ // Session is disconnected
+ return NULL;
+ }
+
+ // Keep the CPU waiting
+ WaitForTubes(tubes, num_tubes, GetNextIntervalForInterrupt(ipc->Interrupt));
+ }
+
+ return NULL;
+}
+
+// Build a DHCP request packet
+BUF *IPCBuildDhcpRequest(IPC *ipc, IP *dest_ip, UINT tran_id, DHCP_OPTION_LIST *opt)
+{
+ IPV4_HEADER ip;
+ UDP_HEADER* udp;
+ DHCPV4_HEADER dhcp;
+ UINT blank_size = 128 + 64;
+ BUF *ret;
+ BUF *b;
+ UDPV4_PSEUDO_HEADER *ph;
+ UINT ph_size;
+ UINT udp_size;
+ UINT magic_number = Endian32(DHCP_MAGIC_COOKIE);
+ USHORT checksum;
+ // Validate arguments
+ if (ipc == NULL || opt == NULL)
+ {
+ return NULL;
+ }
+
+ // DHCPv4 Options
+ b = IPCBuildDhcpRequestOptions(ipc, opt);
+ if (b == NULL)
+ {
+ return NULL;
+ }
+
+ // DHCPv4 Header
+ Zero(&dhcp, sizeof(dhcp));
+ dhcp.OpCode = 1;
+ dhcp.HardwareType = ARP_HARDWARE_TYPE_ETHERNET;
+ dhcp.HardwareAddressSize = 6;
+ dhcp.Hops = 0;
+ dhcp.TransactionId = Endian32(tran_id);
+ dhcp.ClientIP = IPToUINT(&ipc->ClientIPAddress);
+ if (dhcp.ClientIP == 0)
+ {
+ dhcp.ClientIP = opt->ClientAddress;
+ }
+ Copy(dhcp.ClientMacAddress, ipc->MacAddress, 6);
+
+ // UDP pseudo header
+ ph_size = b->Size + sizeof(dhcp) + blank_size + sizeof(UINT) + sizeof(UDPV4_PSEUDO_HEADER);
+ udp_size = b->Size + sizeof(dhcp) + blank_size + sizeof(UINT) + sizeof(UDP_HEADER);
+
+ ph = ZeroMalloc(ph_size);
+ ph->SrcIP = IPToUINT(&ipc->ClientIPAddress);
+ ph->DstIP = IPToUINT(dest_ip);
+ ph->Protocol = IP_PROTO_UDP;
+ ph->PacketLength1 = Endian16(udp_size);
+ ph->SrcPort = Endian16(NAT_DHCP_CLIENT_PORT);
+ ph->DstPort = Endian16(NAT_DHCP_SERVER_PORT);
+ ph->PacketLength2 = Endian16(udp_size);
+
+ Copy(((UCHAR *)(ph)) + sizeof(UDPV4_PSEUDO_HEADER), &dhcp, sizeof(dhcp));
+ Copy(((UCHAR *)(ph)) + sizeof(UDPV4_PSEUDO_HEADER) + sizeof(dhcp) + blank_size, &magic_number, sizeof(UINT));
+ Copy(((UCHAR *)(ph)) + sizeof(UDPV4_PSEUDO_HEADER) + sizeof(dhcp) + blank_size + sizeof(UINT),
+ b->Buf, b->Size);
+
+ // UDP Header
+ udp = (UDP_HEADER *)(((UCHAR *)ph) + 12);
+
+ // Calculate the checksum
+ checksum = IpChecksum(ph, ph_size);
+ if (checksum == 0x0000)
+ {
+ checksum = 0xffff;
+ }
+ udp->Checksum = checksum;
+
+ // IP Header
+ Zero(&ip, sizeof(ip));
+ IPV4_SET_VERSION(&ip, 4);
+ IPV4_SET_HEADER_LEN(&ip, 5);
+ ip.Identification = Rand16();
+ ip.TimeToLive = 128;
+ ip.Protocol = IP_PROTO_UDP;
+ ip.SrcIP = IPToUINT(&ipc->ClientIPAddress);
+ if (dest_ip != NULL)
+ {
+ ip.DstIP = IPToUINT(dest_ip);
+ }
+ else
+ {
+ ip.DstIP = Endian32(0xffffffff);
+ }
+ ip.TotalLength = Endian16((USHORT)(sizeof(IPV4_HEADER) + udp_size));
+ ip.Checksum = IpChecksum(&ip, sizeof(IPV4_HEADER));
+
+ ret = NewBuf();
+
+ WriteBuf(ret, &ip, sizeof(IPV4_HEADER));
+ WriteBuf(ret, udp, udp_size);
+
+ FreeBuf(b);
+ Free(ph);
+
+ return ret;
+}
+
+// Build a option data in the DHCP request packet
+BUF *IPCBuildDhcpRequestOptions(IPC *ipc, DHCP_OPTION_LIST *opt)
+{
+ LIST *o;
+ UCHAR opcode;
+ UCHAR client_id[7];
+ BUF *ret;
+ // Validate arguments
+ if (ipc == NULL || opt == NULL)
+ {
+ return NULL;
+ }
+
+ o = NewListFast(NULL);
+
+ // Opcode
+ opcode = opt->Opcode;
+ Add(o, NewDhcpOption(DHCP_ID_MESSAGE_TYPE, &opcode, sizeof(opcode)));
+
+ // Server ID
+ if (opt->ServerAddress != 0)
+ {
+ Add(o, NewDhcpOption(DHCP_ID_SERVER_ADDRESS, &opt->ServerAddress, 4));
+ }
+
+ // Client MAC Address
+ client_id[0] = ARP_HARDWARE_TYPE_ETHERNET;
+ Copy(client_id + 1, ipc->MacAddress, 6);
+ Add(o, NewDhcpOption(DHCP_ID_CLIENT_ID, client_id, sizeof(client_id)));
+
+ // Requested IP Address
+ if (opt->RequestedIp != 0)
+ {
+ Add(o, NewDhcpOption(DHCP_ID_REQUEST_IP_ADDRESS, &opt->RequestedIp, 4));
+ }
+
+ // Hostname
+ if (IsEmptyStr(opt->Hostname) == false)
+ {
+ Add(o, NewDhcpOption(DHCP_ID_HOST_NAME, opt->Hostname, StrLen(opt->Hostname)));
+ }
+
+ // Vendor
+ Add(o, NewDhcpOption(DHCP_ID_VENDOR_ID, IPC_DHCP_VENDOR_ID, StrLen(IPC_DHCP_VENDOR_ID)));
+
+ // Parameter Request List
+ if (opcode == DHCP_DISCOVER || opcode == DHCP_REQUEST || opcode == DHCP_INFORM)
+ {
+ UCHAR param_list[12];
+
+ param_list[0] = 1;
+ param_list[1] = 15;
+ param_list[2] = 3;
+ param_list[3] = 6;
+ param_list[4] = 44;
+ param_list[5] = 46;
+ param_list[6] = 47;
+ param_list[7] = 31;
+ param_list[8] = 33;
+ param_list[9] = 121;
+ param_list[10] = 249;
+ param_list[11] = 43;
+
+ Add(o, NewDhcpOption(DHCP_ID_REQ_PARAM_LIST, param_list, sizeof(param_list)));
+ }
+
+ ret = BuildDhcpOptionsBuf(o);
+
+ FreeDhcpOptions(o);
+
+ return ret;
+}
+
+// Process the received ARP
+void IPCProcessArp(IPC *ipc, BLOCK *b)
+{
+ UCHAR *dest_mac;
+ UCHAR *src_mac;
+ ARPV4_HEADER *arp;
+ UCHAR *sender_mac;
+ IP sender_ip;
+ UCHAR *target_mac;
+ IP target_ip;
+ // Validate arguments
+ if (ipc == NULL || b == NULL || b->Size < (14 + sizeof(ARPV4_HEADER)))
+ {
+ return;
+ }
+
+ dest_mac = b->Buf + 0;
+ src_mac = b->Buf + 6;
+
+ arp = (ARPV4_HEADER *)(b->Buf + 14);
+
+ if (arp->HardwareType != Endian16(ARP_HARDWARE_TYPE_ETHERNET))
+ {
+ return;
+ }
+ if (arp->ProtocolType != Endian16(MAC_PROTO_IPV4))
+ {
+ return;
+ }
+ if (arp->HardwareSize != 6 || arp->ProtocolSize != 4)
+ {
+ return;
+ }
+
+ sender_mac = arp->SrcAddress;
+ UINTToIP(&sender_ip, arp->SrcIP);
+
+ target_mac = arp->TargetAddress;
+ UINTToIP(&target_ip, arp->TargetIP);
+
+ if (CmpIpAddr(&sender_ip, &ipc->ClientIPAddress) == 0)
+ {
+ // Source is myself
+ return;
+ }
+
+ IPCAssociateOnArpTable(ipc, &sender_ip, sender_mac);
+ IPCAssociateOnArpTable(ipc, &target_ip, target_mac);
+
+ if (Endian16(arp->Operation) == ARP_OPERATION_REQUEST)
+ {
+ // Received an ARP request
+ if (CmpIpAddr(&target_ip, &ipc->ClientIPAddress) == 0)
+ {
+ // Create a response since a request for its own IP address have received
+ if (IsValidUnicastMacAddress(sender_mac))
+ {
+ UCHAR tmp[14 + sizeof(ARPV4_HEADER)];
+ ARPV4_HEADER *arp = (ARPV4_HEADER *)(tmp + 14);
+
+ Copy(tmp + 0, sender_mac, 6);
+ Copy(tmp + 6, ipc->MacAddress, 6);
+ WRITE_USHORT(tmp + 12, MAC_PROTO_ARPV4);
+
+ arp->HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+ arp->ProtocolType = Endian16(MAC_PROTO_IPV4);
+ arp->HardwareSize = 6;
+ arp->ProtocolSize = 4;
+ arp->Operation = Endian16(ARP_OPERATION_RESPONSE);
+
+ Copy(arp->SrcAddress, ipc->MacAddress, 6);
+ arp->SrcIP = IPToUINT(&ipc->ClientIPAddress);
+
+ Copy(arp->TargetAddress, sender_mac, 6);
+ arp->TargetIP = IPToUINT(&sender_ip);
+
+ IPCSendL2(ipc, tmp, sizeof(tmp));
+ }
+ }
+ }
+}
+
+// Associate the MAC address and IP address on the ARP table
+void IPCAssociateOnArpTable(IPC *ipc, IP *ip, UCHAR *mac_address)
+{
+ IPC_ARP *a;
+ // Validate arguments
+ if (ipc == NULL || ip == NULL || IsValidUnicastIPAddress4(ip) == false || IsValidUnicastMacAddress(mac_address) == false)
+ {
+ return;
+ }
+ if (CmpIpAddr(&ipc->ClientIPAddress, ip) == 0 || Cmp(ipc->MacAddress, mac_address, 6) == 0)
+ {
+ return;
+ }
+ if (IsInSameNetwork4(ip, &ipc->ClientIPAddress, &ipc->SubnetMask) == false)
+ {
+ // Not to learn the IP address of outside the subnet
+ return;
+ }
+
+ if (CmpIpAddr(&ipc->BroadcastAddress, ip) == 0)
+ {
+ // Not to learn the broadcast IP address
+ return;
+ }
+
+ // Search whether there is ARP table entry already
+ a = IPCSearchArpTable(ipc, ip);
+ if (a == NULL)
+ {
+ // Add to the ARP table
+ a = IPCNewARP(ip, mac_address);
+
+ Insert(ipc->ArpTable, a);
+ }
+ else
+ {
+ Copy(a->MacAddress, mac_address, 6);
+
+ // There is the ARP table entry already
+ if (a->Resolved == false)
+ {
+ a->Resolved = true;
+ a->GiveupTime = 0;
+
+ // Send all the packets that are accumulated to be sent
+ while (true)
+ {
+ BLOCK *b = GetNext(a->PacketQueue);
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ IPCSendIPv4WithDestMacAddr(ipc, b->Buf, b->Size, a->MacAddress);
+
+ FreeBlock(b);
+ }
+ }
+
+ // Extend the expiration date
+ a->ExpireTime = Tick64() + (UINT64)IPC_ARP_LIFETIME;
+ }
+}
+
+// Identifiy whether the MAC address is a normal unicast address
+bool IsValidUnicastMacAddress(UCHAR *mac)
+{
+ // Validate arguments
+ if (mac == NULL)
+ {
+ return false;
+ }
+
+ if (mac[0] & 0x01)
+ {
+ return false;
+ }
+
+ if (IsZero(mac, 6))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Identify whether the IP address is a normal unicast address
+bool IsValidUnicastIPAddress4(IP *ip)
+{
+ UINT i;
+ // Validate arguments
+ if (IsIP4(ip) == false)
+ {
+ return false;
+ }
+
+ if (IsZeroIP(ip))
+ {
+ return false;
+ }
+
+ if (ip->addr[0] >= 224 && ip->addr[0] <= 239)
+ {
+ // IPv4 Multicast
+ return false;
+ }
+
+ for (i = 0;i < 4;i++)
+ {
+ if (ip->addr[i] != 255)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+bool IsValidUnicastIPAddressUINT4(UINT ip)
+{
+ IP a;
+
+ UINTToIP(&a, ip);
+
+ return IsValidUnicastIPAddress4(&a);
+}
+
+// Interrupt process (This is called periodically)
+void IPCProcessInterrupts(IPC *ipc)
+{
+ // Validate arguments
+ if (ipc == NULL)
+ {
+ return;
+ }
+
+ FlushTubeFlushList(ipc->FlushList);
+}
+
+// Process the L3 event by the IPC
+void IPCProcessL3Events(IPC *ipc)
+{
+ IPCProcessL3EventsEx(ipc, 0);
+}
+void IPCProcessL3EventsEx(IPC *ipc, UINT64 now)
+{
+ // Validate arguments
+ if (ipc == NULL)
+ {
+ return;
+ }
+ if (now == 0)
+ {
+ now = Tick64();
+ }
+
+ // Remove old ARP table entries
+ IPCFlushArpTableEx(ipc, now);
+
+ // Receive all the L2 packet
+ while (true)
+ {
+ BLOCK *b = IPCRecvL2(ipc);
+ if (b == NULL)
+ {
+ // All reception completed
+ break;
+ }
+
+ if (b->Size >= 14)
+ {
+ UCHAR *dest_mac = b->Buf + 0;
+ UCHAR *src_mac = b->Buf + 6;
+ USHORT protocol = READ_USHORT(b->Buf + 12);
+
+ // Confirm the destination MAC address
+ // (Receive if the destination MAC address is the IPC address or a broadcast address)
+ if (Cmp(dest_mac, ipc->MacAddress, 6) == 0 || dest_mac[0] & 0x01)
+ {
+ // If the source MAC address is itselves or invalid address, ignore the packet
+ if (Cmp(src_mac, ipc->MacAddress, 6) != 0 && IsValidUnicastMacAddress(src_mac))
+ {
+ if (protocol == MAC_PROTO_ARPV4)
+ {
+ // ARP receiving process
+ IPCProcessArp(ipc, b);
+ }
+ else if (protocol == MAC_PROTO_IPV4)
+ {
+ // IPv4 receiving process
+ if (b->Size >= (14 + 20))
+ {
+ UCHAR *data = Clone(b->Buf + 14, b->Size - 14);
+ UINT size = b->Size - 14;
+ IP ip_src, ip_dst;
+ bool ok = false;
+
+ // Extract the IP address portion
+ UINTToIP(&ip_src, *((UINT *)(((UCHAR *)data) + 12)));
+ UINTToIP(&ip_dst, *((UINT *)(((UCHAR *)data) + 16)));
+
+ // Receive only if the IPv4 destination address is its own
+ // or 255.255.255.255 or a multicast address or a broadcast address
+ if (CmpIpAddr(&ip_dst, &ipc->ClientIPAddress) == 0)
+ {
+ ok = true;
+ }
+ else if (ip_dst.addr[0] == 255 && ip_dst.addr[1] == 255 &&
+ ip_dst.addr[2] == 255 && ip_dst.addr[3] == 255)
+ {
+ ok = true;
+ }
+ else if (ip_dst.addr[0] >= 224 && ip_dst.addr[0] <= 239)
+ {
+ ok = true;
+ }
+ else
+ {
+ if (CmpIpAddr(&ipc->BroadcastAddress, &ip_dst) == 0)
+ {
+ ok = true;
+ }
+
+ if (IsZeroIP(&ipc->ClientIPAddress))
+ {
+ // Client IP address is undetermined
+ ok = true;
+ }
+ }
+
+ if (ok)
+ {
+ IPCAssociateOnArpTable(ipc, &ip_src, src_mac);
+
+ // Place in the reception queue
+ InsertQueue(ipc->IPv4RecviedQueue, NewBlock(data, size, 0));
+ }
+ else
+ {
+ // This packet is discarded because it is irrelevant for me
+ Free(data);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ FreeBlock(b);
+ }
+
+ IPCProcessInterrupts(ipc);
+}
+
+// Configure IPv4 parameters
+bool IPCSetIPv4Parameters(IPC *ipc, IP *ip, IP *subnet, IP *gw)
+{
+ bool changed = false;
+ // Validate arguments
+ if (ipc == NULL || ip == NULL || subnet == NULL)
+ {
+ return false;
+ }
+
+ if (CmpIpAddr(&ipc->ClientIPAddress, ip) != 0)
+ {
+ changed = true;
+ }
+ Copy(&ipc->ClientIPAddress, ip, sizeof(IP));
+
+ if (CmpIpAddr(&ipc->SubnetMask, subnet) != 0)
+ {
+ changed = true;
+ }
+ Copy(&ipc->SubnetMask, subnet, sizeof(IP));
+
+ if (gw != NULL)
+ {
+ if (CmpIpAddr(&ipc->DefaultGateway, gw) != 0)
+ {
+ changed = true;
+ }
+
+ Copy(&ipc->DefaultGateway, gw, sizeof(IP));
+ }
+ else
+ {
+ if (IsZeroIP(&ipc->DefaultGateway) == false)
+ {
+ changed = true;
+ }
+
+ Zero(&ipc->DefaultGateway, sizeof(IP));
+ }
+
+ GetBroadcastAddress4(&ipc->BroadcastAddress, ip, subnet);
+
+ return changed;
+}
+
+// Send an IPv4 packet (client -> server)
+void IPCSendIPv4(IPC *ipc, void *data, UINT size)
+{
+ IP ip_src, ip_dst;
+ IP ip_dst_local;
+ bool is_broadcast = false;
+ UCHAR uc;
+ // Validate arguments
+ if (ipc == NULL || data == NULL || size < 20 || size > 1500)
+ {
+ return;
+ }
+
+ uc = ((UCHAR *)data)[0];
+ if (((uc >> 4) & 0x0f) != 4)
+ {
+ // Not an IPv4
+ return;
+ }
+
+ // Extract the IP address portion
+ UINTToIP(&ip_src, *((UINT *)(((UCHAR *)data) + 12)));
+ UINTToIP(&ip_dst, *((UINT *)(((UCHAR *)data) + 16)));
+
+ // Filter the source IP address
+ if (CmpIpAddr(&ip_src, &ipc->ClientIPAddress) != 0)
+ {
+ // Cut off packets from illegal IP address
+ return;
+ }
+
+ if (IsZeroIP(&ip_dst))
+ {
+ // Illegal destination address
+ return;
+ }
+
+ if (CmpIpAddr(&ip_dst, &ipc->ClientIPAddress) == 0)
+ {
+ // Packet destined for myself
+ return;
+ }
+
+ // Get the IP address of the relayed destination
+ Copy(&ip_dst_local, &ip_dst, sizeof(IP));
+ if (ip_dst.addr[0]==8)
+ DoNothing();
+ if (IsInSameNetwork4(&ip_dst, &ipc->ClientIPAddress, &ipc->SubnetMask) == false)
+ {
+ Copy(&ip_dst_local, &ipc->DefaultGateway, sizeof(IP));
+ }
+
+ if (CmpIpAddr(&ipc->BroadcastAddress, &ip_dst) == 0)
+ {
+ // Local Broadcast
+ is_broadcast = true;
+ }
+
+ if (ip_dst.addr[0] == 255 && ip_dst.addr[1] == 255 && ip_dst.addr[2] == 255 && ip_dst.addr[3] == 255)
+ {
+ // Global Broadcast
+ is_broadcast = true;
+ }
+
+ if (ip_dst.addr[0] >= 224 && ip_dst.addr[0] <= 239)
+ {
+ // IPv4 Multicast
+ is_broadcast = true;
+ }
+
+ if (is_broadcast)
+ {
+ // Send a broadcast packet
+ UCHAR dest[6];
+ UINT i;
+
+ // Destination
+ for (i = 0;i < 6;i++)
+ {
+ dest[i] = 0xff;
+ }
+
+ // Send
+ IPCSendIPv4WithDestMacAddr(ipc, data, size, dest);
+
+ return;
+ }
+
+ if (IsZeroIP(&ip_dst_local))
+ {
+ return;
+ }
+
+ IPCSendIPv4Unicast(ipc, data, size, &ip_dst_local);
+}
+
+// Send an IPv4 packet with a specified destination MAC address
+void IPCSendIPv4WithDestMacAddr(IPC *ipc, void *data, UINT size, UCHAR *dest_mac_addr)
+{
+ UCHAR tmp[1514];
+ // Validate arguments
+ if (ipc == NULL || data == NULL || size < 20 || size > 1500 || dest_mac_addr == NULL)
+ {
+ return;
+ }
+
+ // Destination
+ Copy(tmp + 0, dest_mac_addr, 6);
+
+ // Source
+ Copy(tmp + 6, ipc->MacAddress, 6);
+
+ // Protocol number
+ WRITE_USHORT(tmp + 12, MAC_PROTO_IPV4);
+
+ // Data
+ Copy(tmp + 14, data, size);
+
+ // Send
+ IPCSendL2(ipc, tmp, size + 14);
+}
+
+// Remove old ARP table entries
+void IPCFlushArpTable(IPC *ipc)
+{
+ IPCFlushArpTableEx(ipc, 0);
+}
+void IPCFlushArpTableEx(IPC *ipc, UINT64 now)
+{
+ UINT i;
+ LIST *o = NULL;
+ // Validate arguments
+ if (ipc == NULL)
+ {
+ return;
+ }
+ if (now == 0)
+ {
+ now = Tick64();
+ }
+
+ for (i = 0;i < LIST_NUM(ipc->ArpTable);i++)
+ {
+ IPC_ARP *a = LIST_DATA(ipc->ArpTable, i);
+ bool b = false;
+
+ if (a->Resolved && a->ExpireTime <= now)
+ {
+ b = true;
+ }
+ else if (a->Resolved == false && a->GiveupTime <= now)
+ {
+ b = true;
+ }
+
+ if (b)
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Add(o, a);
+ }
+ }
+
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IPC_ARP *a = LIST_DATA(o, i);
+
+ IPCFreeARP(a);
+
+ Delete(ipc->ArpTable, a);
+ }
+
+ ReleaseList(o);
+ }
+}
+
+// Send an IPv4 unicast packet
+void IPCSendIPv4Unicast(IPC *ipc, void *data, UINT size, IP *next_ip)
+{
+ IPC_ARP *a;
+ // Validate arguments
+ if (ipc == NULL || data == NULL || size < 20 || size > 1500 || next_ip == NULL)
+ {
+ return;
+ }
+
+ a = IPCSearchArpTable(ipc, next_ip);
+
+ if (a != NULL)
+ {
+ // ARP entry is found
+ if (a->Resolved)
+ {
+ // Send
+ a->ExpireTime = Tick64() + (UINT64)IPC_ARP_LIFETIME;
+
+ IPCSendIPv4WithDestMacAddr(ipc, data, size, a->MacAddress);
+ }
+ else
+ {
+ // Undeliverable because of unresolved table. Accumulate in the queue
+ if (a->PacketQueue->num_item < IPC_MAX_PACKET_QUEUE_LEN)
+ {
+ InsertQueue(a->PacketQueue, NewBlock(Clone(data, size), size, false));
+ }
+ }
+ }
+ else
+ {
+ ARPV4_HEADER arp;
+ UCHAR tmp[14 + sizeof(ARPV4_HEADER)];
+ UINT i;
+
+ // Because there is no such ARP entry, create a new one
+ a = IPCNewARP(next_ip, NULL);
+
+ // Send an ARP request
+ Zero(&arp, sizeof(arp));
+ arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+ arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
+ arp.HardwareSize = 6;
+ arp.ProtocolSize = 4;
+ arp.Operation = Endian16(ARP_OPERATION_REQUEST);
+ Copy(&arp.SrcAddress, &ipc->MacAddress, 6);
+ arp.SrcIP = IPToUINT(&ipc->ClientIPAddress);
+ arp.TargetIP = IPToUINT(next_ip);
+
+ for (i = 0;i < 6;i++)
+ {
+ tmp[i] = 0xff;
+ }
+
+ Copy(tmp + 6, ipc->MacAddress, 6);
+
+ WRITE_USHORT(tmp + 12, MAC_PROTO_ARPV4);
+ Copy(tmp + 14, &arp, sizeof(ARPV4_HEADER));
+
+ IPCSendL2(ipc, tmp, 14 + sizeof(ARPV4_HEADER));
+
+ // Accumulate the IP packet to be transmitted in the queue
+ if (a->PacketQueue->num_item < IPC_MAX_PACKET_QUEUE_LEN)
+ {
+ InsertQueue(a->PacketQueue, NewBlock(Clone(data, size), size, false));
+ }
+
+ Insert(ipc->ArpTable, a);
+ }
+}
+
+// Search the ARP table
+IPC_ARP *IPCSearchArpTable(IPC *ipc, IP *ip)
+{
+ IPC_ARP t;
+ IPC_ARP *a;
+ // Validate arguments
+ if (ipc == NULL || ip == NULL)
+ {
+ return NULL;
+ }
+
+ Copy(&t.Ip, ip, sizeof(IP));
+
+ a = Search(ipc->ArpTable, &t);
+
+ return a;
+}
+
+// Release the ARP entry
+void IPCFreeARP(IPC_ARP *a)
+{
+ BLOCK *b;
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ b = GetNext(a->PacketQueue);
+ if (b == NULL)
+ {
+ break;
+ }
+
+ FreeBlock(b);
+ }
+
+ ReleaseQueue(a->PacketQueue);
+
+ Free(a);
+}
+
+// Create a new ARP entry
+IPC_ARP *IPCNewARP(IP *ip, UCHAR *mac_address)
+{
+ IPC_ARP *a;
+ // Validate arguments
+ if (ip == NULL)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(IPC_ARP));
+
+ Copy(&a->Ip, ip, sizeof(IP));
+ if (mac_address != NULL)
+ {
+ Copy(a->MacAddress, mac_address, 6);
+ a->Resolved = true;
+ a->ExpireTime = Tick64() + (UINT64)IPC_ARP_LIFETIME;
+ }
+ else
+ {
+ a->GiveupTime = Tick64() + (UINT64)IPC_ARP_GIVEUPTIME;
+ }
+
+ a->PacketQueue = NewQueueFast();
+
+ return a;
+}
+
+// Compare ARP entries
+int IPCCmpArpTable(void *p1, void *p2)
+{
+ IPC_ARP *a1, *a2;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ a1 = *(IPC_ARP **)p1;
+ a2 = *(IPC_ARP **)p2;
+ if (a1 == NULL || a2 == NULL)
+ {
+ return 0;
+ }
+
+ return CmpIpAddr(&a1->Ip, &a2->Ip);
+}
+
+// Send an Ethernet packet (client -> server)
+void IPCSendL2(IPC *ipc, void *data, UINT size)
+{
+ // Validate arguments
+ if (ipc == NULL || data == NULL || size == 0)
+ {
+ return;
+ }
+
+ if (ipc->Sock == NULL)
+ {
+ return;
+ }
+
+ TubeSendEx(ipc->Sock->SendTube, data, size, NULL, true);
+ AddTubeToFlushList(ipc->FlushList, ipc->Sock->SendTube);
+}
+
+// Receive an IPv4 packet (server -> client)
+BLOCK *IPCRecvIPv4(IPC *ipc)
+{
+ BLOCK *b;
+ // Validate arguments
+ if (ipc == NULL)
+ {
+ return NULL;
+ }
+
+ b = GetNext(ipc->IPv4RecviedQueue);
+
+ return b;
+}
+
+// Receive an Ethernet packet (server -> client)
+BLOCK *IPCRecvL2(IPC *ipc)
+{
+ TUBEDATA *d;
+ BLOCK *b;
+ // Validate arguments
+ if (ipc == NULL)
+ {
+ return NULL;
+ }
+
+ if (ipc->Sock == NULL)
+ {
+ return NULL;
+ }
+
+ d = TubeRecvAsync(ipc->Sock->RecvTube);
+
+ if (d == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBlock(d->Data, d->DataSize, 0);
+
+ Free(d->Header);
+ Free(d);
+
+ return b;
+}
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_IPC.h b/src/Cedar/IPsec_IPC.h
new file mode 100644
index 00000000..0861c13f
--- /dev/null
+++ b/src/Cedar/IPsec_IPC.h
@@ -0,0 +1,243 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_IPC.h
+// Header of IPsec_IPC.c
+
+#ifndef IPSEC_IPC
+#define IPSEC_IPC
+
+// Constants
+#define IPC_ARP_LIFETIME (3 * 60 * 1000)
+#define IPC_ARP_GIVEUPTIME (1 * 1000)
+#define IPC_DHCP_TIMEOUT (5 * 1000)
+#define IPC_DHCP_TIMEOUT_TOTAL_GIVEUP (20 * 1000)
+#define IPC_DHCP_MIN_LEASE 5
+#define IPC_DHCP_DEFAULT_LEASE 3600
+
+#define IPC_MAX_PACKET_QUEUE_LEN 10000
+
+#define IPC_DHCP_VENDOR_ID "MSFT 5.0"
+
+#define IPC_PASSWORD_MSCHAPV2_TAG "xH7DiNlurDhcYV4a:"
+
+// ARP table entry
+struct IPC_ARP
+{
+ IP Ip; // IP address
+ bool Resolved; // Whether the MAC address have been resolved
+ UCHAR MacAddress[6]; // MAC address
+ UINT64 GiveupTime; // Time to give up (in the case of unresolved)
+ UINT64 ExpireTime; // Expiration date (If resolved)
+ QUEUE *PacketQueue; // Transmission packet queue
+};
+
+// DHCP release queue
+struct IPC_DHCP_RELESAE_QUEUE
+{
+ DHCP_OPTION_LIST Req;
+ UINT TranId;
+ UCHAR MacAddress[6];
+};
+
+// IPC_PARAM
+struct IPC_PARAM
+{
+ char ClientName[MAX_SIZE];
+ char Postfix[MAX_SIZE];
+ char HubName[MAX_HUBNAME_LEN + 1];
+ char UserName[MAX_USERNAME_LEN + 1];
+ char Password[MAX_PASSWORD_LEN + 1];
+ IP ClientIp;
+ UINT ClientPort;
+ IP ServerIp;
+ UINT ServerPort;
+ char ClientHostname[MAX_SIZE];
+ char CryptName[MAX_SIZE];
+ bool BridgeMode;
+ UINT Mss;
+ bool IsL3Mode;
+ bool IsOpenVPN;
+};
+
+// IPC_ASYNC object
+struct IPC_ASYNC
+{
+ CEDAR *Cedar; // Cedar
+ IPC_PARAM Param; // Parameters for creating IPC
+ THREAD *Thread; // Thread
+ SOCK_EVENT *SockEvent; // Socket events that is set when the connection is completed
+ bool Done; // Processing completion flag
+ IPC *Ipc; // IPC object (if it fails to connect, the value is NULL)
+ TUBE *TubeForDisconnect; // Tube for disconnection notification
+ UINT ErrorCode; // Error code in the case of failing to connect
+ DHCP_OPTION_LIST L3ClientAddressOption; // Client IP address option (Only in the case of L3 mode)
+ UINT64 L3DhcpRenewInterval; // DHCP update interval
+ UINT64 L3NextDhcpRenewTick; // DHCP renewal time of the next
+ bool DhcpAllocFailed; // Failed to get IP address from the DHCP server
+};
+
+// IPC object
+struct IPC
+{
+ CEDAR *Cedar;
+ char HubName[MAX_HUBNAME_LEN + 1];
+ char UserName[MAX_USERNAME_LEN + 1];
+ char Password[MAX_PASSWORD_LEN + 1];
+ char ClientHostname[MAX_SIZE];
+ UCHAR random[SHA1_SIZE];
+ char SessionName[MAX_SESSION_NAME_LEN + 1];
+ char ConnectionName[MAX_CONNECTION_NAME_LEN + 1];
+ POLICY *Policy;
+ SOCK *Sock;
+ INTERRUPT_MANAGER *Interrupt; // Interrupt manager
+ IP ClientIPAddress; // IP address of the client
+ IP SubnetMask; // Subnet mask of the client
+ IP DefaultGateway; // Default gateway address
+ IP BroadcastAddress; // Broadcast address
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2];
+ LIST *ArpTable; // ARP table
+ QUEUE *IPv4RecviedQueue; // IPv4 reception queue
+ TUBE_FLUSH_LIST *FlushList; // Tube Flush List
+ UCHAR MsChapV2_ServerResponse[20]; // Server response
+};
+
+// MS-CHAPv2 authentication information
+struct IPC_MSCHAP_V2_AUTHINFO
+{
+ char MsChapV2_PPPUsername[MAX_SIZE]; // MS-CHAPv2 Username
+ UCHAR MsChapV2_ServerChallenge[16]; // MS-CHAPv2 Server Challenge
+ UCHAR MsChapV2_ClientChallenge[16]; // MS-CHAPv2 Client Challenge
+ UCHAR MsChapV2_ClientResponse[24]; // MS-CHAPv2 Client Response
+};
+
+IPC *NewIPC(CEDAR *cedar, char *client_name, char *postfix, char *hubname, char *username, char *password,
+ UINT *error_code, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port,
+ char *client_hostname, char *crypt_name,
+ bool bridge_mode, UINT mss);
+IPC *NewIPCByParam(CEDAR *cedar, IPC_PARAM *param, UINT *error_code);
+IPC *NewIPCBySock(CEDAR *cedar, SOCK *s, void *mac_address);
+void FreeIPC(IPC *ipc);
+bool IsIPCConnected(IPC *ipc);
+void IPCSetSockEventWhenRecvL2Packet(IPC *ipc, SOCK_EVENT *e);
+void IPCSendL2(IPC *ipc, void *data, UINT size);
+void IPCSendIPv4(IPC *ipc, void *data, UINT size);
+BLOCK *IPCRecvL2(IPC *ipc);
+BLOCK *IPCRecvIPv4(IPC *ipc);
+void IPCProcessInterrupts(IPC *ipc);
+void IPCProcessL3Events(IPC *ipc);
+void IPCProcessL3EventsEx(IPC *ipc, UINT64 now);
+bool IPCSetIPv4Parameters(IPC *ipc, IP *ip, IP *subnet, IP *gw);
+IPC_ARP *IPCNewARP(IP *ip, UCHAR *mac_address);
+void IPCFreeARP(IPC_ARP *a);
+int IPCCmpArpTable(void *p1, void *p2);
+void IPCSendIPv4Unicast(IPC *ipc, void *data, UINT size, IP *next_ip);
+IPC_ARP *IPCSearchArpTable(IPC *ipc, IP *ip);
+void IPCSendIPv4WithDestMacAddr(IPC *ipc, void *data, UINT size, UCHAR *dest_mac_addr);
+void IPCFlushArpTable(IPC *ipc);
+void IPCFlushArpTableEx(IPC *ipc, UINT64 now);
+void IPCProcessArp(IPC *ipc, BLOCK *b);
+void IPCAssociateOnArpTable(IPC *ipc, IP *ip, UCHAR *mac_address);
+bool IsValidUnicastMacAddress(UCHAR *mac);
+bool IsValidUnicastIPAddress4(IP *ip);
+bool IsValidUnicastIPAddressUINT4(UINT ip);
+DHCPV4_DATA *IPCSendDhcpRequest(IPC *ipc, IP *dest_ip, UINT tran_id, DHCP_OPTION_LIST *opt, UINT expecting_code, UINT timeout, TUBE *discon_poll_tube);
+BUF *IPCBuildDhcpRequest(IPC *ipc, IP *dest_ip, UINT tran_id, DHCP_OPTION_LIST *opt);
+BUF *IPCBuildDhcpRequestOptions(IPC *ipc, DHCP_OPTION_LIST *opt);
+bool IPCDhcpAllocateIP(IPC *ipc, DHCP_OPTION_LIST *opt, TUBE *discon_poll_tube);
+bool IPCDhcpAllocateIPEx(IPC *ipc, DHCP_OPTION_LIST *opt, TUBE *discon_poll_tube, bool openvpn_compatible);
+bool IPCDhcpRequestInformIP(IPC *ipc, DHCP_OPTION_LIST *opt, TUBE *discon_poll_tube, IP *client_ip);
+void IPCDhcpRenewIP(IPC *ipc, IP *dhcp_server);
+void IPCDhcpFreeIP(IPC *ipc, IP *dhcp_server);
+IPC_ASYNC *NewIPCAsync(CEDAR *cedar, IPC_PARAM *param, SOCK_EVENT *sock_event);
+void IPCAsyncThreadProc(THREAD *thread, void *param);
+void FreeIPCAsync(IPC_ASYNC *a);
+
+bool ParseAndExtractMsChapV2InfoFromPassword(IPC_MSCHAP_V2_AUTHINFO *d, char *password);
+
+#endif // IPSEC_IPC
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_IkePacket.c b/src/Cedar/IPsec_IkePacket.c
new file mode 100644
index 00000000..8fa02e90
--- /dev/null
+++ b/src/Cedar/IPsec_IkePacket.c
@@ -0,0 +1,3129 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_IkePacket.c
+// IKE (ISAKMP) packet processing
+
+#include "CedarPch.h"
+
+// Convert the string to a password
+BUF *IkeStrToPassword(char *str)
+{
+ BUF *b;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return NewBuf();
+ }
+
+ if (StartWith(str, "0x") == false)
+ {
+ // Accept the string as is
+ b = NewBuf();
+ WriteBuf(b, str, StrLen(str));
+ }
+ else
+ {
+ // Interpret as a hexadecimal value
+ b = StrToBin(str + 2);
+ }
+
+ return b;
+}
+
+// Phase 1: Convert the encryption algorithm name to key size
+UINT IkePhase1CryptIdToKeySize(UCHAR id)
+{
+ switch (id)
+ {
+ case IKE_P1_CRYPTO_3DES_CBC:
+ return DES3_KEY_SIZE;
+
+ case IKE_P1_CRYPTO_DES_CBC:
+ return DES_KEY_SIZE;
+ }
+
+ return 0;
+}
+
+// Phase 2: Convert the encryption algorithm name to key size
+UINT IkePhase2CryptIdToKeySize(UCHAR id)
+{
+ switch (id)
+ {
+ case IKE_TRANSFORM_ID_P2_ESP_3DES:
+ return DES3_KEY_SIZE;
+
+ case IKE_TRANSFORM_ID_P2_ESP_DES:
+ return DES_KEY_SIZE;
+ }
+
+ return 0;
+}
+
+// Convert a string to an algorithm name
+UCHAR IkeStrToPhase1CryptId(char *name)
+{
+ if (StartWith(name, "3DES") || StartWith("3DES", name))
+ {
+ return IKE_P1_CRYPTO_3DES_CBC;
+ }
+ else if (StartWith(name, "DES") || StartWith("DES", name))
+ {
+ return IKE_P1_CRYPTO_DES_CBC;
+ }
+ else
+ {
+ return 0;
+ }
+}
+UCHAR IkeStrToPhase1HashId(char *name)
+{
+ if (StartWith(name, "SHA-1") || StartWith("SHA-1", name))
+ {
+ return IKE_P1_HASH_SHA1;
+ }
+
+ return 0;
+}
+UCHAR IkeStrToPhase2CryptId(char *name)
+{
+ if (StartWith(name, "3DES") || StartWith("3DES", name))
+ {
+ return IKE_TRANSFORM_ID_P2_ESP_3DES;
+ }
+ else if (StartWith(name, "DES") || StartWith("DES", name))
+ {
+ return IKE_TRANSFORM_ID_P2_ESP_DES;
+ }
+ else
+ {
+ return 0;
+ }
+}
+UCHAR IkeStrToPhase2HashId(char *name)
+{
+ if (StartWith(name, "SHA-1") || StartWith("SHA-1", name))
+ {
+ return IKE_P2_HMAC_SHA1_96;
+ }
+
+ return 0;
+}
+
+// Build a data payload
+BUF *IkeBuildDataPayload(IKE_PACKET_DATA_PAYLOAD *t)
+{
+ BUF *b;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+ WriteBuf(b, t->Data->Buf, t->Data->Size);
+
+ return b;
+}
+
+// Build a SA payload
+BUF *IkeBuildSaPayload(IKE_PACKET_SA_PAYLOAD *t)
+{
+ IKE_SA_HEADER h;
+ BUF *ret;
+ BUF *b;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+ h.DoI = Endian32(IKE_SA_DOI_IPSEC);
+ h.Situation = Endian32(IKE_SA_SITUATION_IDENTITY);
+
+ ret = NewBuf();
+
+ WriteBuf(ret, &h, sizeof(h));
+
+ b = IkeBuildPayloadList(t->PayloadList);
+ WriteBufBuf(ret, b);
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Build a proposal payload
+BUF *IkeBuildProposalPayload(IKE_PACKET_PROPOSAL_PAYLOAD *t)
+{
+ IKE_PROPOSAL_HEADER h;
+ BUF *ret, *b;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+ h.Number = t->Number;
+ h.NumTransforms = LIST_NUM(t->PayloadList);
+ h.ProtocolId = t->ProtocolId;
+ h.SpiSize = t->Spi->Size;
+
+ ret = NewBuf();
+ WriteBuf(ret, &h, sizeof(h));
+ WriteBufBuf(ret, t->Spi);
+
+ b = IkeBuildPayloadList(t->PayloadList);
+ WriteBufBuf(ret, b);
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Build the transform value list
+BUF *IkeBuildTransformValueList(LIST *o)
+{
+ BUF *b;
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IKE_PACKET_TRANSFORM_VALUE *v = LIST_DATA(o, i);
+ BUF *tmp = IkeBuildTransformValue(v);
+
+ WriteBufBuf(b, tmp);
+
+ FreeBuf(tmp);
+ }
+
+ return b;
+}
+
+// Build a transform value
+BUF *IkeBuildTransformValue(IKE_PACKET_TRANSFORM_VALUE *v)
+{
+ BUF *b;
+ UCHAR af_bit, type;
+ USHORT size_or_value;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return NULL;
+ }
+
+ type = v->Type;
+
+ if (v->Value >= 65536)
+ {
+ // 32 bit
+ af_bit = 0;
+ size_or_value = Endian16(sizeof(UINT));
+ }
+ else
+ {
+ // 16 bit
+ af_bit = 0x80;
+ size_or_value = Endian16((USHORT)v->Value);
+ }
+
+ b = NewBuf();
+ WriteBuf(b, &af_bit, sizeof(af_bit));
+ WriteBuf(b, &type, sizeof(type));
+ WriteBuf(b, &size_or_value, sizeof(size_or_value));
+
+ if (af_bit == 0)
+ {
+ UINT value = Endian32(v->Value);
+ WriteBuf(b, &value, sizeof(UINT));
+ }
+
+ return b;
+}
+
+// Build a transform payload
+BUF *IkeBuildTransformPayload(IKE_PACKET_TRANSFORM_PAYLOAD *t)
+{
+ IKE_TRANSFORM_HEADER h;
+ BUF *ret, *b;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+ h.Number = t->Number;
+ h.TransformId = t->TransformId;
+
+ ret = NewBuf();
+ WriteBuf(ret, &h, sizeof(h));
+
+ b = IkeBuildTransformValueList(t->ValueList);
+ WriteBufBuf(ret, b);
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Get the value from the transform payload
+UINT IkeGetTransformValue(IKE_PACKET_TRANSFORM_PAYLOAD *t, UINT type, UINT index)
+{
+ UINT i;
+ UINT num;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return 0;
+ }
+
+ num = 0;
+
+ for (i = 0;i < LIST_NUM(t->ValueList);i++)
+ {
+ IKE_PACKET_TRANSFORM_VALUE *v = LIST_DATA(t->ValueList, i);
+
+ if (v->Type == type)
+ {
+ if (num == index)
+ {
+ return v->Value;
+ }
+
+ num++;
+ }
+ }
+
+ return 0;
+}
+
+// Get the number of values from the transform payload
+UINT IkeGetTransformValueNum(IKE_PACKET_TRANSFORM_PAYLOAD *t, UINT type)
+{
+ UINT i;
+ UINT num;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return 0;
+ }
+
+ num = 0;
+
+ for (i = 0;i < LIST_NUM(t->ValueList);i++)
+ {
+ IKE_PACKET_TRANSFORM_VALUE *v = LIST_DATA(t->ValueList, i);
+
+ if (v->Type == type)
+ {
+ num++;
+ }
+ }
+
+ return num;
+}
+
+// Build the ID payload
+BUF *IkeBuildIdPayload(IKE_PACKET_ID_PAYLOAD *t)
+{
+ IKE_ID_HEADER h;
+ BUF *ret;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+ h.IdType = t->Type;
+ h.Port = Endian16(t->Port);
+ h.ProtocolId = t->ProtocolId;
+
+ ret = NewBuf();
+ WriteBuf(ret, &h, sizeof(h));
+
+ WriteBufBuf(ret, t->IdData);
+
+ return ret;
+}
+
+// Build a certificate payload
+BUF *IkeBuildCertPayload(IKE_PACKET_CERT_PAYLOAD *t)
+{
+ IKE_CERT_HEADER h;
+ BUF *ret;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+ h.CertType = t->CertType;
+
+ ret = NewBuf();
+ WriteBuf(ret, &h, sizeof(h));
+ WriteBufBuf(ret, t->CertData);
+
+ return ret;
+}
+
+// Build a certificate request payload
+BUF *IkeBuildCertRequestPayload(IKE_PACKET_CERT_REQUEST_PAYLOAD *t)
+{
+ IKE_CERT_REQUEST_HEADER h;
+ BUF *ret;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+ h.CertType = t->CertType;
+
+ ret = NewBuf();
+ WriteBuf(ret, &h, sizeof(h));
+ WriteBufBuf(ret, t->Data);
+
+ return ret;
+}
+
+// Build a notification payload
+BUF *IkeBuildNoticePayload(IKE_PACKET_NOTICE_PAYLOAD *t)
+{
+ IKE_NOTICE_HEADER h;
+ BUF *ret;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+ h.DoI = Endian32(IKE_SA_DOI_IPSEC);
+ h.MessageType = Endian16(t->MessageType);
+ h.ProtocolId = t->ProtocolId;
+ h.SpiSize = t->Spi->Size;
+
+ ret = NewBuf();
+ WriteBuf(ret, &h, sizeof(h));
+ WriteBuf(ret, t->Spi->Buf, t->Spi->Size);
+
+ if (t->MessageData != NULL)
+ {
+ WriteBuf(ret, t->MessageData->Buf, t->MessageData->Size);
+ }
+
+ return ret;
+}
+
+// Build a NAT-OA payload
+BUF *IkeBuildNatOaPayload(IKE_PACKET_NAT_OA_PAYLOAD *t)
+{
+ IKE_NAT_OA_HEADER h;
+ BUF *ret;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+
+ if (IsIP6(&t->IpAddress))
+ {
+ h.IdType = IKE_ID_IPV6_ADDR;
+ }
+ else
+ {
+ h.IdType = IKE_ID_IPV4_ADDR;
+ }
+
+ ret = NewBuf();
+
+ WriteBuf(ret, &h, sizeof(h));
+
+ if (IsIP6(&t->IpAddress))
+ {
+ WriteBuf(ret, t->IpAddress.ipv6_addr, 16);
+ }
+ else
+ {
+ WriteBuf(ret, t->IpAddress.addr, 4);
+ }
+
+ return ret;
+}
+
+// Build a deletion payload
+BUF *IkeBuildDeletePayload(IKE_PACKET_DELETE_PAYLOAD *t)
+{
+ IKE_DELETE_HEADER h;
+ BUF *ret;
+ UINT i;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+ h.DoI = Endian32(IKE_SA_DOI_IPSEC);
+ h.NumSpis = Endian16(LIST_NUM(t->SpiList));
+ h.ProtocolId = t->ProtocolId;
+
+ if (LIST_NUM(t->SpiList) >= 1)
+ {
+ BUF *b = LIST_DATA(t->SpiList, 0);
+
+ h.SpiSize = b->Size;
+ }
+
+ ret = NewBuf();
+ WriteBuf(ret, &h, sizeof(h));
+
+ for (i = 0;i < LIST_NUM(t->SpiList);i++)
+ {
+ BUF *b = LIST_DATA(t->SpiList, i);
+
+ WriteBuf(ret, b->Buf, b->Size);
+ }
+
+ return ret;
+}
+
+// Build a bit array from the payload
+BUF *IkeBuildPayload(IKE_PACKET_PAYLOAD *p)
+{
+ BUF *b = NULL;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ switch (p->PayloadType)
+ {
+ case IKE_PAYLOAD_SA: // SA payload
+ b = IkeBuildSaPayload(&p->Payload.Sa);
+ break;
+
+ case IKE_PAYLOAD_PROPOSAL: // Proposal payload
+ b = IkeBuildProposalPayload(&p->Payload.Proposal);
+ break;
+
+ case IKE_PAYLOAD_TRANSFORM: // Transform payload
+ b = IkeBuildTransformPayload(&p->Payload.Transform);
+ break;
+
+ case IKE_PAYLOAD_ID: // ID payload
+ b = IkeBuildIdPayload(&p->Payload.Id);
+ break;
+
+ case IKE_PAYLOAD_CERT: // Certificate payload
+ b = IkeBuildCertPayload(&p->Payload.Cert);
+ break;
+
+ case IKE_PAYLOAD_CERT_REQUEST: // Certificate request payload
+ b = IkeBuildCertRequestPayload(&p->Payload.CertRequest);
+ break;
+
+ case IKE_PAYLOAD_NOTICE: // Notification Payload
+ b = IkeBuildNoticePayload(&p->Payload.Notice);
+ break;
+
+ case IKE_PAYLOAD_DELETE: // Deletion payload
+ b = IkeBuildDeletePayload(&p->Payload.Delete);
+ break;
+
+ case IKE_PAYLOAD_NAT_OA: // NAT-OA payload
+ case IKE_PAYLOAD_NAT_OA_DRAFT:
+ case IKE_PAYLOAD_NAT_OA_DRAFT_2:
+ b = IkeBuildNatOaPayload(&p->Payload.NatOa);
+ break;
+
+ case IKE_PAYLOAD_KEY_EXCHANGE: // Key exchange payload
+ case IKE_PAYLOAD_HASH: // Hash payload
+ case IKE_PAYLOAD_SIGN: // Signature payload
+ case IKE_PAYLOAD_RAND: // Random number payload
+ case IKE_PAYLOAD_VENDOR_ID: // Vendor ID payload
+ case IKE_PAYLOAD_NAT_D: // NAT-D payload
+ case IKE_PAYLOAD_NAT_D_DRAFT: // NAT-D payload (draft)
+ default:
+ b = IkeBuildDataPayload(&p->Payload.GeneralData);
+ break;
+ }
+
+ if (b != NULL)
+ {
+ if (p->BitArray != NULL)
+ {
+ FreeBuf(p->BitArray);
+ }
+ p->BitArray = CloneBuf(b);
+ }
+
+ return b;
+}
+
+// Get the payload type of the first item
+UCHAR IkeGetFirstPayloadType(LIST *o)
+{
+ IKE_PACKET_PAYLOAD *p;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return IKE_PAYLOAD_NONE;
+ }
+
+ if (LIST_NUM(o) == 0)
+ {
+ return IKE_PAYLOAD_NONE;
+ }
+
+ p = (IKE_PACKET_PAYLOAD *)LIST_DATA(o, 0);
+
+ return p->PayloadType;
+}
+
+// Build a bit array from the payload list
+BUF *IkeBuildPayloadList(LIST *o)
+{
+ BUF *b;
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IKE_PACKET_PAYLOAD *p = LIST_DATA(o, i);
+ IKE_PACKET_PAYLOAD *next = NULL;
+ IKE_COMMON_HEADER h;
+ BUF *tmp;
+
+ if (i < (LIST_NUM(o) - 1))
+ {
+ next = LIST_DATA(o, i + 1);
+ }
+
+ Zero(&h, sizeof(h));
+ if (next != NULL)
+ {
+ h.NextPayload = next->PayloadType;
+ }
+ else
+ {
+ h.NextPayload = IKE_PAYLOAD_NONE;
+ }
+
+ tmp = IkeBuildPayload(p);
+ if (tmp != NULL)
+ {
+ h.PayloadSize = Endian16(tmp->Size + (USHORT)sizeof(h));
+
+ WriteBuf(b, &h, sizeof(h));
+ WriteBuf(b, tmp->Buf, tmp->Size);
+
+ FreeBuf(tmp);
+ }
+ }
+
+ SeekBuf(b, 0, 0);
+
+ return b;
+}
+
+// Get the specified payload
+IKE_PACKET_PAYLOAD *IkeGetPayload(LIST *o, UINT payload_type, UINT index)
+{
+ UINT i, num;
+ IKE_PACKET_PAYLOAD *ret = NULL;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return 0;
+ }
+
+ num = 0;
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IKE_PACKET_PAYLOAD *p = LIST_DATA(o, i);
+
+ if (p->PayloadType == payload_type)
+ {
+ if (num == index)
+ {
+ ret = p;
+ break;
+ }
+
+ num++;
+ }
+ }
+
+ return ret;
+}
+
+// Get the number of the payload of the specified type
+UINT IkeGetPayloadNum(LIST *o, UINT payload_type)
+{
+ UINT i, num;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return 0;
+ }
+
+ num = 0;
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IKE_PACKET_PAYLOAD *p = LIST_DATA(o, i);
+
+ if (p->PayloadType == payload_type)
+ {
+ num++;
+ }
+ }
+
+ return num;
+}
+
+// Create a deletion payload
+IKE_PACKET_PAYLOAD *IkeNewDeletePayload(UCHAR protocol_id, LIST *spi_list)
+{
+ IKE_PACKET_PAYLOAD *p;
+ if (spi_list == NULL)
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(IKE_PAYLOAD_DELETE);
+ p->Payload.Delete.ProtocolId = protocol_id;
+ p->Payload.Delete.SpiList = spi_list;
+
+ return p;
+}
+
+// Create a Notification payload
+IKE_PACKET_PAYLOAD *IkeNewNoticePayload(UCHAR protocol_id, USHORT message_type,
+ void *spi, UINT spi_size,
+ void *message, UINT message_size)
+{
+ IKE_PACKET_PAYLOAD *p;
+ if (spi == NULL && spi_size != 0)
+ {
+ return NULL;
+ }
+ if (message == NULL && message_size != 0)
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(IKE_PAYLOAD_NOTICE);
+ p->Payload.Notice.MessageType = message_type;
+ p->Payload.Notice.MessageData = MemToBuf(message, message_size);
+ p->Payload.Notice.Spi = MemToBuf(spi, spi_size);
+ p->Payload.Notice.ProtocolId = protocol_id;
+
+ return p;
+}
+
+// Create a Invalid Cookie Payload
+IKE_PACKET_PAYLOAD *IkeNewNoticeErrorInvalidCookiePayload(UINT64 init_cookie, UINT64 resp_cookie)
+{
+ IKE_PACKET_PAYLOAD *ret;
+ BUF *b = NewBuf();
+
+ WriteBufInt64(b, init_cookie);
+ WriteBufInt64(b, resp_cookie);
+
+ ret = IkeNewNoticePayload(IKE_PROTOCOL_ID_IKE, IKE_NOTICE_ERROR_INVALID_COOKIE, b->Buf, b->Size,
+ b->Buf, b->Size);
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Create an Invalid Exchange Type Payload
+IKE_PACKET_PAYLOAD *IkeNewNoticeErrorInvalidExchangeTypePayload(UINT64 init_cookie, UINT64 resp_cookie, UCHAR exchange_type)
+{
+ IKE_PACKET_PAYLOAD *ret;
+ BUF *b = NewBuf();
+
+ WriteBufInt64(b, init_cookie);
+ WriteBufInt64(b, resp_cookie);
+
+ ret = IkeNewNoticePayload(IKE_PROTOCOL_ID_IKE, IKE_NOTICE_ERROR_INVALID_EXCHANGE_TYPE, b->Buf, b->Size,
+ &exchange_type, 1);
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Create an Invalid SPI payload
+IKE_PACKET_PAYLOAD *IkeNewNoticeErrorInvalidSpiPayload(UINT spi)
+{
+ IKE_PACKET_PAYLOAD *ret;
+ spi = Endian32(spi);
+
+ ret = IkeNewNoticePayload(IKE_PROTOCOL_ID_IPSEC_ESP, IKE_NOTICE_ERROR_INVALID_SPI, &spi, sizeof(UINT),
+ &spi, sizeof(UINT));
+
+ return ret;
+}
+
+// Create a No Proposal Chosen payload
+IKE_PACKET_PAYLOAD *IkeNewNoticeErrorNoProposalChosenPayload(bool quick_mode, UINT64 init_cookie, UINT64 resp_cookie)
+{
+ BUF *b = NewBuf();
+ IKE_PACKET_PAYLOAD *ret;
+
+ WriteBufInt64(b, init_cookie);
+ WriteBufInt64(b, resp_cookie);
+
+ ret = IkeNewNoticePayload((quick_mode ? IKE_PROTOCOL_ID_IPSEC_ESP : IKE_PROTOCOL_ID_IKE),
+ IKE_NOTICE_ERROR_NO_PROPOSAL_CHOSEN, b->Buf, b->Size,
+ NULL, 0);
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Create a DPD payload
+IKE_PACKET_PAYLOAD *IkeNewNoticeDpdPayload(bool ack, UINT64 init_cookie, UINT64 resp_cookie, UINT seq_no)
+{
+ IKE_PACKET_PAYLOAD *ret;
+ BUF *b = NewBuf();
+
+ seq_no = Endian32(seq_no);
+
+ WriteBufInt64(b, init_cookie);
+ WriteBufInt64(b, resp_cookie);
+
+ ret = IkeNewNoticePayload(IKE_PROTOCOL_ID_IKE, (ack ? IKE_NOTICE_DPD_RESPONSE : IKE_NOTICE_DPD_REQUEST),
+ b->Buf, b->Size,
+ &seq_no, sizeof(UINT));
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Create a Certificate Request Payload
+IKE_PACKET_PAYLOAD *IkeNewCertRequestPayload(UCHAR cert_type, void *data, UINT size)
+{
+ IKE_PACKET_PAYLOAD *p;
+ if (data == NULL && size != 0)
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(IKE_PAYLOAD_CERT_REQUEST);
+ p->Payload.CertRequest.CertType = cert_type;
+ p->Payload.CertRequest.Data = MemToBuf(data, size);
+
+ return p;
+}
+
+// Create a Certificate payload
+IKE_PACKET_PAYLOAD *IkeNewCertPayload(UCHAR cert_type, void *cert_data, UINT cert_size)
+{
+ IKE_PACKET_PAYLOAD *p;
+ if (cert_data == NULL && cert_size != 0)
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(IKE_PAYLOAD_CERT);
+ p->Payload.Cert.CertType = cert_type;
+ p->Payload.Cert.CertData = MemToBuf(cert_data, cert_size);
+
+ return p;
+}
+
+// Create an ID payload
+IKE_PACKET_PAYLOAD *IkeNewIdPayload(UCHAR id_type, UCHAR protocol_id, USHORT port, void *id_data, UINT id_size)
+{
+ IKE_PACKET_PAYLOAD *p;
+ if (id_data == NULL && id_size != 0)
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(IKE_PAYLOAD_ID);
+ p->Payload.Id.IdData = MemToBuf(id_data, id_size);
+ p->Payload.Id.Port = port;
+ p->Payload.Id.ProtocolId = protocol_id;
+ p->Payload.Id.Type = id_type;
+
+ return p;
+}
+
+// Create a transform payload
+IKE_PACKET_PAYLOAD *IkeNewTransformPayload(UCHAR number, UCHAR transform_id, LIST *value_list)
+{
+ IKE_PACKET_PAYLOAD *p;
+ if (value_list == NULL)
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(IKE_PAYLOAD_TRANSFORM);
+ p->Payload.Transform.Number = number;
+ p->Payload.Transform.TransformId = transform_id;
+ p->Payload.Transform.ValueList = value_list;
+
+ return p;
+}
+
+// Create a proposal payload
+IKE_PACKET_PAYLOAD *IkeNewProposalPayload(UCHAR number, UCHAR protocol_id, void *spi, UINT spi_size, LIST *payload_list)
+{
+ IKE_PACKET_PAYLOAD *p;
+ if (payload_list == NULL || (spi == NULL && spi_size != 0))
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(IKE_PAYLOAD_PROPOSAL);
+ p->Payload.Proposal.Number = number;
+ p->Payload.Proposal.ProtocolId = protocol_id;
+ p->Payload.Proposal.Spi = MemToBuf(spi, spi_size);
+ p->Payload.Proposal.PayloadList = payload_list;
+
+ return p;
+}
+
+// Create an SA payload
+IKE_PACKET_PAYLOAD *IkeNewSaPayload(LIST *payload_list)
+{
+ IKE_PACKET_PAYLOAD *p;
+ // Validate arguments
+ if (payload_list == NULL)
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(IKE_PAYLOAD_SA);
+ p->Payload.Sa.PayloadList = payload_list;
+
+ return p;
+}
+
+// Create a NAT-OA payload
+IKE_PACKET_PAYLOAD *IkeNewNatOaPayload(UCHAR payload_type, IP *ip)
+{
+ IKE_PACKET_PAYLOAD *p;
+ // Validate arguments
+ if (ip == NULL)
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(payload_type);
+ Copy(&p->Payload.NatOa.IpAddress, ip, sizeof(IP));
+ p->PayloadType = payload_type;
+
+ return p;
+}
+
+// Create a data payload
+IKE_PACKET_PAYLOAD *IkeNewDataPayload(UCHAR payload_type, void *data, UINT size)
+{
+ IKE_PACKET_PAYLOAD *p;
+ // Validate arguments
+ if (data == NULL)
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(payload_type);
+ p->Payload.GeneralData.Data = MemToBuf(data, size);
+
+ return p;
+}
+
+// Create a new payload
+IKE_PACKET_PAYLOAD *IkeNewPayload(UINT payload_type)
+{
+ IKE_PACKET_PAYLOAD *p;
+
+ p = ZeroMalloc(sizeof(IKE_PACKET_PAYLOAD));
+
+ p->PayloadType = payload_type;
+
+ return p;
+}
+
+// Analyse the IKE payload body
+IKE_PACKET_PAYLOAD *IkeParsePayload(UINT payload_type, BUF *b)
+{
+ IKE_PACKET_PAYLOAD *p = NULL;
+ bool ok = true;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return NULL;
+ }
+
+ p = ZeroMalloc(sizeof(IKE_PACKET_PAYLOAD));
+ p->PayloadType = payload_type;
+
+ switch (p->PayloadType)
+ {
+ case IKE_PAYLOAD_SA: // SA payload
+ ok = IkeParseSaPayload(&p->Payload.Sa, b);
+ break;
+
+ case IKE_PAYLOAD_PROPOSAL: // Proposal payload
+ ok = IkeParseProposalPayload(&p->Payload.Proposal, b);
+ break;
+
+ case IKE_PAYLOAD_TRANSFORM: // Proposal payload
+ ok = IkeParseTransformPayload(&p->Payload.Transform, b);
+ break;
+
+ case IKE_PAYLOAD_ID: // ID payload
+ ok = IkeParseIdPayload(&p->Payload.Id, b);
+ break;
+
+ case IKE_PAYLOAD_CERT: // Certificate payload
+ ok = IkeParseCertPayload(&p->Payload.Cert, b);
+ break;
+
+ case IKE_PAYLOAD_CERT_REQUEST: // Certificate request payload
+ ok = IkeParseCertRequestPayload(&p->Payload.CertRequest, b);
+ break;
+
+ case IKE_PAYLOAD_NOTICE: // Notification Payload
+ ok = IkeParseNoticePayload(&p->Payload.Notice, b);
+ break;
+
+ case IKE_PAYLOAD_DELETE: // Deletion payload
+ ok = IkeParseDeletePayload(&p->Payload.Delete, b);
+ break;
+
+ case IKE_PAYLOAD_NAT_OA:
+ case IKE_PAYLOAD_NAT_OA_DRAFT:
+ case IKE_PAYLOAD_NAT_OA_DRAFT_2:
+ ok = IkeParseNatOaPayload(&p->Payload.NatOa, b);
+ break;
+
+ case IKE_PAYLOAD_KEY_EXCHANGE: // Key exchange payload
+ case IKE_PAYLOAD_HASH: // Hash payload
+ case IKE_PAYLOAD_SIGN: // Signature payload
+ case IKE_PAYLOAD_RAND: // Random number payload
+ case IKE_PAYLOAD_VENDOR_ID: // Vendor ID payload
+ case IKE_PAYLOAD_NAT_D: // NAT-D payload
+ case IKE_PAYLOAD_NAT_D_DRAFT: // NAT-D payload (draft)
+ default:
+ ok = IkeParseDataPayload(&p->Payload.GeneralData, b);
+ break;
+ }
+
+ if (ok == false)
+ {
+ Free(p);
+ p = NULL;
+ }
+ else
+ {
+ p->BitArray = CloneBuf(b);
+ }
+
+ return p;
+}
+
+// Parse the SA payload
+bool IkeParseSaPayload(IKE_PACKET_SA_PAYLOAD *t, BUF *b)
+{
+ IKE_SA_HEADER *h;
+ UCHAR *buf;
+ UINT size;
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ if (b->Size < sizeof(IKE_SA_HEADER))
+ {
+ return false;
+ }
+
+ h = (IKE_SA_HEADER *)b->Buf;
+ buf = (UCHAR *)b->Buf;
+ buf += sizeof(IKE_SA_HEADER);
+ size = b->Size - sizeof(IKE_SA_HEADER);
+
+ if (Endian32(h->DoI) != IKE_SA_DOI_IPSEC)
+ {
+ Debug("ISAKMP: Invalid DoI Value: 0x%x\n", Endian32(h->DoI));
+ return false;
+ }
+
+ if (Endian32(h->Situation) != IKE_SA_SITUATION_IDENTITY)
+ {
+ Debug("ISAKMP: Invalid Situation Value: 0x%x\n", Endian32(h->Situation));
+ return false;
+ }
+
+ t->PayloadList = IkeParsePayloadList(buf, size, IKE_PAYLOAD_PROPOSAL);
+
+ return true;
+}
+
+// Release the SA payload
+void IkeFreeSaPayload(IKE_PACKET_SA_PAYLOAD *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->PayloadList != NULL)
+ {
+ IkeFreePayloadList(t->PayloadList);
+ t->PayloadList = NULL;
+ }
+}
+
+// Parse the proposal payload
+bool IkeParseProposalPayload(IKE_PACKET_PROPOSAL_PAYLOAD *t, BUF *b)
+{
+ IKE_PROPOSAL_HEADER *h;
+ UCHAR *buf;
+ UINT size;
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ if (b->Size < sizeof(IKE_PROPOSAL_HEADER))
+ {
+ return false;
+ }
+
+ h = (IKE_PROPOSAL_HEADER *)b->Buf;
+
+ t->Number = h->Number;
+ t->ProtocolId = h->ProtocolId;
+
+ buf = (UCHAR *)b->Buf;
+ buf += sizeof(IKE_PROPOSAL_HEADER);
+ size = b->Size - sizeof(IKE_PROPOSAL_HEADER);
+
+ if (size < (UINT)h->SpiSize)
+ {
+ return false;
+ }
+
+ t->Spi = MemToBuf(buf, h->SpiSize);
+
+ buf += h->SpiSize;
+ size -= h->SpiSize;
+
+ t->PayloadList = IkeParsePayloadList(buf, size, IKE_PAYLOAD_TRANSFORM);
+
+ return true;
+}
+
+// Release the proposal payload
+void IkeFreeProposalPayload(IKE_PACKET_PROPOSAL_PAYLOAD *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->Spi != NULL)
+ {
+ FreeBuf(t->Spi);
+ t->Spi = NULL;
+ }
+
+ if (t->PayloadList != NULL)
+ {
+ IkeFreePayloadList(t->PayloadList);
+ t->PayloadList = NULL;
+ }
+}
+
+// Parse the transform payload
+bool IkeParseTransformPayload(IKE_PACKET_TRANSFORM_PAYLOAD *t, BUF *b)
+{
+ IKE_TRANSFORM_HEADER h;
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ if (ReadBuf(b, &h, sizeof(h)) != sizeof(h))
+ {
+ return false;
+ }
+
+ t->Number = h.Number;
+ t->TransformId = h.TransformId;
+ t->ValueList = IkeParseTransformValueList(b);
+
+ return true;
+}
+
+// Create a new transform value
+IKE_PACKET_TRANSFORM_VALUE *IkeNewTransformValue(UCHAR type, UINT value)
+{
+ IKE_PACKET_TRANSFORM_VALUE *v = ZeroMalloc(sizeof(IKE_PACKET_TRANSFORM_VALUE));
+
+ v->Type = type;
+ v->Value = value;
+
+ return v;
+}
+
+// Parse the transform value list
+LIST *IkeParseTransformValueList(BUF *b)
+{
+ LIST *o;
+ bool ok = true;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return NULL;
+ }
+
+ o = NewListFast(NULL);
+
+ while (b->Current < b->Size)
+ {
+ UCHAR af_bit, type;
+ USHORT size;
+ UINT value = 0;
+ IKE_PACKET_TRANSFORM_VALUE *v;
+
+ if (ReadBuf(b, &af_bit, sizeof(af_bit)) != sizeof(af_bit))
+ {
+ ok = false;
+ break;
+ }
+
+ if (ReadBuf(b, &type, sizeof(type)) != sizeof(type))
+ {
+ ok = false;
+ break;
+ }
+
+ if (ReadBuf(b, &size, sizeof(size)) != sizeof(size))
+ {
+ ok = false;
+ }
+
+ size = Endian16(size);
+
+ if (af_bit == 0)
+ {
+ UCHAR *tmp = Malloc(size);
+
+ if (ReadBuf(b, tmp, size) != size)
+ {
+ ok = false;
+ Free(tmp);
+ break;
+ }
+
+ switch (size)
+ {
+ case sizeof(UINT):
+ value = READ_UINT(tmp);
+ break;
+
+ case sizeof(USHORT):
+ value = READ_USHORT(tmp);
+ break;
+
+ case sizeof(UCHAR):
+ value = *((UCHAR *)tmp);
+ break;
+ }
+
+ Free(tmp);
+ }
+ else
+ {
+ value = (UINT)size;
+ }
+
+ v = ZeroMalloc(sizeof(IKE_PACKET_TRANSFORM_VALUE));
+ v->Type = type;
+ v->Value = value;
+
+ Add(o, v);
+ }
+
+ if (ok == false)
+ {
+ IkeFreeTransformValueList(o);
+ o = NULL;
+ }
+
+ return o;
+}
+
+// Release the transform value list
+void IkeFreeTransformValueList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IKE_PACKET_TRANSFORM_VALUE *v = LIST_DATA(o, i);
+
+ Free(v);
+ }
+
+ ReleaseList(o);
+}
+
+// Release the transform payload
+void IkeFreeTransformPayload(IKE_PACKET_TRANSFORM_PAYLOAD *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->ValueList != NULL)
+ {
+ IkeFreeTransformValueList(t->ValueList);
+ t->ValueList = NULL;
+ }
+}
+
+// Parse the ID payload
+bool IkeParseIdPayload(IKE_PACKET_ID_PAYLOAD *t, BUF *b)
+{
+ IKE_ID_HEADER h;
+ IP ip;
+ IP subnet;
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ if (ReadBuf(b, &h, sizeof(h)) != sizeof(h))
+ {
+ return false;
+ }
+
+ t->Type = h.IdType;
+ t->ProtocolId = h.ProtocolId;
+ t->Port = Endian16(h.Port);
+ t->IdData = ReadRemainBuf(b);
+ if (t->IdData == NULL)
+ {
+ return false;
+ }
+
+ Zero(&ip, sizeof(ip));
+ Zero(&subnet, sizeof(subnet));
+
+ // Convert to string
+ Zero(t->StrData, sizeof(t->StrData));
+ switch (t->Type)
+ {
+ case IKE_ID_FQDN:
+ case IKE_ID_USER_FQDN:
+ case IKE_ID_KEY_ID:
+ Copy(t->StrData, t->IdData->Buf, MIN(t->IdData->Size, sizeof(t->StrData) - 1));
+ break;
+
+ case IKE_ID_IPV4_ADDR:
+ if (t->IdData->Size == 4)
+ {
+ Copy(ip.addr, t->IdData->Buf, 4);
+
+ IPToStr(t->StrData, sizeof(t->StrData), &ip);
+ }
+ break;
+
+ case IKE_ID_IPV6_ADDR:
+ if (t->IdData->Size == 16)
+ {
+ SetIP6(&ip, t->IdData->Buf);
+
+ IPToStr(t->StrData, sizeof(t->StrData), &ip);
+ }
+ break;
+
+ case IKE_ID_IPV4_ADDR_SUBNET:
+ if (t->IdData->Size == 8)
+ {
+ char ipstr[MAX_SIZE];
+ char subnetstr[MAX_SIZE];
+ Copy(ip.addr, t->IdData->Buf, 4);
+ Copy(subnet.addr, ((UCHAR *)t->IdData->Buf) + 4, 4);
+
+ IPToStr(ipstr, sizeof(ipstr), &ip);
+ MaskToStr(subnetstr, sizeof(subnetstr), &subnet);
+
+ Format(t->StrData, sizeof(t->StrData), "%s/%s", ipstr, subnetstr);
+ }
+ break;
+
+ case IKE_ID_IPV6_ADDR_SUBNET:
+ if (t->IdData->Size == 32)
+ {
+ char ipstr[MAX_SIZE];
+ char subnetstr[MAX_SIZE];
+ SetIP6(&ip, t->IdData->Buf);
+ SetIP6(&subnet, ((UCHAR *)t->IdData->Buf) + 16);
+
+ IPToStr(ipstr, sizeof(ipstr), &ip);
+ MaskToStr(subnetstr, sizeof(subnetstr), &subnet);
+
+ Format(t->StrData, sizeof(t->StrData), "%s/%s", ipstr, subnetstr);
+ }
+ break;
+ }
+
+ return true;
+}
+
+// Release the ID payload
+void IkeFreeIdPayload(IKE_PACKET_ID_PAYLOAD *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->IdData != NULL)
+ {
+ FreeBuf(t->IdData);
+ t->IdData = NULL;
+ }
+}
+
+// Parse the certificate payload
+bool IkeParseCertPayload(IKE_PACKET_CERT_PAYLOAD *t, BUF *b)
+{
+ IKE_CERT_HEADER h;
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ if (ReadBuf(b, &h, sizeof(h)) != sizeof(h))
+ {
+ return false;
+ }
+
+ t->CertType = h.CertType;
+ t->CertData = ReadRemainBuf(b);
+ if (t->CertData == NULL)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Release the certificate payload
+void IkeFreeCertPayload(IKE_PACKET_CERT_PAYLOAD *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->CertData != NULL)
+ {
+ FreeBuf(t->CertData);
+ t->CertData = NULL;
+ }
+}
+
+// Parse the certificate request payload
+bool IkeParseCertRequestPayload(IKE_PACKET_CERT_REQUEST_PAYLOAD *t, BUF *b)
+{
+ IKE_CERT_REQUEST_HEADER h;
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ if (ReadBuf(b, &h, sizeof(h)) != sizeof(h))
+ {
+ return false;
+ }
+
+ t->CertType = h.CertType;
+ t->Data = ReadRemainBuf(b);
+ if (t->Data == NULL)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Release the certificate request payload
+void IkeFreeCertRequestPayload(IKE_PACKET_CERT_REQUEST_PAYLOAD *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->Data != NULL)
+ {
+ FreeBuf(t->Data);
+ t->Data = NULL;
+ }
+}
+
+// Parse the notification payload
+bool IkeParseNoticePayload(IKE_PACKET_NOTICE_PAYLOAD *t, BUF *b)
+{
+ IKE_NOTICE_HEADER h;
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ if (ReadBuf(b, &h, sizeof(h)) != sizeof(h))
+ {
+ return false;
+ }
+
+ if (Endian32(h.DoI) != IKE_SA_DOI_IPSEC)
+ {
+ Debug("ISAKMP: Invalid DoI Value: 0x%x\n", Endian32(h.DoI));
+ return false;
+ }
+
+ t->MessageType = Endian16(h.MessageType);
+ t->ProtocolId = h.ProtocolId;
+ t->Spi = ReadBufFromBuf(b, h.SpiSize);
+ if (t->Spi == NULL)
+ {
+ return false;
+ }
+ t->MessageData = ReadRemainBuf(b);
+
+ return true;
+}
+
+// Release the notification payload
+void IkeFreeNoticePayload(IKE_PACKET_NOTICE_PAYLOAD *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->MessageData != NULL)
+ {
+ FreeBuf(t->MessageData);
+ t->MessageData = NULL;
+ }
+
+ if (t->Spi != NULL)
+ {
+ FreeBuf(t->Spi);
+ t->Spi = NULL;
+ }
+}
+
+// Parse the NAT-OA payload
+bool IkeParseNatOaPayload(IKE_PACKET_NAT_OA_PAYLOAD *t, BUF *b)
+{
+ IKE_NAT_OA_HEADER h;
+ UCHAR ip4[4];
+ UCHAR ip6[16];
+ IP ip;
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ Zero(&ip, sizeof(ip));
+
+ if (ReadBuf(b, &h, sizeof(h)) != sizeof(h))
+ {
+ return false;
+ }
+
+ if (h.IdType != IKE_ID_IPV4_ADDR && h.IdType != IKE_ID_IPV6_ADDR)
+ {
+ return false;
+ }
+
+ switch (h.IdType)
+ {
+ case IKE_ID_IPV4_ADDR: // IPv4
+ if (ReadBuf(b, ip4, sizeof(ip4)) != sizeof(ip4))
+ {
+ return false;
+ }
+
+ SetIP(&ip, ip4[0], ip4[1], ip4[2], ip4[3]);
+
+ break;
+
+ case IKE_ID_IPV6_ADDR: // IPv6
+ if (ReadBuf(b, ip6, sizeof(ip6)) != sizeof(ip6))
+ {
+ return false;
+ }
+
+ SetIP6(&ip, ip6);
+
+ break;
+
+ default:
+ return false;
+ }
+
+ Copy(&t->IpAddress, &ip, sizeof(IP));
+
+ return true;
+}
+
+// Parse the deletion payload
+bool IkeParseDeletePayload(IKE_PACKET_DELETE_PAYLOAD *t, BUF *b)
+{
+ IKE_DELETE_HEADER h;
+ UINT num_spi;
+ UINT spi_size;
+ UINT i;
+ bool ok = true;
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ if (ReadBuf(b, &h, sizeof(h)) != sizeof(h))
+ {
+ return false;
+ }
+
+ if (Endian32(h.DoI) != IKE_SA_DOI_IPSEC)
+ {
+ Debug("ISAKMP: Invalid DoI Value: 0x%x\n", Endian32(h.DoI));
+ return false;
+ }
+
+ t->ProtocolId = h.ProtocolId;
+ t->SpiList = NewListFast(NULL);
+ num_spi = Endian16(h.NumSpis);
+ spi_size = h.SpiSize;
+
+ for (i = 0;i < num_spi;i++)
+ {
+ BUF *spi = ReadBufFromBuf(b, spi_size);
+
+ if (spi == NULL)
+ {
+ ok = false;
+ break;
+ }
+
+ Add(t->SpiList, spi);
+ }
+
+ if (ok == false)
+ {
+ IkeFreeDeletePayload(t);
+ return false;
+ }
+
+ return true;
+}
+
+// Release the deletion payload
+void IkeFreeDeletePayload(IKE_PACKET_DELETE_PAYLOAD *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->SpiList != NULL)
+ {
+ for (i = 0;i < LIST_NUM(t->SpiList);i++)
+ {
+ BUF *spi = LIST_DATA(t->SpiList, i);
+
+ FreeBuf(spi);
+ }
+
+ ReleaseList(t->SpiList);
+
+ t->SpiList = NULL;
+ }
+}
+
+// Check whether the hash matches
+bool IkeCompareHash(IKE_PACKET_PAYLOAD *hash_payload, void *hash_data, UINT hash_size)
+{
+ //char tmp1[MAX_SIZE], tmp2[MAX_SIZE];
+ // Validate arguments
+ if (hash_payload == NULL || hash_data == NULL || hash_size == 0)
+ {
+ return false;
+ }
+
+ if (hash_payload->PayloadType != IKE_PAYLOAD_HASH)
+ {
+ return false;
+ }
+
+ if (hash_payload->Payload.Hash.Data == NULL)
+ {
+ return false;
+ }
+
+ if (hash_payload->Payload.Hash.Data->Size != hash_size)
+ {
+ return false;
+ }
+
+ //BinToStrEx(tmp1, sizeof(tmp1), hash_payload->Payload.Hash.Data->Buf, hash_size);
+ //BinToStrEx(tmp2, sizeof(tmp2), hash_data, hash_size);
+
+ //Debug("IkeCompareHash\n 1: %s\n 2: %s\n", tmp1, tmp2);
+
+ if (Cmp(hash_payload->Payload.Hash.Data->Buf, hash_data, hash_size) != 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Parse the data payload
+bool IkeParseDataPayload(IKE_PACKET_DATA_PAYLOAD *t, BUF *b)
+{
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ t->Data = MemToBuf(b->Buf, b->Size);
+
+ return true;
+}
+
+// Release the data payload
+void IkeFreeDataPayload(IKE_PACKET_DATA_PAYLOAD *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FreeBuf(t->Data);
+}
+
+// Release the IKE payload body
+void IkeFreePayload(IKE_PACKET_PAYLOAD *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ switch (p->PayloadType)
+ {
+ case IKE_PAYLOAD_SA: // SA payload
+ IkeFreeSaPayload(&p->Payload.Sa);
+ break;
+
+ case IKE_PAYLOAD_PROPOSAL: // Proposal payload
+ IkeFreeProposalPayload(&p->Payload.Proposal);
+ break;
+
+ case IKE_PAYLOAD_TRANSFORM: // Proposal payload
+ IkeFreeTransformPayload(&p->Payload.Transform);
+ break;
+
+ case IKE_PAYLOAD_ID: // ID payload
+ IkeFreeIdPayload(&p->Payload.Id);
+ break;
+
+ case IKE_PAYLOAD_CERT: // Certificate payload
+ IkeFreeCertPayload(&p->Payload.Cert);
+ break;
+
+ case IKE_PAYLOAD_CERT_REQUEST: // Certificate request payload
+ IkeFreeCertRequestPayload(&p->Payload.CertRequest);
+ break;
+
+ case IKE_PAYLOAD_NOTICE: // Notification Payload
+ IkeFreeNoticePayload(&p->Payload.Notice);
+ break;
+
+ case IKE_PAYLOAD_DELETE: // Deletion payload
+ IkeFreeDeletePayload(&p->Payload.Delete);
+ break;
+
+ case IKE_PAYLOAD_NAT_OA: // NAT-OD payload
+ case IKE_PAYLOAD_NAT_OA_DRAFT:
+ case IKE_PAYLOAD_NAT_OA_DRAFT_2:
+ // Do Nothing
+ break;
+
+ case IKE_PAYLOAD_KEY_EXCHANGE: // Key exchange payload
+ case IKE_PAYLOAD_HASH: // Hash payload
+ case IKE_PAYLOAD_SIGN: // Signature payload
+ case IKE_PAYLOAD_RAND: // Random number payload
+ case IKE_PAYLOAD_VENDOR_ID: // Vendor ID payload
+ case IKE_PAYLOAD_NAT_D: // NAT-D payload
+ case IKE_PAYLOAD_NAT_D_DRAFT: // NAT-D payload (draft)
+ default:
+ IkeFreeDataPayload(&p->Payload.GeneralData);
+ break;
+ }
+
+ if (p->BitArray != NULL)
+ {
+ FreeBuf(p->BitArray);
+ }
+
+ Free(p);
+}
+
+// Analyse the IKE payload list
+LIST *IkeParsePayloadList(void *data, UINT size, UCHAR first_payload)
+{
+ return IkeParsePayloadListEx(data, size, first_payload, NULL);
+}
+LIST *IkeParsePayloadListEx(void *data, UINT size, UCHAR first_payload, UINT *total_read_size)
+{
+ LIST *o;
+ BUF *b;
+ UCHAR payload_type = first_payload;
+ UINT total = 0;
+ // Validate arguments
+ if (data == NULL)
+ {
+ return NULL;
+ }
+
+ o = NewListFast(NULL);
+ b = MemToBuf(data, size);
+
+ while (payload_type != IKE_PAYLOAD_NONE)
+ {
+ // Read the common header
+ IKE_COMMON_HEADER header;
+ USHORT payload_size;
+ BUF *payload_data;
+ IKE_PACKET_PAYLOAD *pay;
+
+ if (ReadBuf(b, &header, sizeof(header)) != sizeof(header))
+ {
+ Debug("ISAKMP: Broken Packet (Invalid Payload Size)\n");
+
+LABEL_ERROR:
+ // Header reading failure
+ IkeFreePayloadList(o);
+ o = NULL;
+
+ break;
+ }
+
+ total += sizeof(header);
+
+ // Get the payload size
+ payload_size = Endian16(header.PayloadSize);
+
+ if (payload_size < sizeof(header))
+ {
+ Debug("ISAKMP: Broken Packet (Invalid Payload Size)\n");
+ goto LABEL_ERROR;
+ }
+
+ payload_size -= sizeof(header);
+
+ // Read the payload data
+ payload_data = ReadBufFromBuf(b, payload_size);
+ if (payload_data == NULL)
+ {
+ // Data read failure
+ Debug("ISAKMP: Broken Packet (Invalid Payload Data)\n");
+ goto LABEL_ERROR;
+ }
+
+ total += payload_size;
+
+ // Analyse the payload body
+ if (IKE_IS_SUPPORTED_PAYLOAD_TYPE(payload_type))
+ {
+ // Supported payload type
+ pay = IkeParsePayload(payload_type, payload_data);
+
+ if (pay == NULL)
+ {
+ FreeBuf(payload_data);
+ Debug("ISAKMP: Broken Packet (Payload Data Parse Failed)\n");
+ goto LABEL_ERROR;
+ }
+
+ Add(o, pay);
+ }
+ else
+ {
+ // Unsupported payload type
+ Debug("ISAKMP: Ignored Payload Type: %u\n", payload_type);
+ pay = IkeParsePayload(payload_type, payload_data);
+
+ if (pay == NULL)
+ {
+ FreeBuf(payload_data);
+ Debug("ISAKMP: Broken Packet (Payload Data Parse Failed)\n");
+ goto LABEL_ERROR;
+ }
+
+ Add(o, pay);
+ }
+
+ payload_type = header.NextPayload;
+
+ FreeBuf(payload_data);
+ }
+
+ FreeBuf(b);
+
+ if (total_read_size != NULL)
+ {
+ *total_read_size = total;
+ }
+
+ return o;
+}
+
+// Release the IKE payload list
+void IkeFreePayloadList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IKE_PACKET_PAYLOAD *p = LIST_DATA(o, i);
+
+ IkeFreePayload(p);
+ }
+
+ ReleaseList(o);
+}
+
+// Build an IKE packet
+BUF *IkeBuild(IKE_PACKET *p, IKE_CRYPTO_PARAM *cparam)
+{
+ return IkeBuildEx(p, cparam, false);
+}
+BUF *IkeBuildEx(IKE_PACKET *p, IKE_CRYPTO_PARAM *cparam, bool use_original_decrypted)
+{
+ IKE_HEADER h;
+ BUF *msg_buf;
+ BUF *ret;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ if (p->PayloadList == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+ h.InitiatorCookie = Endian64(p->InitiatorCookie);
+ h.ResponderCookie = Endian64(p->ResponderCookie);
+ h.NextPayload = IkeGetFirstPayloadType(p->PayloadList);
+ h.Version = IKE_VERSION;
+ h.ExchangeType = p->ExchangeType;
+ h.Flag = (p->FlagEncrypted ? IKE_HEADER_FLAG_ENCRYPTED : 0) |
+ (p->FlagCommit ? IKE_HEADER_FLAG_COMMIT : 0) |
+ (p->FlagAuthOnly ? IKE_HEADER_FLAG_AUTH_ONLY : 0);
+ h.MessageId = Endian32(p->MessageId);
+
+ if (p->DecryptedPayload != NULL && use_original_decrypted)
+ {
+ msg_buf = CloneBuf(p->DecryptedPayload);
+ }
+ else
+ {
+ msg_buf = IkeBuildPayloadList(p->PayloadList);
+ }
+
+ if (p->DecryptedPayload != NULL)
+ {
+ FreeBuf(p->DecryptedPayload);
+ }
+
+ p->DecryptedPayload = CloneBuf(msg_buf);
+
+ if (p->FlagEncrypted)
+ {
+ BUF *b;
+ // Encryption
+ b = IkeEncryptWithPadding(msg_buf->Buf, msg_buf->Size, cparam);
+
+ if (b == NULL)
+ {
+ Debug("ISAKMP: Packet Encrypt Failed\n");
+ FreeBuf(msg_buf);
+ return NULL;
+ }
+
+ FreeBuf(msg_buf);
+
+ msg_buf = b;
+ }
+
+ h.MessageSize = Endian32(msg_buf->Size + sizeof(h));
+
+ ret = NewBuf();
+ WriteBuf(ret, &h, sizeof(h));
+ WriteBufBuf(ret, msg_buf);
+
+ FreeBuf(msg_buf);
+
+ SeekBuf(ret, 0, 0);
+
+ return ret;
+}
+
+// Analyse the IKE packet
+IKE_PACKET *IkeParseEx(void *data, UINT size, IKE_CRYPTO_PARAM *cparam, bool header_only)
+{
+ IKE_PACKET *p = NULL;
+ BUF *b;
+ // Validate arguments
+ if (data == NULL)
+ {
+ return NULL;
+ }
+
+ b = MemToBuf(data, size);
+
+ if (b->Size < sizeof(IKE_HEADER))
+ {
+ Debug("ISAKMP: Invalid Packet Size\n");
+ }
+ else
+ {
+ // Header analysis
+ IKE_HEADER *h = (IKE_HEADER *)b->Buf;
+
+ p = ZeroMalloc(sizeof(IKE_PACKET));
+
+ p->MessageSize = Endian32(h->MessageSize);
+ p->InitiatorCookie = Endian64(h->InitiatorCookie);
+ p->ResponderCookie = Endian64(h->ResponderCookie);
+ p->ExchangeType = h->ExchangeType;
+ p->FlagEncrypted = (h->Flag & IKE_HEADER_FLAG_ENCRYPTED) ? true : false;
+ p->FlagCommit = (h->Flag & IKE_HEADER_FLAG_COMMIT) ? true : false;
+ p->FlagAuthOnly = (h->Flag & IKE_HEADER_FLAG_AUTH_ONLY) ? true : false;
+ p->MessageId = Endian32(h->MessageId);
+
+ if (b->Size < Endian32(h->MessageSize) ||
+ Endian32(h->MessageSize) < sizeof(IKE_HEADER))
+ {
+ Debug("ISAKMP: Invalid Packet Size\n");
+
+ IkeFree(p);
+ p = NULL;
+ }
+ else
+ {
+ if (header_only == false)
+ {
+ bool ok = false;
+ UCHAR *payload_data;
+ UINT payload_size;
+ BUF *buf = NULL;
+
+ payload_data = ((UCHAR *)h) + sizeof(IKE_HEADER);
+ payload_size = Endian32(h->MessageSize) - sizeof(IKE_HEADER);
+
+ // Decrypt if it is encrypted
+ if (p->FlagEncrypted)
+ {
+ buf = IkeDecrypt(payload_data, payload_size, cparam);
+
+ if (buf != NULL)
+ {
+ ok = true;
+
+ payload_data = buf->Buf;
+ payload_size = buf->Size;
+
+ p->DecryptedPayload = CloneBuf(buf);
+ }
+ }
+ else
+ {
+ ok = true;
+ }
+
+ if (ok == false)
+ {
+ Debug("ISAKMP: Decrypt Failed\n");
+
+ IkeFree(p);
+ p = NULL;
+ }
+ else
+ {
+ UINT total_read_size;
+
+ // Payload analysis
+ p->PayloadList = IkeParsePayloadListEx(payload_data,
+ payload_size,
+ h->NextPayload,
+ &total_read_size);
+
+ if (p->DecryptedPayload != NULL)
+ {
+ p->DecryptedPayload->Size = MIN(p->DecryptedPayload->Size, total_read_size);
+ }
+ else
+ {
+ p->DecryptedPayload = MemToBuf(payload_data, payload_size);
+ }
+ }
+
+ if (buf != NULL)
+ {
+ FreeBuf(buf);
+ }
+ }
+ }
+ }
+
+ FreeBuf(b);
+
+ return p;
+}
+IKE_PACKET *IkeParseHeader(void *data, UINT size, IKE_CRYPTO_PARAM *cparam)
+{
+ return IkeParseEx(data, size, cparam, true);
+}
+IKE_PACKET *IkeParse(void *data, UINT size, IKE_CRYPTO_PARAM *cparam)
+{
+ return IkeParseEx(data, size, cparam, false);
+}
+
+// Send packet for debugging by UDP (For debugging with Ethereal)
+void IkeDebugUdpSendRawPacket(IKE_PACKET *p)
+{
+ BUF *b;
+ IP ip;
+ SOCK *udp;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ p->FlagEncrypted = false;
+
+ b = NULL;
+
+ if (b == NULL)
+ {
+ b = IkeBuildEx(p, NULL, true);
+ }
+
+ if (b == NULL)
+ {
+ return;
+ }
+
+ Zero(&ip, sizeof(ip));
+ SetIP(&ip, 1, 2, 3, 4);
+
+ udp = NewUDP(0);
+
+ SendTo(udp, &ip, 500, b->Buf, b->Size);
+
+ ReleaseSock(udp);
+ FreeBuf(b);
+}
+
+// Output the payload list
+void IkeDebugPrintPayloads(LIST *o, UINT depth)
+{
+ UINT i;
+ char space[MAX_SIZE];
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ MakeCharArray2(space, ' ', depth * 2);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IKE_PACKET_PAYLOAD *payload = LIST_DATA(o, i);
+
+ Debug("%s%u: Type = %u, Size = %u\n", space, i, payload->PayloadType, payload->BitArray->Size);
+
+ switch (payload->PayloadType)
+ {
+ case IKE_PAYLOAD_SA:
+ IkeDebugPrintPayloads(payload->Payload.Sa.PayloadList, depth + 1);
+ break;
+
+ case IKE_PAYLOAD_PROPOSAL:
+ IkeDebugPrintPayloads(payload->Payload.Proposal.PayloadList, depth + 1);
+ break;
+ }
+ }
+}
+
+// Encryption (also with padding)
+BUF *IkeEncryptWithPadding(void *data, UINT size, IKE_CRYPTO_PARAM *cparam)
+{
+ UINT total_size;
+ UINT i;
+ UCHAR n = 0;
+ UCHAR *tmp;
+ BUF *ret;
+ UCHAR tmp1600[1600];
+ bool no_free = false;
+ // Validate arguments
+ if (data == NULL || cparam == NULL)
+ {
+ return NULL;
+ }
+
+ total_size = ((size / cparam->Key->Crypto->BlockSize) + ((size % cparam->Key->Crypto->BlockSize) == 0 ? 0 : 1))
+ * cparam->Key->Crypto->BlockSize;
+ if (total_size == 0)
+ {
+ total_size = cparam->Key->Crypto->BlockSize;
+ }
+
+ if (total_size > sizeof(tmp1600))
+ {
+ tmp = Malloc(total_size);
+ }
+ else
+ {
+ tmp = tmp1600;
+ no_free = true;
+ }
+
+ Copy(tmp, data, size);
+
+ for (i = size;i < total_size;i++)
+ {
+ tmp[i] = ++n;
+ }
+
+ ret = IkeEncrypt(tmp, total_size, cparam);
+
+ if (no_free == false)
+ {
+ Free(tmp);
+ }
+
+ return ret;
+}
+
+// Encryption
+BUF *IkeEncrypt(void *data, UINT size, IKE_CRYPTO_PARAM *cparam)
+{
+ void *tmp;
+ BUF *b;
+ UCHAR tmp1600[1600];
+ bool no_free = false;
+ // Validate arguments
+ if (data == NULL || cparam == NULL)
+ {
+ return NULL;
+ }
+
+ if ((size % cparam->Key->Crypto->BlockSize) != 0)
+ {
+ // Not an integral multiple of block size
+ return NULL;
+ }
+
+ if (size > sizeof(tmp1600))
+ {
+ tmp = Malloc(size);
+ }
+ else
+ {
+ tmp = tmp1600;
+ no_free = true;
+ }
+
+ IkeCryptoEncrypt(cparam->Key, tmp, data, size, cparam->Iv);
+
+ if (size >= cparam->Key->Crypto->BlockSize)
+ {
+ Copy(cparam->NextIv, ((UCHAR *)tmp) + (size - cparam->Key->Crypto->BlockSize), cparam->Key->Crypto->BlockSize);
+ }
+ else
+ {
+ Zero(cparam->NextIv, cparam->Key->Crypto->BlockSize);
+ }
+
+ b = MemToBuf(tmp, size);
+
+ if (no_free == false)
+ {
+ Free(tmp);
+ }
+
+ return b;
+}
+
+// Decryption
+BUF *IkeDecrypt(void *data, UINT size, IKE_CRYPTO_PARAM *cparam)
+{
+ void *tmp;
+ BUF *b;
+ UCHAR tmp1600[1600];
+ bool no_free = false;
+ // Validate arguments
+ if (data == NULL || cparam == NULL)
+ {
+ return NULL;
+ }
+
+ if ((size % cparam->Key->Crypto->BlockSize) != 0)
+ {
+ // Not an integral multiple of block size
+ return NULL;
+ }
+
+ if (size > sizeof(tmp1600))
+ {
+ tmp = Malloc(size);
+ }
+ else
+ {
+ tmp = tmp1600;
+ no_free = true;
+ }
+
+ IkeCryptoDecrypt(cparam->Key, tmp, data, size, cparam->Iv);
+
+ if (size >= cparam->Key->Crypto->BlockSize)
+ {
+ Copy(cparam->NextIv, ((UCHAR *)data) + (size - cparam->Key->Crypto->BlockSize), cparam->Key->Crypto->BlockSize);
+ }
+ else
+ {
+ Zero(cparam->NextIv, cparam->Key->Crypto->BlockSize);
+ }
+
+ b = MemToBuf(tmp, size);
+
+ if (no_free == false)
+ {
+ Free(tmp);
+ }
+
+ return b;
+}
+
+// Release the IKE packet
+void IkeFree(IKE_PACKET *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ if (p->PayloadList != NULL)
+ {
+ IkeFreePayloadList(p->PayloadList);
+ }
+
+ if (p->DecryptedPayload != NULL)
+ {
+ FreeBuf(p->DecryptedPayload);
+ }
+
+ Free(p);
+}
+
+// Create an IKE packet
+IKE_PACKET *IkeNew(UINT64 init_cookie, UINT64 resp_cookie, UCHAR exchange_type,
+ bool encrypted, bool commit, bool auth_only, UINT msg_id,
+ LIST *payload_list)
+{
+ IKE_PACKET *p = ZeroMalloc(sizeof(IKE_PACKET));
+
+ p->InitiatorCookie = init_cookie;
+ p->ResponderCookie = resp_cookie;
+ p->ExchangeType = exchange_type;
+ p->FlagEncrypted = encrypted;
+ p->FlagCommit = commit;
+ p->FlagAuthOnly = auth_only;
+ p->MessageId = msg_id;
+ p->PayloadList = payload_list;
+
+ return p;
+}
+
+// Create a new SPI value
+UINT IkeNewSpi()
+{
+ while (true)
+ {
+ UINT i = Rand32();
+
+ if (i >= 4096)
+ {
+ return i;
+ }
+ }
+}
+
+
+// Create an encryption engine for IKE
+IKE_ENGINE *NewIkeEngine()
+{
+ IKE_ENGINE *e = ZeroMalloc(sizeof(IKE_ENGINE));
+ IKE_CRYPTO *des, *des3, *aes;
+ IKE_HASH *sha1, *md5;
+ IKE_DH *dh1, *dh2, *dh5;
+ UINT des_key_sizes[] =
+ {
+ 8,
+ };
+ UINT des3_key_sizes[] =
+ {
+ 24,
+ };
+ UINT aes_key_sizes[] =
+ {
+ 16, 24, 32,
+ };
+
+ e->CryptosList = NewListFast(NULL);
+ e->HashesList = NewListFast(NULL);
+ e->DhsList = NewListFast(NULL);
+
+ //// Encryption algorithm
+ // DES
+ des = NewIkeCrypto(e, IKE_CRYPTO_DES_ID, IKE_CRYPTO_DES_STRING,
+ des_key_sizes, sizeof(des_key_sizes) / sizeof(UINT), 8);
+
+ // 3DES
+ des3 = NewIkeCrypto(e, IKE_CRYPTO_3DES_ID, IKE_CRYPTO_3DES_STRING,
+ des3_key_sizes, sizeof(des3_key_sizes) / sizeof(UINT), 8);
+
+ // AES
+ aes = NewIkeCrypto(e, IKE_CRYPTO_AES_ID, IKE_CRYPTO_AES_STRING,
+ aes_key_sizes, sizeof(aes_key_sizes) / sizeof(UINT), 16);
+
+ //// Hash algorithm
+ // SHA-1
+ sha1 = NewIkeHash(e, IKE_HASH_SHA1_ID, IKE_HASH_SHA1_STRING, 20);
+
+ // MD5
+ md5 = NewIkeHash(e, IKE_HASH_MD5_ID, IKE_HASH_MD5_STRING, 16);
+
+ //// DH algorithm
+ dh1 = NewIkeDh(e, IKE_DH_1_ID, IKE_DH_1_STRING, 96);
+ dh2 = NewIkeDh(e, IKE_DH_2_ID, IKE_DH_2_STRING, 128);
+ dh5 = NewIkeDh(e, IKE_DH_5_ID, IKE_DH_5_STRING, 192);
+
+ // Define the IKE algorithm
+ e->IkeCryptos[IKE_P1_CRYPTO_DES_CBC] = des;
+ e->IkeCryptos[IKE_P1_CRYPTO_3DES_CBC] = des3;
+ e->IkeCryptos[IKE_P1_CRYPTO_AES_CBC] = aes;
+ e->IkeHashes[IKE_P1_HASH_MD5] = md5;
+ e->IkeHashes[IKE_P1_HASH_SHA1] = sha1;
+
+ // Definition of ESP algorithm
+ e->EspCryptos[IKE_TRANSFORM_ID_P2_ESP_DES] = des;
+ e->EspCryptos[IKE_TRANSFORM_ID_P2_ESP_3DES] = des3;
+ e->EspCryptos[IKE_TRANSFORM_ID_P2_ESP_AES] = aes;
+ e->EspHashes[IKE_P2_HMAC_MD5_96] = md5;
+ e->EspHashes[IKE_P2_HMAC_SHA1_96] = sha1;
+
+ // Definition of the DH algorithm
+ e->IkeDhs[IKE_P1_DH_GROUP_768_MODP] = e->EspDhs[IKE_P2_DH_GROUP_768_MODP] = dh1;
+ e->IkeDhs[IKE_P1_DH_GROUP_1024_MODP] = e->EspDhs[IKE_P2_DH_GROUP_1024_MODP] = dh2;
+ e->IkeDhs[IKE_P1_DH_GROUP_1536_MODP] = e->EspDhs[IKE_P2_DH_GROUP_1536_MODP] = dh5;
+
+ return e;
+}
+
+// Release the encryption engine for IKE
+void FreeIkeEngine(IKE_ENGINE *e)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(e->CryptosList);i++)
+ {
+ IKE_CRYPTO *c = LIST_DATA(e->CryptosList, i);
+
+ FreeIkeCrypto(c);
+ }
+
+ ReleaseList(e->CryptosList);
+
+ for (i = 0;i < LIST_NUM(e->HashesList);i++)
+ {
+ IKE_HASH *h = LIST_DATA(e->HashesList, i);
+
+ FreeIkeHash(h);
+ }
+ ReleaseList(e->HashesList);
+
+ for (i = 0;i < LIST_NUM(e->DhsList);i++)
+ {
+ IKE_DH *d = LIST_DATA(e->DhsList, i);
+
+ FreeIkeDh(d);
+ }
+ ReleaseList(e->DhsList);
+
+ Free(e);
+}
+
+// Definition of a new DH algorithm for IKE
+IKE_DH *NewIkeDh(IKE_ENGINE *e, UINT dh_id, char *name, UINT key_size)
+{
+ IKE_DH *d;
+ // Validate arguments
+ if (e == NULL || name == NULL || key_size == 0)
+ {
+ return NULL;
+ }
+
+ d = ZeroMalloc(sizeof(IKE_DH));
+
+ d->DhId = dh_id;
+ d->Name = name;
+ d->KeySize = key_size;
+
+ Add(e->DhsList, d);
+
+ return d;
+}
+
+// Definition of a new encryption algorithm for IKE
+IKE_CRYPTO *NewIkeCrypto(IKE_ENGINE *e, UINT crypto_id, char *name, UINT *key_sizes, UINT num_key_sizes, UINT block_size)
+{
+ IKE_CRYPTO *c;
+ UINT i;
+ // Validate arguments
+ if (e == NULL || name == NULL || key_sizes == NULL)
+ {
+ return NULL;
+ }
+
+ c = ZeroMalloc(sizeof(IKE_CRYPTO));
+
+ c->CryptoId = crypto_id;
+ c->Name = name;
+
+ for (i = 0;i < MIN(num_key_sizes, 16);i++)
+ {
+ c->KeySizes[i] = key_sizes[i];
+ }
+
+ if (num_key_sizes >= 2)
+ {
+ c->VariableKeySize = true;
+ }
+
+ c->BlockSize = block_size;
+
+ Add(e->CryptosList, c);
+
+ return c;
+}
+
+// Release the definition of Encryption algorithm for IKE
+void FreeIkeCrypto(IKE_CRYPTO *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ Free(c);
+}
+
+// Release the definition of IKE hash algorithm
+void FreeIkeHash(IKE_HASH *h)
+{
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ Free(h);
+}
+
+// Release the definition of the DH algorithm for IKE
+void FreeIkeDh(IKE_DH *d)
+{
+ // Validate arguments
+ if (d == NULL)
+ {
+ return;
+ }
+
+ Free(d);
+}
+
+// Definition of a new hash algorithm for IKE
+IKE_HASH *NewIkeHash(IKE_ENGINE *e, UINT hash_id, char *name, UINT size)
+{
+ IKE_HASH *h;
+ // Validate arguments
+ if (e == NULL || name == NULL || size == 0)
+ {
+ return NULL;
+ }
+
+ h = ZeroMalloc(sizeof(IKE_HASH));
+
+ h->HashId = hash_id;
+ h->Name = name;
+ h->HashSize = size;
+
+ Add(e->HashesList, h);
+
+ return h;
+}
+
+// Get the encryption algorithm that is used in IKE
+IKE_CRYPTO *GetIkeCrypto(IKE_ENGINE *e, bool for_esp, UINT i)
+{
+ // Validate arguments
+ if (e == NULL || i == 0 || i >= MAX_IKE_ENGINE_ELEMENTS)
+ {
+ return NULL;
+ }
+
+ if (for_esp)
+ {
+ return e->EspCryptos[i];
+ }
+ else
+ {
+ return e->IkeCryptos[i];
+ }
+}
+
+// Get the hash algorithm used in the IKE
+IKE_HASH *GetIkeHash(IKE_ENGINE *e, bool for_esp, UINT i)
+{
+ // Validate arguments
+ if (e == NULL || i == 0 || i >= MAX_IKE_ENGINE_ELEMENTS)
+ {
+ return NULL;
+ }
+
+ if (for_esp)
+ {
+ return e->EspHashes[i];
+ }
+ else
+ {
+ return e->IkeHashes[i];
+ }
+}
+
+// Get the DH algorithm used in the IKE
+IKE_DH *GetIkeDh(IKE_ENGINE *e, bool for_esp, UINT i)
+{
+ // Validate arguments
+ if (e == NULL || i == 0 || i >= MAX_IKE_ENGINE_ELEMENTS)
+ {
+ return NULL;
+ }
+
+ if (for_esp)
+ {
+ return e->EspDhs[i];
+ }
+ else
+ {
+ return e->IkeDhs[i];
+ }
+}
+
+// Perform encryption
+void IkeCryptoEncrypt(IKE_CRYPTO_KEY *k, void *dst, void *src, UINT size, void *ivec)
+{
+ // Validate arguments
+ if (k == NULL || dst == NULL || src == NULL || size == 0 || ivec == NULL)
+ {
+ Zero(dst, size);
+ return;
+ }
+
+ if ((size % k->Crypto->BlockSize) != 0)
+ {
+ Zero(dst, size);
+ return;
+ }
+
+ switch (k->Crypto->CryptoId)
+ {
+ case IKE_CRYPTO_DES_ID: // DES
+ DesEncrypt(dst, src, size, k->DesKey1, ivec);
+ break;
+
+ case IKE_CRYPTO_3DES_ID: // 3DES
+ Des3Encrypt2(dst, src, size, k->DesKey1, k->DesKey2, k->DesKey3, ivec);
+ break;
+
+ case IKE_CRYPTO_AES_ID: // AES
+ AesEncrypt(dst, src, size, k->AesKey, ivec);
+ break;
+
+ default:
+ // Unknown
+ Zero(dst, size);
+ break;
+ }
+}
+
+// Perform decryption
+void IkeCryptoDecrypt(IKE_CRYPTO_KEY *k, void *dst, void *src, UINT size, void *ivec)
+{
+ // Validate arguments
+ if (k == NULL || dst == NULL || src == NULL || size == 0 || ivec == NULL)
+ {
+ Zero(dst, size);
+ return;
+ }
+
+ if ((size % k->Crypto->BlockSize) != 0)
+ {
+ Zero(dst, size);
+ return;
+ }
+
+ switch (k->Crypto->CryptoId)
+ {
+ case IKE_CRYPTO_DES_ID: // DES
+ DesDecrypt(dst, src, size, k->DesKey1, ivec);
+ break;
+
+ case IKE_CRYPTO_3DES_ID: // 3DES
+ Des3Decrypt2(dst, src, size, k->DesKey1, k->DesKey2, k->DesKey3, ivec);
+ break;
+
+ case IKE_CRYPTO_AES_ID: // AES
+ AesDecrypt(dst, src, size, k->AesKey, ivec);
+ break;
+
+ default:
+ // Unknown
+ Zero(dst, size);
+ break;
+ }
+}
+
+// Calculate a hash
+void IkeHash(IKE_HASH *h, void *dst, void *src, UINT size)
+{
+ // Validate arguments
+ if (h == NULL || dst == NULL || (size != 0 && src == NULL))
+ {
+ Zero(dst, size);
+ return;
+ }
+
+ switch (h->HashId)
+ {
+ case IKE_HASH_MD5_ID:
+ // MD5
+ Md5(dst, src, size);
+ break;
+
+ case IKE_HASH_SHA1_ID:
+ // SHA-1
+ Sha1(dst, src, size);
+ break;
+
+ default:
+ // Unknown
+ Zero(dst, size);
+ break;
+ }
+}
+
+// Calculation of HMAC
+void IkeHMac(IKE_HASH *h, void *dst, void *key, UINT key_size, void *data, UINT data_size)
+{
+ UCHAR k[HMAC_BLOCK_SIZE];
+ UCHAR *data1;
+ UCHAR hash1[IKE_MAX_HASH_SIZE];
+ UINT data1_size;
+ UCHAR data2[IKE_MAX_HASH_SIZE + HMAC_BLOCK_SIZE];
+ UINT data2_size;
+ UCHAR tmp1600[1600];
+ bool no_free = false;
+ UINT i;
+ // Validate arguments
+ if (h == NULL || dst == NULL || (key == NULL && key_size != 0) || (data == NULL && data_size != 0))
+ {
+ return;
+ }
+
+ if (h->HashId == IKE_HASH_SHA1_ID)
+ {
+ // Use special function (fast) in the case of SHA-1
+ HMacSha1(dst, key, key_size, data, data_size);
+ return;
+ }
+ else if (h->HashId == IKE_HASH_MD5_ID)
+ {
+ // Use the special function (fast) in the case of MD5
+ HMacMd5(dst, key, key_size, data, data_size);
+ return;
+ }
+
+ // Creating a K
+ Zero(k, sizeof(k));
+ if (key_size <= HMAC_BLOCK_SIZE)
+ {
+ Copy(k, key, key_size);
+ }
+ else
+ {
+ IkeHash(h, k, key, key_size);
+ }
+
+ // Generation of data 1
+ data1_size = data_size + HMAC_BLOCK_SIZE;
+
+ if (data1_size > sizeof(tmp1600))
+ {
+ data1 = Malloc(data1_size);
+ }
+ else
+ {
+ data1 = tmp1600;
+ no_free = true;
+ }
+
+ for (i = 0;i < HMAC_BLOCK_SIZE;i++)
+ {
+ data1[i] = k[i] ^ 0x36;
+ }
+
+ Copy(data1 + HMAC_BLOCK_SIZE, data, data_size);
+
+ // Calculate the hash value
+ IkeHash(h, hash1, data1, data1_size);
+
+ if (no_free == false)
+ {
+ Free(data1);
+ }
+
+ // Generation of data 2
+ data2_size = h->HashSize + HMAC_BLOCK_SIZE;
+
+ for (i = 0;i < HMAC_BLOCK_SIZE;i++)
+ {
+ data2[i] = k[i] ^ 0x5c;
+ }
+
+ Copy(data2 + HMAC_BLOCK_SIZE, hash1, h->HashSize);
+
+ // Calculate the hash value
+ IkeHash(h, dst, data2, data2_size);
+}
+void IkeHMacBuf(IKE_HASH *h, void *dst, BUF *key, BUF *data)
+{
+ // Validate arguments
+ if (h == NULL || dst == NULL || key == NULL || data == NULL)
+ {
+ return;
+ }
+
+ IkeHMac(h, dst, key->Buf, key->Size, data->Buf, data->Size);
+}
+
+// Check whether the key size is valid
+bool IkeCheckKeySize(IKE_CRYPTO *c, UINT size)
+{
+ bool ok = false;
+ UINT i;
+ // Validate arguments
+ if (c == NULL || size == 0)
+ {
+ return false;
+ }
+
+ for (i = 0;i < sizeof(c->KeySizes) / sizeof(UINT);i++)
+ {
+ if (c->KeySizes[i] == size)
+ {
+ ok = true;
+ break;
+ }
+ }
+
+ return ok;
+}
+
+// Create a key
+IKE_CRYPTO_KEY *IkeNewKey(IKE_CRYPTO *c, void *data, UINT size)
+{
+ IKE_CRYPTO_KEY *k;
+ // Validate arguments
+ if (c == NULL || data == NULL || size == 0)
+ {
+ return NULL;
+ }
+
+ if (IkeCheckKeySize(c, size) == false)
+ {
+ return NULL;
+ }
+
+ k = ZeroMalloc(sizeof(IKE_CRYPTO_KEY));
+ k->Crypto = c;
+ k->Data = Clone(data, size);
+ k->Size = size;
+
+ switch (k->Crypto->CryptoId)
+ {
+ case IKE_CRYPTO_DES_ID:
+ // DES 64bit key
+ k->DesKey1 = DesNewKeyValue(data);
+ break;
+
+ case IKE_CRYPTO_3DES_ID:
+ // 3DES 192bit key
+ k->DesKey1 = DesNewKeyValue(((UCHAR *)data) + DES_KEY_SIZE * 0);
+ k->DesKey2 = DesNewKeyValue(((UCHAR *)data) + DES_KEY_SIZE * 1);
+ k->DesKey3 = DesNewKeyValue(((UCHAR *)data) + DES_KEY_SIZE * 2);
+ break;
+
+ case IKE_CRYPTO_AES_ID:
+ // AES variable length key
+ k->AesKey = AesNewKey(data, size);
+ break;
+ }
+
+ return k;
+}
+
+// Release the key
+void IkeFreeKey(IKE_CRYPTO_KEY *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ DesFreeKeyValue(k->DesKey1);
+ DesFreeKeyValue(k->DesKey2);
+ DesFreeKeyValue(k->DesKey3);
+
+ AesFreeKey(k->AesKey);
+
+ Free(k->Data);
+
+ Free(k);
+}
+
+// Create a DH object
+DH_CTX *IkeDhNewCtx(IKE_DH *d)
+{
+ // Validate arguments
+ if (d == NULL)
+ {
+ return NULL;
+ }
+
+ switch (d->DhId)
+ {
+ case IKE_DH_1_ID:
+ return DhNewGroup1();
+
+ case IKE_DH_2_ID:
+ return DhNewGroup2();
+
+ case IKE_DH_5_ID:
+ return DhNewGroup5();
+ }
+
+ return NULL;
+}
+
+// Release the DH object
+void IkeDhFreeCtx(DH_CTX *dh)
+{
+ // Validate arguments
+ if (dh == NULL)
+ {
+ return;
+ }
+
+ DhFree(dh);
+}
+
+
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_IkePacket.h b/src/Cedar/IPsec_IkePacket.h
new file mode 100644
index 00000000..98a10392
--- /dev/null
+++ b/src/Cedar/IPsec_IkePacket.h
@@ -0,0 +1,711 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_IkePacket.h
+// Header of IPsec_IkePacket.c
+
+#ifndef IPSEC_PACKET_H
+#define IPSEC_PACKET_H
+
+// Constants
+#ifdef OS_WIN32
+#pragma pack(push, 1)
+#endif // OS_WIN32
+
+// Maximum hash size
+#define IKE_MAX_HASH_SIZE 20 // Size of SHA-1 is the maximum for now
+
+// Maximum block size
+#define IKE_MAX_BLOCK_SIZE 16 // Size of AES is maximum at the moment
+
+// Maximum key size
+#define IKE_MAX_KEY_SIZE 32 // Size of AES-256 is the maximum for now
+
+// IKE version
+#define IKE_VERSION 0x10 // 1.0
+
+// IKE payload type
+#define IKE_PAYLOAD_NONE 0 // No payload
+#define IKE_PAYLOAD_SA 1 // SA payload
+#define IKE_PAYLOAD_PROPOSAL 2 // Proposal payload
+#define IKE_PAYLOAD_TRANSFORM 3 // Transform payload
+#define IKE_PAYLOAD_KEY_EXCHANGE 4 // Key exchange payload
+#define IKE_PAYLOAD_ID 5 // ID payload
+#define IKE_PAYLOAD_CERT 6 // Certificate payload
+#define IKE_PAYLOAD_CERT_REQUEST 7 // Certificate request payload
+#define IKE_PAYLOAD_HASH 8 // Hash payload
+#define IKE_PAYLOAD_SIGN 9 // Signature payload
+#define IKE_PAYLOAD_RAND 10 // Random number payload
+#define IKE_PAYLOAD_NOTICE 11 // Notification Payload
+#define IKE_PAYLOAD_DELETE 12 // Deletion payload
+#define IKE_PAYLOAD_VENDOR_ID 13 // Vendor ID payload
+#define IKE_PAYLOAD_NAT_D 20 // NAT-D payload
+#define IKE_PAYLOAD_NAT_OA 21 // NAT-OA payload
+#define IKE_PAYLOAD_NAT_D_DRAFT 130 // NAT-D payload draft
+#define IKE_PAYLOAD_NAT_OA_DRAFT 16 // NAT-OA payload draft
+#define IKE_PAYLOAD_NAT_OA_DRAFT_2 131 // NAT-OA payload draft 2
+
+// Macro to check whether the payload type is supported
+#define IKE_IS_SUPPORTED_PAYLOAD_TYPE(i) ((((i) >= IKE_PAYLOAD_SA) && ((i) <= IKE_PAYLOAD_VENDOR_ID)) || ((i) == IKE_PAYLOAD_NAT_D) || ((i) == IKE_PAYLOAD_NAT_OA) || ((i) == IKE_PAYLOAD_NAT_OA_DRAFT) || ((i) == IKE_PAYLOAD_NAT_OA_DRAFT_2) || ((i) == IKE_PAYLOAD_NAT_D_DRAFT))
+
+// IKE header flag
+#define IKE_HEADER_FLAG_ENCRYPTED 1 // Encryption
+#define IKE_HEADER_FLAG_COMMIT 2 // Commit
+#define IKE_HEADER_FLAG_AUTH_ONLY 4 // Only authentication
+
+// IKE payload common header
+struct IKE_COMMON_HEADER
+{
+ UCHAR NextPayload;
+ UCHAR Reserved;
+ USHORT PayloadSize;
+} GCC_PACKED;
+
+// IKE SA payload header
+struct IKE_SA_HEADER
+{
+ UINT DoI; // DOI value
+ UINT Situation; // Situation value
+} GCC_PACKED;
+
+// DOI value in the IKE SA payload
+#define IKE_SA_DOI_IPSEC 1 // IPsec
+
+// Situation value in the IKE SA payload
+#define IKE_SA_SITUATION_IDENTITY 1 // Only authentication
+
+// IKE proposal payload header
+struct IKE_PROPOSAL_HEADER
+{
+ UCHAR Number; // Number
+ UCHAR ProtocolId; // Protocol ID
+ UCHAR SpiSize; // Length of SPI
+ UCHAR NumTransforms; // Transform number
+} GCC_PACKED;
+
+// Protocol ID in the IKE proposal payload header
+#define IKE_PROTOCOL_ID_IKE 1 // IKE
+#define IKE_PROTOCOL_ID_IPSEC_AH 2 // AH
+#define IKE_PROTOCOL_ID_IPSEC_ESP 3 // ESP
+#define IKE_PROTOCOL_ID_IPV4 4 // IP
+#define IKE_PROTOCOL_ID_IPV6 41 // IPv6
+
+// IKE transform payload header
+struct IKE_TRANSFORM_HEADER
+{
+ UCHAR Number; // Number
+ UCHAR TransformId; // Transform ID
+ USHORT Reserved; // Reserved
+} GCC_PACKED;
+
+// Transform ID (Phase 1) in IKE transform payload header
+#define IKE_TRANSFORM_ID_P1_KEY_IKE 1 // IKE
+
+// Transform ID (Phase 2) in IKE transform payload header
+#define IKE_TRANSFORM_ID_P2_ESP_DES 2 // DES-CBC
+#define IKE_TRANSFORM_ID_P2_ESP_3DES 3 // 3DES-CBC
+#define IKE_TRANSFORM_ID_P2_ESP_CAST 6 // CAST
+#define IKE_TRANSFORM_ID_P2_ESP_BLOWFISH 7 // BLOWFISH
+#define IKE_TRANSFORM_ID_P2_ESP_AES 12 // AES
+
+// IKE transform value (fixed length)
+struct IKE_TRANSFORM_VALUE
+{
+ UCHAR AfBit; // AF bit (0: Fixed length, 1: Variable length)
+ UCHAR Type; // Type
+ USHORT Value; // Value data (16bit)
+} GCC_PACKED;
+
+// The Type value in IKE transform value (Phase 1)
+#define IKE_TRANSFORM_VALUE_P1_CRYPTO 1 // Encryption algorithm
+#define IKE_TRANSFORM_VALUE_P1_HASH 2 // Hash algorithm
+#define IKE_TRANSFORM_VALUE_P1_AUTH_METHOD 3 // Authentication method
+#define IKE_TRANSFORM_VALUE_P1_DH_GROUP 4 // DH group number
+#define IKE_TRANSFORM_VALUE_P1_LIFE_TYPE 11 // Expiration date type
+#define IKE_TRANSFORM_VALUE_P1_LIFE_VALUE 12 // Expiration date
+#define IKE_TRANSFORM_VALUE_P1_KET_SIZE 14 // Key size
+
+// The Type value in IKE transform values (Phase 2)
+#define IKE_TRANSFORM_VALUE_P2_LIFE_TYPE 1 // Expiration date type
+#define IKE_TRANSFORM_VALUE_P2_LIFE_VALUE 2 // Expiration date
+#define IKE_TRANSFORM_VALUE_P2_DH_GROUP 3 // DH group number
+#define IKE_TRANSFORM_VALUE_P2_CAPSULE 4 // Encapsulation mode
+#define IKE_TRANSFORM_VALUE_P2_HMAC 5 // HMAC algorithm
+#define IKE_TRANSFORM_VALUE_P2_KEY_SIZE 6 // Key size
+
+// Phase 1: The encryption algorithm in the IKE transform value
+#define IKE_P1_CRYPTO_DES_CBC 1
+#define IKE_P1_CRYPTO_BLOWFISH 3
+#define IKE_P1_CRYPTO_3DES_CBC 5
+#define IKE_P1_CRYPTO_CAST_CBC 6
+#define IKE_P1_CRYPTO_AES_CBC 7
+
+// Phase 1: The hash algorithm in IKE transform value
+#define IKE_P1_HASH_MD5 1
+#define IKE_P1_HASH_SHA1 2
+
+// Phase 1: The authentication method in the IKE transform value
+#define IKE_P1_AUTH_METHOD_PRESHAREDKEY 1
+#define IKE_P1_AUTH_METHOD_RSA_SIGN 3
+
+// Phase 1: The DH group number in the IKE transform value
+#define IKE_P1_DH_GROUP_768_MODP 1
+#define IKE_P1_DH_GROUP_1024_MODP 2
+#define IKE_P1_DH_GROUP_1536_MODP 5
+
+// Phase 1: The expiration date type in IKE transform value
+#define IKE_P1_LIFE_TYPE_SECONDS 1
+#define IKE_P1_LIFE_TYPE_KILOBYTES 2
+
+// Phase 2: The HMAC algorithm in IPsec transform value
+#define IKE_P2_HMAC_MD5_96 1
+#define IKE_P2_HMAC_SHA1_96 2
+
+// Phase 2: The DH group number in the IPsec transform value
+#define IKE_P2_DH_GROUP_768_MODP 1
+#define IKE_P2_DH_GROUP_1024_MODP 2
+#define IKE_P2_DH_GROUP_1536_MODP 5
+
+// Phase 2: The encapsulation mode in IPsec transform value
+#define IKE_P2_CAPSULE_TUNNEL 1
+#define IKE_P2_CAPSULE_TRANSPORT 2
+#define IKE_P2_CAPSULE_NAT_TUNNEL_1 3
+#define IKE_P2_CAPSULE_NAT_TUNNEL_2 61443
+#define IKE_P2_CAPSULE_NAT_TRANSPORT_1 4
+#define IKE_P2_CAPSULE_NAT_TRANSPORT_2 61444
+
+// Phase 2: The expiration date type in IPsec transform value
+#define IKE_P2_LIFE_TYPE_SECONDS 1
+#define IKE_P2_LIFE_TYPE_KILOBYTES 2
+
+
+// IKE ID payload header
+struct IKE_ID_HEADER
+{
+ UCHAR IdType; // Type of ID
+ UCHAR ProtocolId; // Protocol ID
+ USHORT Port; // Port
+} GCC_PACKED;
+
+// Type of ID in the IKE ID payload header
+#define IKE_ID_IPV4_ADDR 1 // IPv4 address (32 bit)
+#define IKE_ID_FQDN 2 // FQDN
+#define IKE_ID_USER_FQDN 3 // User FQDN
+#define IKE_ID_IPV4_ADDR_SUBNET 4 // IPv4 + subnet (64 bit)
+#define IKE_ID_IPV6_ADDR 5 // IPv6 address (128 bit)
+#define IKE_ID_IPV6_ADDR_SUBNET 6 // IPv6 + subnet (256 bit)
+#define IKE_ID_DER_ASN1_DN 9 // X.500 Distinguished Name
+#define IKE_ID_DER_ASN1_GN 10 // X.500 General Name
+#define IKE_ID_KEY_ID 11 // Key
+
+// The protocol ID in the IKE ID payload
+#define IKE_ID_PROTOCOL_UDP IP_PROTO_UDP // UDP
+
+// IKE certificate payload header
+struct IKE_CERT_HEADER
+{
+ UCHAR CertType; // Certificate Type
+} GCC_PACKED;
+
+// The certificate type in IKE certificate payload header
+#define IKE_CERT_TYPE_X509 4 // X.509 certificate (for digital signature)
+
+// IKE certificate payload header
+struct IKE_CERT_REQUEST_HEADER
+{
+ UCHAR CertType; // Certificate Type
+} GCC_PACKED;
+
+// IKE notification payload header
+struct IKE_NOTICE_HEADER
+{
+ UINT DoI; // DOI value
+ UCHAR ProtocolId; // Protocol ID
+ // Same to the protocol ID in the IKE proposal payload header
+ UCHAR SpiSize; // SPI size
+ USHORT MessageType; // Message type
+} GCC_PACKED;
+
+// IKE Deletion payload header
+struct IKE_DELETE_HEADER
+{
+ UINT DoI; // DOI value
+ UCHAR ProtocolId; // Protocol ID
+ // Same to the protocol ID in the IKE proposal payload header
+ UCHAR SpiSize; // SPI size
+ USHORT NumSpis; // SPI number
+} GCC_PACKED;
+
+// IKE NAT-OA payload header
+struct IKE_NAT_OA_HEADER
+{
+ UCHAR IdType; // Type of ID
+ UCHAR Reserved1;
+ USHORT Reserved2;
+} GCC_PACKED;
+
+
+#ifdef OS_WIN32
+#pragma pack(pop)
+#endif // OS_WIN32
+
+
+
+//
+// IKE internal data structure
+//
+
+// IKE packet SA payload
+struct IKE_PACKET_SA_PAYLOAD
+{
+ LIST *PayloadList; // Proposal payload list
+};
+
+// IKE proposal packet payload
+struct IKE_PACKET_PROPOSAL_PAYLOAD
+{
+ UCHAR Number; // Number
+ UCHAR ProtocolId; // Protocol ID
+ BUF *Spi; // SPI data
+
+ LIST *PayloadList; // Payload list
+};
+
+// IKE packet transform payload
+struct IKE_PACKET_TRANSFORM_PAYLOAD
+{
+ UCHAR Number; // Number
+ UCHAR TransformId; // Transform ID
+
+ LIST *ValueList; // Value list
+};
+
+// IKE packet transform value
+struct IKE_PACKET_TRANSFORM_VALUE
+{
+ UCHAR Type; // Type
+ UINT Value; // Value
+};
+
+// IKE generic data payload
+struct IKE_PACKET_DATA_PAYLOAD
+{
+ BUF *Data; // Generic data
+};
+
+// IKE packet ID payload
+struct IKE_PACKET_ID_PAYLOAD
+{
+ UCHAR Type; // Type
+ UCHAR ProtocolId; // Protocol ID
+ USHORT Port; // Port number
+ BUF *IdData; // ID data
+ char StrData[128]; // Data of the result of converting to a string
+};
+
+// IKE packet certificate payload
+struct IKE_PACKET_CERT_PAYLOAD
+{
+ UCHAR CertType; // Certificate type
+ BUF *CertData; // Certificate data
+};
+
+// IKE packet certificate request payload
+struct IKE_PACKET_CERT_REQUEST_PAYLOAD
+{
+ UCHAR CertType; // Certificate type
+ BUF *Data; // Request data
+};
+
+// IKE packet notification payload
+struct IKE_PACKET_NOTICE_PAYLOAD
+{
+ UCHAR ProtocolId; // Protocol ID
+ USHORT MessageType; // Message type
+ BUF *Spi; // SPI data
+ BUF *MessageData; // Message data
+};
+
+// IKE notification message type
+// Error
+#define IKE_NOTICE_ERROR_INVALID_COOKIE 4 // Invalid cookie
+#define IKE_NOTICE_ERROR_INVALID_EXCHANGE_TYPE 7 // Invalid exchange type
+#define IKE_NOTICE_ERROR_INVALID_SPI 11 // Invalid SPI
+#define IKE_NOTICE_ERROR_NO_PROPOSAL_CHOSEN 14 // There is nothing worth mentioning in the presented proposal
+
+// DPD
+#define IKE_NOTICE_DPD_REQUEST 36136 // R-U-THERE
+#define IKE_NOTICE_DPD_RESPONSE 36137 // R-U-THERE-ACK
+
+
+// IKE packet deletion payload
+struct IKE_PACKET_DELETE_PAYLOAD
+{
+ UCHAR ProtocolId; // Protocol ID
+ LIST *SpiList; // SPI list
+};
+
+// IKE NAT-OA payload
+struct IKE_PACKET_NAT_OA_PAYLOAD
+{
+ IP IpAddress; // IP address
+};
+
+// IKE packet payload
+struct IKE_PACKET_PAYLOAD
+{
+ UCHAR PayloadType; // Payload type
+ UCHAR Padding[3];
+ BUF *BitArray; // Bit array
+
+ union
+ {
+ IKE_PACKET_SA_PAYLOAD Sa; // SA payload
+ IKE_PACKET_PROPOSAL_PAYLOAD Proposal; // Proposal payload
+ IKE_PACKET_TRANSFORM_PAYLOAD Transform; // Transform payload
+ IKE_PACKET_DATA_PAYLOAD KeyExchange; // Key exchange payload
+ IKE_PACKET_ID_PAYLOAD Id; // ID payload
+ IKE_PACKET_CERT_PAYLOAD Cert; // Certificate payload
+ IKE_PACKET_CERT_REQUEST_PAYLOAD CertRequest; // Certificate request payload
+ IKE_PACKET_DATA_PAYLOAD Hash; // Hash payload
+ IKE_PACKET_DATA_PAYLOAD Sign; // Signature payload
+ IKE_PACKET_DATA_PAYLOAD Rand; // Random number payload
+ IKE_PACKET_NOTICE_PAYLOAD Notice; // Notification Payload
+ IKE_PACKET_DELETE_PAYLOAD Delete; // Deletion payload
+ IKE_PACKET_DATA_PAYLOAD VendorId; // Vendor ID payload
+ IKE_PACKET_NAT_OA_PAYLOAD NatOa; // NAT-OA payload
+ IKE_PACKET_DATA_PAYLOAD GeneralData; // Generic data payload
+ } Payload;
+};
+
+struct IKE_PACKET
+{
+ UINT64 InitiatorCookie; // Initiator cookie
+ UINT64 ResponderCookie; // Responder cookie
+ UCHAR ExchangeType; // Exchange type
+ bool FlagEncrypted; // Encryption flag
+ bool FlagCommit; // Commit flag
+ bool FlagAuthOnly; // Flag only authentication
+ UINT MessageId; // Message ID
+ LIST *PayloadList; // Payload list
+ BUF *DecryptedPayload; // Decrypted payload
+ UINT MessageSize; // Original size
+};
+
+// IKE P1 key set
+struct IKE_P1_KEYSET
+{
+ BUF *SKEYID_d; // IPsec SA key
+ BUF *SKEYID_a; // IKE SA authentication key
+ BUF *SKEYID_e; // IKE SA encryption key
+};
+
+// Number and name of the encryption algorithm for IKE
+#define IKE_CRYPTO_DES_ID 0
+#define IKE_CRYPTO_DES_STRING "DES-CBC"
+
+#define IKE_CRYPTO_3DES_ID 1
+#define IKE_CRYPTO_3DES_STRING "3DES-CBC"
+
+#define IKE_CRYPTO_AES_ID 2
+#define IKE_CRYPTO_AES_STRING "AES-CBC"
+
+#define IKE_CRYPTO_BLOWFISH_ID 3
+#define IKE_CRYPTO_BLOWFISH_STRING "Blowfish-CBC"
+
+#define IKE_CRYPTO_CAST_ID 4
+#define IKE_CRYPTO_CAST_STRING "CAST-128-CBC"
+
+// Number and name of the IKE hash algorithm
+#define IKE_HASH_MD5_ID 0
+#define IKE_HASH_MD5_STRING "MD5"
+
+#define IKE_HASH_SHA1_ID 1
+#define IKE_HASH_SHA1_STRING "SHA-1"
+
+// Number and name of DH algorithm for IKE
+#define IKE_DH_1_ID 0
+#define IKE_DH_1_STRING "MODP 768 (Group 1)"
+
+#define IKE_DH_2_ID 1
+#define IKE_DH_2_STRING "MODP 1024 (Group 2)"
+
+#define IKE_DH_5_ID 2
+#define IKE_DH_5_STRING "MODP 1536 (Group 5)"
+
+
+// Encryption algorithm for IKE
+struct IKE_CRYPTO
+{
+ UINT CryptoId; // ID
+ char *Name; // Name
+ UINT KeySizes[16]; // Key size candidate
+ UINT BlockSize; // Block size
+ bool VariableKeySize; // Whether the key size is variable
+};
+
+// IKE encryption key
+struct IKE_CRYPTO_KEY
+{
+ IKE_CRYPTO *Crypto;
+ void *Data; // Key data
+ UINT Size; // Key size
+
+ DES_KEY_VALUE *DesKey1, *DesKey2, *DesKey3; // DES key
+ AES_KEY_VALUE *AesKey; // AES key
+};
+
+// IKE hash algorithm
+struct IKE_HASH
+{
+ UINT HashId; // ID
+ char *Name; // Name
+ UINT HashSize; // Output size
+};
+
+// DH algorithm for IKE
+struct IKE_DH
+{
+ UINT DhId; // ID
+ char *Name; // Name
+ UINT KeySize; // Key size
+};
+
+#define MAX_IKE_ENGINE_ELEMENTS 16
+
+// Encryption engine for IKE
+struct IKE_ENGINE
+{
+ IKE_CRYPTO *IkeCryptos[MAX_IKE_ENGINE_ELEMENTS]; // Encryption algorithm list that is used in the IKE
+ IKE_HASH *IkeHashes[MAX_IKE_ENGINE_ELEMENTS]; // Hash algorithm list that is used in the IKE
+ IKE_DH *IkeDhs[MAX_IKE_ENGINE_ELEMENTS]; // DH algorithm list that is used in the IKE
+
+ IKE_CRYPTO *EspCryptos[MAX_IKE_ENGINE_ELEMENTS]; // Encryption algorithm list that is used by ESP
+ IKE_HASH *EspHashes[MAX_IKE_ENGINE_ELEMENTS]; // Hash algorithm list that is used by ESP
+ IKE_DH *EspDhs[MAX_IKE_ENGINE_ELEMENTS]; // DH algorithm list that is used by ESP
+
+ LIST *CryptosList;
+ LIST *HashesList;
+ LIST *DhsList;
+};
+
+// IKE encryption parameters
+struct IKE_CRYPTO_PARAM
+{
+ IKE_CRYPTO_KEY *Key; // Key
+ UCHAR Iv[IKE_MAX_BLOCK_SIZE]; // IV
+ UCHAR NextIv[IKE_MAX_BLOCK_SIZE]; // IV to be used next
+};
+
+
+// Function prototype
+IKE_PACKET *IkeParseHeader(void *data, UINT size, IKE_CRYPTO_PARAM *cparam);
+IKE_PACKET *IkeParse(void *data, UINT size, IKE_CRYPTO_PARAM *cparam);
+IKE_PACKET *IkeParseEx(void *data, UINT size, IKE_CRYPTO_PARAM *cparam, bool header_only);
+void IkeFree(IKE_PACKET *p);
+IKE_PACKET *IkeNew(UINT64 init_cookie, UINT64 resp_cookie, UCHAR exchange_type,
+ bool encrypted, bool commit, bool auth_only, UINT msg_id,
+ LIST *payload_list);
+
+void IkeDebugPrintPayloads(LIST *o, UINT depth);
+void IkeDebugUdpSendRawPacket(IKE_PACKET *p);
+
+BUF *IkeEncrypt(void *data, UINT size, IKE_CRYPTO_PARAM *cparam);
+BUF *IkeEncryptWithPadding(void *data, UINT size, IKE_CRYPTO_PARAM *cparam);
+BUF *IkeDecrypt(void *data, UINT size, IKE_CRYPTO_PARAM *cparam);
+
+LIST *IkeParsePayloadList(void *data, UINT size, UCHAR first_payload);
+LIST *IkeParsePayloadListEx(void *data, UINT size, UCHAR first_payload, UINT *total_read_size);
+void IkeFreePayloadList(LIST *o);
+UINT IkeGetPayloadNum(LIST *o, UINT payload_type);
+IKE_PACKET_PAYLOAD *IkeGetPayload(LIST *o, UINT payload_type, UINT index);
+
+IKE_PACKET_PAYLOAD *IkeParsePayload(UINT payload_type, BUF *b);
+void IkeFreePayload(IKE_PACKET_PAYLOAD *p);
+bool IkeParseDataPayload(IKE_PACKET_DATA_PAYLOAD *t, BUF *b);
+void IkeFreeDataPayload(IKE_PACKET_DATA_PAYLOAD *t);
+bool IkeParseSaPayload(IKE_PACKET_SA_PAYLOAD *t, BUF *b);
+void IkeFreeSaPayload(IKE_PACKET_SA_PAYLOAD *t);
+bool IkeParseProposalPayload(IKE_PACKET_PROPOSAL_PAYLOAD *t, BUF *b);
+void IkeFreeProposalPayload(IKE_PACKET_PROPOSAL_PAYLOAD *t);
+bool IkeParseTransformPayload(IKE_PACKET_TRANSFORM_PAYLOAD *t, BUF *b);
+void IkeFreeTransformPayload(IKE_PACKET_TRANSFORM_PAYLOAD *t);
+LIST *IkeParseTransformValueList(BUF *b);
+void IkeFreeTransformValueList(LIST *o);
+bool IkeParseIdPayload(IKE_PACKET_ID_PAYLOAD *t, BUF *b);
+void IkeFreeIdPayload(IKE_PACKET_ID_PAYLOAD *t);
+bool IkeParseCertPayload(IKE_PACKET_CERT_PAYLOAD *t, BUF *b);
+void IkeFreeCertPayload(IKE_PACKET_CERT_PAYLOAD *t);
+bool IkeParseCertRequestPayload(IKE_PACKET_CERT_REQUEST_PAYLOAD *t, BUF *b);
+void IkeFreeCertRequestPayload(IKE_PACKET_CERT_REQUEST_PAYLOAD *t);
+bool IkeParseNoticePayload(IKE_PACKET_NOTICE_PAYLOAD *t, BUF *b);
+void IkeFreeNoticePayload(IKE_PACKET_NOTICE_PAYLOAD *t);
+bool IkeParseDeletePayload(IKE_PACKET_DELETE_PAYLOAD *t, BUF *b);
+void IkeFreeDeletePayload(IKE_PACKET_DELETE_PAYLOAD *t);
+bool IkeParseNatOaPayload(IKE_PACKET_NAT_OA_PAYLOAD *t, BUF *b);
+
+
+bool IkeCompareHash(IKE_PACKET_PAYLOAD *hash_payload, void *hash_data, UINT hash_size);
+
+IKE_PACKET_PAYLOAD *IkeNewPayload(UINT payload_type);
+IKE_PACKET_PAYLOAD *IkeNewDataPayload(UCHAR payload_type, void *data, UINT size);
+IKE_PACKET_PAYLOAD *IkeNewNatOaPayload(UCHAR payload_type, IP *ip);
+IKE_PACKET_PAYLOAD *IkeNewSaPayload(LIST *payload_list);
+IKE_PACKET_PAYLOAD *IkeNewProposalPayload(UCHAR number, UCHAR protocol_id, void *spi, UINT spi_size, LIST *payload_list);
+IKE_PACKET_PAYLOAD *IkeNewTransformPayload(UCHAR number, UCHAR transform_id, LIST *value_list);
+IKE_PACKET_TRANSFORM_VALUE *IkeNewTransformValue(UCHAR type, UINT value);
+IKE_PACKET_PAYLOAD *IkeNewIdPayload(UCHAR id_type, UCHAR protocol_id, USHORT port, void *id_data, UINT id_size);
+IKE_PACKET_PAYLOAD *IkeNewCertPayload(UCHAR cert_type, void *cert_data, UINT cert_size);
+IKE_PACKET_PAYLOAD *IkeNewCertRequestPayload(UCHAR cert_type, void *data, UINT size);
+IKE_PACKET_PAYLOAD *IkeNewNoticePayload(UCHAR protocol_id, USHORT message_type,
+ void *spi, UINT spi_size,
+ void *message, UINT message_size);
+IKE_PACKET_PAYLOAD *IkeNewDeletePayload(UCHAR protocol_id, LIST *spi_list);
+
+IKE_PACKET_PAYLOAD *IkeNewNoticeErrorInvalidCookiePayload(UINT64 init_cookie, UINT64 resp_cookie);
+IKE_PACKET_PAYLOAD *IkeNewNoticeErrorInvalidExchangeTypePayload(UINT64 init_cookie, UINT64 resp_cookie, UCHAR exchange_type);
+IKE_PACKET_PAYLOAD *IkeNewNoticeErrorInvalidSpiPayload(UINT spi);
+IKE_PACKET_PAYLOAD *IkeNewNoticeErrorNoProposalChosenPayload(bool quick_mode, UINT64 init_cookie, UINT64 resp_cookie);
+IKE_PACKET_PAYLOAD *IkeNewNoticeDpdPayload(bool ack, UINT64 init_cookie, UINT64 resp_cookie, UINT seq_no);
+
+UCHAR IkeGetFirstPayloadType(LIST *o);
+BUF *IkeBuild(IKE_PACKET *p, IKE_CRYPTO_PARAM *cparam);
+BUF *IkeBuildEx(IKE_PACKET *p, IKE_CRYPTO_PARAM *cparam, bool use_original_decrypted);
+BUF *IkeBuildPayloadList(LIST *o);
+BUF *IkeBuildPayload(IKE_PACKET_PAYLOAD *p);
+BUF *IkeBuildDataPayload(IKE_PACKET_DATA_PAYLOAD *t);
+BUF *IkeBuildSaPayload(IKE_PACKET_SA_PAYLOAD *t);
+BUF *IkeBuildProposalPayload(IKE_PACKET_PROPOSAL_PAYLOAD *t);
+BUF *IkeBuildTransformPayload(IKE_PACKET_TRANSFORM_PAYLOAD *t);
+BUF *IkeBuildTransformValue(IKE_PACKET_TRANSFORM_VALUE *v);
+BUF *IkeBuildTransformValueList(LIST *o);
+BUF *IkeBuildIdPayload(IKE_PACKET_ID_PAYLOAD *t);
+BUF *IkeBuildCertPayload(IKE_PACKET_CERT_PAYLOAD *t);
+BUF *IkeBuildCertRequestPayload(IKE_PACKET_CERT_REQUEST_PAYLOAD *t);
+BUF *IkeBuildNoticePayload(IKE_PACKET_NOTICE_PAYLOAD *t);
+BUF *IkeBuildDeletePayload(IKE_PACKET_DELETE_PAYLOAD *t);
+
+BUF *IkeBuildTransformPayload(IKE_PACKET_TRANSFORM_PAYLOAD *t);
+UINT IkeGetTransformValue(IKE_PACKET_TRANSFORM_PAYLOAD *t, UINT type, UINT index);
+UINT IkeGetTransformValueNum(IKE_PACKET_TRANSFORM_PAYLOAD *t, UINT type);
+
+UCHAR IkeStrToPhase1CryptId(char *name);
+UCHAR IkeStrToPhase1HashId(char *name);
+UCHAR IkeStrToPhase2CryptId(char *name);
+UCHAR IkeStrToPhase2HashId(char *name);
+BUF *IkeStrToPassword(char *str);
+UINT IkePhase1CryptIdToKeySize(UCHAR id);
+UINT IkePhase2CryptIdToKeySize(UCHAR id);
+
+UINT IkeNewSpi();
+
+IKE_ENGINE *NewIkeEngine();
+IKE_CRYPTO *NewIkeCrypto(IKE_ENGINE *e, UINT crypto_id, char *name, UINT *key_sizes, UINT num_key_sizes, UINT block_size);
+IKE_HASH *NewIkeHash(IKE_ENGINE *e, UINT hash_id, char *name, UINT size);
+IKE_DH *NewIkeDh(IKE_ENGINE *e, UINT dh_id, char *name, UINT key_size);
+void FreeIkeEngine(IKE_ENGINE *e);
+void FreeIkeCrypto(IKE_CRYPTO *c);
+void FreeIkeHash(IKE_HASH *h);
+void FreeIkeDh(IKE_DH *d);
+IKE_CRYPTO *GetIkeCrypto(IKE_ENGINE *e, bool for_esp, UINT i);
+IKE_HASH *GetIkeHash(IKE_ENGINE *e, bool for_esp, UINT i);
+IKE_DH *GetIkeDh(IKE_ENGINE *e, bool for_esp, UINT i);
+
+void IkeHash(IKE_HASH *h, void *dst, void *src, UINT size);
+void IkeHMac(IKE_HASH *h, void *dst, void *key, UINT key_size, void *data, UINT data_size);
+void IkeHMacBuf(IKE_HASH *h, void *dst, BUF *key, BUF *data);
+
+IKE_CRYPTO_KEY *IkeNewKey(IKE_CRYPTO *c, void *data, UINT size);
+bool IkeCheckKeySize(IKE_CRYPTO *c, UINT size);
+void IkeFreeKey(IKE_CRYPTO_KEY *k);
+void IkeCryptoEncrypt(IKE_CRYPTO_KEY *k, void *dst, void *src, UINT size, void *ivec);
+void IkeCryptoDecrypt(IKE_CRYPTO_KEY *k, void *dst, void *src, UINT size, void *ivec);
+
+DH_CTX *IkeDhNewCtx(IKE_DH *d);
+void IkeDhFreeCtx(DH_CTX *dh);
+
+
+#endif // IPSEC_PACKET_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_L2TP.c b/src/Cedar/IPsec_L2TP.c
new file mode 100644
index 00000000..6a4ecf6a
--- /dev/null
+++ b/src/Cedar/IPsec_L2TP.c
@@ -0,0 +1,2498 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_L2TP.c
+// L2TP protocol stack
+
+#include "CedarPch.h"
+
+// Release the L2TP AVP value
+void FreeL2TPAVP(L2TP_AVP *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ if (a->Data != NULL)
+ {
+ Free(a->Data);
+ }
+
+ Free(a);
+}
+
+// Release the L2TP packet
+void FreeL2TPPacket(L2TP_PACKET *p)
+{
+ UINT i;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ if (p->AvpList != NULL)
+ {
+ for (i = 0;i < LIST_NUM(p->AvpList);i++)
+ {
+ L2TP_AVP *a = LIST_DATA(p->AvpList, i);
+
+ FreeL2TPAVP(a);
+ }
+
+ ReleaseList(p->AvpList);
+ }
+
+ if (p->Data != NULL)
+ {
+ Free(p->Data);
+ }
+
+ Free(p);
+}
+
+// Send an L2TP control packet
+void SendL2TPControlPacket(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, UINT session_id, L2TP_PACKET *p)
+{
+ BUF *buf;
+ L2TP_QUEUE *q;
+ // Validate arguments
+ if (l2tp == NULL || t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ p->IsControl = true;
+ p->TunnelId = t->TunnelId1;
+ p->SessionId = session_id;
+
+ p->Ns = t->NextNs;
+ t->NextNs++;
+
+ p->Nr = t->LastNr + 1;
+
+ buf = BuildL2TPPacketData(p);
+
+ q = ZeroMalloc(sizeof(L2TP_QUEUE));
+ q->Buf = buf;
+ q->Ns = p->Ns;
+ q->NextSendTick = l2tp->Now + (UINT64)L2TP_PACKET_RESEND_INTERVAL;
+ SendL2TPControlPacketMain(l2tp, t, q);
+
+ L2TPAddInterrupt(l2tp, q->NextSendTick);
+
+ Add(t->SendQueue, q);
+
+}
+
+// Specify the interrupt occurrence time of the next
+void L2TPAddInterrupt(L2TP_SERVER *l2tp, UINT64 next_tick)
+{
+ // Validate arguments
+ if (l2tp == NULL || next_tick == 0)
+ {
+ return;
+ }
+
+ AddInterrupt(l2tp->Interrupts, next_tick);
+}
+
+// Send a L2TP data packet
+void SendL2TPDataPacket(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s, void *data, UINT size)
+{
+ UDPPACKET *p;
+ UCHAR *buf;
+ UINT buf_size;
+ // Validate arguments
+ if (l2tp == NULL || t == NULL || s == NULL || (size != 0 && data == NULL))
+ {
+ return;
+ }
+
+ // Build a L2TP data packet
+ if (s->IsV3 == false)
+ {
+ // L2TP Ver 2
+ buf_size = 8 + size;
+ buf = Malloc(buf_size);
+ buf[0] = 0x40;
+ buf[1] = 0x02;
+
+ WRITE_USHORT(buf + 2, buf_size);
+ WRITE_USHORT(buf + 4, t->TunnelId1);
+ WRITE_USHORT(buf + 6, s->SessionId1);
+
+ Copy(buf + 8, data, size);
+
+ // Transmission
+ p = NewUdpPacket(&t->ServerIp, t->ServerPort, &t->ClientIp, t->ClientPort, buf, buf_size);
+ }
+ else
+ {
+ // L2TPv3
+ buf_size = 4 + size;
+ buf = Malloc(buf_size);
+
+ WRITE_UINT(buf, s->SessionId1);
+
+ Copy(buf + 4, data, size);
+
+ // Transmission
+ p = NewUdpPacket(&t->ServerIp, IPSEC_PORT_L2TPV3_VIRTUAL, &t->ClientIp, IPSEC_PORT_L2TPV3_VIRTUAL, buf, buf_size);
+ }
+
+ L2TPSendUDP(l2tp, p);
+}
+
+// L2TP packet transmission main
+void SendL2TPControlPacketMain(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_QUEUE *q)
+{
+ UDPPACKET *p;
+ // Validate arguments
+ if (l2tp == NULL || t == NULL || q == NULL)
+ {
+ return;
+ }
+
+ p = NewUdpPacket(&t->ServerIp, t->ServerPort, &t->ClientIp, t->ClientPort,
+ Clone(q->Buf->Buf, q->Buf->Size), q->Buf->Size);
+
+ // Update the received sequence number
+ WRITE_USHORT(((UCHAR *)p->Data) + (p->SrcPort == IPSEC_PORT_L2TPV3_VIRTUAL ? 14 : 10), t->LastNr + 1);
+
+ L2TPSendUDP(l2tp, p);
+}
+
+// Send a UDP packet
+void L2TPSendUDP(L2TP_SERVER *l2tp, UDPPACKET *p)
+{
+ // Validate arguments
+ if (l2tp == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Add(l2tp->SendPacketList, p);
+}
+
+// Build a L2TP packet
+BUF *BuildL2TPPacketData(L2TP_PACKET *pp)
+{
+ BUF *ret;
+ UCHAR c;
+ USHORT us;
+ UINT ui;
+ // Validate arguments
+ if (pp == NULL)
+ {
+ return NULL;
+ }
+
+ ret = NewBuf();
+
+ c = 0;
+
+ if (pp->Ver == 3)
+ {
+ if (pp->SessionId != 0)
+ {
+ // Add the Remote Session ID AVP
+ L2TP_AVP *a = GetAVPValue(pp, L2TP_AVP_TYPE_V3_SESSION_ID_REMOTE);
+ if (a == NULL || a->DataSize != sizeof(UINT))
+ {
+ UINT ui = Endian32(pp->SessionId);
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_V3_SESSION_ID_REMOTE, true, 0, &ui, sizeof(UINT)));
+
+ if (GetAVPValueEx(pp, L2TPV3_CISCO_AVP_SESSION_ID_LOCAL, L2TP_AVP_VENDOR_ID_CISCO) != NULL)
+ {
+ Add(pp->AvpList, NewAVP(L2TPV3_CISCO_AVP_SESSION_ID_REMOTE, true, L2TP_AVP_VENDOR_ID_CISCO, &ui, sizeof(UINT)));
+ }
+ }
+ }
+ }
+
+ if (pp->Ver == 3)
+ {
+ // Zero as Session ID
+ ui = 0;
+ WriteBuf(ret, &ui, sizeof(UINT));
+ }
+
+ // Flags
+ if (pp->IsControl)
+ {
+ c |= L2TP_HEADER_BIT_TYPE;
+ c |= L2TP_HEADER_BIT_LENGTH;
+ c |= L2TP_HEADER_BIT_SEQUENCE;
+ }
+ else
+ {
+ c |= L2TP_HEADER_BIT_OFFSET;
+ }
+
+ WriteBuf(ret, &c, 1);
+
+ // Ver
+ c = 2;
+ if (pp->Ver == 3)
+ {
+ c = 3;
+ }
+ WriteBuf(ret, &c, 1);
+
+ // Length
+ if (pp->IsControl)
+ {
+ us = 0;
+ WriteBuf(ret, &us, sizeof(USHORT));
+ }
+
+ // Tunnel ID
+ if (pp->Ver != 3)
+ {
+ us = Endian16((USHORT)pp->TunnelId);
+ WriteBuf(ret, &us, sizeof(USHORT));
+ }
+ else
+ {
+ ui = Endian32(pp->TunnelId);
+ WriteBuf(ret, &ui, sizeof(UINT));
+ }
+
+ // Session ID
+ if (pp->Ver != 3)
+ {
+ us = Endian16((USHORT)pp->SessionId);
+ WriteBuf(ret, &us, sizeof(USHORT));
+ }
+
+ if (pp->IsControl)
+ {
+ // Ns
+ us = Endian16(pp->Ns);
+ WriteBuf(ret, &us, sizeof(USHORT));
+
+ // Nr
+ us = Endian16(pp->Nr);
+ WriteBuf(ret, &us, sizeof(USHORT));
+ }
+ else
+ {
+ // Offset Size = 0
+ us = 0;
+ WriteBuf(ret, &us, sizeof(USHORT));
+ }
+
+ if (pp->IsControl)
+ {
+ // AVP
+ UINT i;
+ for (i = 0;i < LIST_NUM(pp->AvpList);i++)
+ {
+ L2TP_AVP *a = LIST_DATA(pp->AvpList, i);
+
+ // Length and Flags
+ us = Endian16(a->DataSize + 6);
+
+ if (a->Mandatory)
+ {
+ *((UCHAR *)&us) |= L2TP_AVP_BIT_MANDATORY;
+ }
+
+ WriteBuf(ret, &us, sizeof(USHORT));
+
+ // Vendor ID
+ us = Endian16(a->VendorID);
+ WriteBuf(ret, &us, sizeof(USHORT));
+
+ // Type
+ us = Endian16(a->Type);
+ WriteBuf(ret, &us, sizeof(USHORT));
+
+ // Data
+ WriteBuf(ret, a->Data, a->DataSize);
+ }
+ }
+ else
+ {
+ // Payload
+ WriteBuf(ret, pp->Data, pp->DataSize);
+ }
+
+ if (pp->IsControl)
+ {
+ // Update Length
+ WRITE_USHORT(((UCHAR *)ret->Buf) + 2 + (pp->Ver == 3 ? sizeof(UINT) : 0), (USHORT)(ret->Size - (pp->Ver == 3 ? sizeof(UINT) : 0)));
+ }
+
+ SeekBuf(ret, 0, 0);
+
+ return ret;
+}
+
+// Parse the L2TP packet
+L2TP_PACKET *ParseL2TPPacket(UDPPACKET *p)
+{
+ L2TP_PACKET *ret;
+ UCHAR *buf;
+ UINT size;
+ bool is_l2tpv3 = false;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ ret = ZeroMalloc(sizeof(L2TP_PACKET));
+
+ if (p->SrcPort == IPSEC_PORT_L2TPV3_VIRTUAL)
+ {
+ // It is L2TPv3
+ is_l2tpv3 = true;
+ }
+
+ buf = p->Data;
+ size = p->Size;
+
+ if (is_l2tpv3)
+ {
+ UINT session_id;
+ // In the case of L2TPv3
+ if (size < 4)
+ {
+ goto LABEL_ERROR;
+ }
+
+ session_id = READ_UINT(buf);
+
+ if (session_id != 0)
+ {
+ // L2TPv3 data packet reception
+ ret->SessionId = session_id;
+
+ buf += sizeof(UINT);
+ size -= sizeof(UINT);
+
+ ret->Data = Clone(buf, size);
+ ret->DataSize = size;
+
+ ret->Ver = 3;
+
+ return ret;
+ }
+ else
+ {
+ // L2TPv3 control packet reception
+ buf += sizeof(UINT);
+ size -= sizeof(UINT);
+ }
+ }
+
+ // L2TP
+ if (size < 6)
+ {
+ goto LABEL_ERROR;
+ }
+
+ if (*buf & L2TP_HEADER_BIT_TYPE)
+ {
+ ret->IsControl = true;
+ }
+
+ if (*buf & L2TP_HEADER_BIT_LENGTH)
+ {
+ ret->HasLength = true;
+ }
+
+ if (*buf & L2TP_HEADER_BIT_SEQUENCE)
+ {
+ ret->HasSequence = true;
+ }
+
+ if (is_l2tpv3 == false)
+ {
+ if (*buf & L2TP_HEADER_BIT_OFFSET)
+ {
+ ret->HasOffset = true;
+ }
+
+ if (*buf & L2TP_HEADER_BIT_PRIORITY)
+ {
+ ret->IsPriority = true;
+ }
+ }
+
+ buf++;
+ size--;
+
+ ret->Ver = *buf & L2TP_HEADER_BIT_VER;
+
+ buf++;
+ size--;
+
+ if (is_l2tpv3 == false)
+ {
+ // L2TP
+ if (ret->Ver != 2)
+ {
+ goto LABEL_ERROR;
+ }
+ }
+ else
+ {
+ // L2TPv3
+ if (ret->Ver != 3)
+ {
+ goto LABEL_ERROR;
+ }
+ }
+
+ if (ret->IsControl)
+ {
+ if (ret->HasLength == false || ret->HasSequence == false)
+ {
+ goto LABEL_ERROR;
+ }
+ }
+ else
+ {
+ /*if (ret->HasSequence)
+ {
+ goto LABEL_ERROR;
+ }*/
+ }
+
+ if (ret->HasLength)
+ {
+ // Length
+ if (size < 2)
+ {
+ goto LABEL_ERROR;
+ }
+ ret->Length = READ_USHORT(buf);
+ buf += 2;
+ size -= 2;
+
+ if (size < (ret->Length - 4))
+ {
+ goto LABEL_ERROR;
+ }
+
+ size = ret->Length - 4;
+ }
+
+ // Tunnel ID, Session ID
+ if (size < 4)
+ {
+ goto LABEL_ERROR;
+ }
+
+ if (is_l2tpv3 == false)
+ {
+ // L2TP
+ ret->TunnelId = READ_USHORT(buf);
+ buf += 2;
+ size -= 2;
+
+ ret->SessionId = READ_USHORT(buf);
+ buf += 2;
+ size -= 2;
+ }
+ else
+ {
+ // L2TPv3: Only tunnel ID is written in the header
+ ret->TunnelId = READ_UINT(buf);
+ buf += 4;
+ size -= 4;
+
+ // The session ID is not written in the header
+ ret->SessionId = 0;
+ }
+
+ if (ret->HasSequence)
+ {
+ // Ns, Nr
+ if (size < 4)
+ {
+ goto LABEL_ERROR;
+ }
+
+ ret->Ns = READ_USHORT(buf);
+ buf += 2;
+ size -= 2;
+
+ ret->Nr = READ_USHORT(buf);
+ buf += 2;
+ size -= 2;
+ }
+
+ if (ret->HasOffset)
+ {
+ // Offset
+ if (size < 2)
+ {
+ goto LABEL_ERROR;
+ }
+
+ ret->OffsetSize = READ_USHORT(buf);
+ buf += 2;
+ size -= 2;
+
+ if (size < ret->OffsetSize)
+ {
+ goto LABEL_ERROR;
+ }
+
+ buf += ret->OffsetSize;
+ size -= ret->OffsetSize;
+ }
+
+ ret->DataSize = size;
+ ret->Data = Clone(buf, ret->DataSize);
+
+ if (ret->IsControl == false)
+ {
+ if (ret->DataSize == 0)
+ {
+ goto LABEL_ERROR;
+ }
+ }
+
+ if (ret->IsControl)
+ {
+ if (ret->DataSize == 0)
+ {
+ ret->IsZLB = true;
+ }
+ }
+
+ if (ret->IsControl)
+ {
+ ret->AvpList = NewListFast(NULL);
+
+ // Parse the AVP field
+ while (size != 0)
+ {
+ L2TP_AVP a;
+
+ Zero(&a, sizeof(a));
+
+ // Header
+ if (size < 6)
+ {
+ goto LABEL_ERROR;
+ }
+
+ if (*buf & L2TP_AVP_BIT_MANDATORY)
+ {
+ a.Mandatory = true;
+ }
+
+ if (*buf & L2TP_AVP_BIT_HIDDEN)
+ {
+ goto LABEL_ERROR;
+ }
+
+ a.Length = READ_USHORT(buf) & L2TP_AVP_LENGTH;
+
+ if (a.Length < 6)
+ {
+ goto LABEL_ERROR;
+ }
+
+ buf += 2;
+ size -= 2;
+
+ a.VendorID = READ_USHORT(buf);
+ buf += 2;
+ size -= 2;
+
+ a.Type = READ_USHORT(buf);
+ buf += 2;
+ size -= 2;
+
+ a.DataSize = a.Length - 6;
+ a.Data = Clone(buf, a.DataSize);
+
+ buf += a.DataSize;
+ size -= a.DataSize;
+
+ Add(ret->AvpList, Clone(&a, sizeof(a)));
+ }
+ }
+
+ if (ret->IsControl && ret->IsZLB == false)
+ {
+ // Get the MessageType in the case of Control packet
+ L2TP_AVP *a = GetAVPValue(ret, L2TP_AVP_TYPE_MESSAGE_TYPE);
+ if (a == NULL || a->DataSize != 2)
+ {
+ goto LABEL_ERROR;
+ }
+
+ ret->MessageType = READ_USHORT(a->Data);
+ }
+
+ if (ret->Ver == 3)
+ {
+ // Get the Remote Session ID in the case of L2TPv3
+ L2TP_AVP *a = GetAVPValue(ret, L2TP_AVP_TYPE_V3_SESSION_ID_REMOTE);
+ if (a != NULL && a->DataSize == sizeof(UINT))
+ {
+ ret->SessionId = READ_UINT(a->Data);
+ }
+ }
+
+ return ret;
+
+LABEL_ERROR:
+ FreeL2TPPacket(ret);
+ return NULL;
+}
+
+// Get the AVP value
+L2TP_AVP *GetAVPValue(L2TP_PACKET *p, UINT type)
+{
+ return GetAVPValueEx(p, type, 0);
+}
+L2TP_AVP *GetAVPValueEx(L2TP_PACKET *p, UINT type, UINT vendor_id)
+{
+ UINT i;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(p->AvpList);i++)
+ {
+ L2TP_AVP *a = LIST_DATA(p->AvpList, i);
+
+ if (a->Type == type && a->VendorID == vendor_id)
+ {
+ return a;
+ }
+ }
+
+ return NULL;
+}
+
+// Release the L2TP transmission queue
+void FreeL2TPQueue(L2TP_QUEUE *q)
+{
+ // Validate arguments
+ if (q == NULL)
+ {
+ return;
+ }
+
+ FreeBuf(q->Buf);
+
+ FreeL2TPPacket(q->L2TPPacket);
+
+ Free(q);
+}
+
+// Sort function of L2TP reception queue
+int CmpL2TPQueueForRecv(void *p1, void *p2)
+{
+ L2TP_QUEUE *q1, *q2;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ q1 = *(L2TP_QUEUE **)p1;
+ q2 = *(L2TP_QUEUE **)p2;
+ if (q1 == NULL || q2 == NULL)
+ {
+ return 0;
+ }
+
+ if (L2TP_SEQ_LT(q1->Ns, q2->Ns))
+ {
+ return -1;
+ }
+ else if (q1->Ns == q2->Ns)
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+// Create a L2TP tunnel
+L2TP_TUNNEL *NewL2TPTunnel(L2TP_SERVER *l2tp, L2TP_PACKET *p, UDPPACKET *udp)
+{
+ L2TP_TUNNEL *t;
+ L2TP_AVP *a;
+ // Validate arguments
+ if (l2tp == NULL || p == NULL || udp == NULL)
+ {
+ return NULL;
+ }
+
+ t = ZeroMalloc(sizeof(L2TP_TUNNEL));
+
+ if (p->Ver == 3)
+ {
+ t->IsV3 = true;
+ }
+
+ t->SessionList = NewList(NULL);
+
+ Copy(&t->ClientIp, &udp->SrcIP, sizeof(IP));
+ t->ClientPort = udp->SrcPort;
+
+ Copy(&t->ServerIp, &udp->DstIP, sizeof(IP));
+ t->ServerPort = udp->DestPort;
+
+ // Hostname
+ a = GetAVPValue(p, L2TP_AVP_TYPE_HOST_NAME);
+ if (a != NULL && a->DataSize >= 1 && a->DataSize < sizeof(t->HostName))
+ {
+ Copy(t->HostName, a->Data, a->DataSize);
+ }
+ else
+ {
+ IPToStr(t->HostName, sizeof(t->HostName), &t->ClientIp);
+ }
+
+ // Vendor Name
+ a = GetAVPValue(p, L2TP_AVP_TYPE_VENDOR_NAME);
+ if (a != NULL && a->DataSize >= 1 && a->DataSize < sizeof(t->VendorName))
+ {
+ Copy(t->VendorName, a->Data, a->DataSize);
+ }
+
+ // Assigned Tunnel ID
+ a = GetAVPValue(p, (p->Ver == 3 ? L2TP_AVP_TYPE_V3_TUNNEL_ID : L2TP_AVP_TYPE_ASSIGNED_TUNNEL));
+ if (a == NULL || a->DataSize != (t->IsV3 ? sizeof(UINT) : sizeof(USHORT)))
+ {
+ goto LABEL_ERROR;
+ }
+
+ t->TunnelId1 = (t->IsV3 ? READ_UINT(a->Data) : READ_USHORT(a->Data));
+ t->TunnelId2 = GenerateNewTunnelIdEx(l2tp, &t->ClientIp, t->IsV3);
+
+ if (t->TunnelId2 == 0)
+ {
+ goto LABEL_ERROR;
+ }
+
+ if (p->Ver == 3)
+ {
+ // Identify whether it's Cisco
+ a = GetAVPValueEx(p, L2TPV3_CISCO_AVP_TUNNEL_ID, L2TP_AVP_VENDOR_ID_CISCO);
+ if (a != NULL)
+ {
+ t->IsCiscoV3 = true;
+ }
+ }
+
+ // Transmission queue
+ t->SendQueue = NewList(NULL);
+
+ // Reception queue
+ t->RecvQueue = NewList(CmpL2TPQueueForRecv);
+
+ t->LastRecvTick = l2tp->Now;
+ t->LastHelloSent = l2tp->Now;
+
+ return t;
+
+LABEL_ERROR:
+ FreeL2TPTunnel(t);
+ return NULL;
+}
+
+// Search a tunnel
+L2TP_TUNNEL *GetTunnelFromId(L2TP_SERVER *l2tp, IP *client_ip, UINT tunnel_id, bool is_v3)
+{
+ UINT i;
+ // Validate arguments
+ if (l2tp == NULL || client_ip == 0 || tunnel_id == 0)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(l2tp->TunnelList);i++)
+ {
+ L2TP_TUNNEL *t = LIST_DATA(l2tp->TunnelList, i);
+
+ if (t->TunnelId2 == tunnel_id && CmpIpAddr(&t->ClientIp, client_ip) == 0)
+ {
+ if (EQUAL_BOOL(t->IsV3, is_v3))
+ {
+ return t;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+// Search the tunnel by the tunnel ID that is assigned by the client
+L2TP_TUNNEL *GetTunnelFromIdOfAssignedByClient(L2TP_SERVER *l2tp, IP *client_ip, UINT tunnel_id)
+{
+ UINT i;
+ // Validate arguments
+ if (l2tp == NULL || client_ip == 0 || tunnel_id == 0)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(l2tp->TunnelList);i++)
+ {
+ L2TP_TUNNEL *t = LIST_DATA(l2tp->TunnelList, i);
+
+ if (t->TunnelId1 == tunnel_id && CmpIpAddr(&t->ClientIp, client_ip) == 0)
+ {
+ return t;
+ }
+ }
+
+ return NULL;
+}
+
+// Create a new tunnel ID
+UINT GenerateNewTunnelId(L2TP_SERVER *l2tp, IP *client_ip)
+{
+ return GenerateNewTunnelIdEx(l2tp, client_ip, false);
+}
+UINT GenerateNewTunnelIdEx(L2TP_SERVER *l2tp, IP *client_ip, bool is_32bit)
+{
+ UINT id;
+ UINT max_number = 0xffff;
+ // Validate arguments
+ if (l2tp == NULL || client_ip == NULL)
+ {
+ return 0;
+ }
+
+ if (is_32bit)
+ {
+ max_number = 0xfffffffe;
+ }
+
+ for (id = 1;id <= max_number;id++)
+ {
+ if (GetTunnelFromId(l2tp, client_ip, id, is_32bit) == NULL)
+ {
+ return id;
+ }
+ }
+
+ return 0;
+}
+
+// Release the L2TP tunnel
+void FreeL2TPTunnel(L2TP_TUNNEL *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(t->SessionList);i++)
+ {
+ L2TP_SESSION *s = LIST_DATA(t->SessionList, i);
+
+ FreeL2TPSession(s);
+ }
+
+ ReleaseList(t->SessionList);
+
+ for (i = 0;i < LIST_NUM(t->SendQueue);i++)
+ {
+ L2TP_QUEUE *q = LIST_DATA(t->SendQueue, i);
+
+ FreeL2TPQueue(q);
+ }
+
+ ReleaseList(t->SendQueue);
+
+ for (i = 0;i < LIST_NUM(t->RecvQueue);i++)
+ {
+ L2TP_QUEUE *q = LIST_DATA(t->RecvQueue, i);
+
+ FreeL2TPQueue(q);
+ }
+
+ ReleaseList(t->RecvQueue);
+
+ Free(t);
+}
+
+// Generate a new L2TP control packet
+L2TP_PACKET *NewL2TPControlPacket(UINT message_type, bool is_v3)
+{
+ L2TP_PACKET *p = ZeroMalloc(sizeof(L2TP_PACKET));
+
+ p->IsControl = true;
+ p->HasLength = true;
+ p->HasSequence = true;
+ p->Ver = (is_v3 ? 3 : 2);
+ p->MessageType = message_type;
+
+ p->AvpList = NewListFast(NULL);
+
+ if (message_type != 0)
+ {
+ L2TP_AVP *a;
+ USHORT us;
+
+ a = ZeroMalloc(sizeof(L2TP_AVP));
+
+ a->Type = L2TP_AVP_TYPE_MESSAGE_TYPE;
+ a->Mandatory = true;
+
+ us = Endian16(message_type);
+ a->Data = Clone(&us, sizeof(USHORT));
+ a->DataSize = sizeof(USHORT);
+
+ Add(p->AvpList, a);
+ }
+
+ return p;
+}
+
+// Create a new AVP value
+L2TP_AVP *NewAVP(USHORT type, bool mandatory, USHORT vendor_id, void *data, UINT data_size)
+{
+ L2TP_AVP *a;
+ // Validate arguments
+ if (data_size != 0 && data == NULL)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(L2TP_AVP));
+
+ a->Type = type;
+ a->Mandatory = mandatory;
+ a->VendorID = vendor_id;
+ a->Data = Clone(data, data_size);
+ a->DataSize = data_size;
+
+ return a;
+}
+
+// Process a received L2TP packet
+void L2TPProcessRecvControlPacket(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_PACKET *p)
+{
+ // Validate arguments
+ if (l2tp == NULL || t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (p->SessionId == 0)
+ {
+ if (p->MessageType == L2TP_MESSAGE_TYPE_SCCCN && l2tp->Halt == false)
+ {
+ // Tunnel establishment completed
+ if (t->Established == false)
+ {
+ if (t->Disconnecting == false)
+ {
+ t->Established = true;
+ t->LastHelloSent = l2tp->Now;
+ }
+ }
+ }
+
+ if (t->Established)
+ {
+ if (p->MessageType == L2TP_MESSAGE_TYPE_ICRQ && t->WantToDisconnect == false && l2tp->Halt == false)
+ {
+ // Request to establish a new session arrives
+ L2TP_AVP *a = GetAVPValue(p,
+ (t->IsV3 ? L2TP_AVP_TYPE_V3_SESSION_ID_LOCAL : L2TP_AVP_TYPE_ASSIGNED_SESSION));
+ if (a != NULL && a->DataSize == (t->IsV3 ? sizeof(UINT) : sizeof(USHORT)) && IsZero(a->Data, (t->IsV3 ? sizeof(UINT) : sizeof(USHORT))) == false)
+ {
+ UINT session_id = (t->IsV3 ? READ_UINT(a->Data) : READ_USHORT(a->Data));
+
+ // Check whether there is other same session ID
+ if (GetSessionFromIdAssignedByClient(t, session_id) == NULL)
+ {
+ // Create a session
+ L2TP_SESSION *s = NewL2TPSession(l2tp, t, session_id);
+
+ if (s != NULL)
+ {
+ L2TP_PACKET *pp;
+ USHORT us;
+ UINT ui;
+
+ // Get the PseudowireType
+ if (t->IsV3)
+ {
+ s->PseudowireType = L2TPV3_PW_TYPE_ETHERNET;
+
+ a = GetAVPValue(p, L2TP_AVP_TYPE_V3_PW_TYPE);
+
+ if (a != NULL && a->DataSize == sizeof(USHORT))
+ {
+ ui = READ_USHORT(a->Data);
+
+ s->PseudowireType = ui;
+ }
+ }
+
+ Add(t->SessionList, s);
+ Debug("L2TP New Session: ID = %u/%u on Tunnel %u/%u\n", s->SessionId1, s->SessionId2,
+ t->TunnelId1, t->TunnelId2);
+
+ // Respond the session creation completion notice
+ pp = NewL2TPControlPacket(L2TP_MESSAGE_TYPE_ICRP, s->IsV3);
+
+ // Assigned Session AVP
+ if (s->IsV3 == false)
+ {
+ us = Endian16(s->SessionId2);
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_ASSIGNED_SESSION, true, 0, &us, sizeof(USHORT)));
+ }
+ else
+ {
+ ui = Endian32(s->SessionId2);
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_V3_SESSION_ID_LOCAL, true, 0, &ui, sizeof(UINT)));
+
+ if (s->IsCiscoV3)
+ {
+ Add(pp->AvpList, NewAVP(L2TPV3_CISCO_AVP_SESSION_ID_LOCAL, true, L2TP_AVP_VENDOR_ID_CISCO, &ui, sizeof(UINT)));
+ }
+ }
+
+ if (s->IsV3)
+ {
+ // Pseudowire AVP
+ us = Endian16(s->PseudowireType);
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_V3_PW_TYPE, true, 0, &us, sizeof(USHORT)));
+
+ if (s->IsCiscoV3)
+ {
+ Add(pp->AvpList, NewAVP(L2TPV3_CISCO_AVP_PW_TYPE, true, L2TP_AVP_VENDOR_ID_CISCO, &us, sizeof(USHORT)));
+ }
+ }
+
+ SendL2TPControlPacket(l2tp, t, session_id, pp);
+
+ FreeL2TPPacket(pp);
+ }
+ }
+ }
+ }
+ else if (p->MessageType == L2TP_MESSAGE_TYPE_STOPCCN)
+ {
+ // Tunnel disconnect request arrives
+ L2TP_AVP *a = GetAVPValue(p, (t->IsV3 ? L2TP_AVP_TYPE_V3_TUNNEL_ID : L2TP_AVP_TYPE_ASSIGNED_TUNNEL));
+ if (a != NULL && a->DataSize == (t->IsV3 ? sizeof(UINT) : sizeof(USHORT)))
+ {
+ UINT ui = (t->IsV3 ? READ_UINT(a->Data) : READ_USHORT(a->Data));
+
+ if (ui == t->TunnelId1)
+ {
+ // Disconnect the tunnel
+ DisconnectL2TPTunnel(t);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Search a session
+ L2TP_SESSION *s = GetSessionFromId(t, p->SessionId);
+
+ if (s != NULL)
+ {
+ if (s->Established == false)
+ {
+ if (p->MessageType == L2TP_MESSAGE_TYPE_ICCN)
+ {
+ // Session establishment completed
+ if (s->Disconnecting == false)
+ {
+ s->Established = true;
+ }
+ }
+ }
+ else
+ {
+ if (p->MessageType == L2TP_MESSAGE_TYPE_CDN)
+ {
+ // Received a session disconnection request
+ L2TP_AVP *a = GetAVPValue(p,
+ (t->IsV3 ? L2TP_AVP_TYPE_V3_SESSION_ID_LOCAL : L2TP_AVP_TYPE_ASSIGNED_SESSION));
+ if (a != NULL && a->DataSize == (t->IsV3 ? sizeof(UINT) : sizeof(USHORT)))
+ {
+ UINT ui = (t->IsV3 ? READ_UINT(a->Data) : READ_USHORT(a->Data));
+
+ if (ui == s->SessionId1)
+ {
+ // Disconnect the session
+ DisconnectL2TPSession(t, s);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ Debug("Session ID %u not found in Tunnel ID %u/%u\n", p->SessionId, t->TunnelId1, t->TunnelId2);
+ }
+ }
+}
+
+// Disconnect the L2TP tunnel
+void DisconnectL2TPTunnel(L2TP_TUNNEL *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (/*t->Established && */t->Disconnecting == false && t->WantToDisconnect == false)
+ {
+ UINT i;
+
+ Debug("Trying to Disconnect Tunnel ID %u/%u\n", t->TunnelId1, t->TunnelId2);
+ t->WantToDisconnect = true;
+
+ // Disconnect all sessions within the tunnel
+ for (i = 0;i < LIST_NUM(t->SessionList);i++)
+ {
+ L2TP_SESSION *s = LIST_DATA(t->SessionList, i);
+
+ DisconnectL2TPSession(t, s);
+ }
+ }
+}
+
+// Disconnect the L2TP session
+void DisconnectL2TPSession(L2TP_TUNNEL *t, L2TP_SESSION *s)
+{
+ // Validate arguments
+ if (t == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (s->Established && s->Disconnecting == false && s->WantToDisconnect == false)
+ {
+ Debug("Trying to Disconnect Session ID %u/%u on Tunnel %u/%u\n", s->SessionId1, s->SessionId2,
+ t->TunnelId1, t->TunnelId2);
+ s->WantToDisconnect = true;
+ }
+}
+
+// Create a new session
+L2TP_SESSION *NewL2TPSession(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, UINT session_id_by_client)
+{
+ L2TP_SESSION *s;
+ UINT session_id_by_server;
+ // Validate arguments
+ if (l2tp == NULL || t == NULL || session_id_by_client == 0)
+ {
+ return NULL;
+ }
+
+ if (t->IsV3 == false)
+ {
+ session_id_by_server = GenerateNewSessionIdEx(t, t->IsV3);
+ }
+ else
+ {
+ session_id_by_server = GenerateNewSessionIdForL2TPv3(l2tp);
+ }
+ if (session_id_by_server == 0)
+ {
+ return NULL;
+ }
+
+ s = ZeroMalloc(sizeof(L2TP_SESSION));
+
+ s->SessionId1 = session_id_by_client;
+ s->SessionId2 = session_id_by_server;
+
+ s->IsV3 = t->IsV3;
+ s->IsCiscoV3 = t->IsCiscoV3;
+
+ s->Tunnel = t;
+
+ return s;
+}
+
+// Retrieve a session from L2TP session ID
+L2TP_SESSION *SearchL2TPSessionById(L2TP_SERVER *l2tp, bool is_v3, UINT id)
+{
+ UINT i, j;
+ // Validate arguments
+ if (l2tp == NULL || id == 0)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(l2tp->TunnelList);i++)
+ {
+ L2TP_TUNNEL *t = LIST_DATA(l2tp->TunnelList, i);
+
+ for (j = 0;j < LIST_NUM(t->SessionList);j++)
+ {
+ L2TP_SESSION *s = LIST_DATA(t->SessionList, j);
+
+ if (s->SessionId2 == id)
+ {
+ if (EQUAL_BOOL(s->IsV3, is_v3))
+ {
+ return s;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+// Create a new session ID
+UINT GenerateNewSessionId(L2TP_TUNNEL *t)
+{
+ return GenerateNewSessionIdEx(t, false);
+}
+UINT GenerateNewSessionIdEx(L2TP_TUNNEL *t, bool is_32bit)
+{
+ UINT i;
+ UINT max_number = 0xffff;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return 0;
+ }
+
+ if (is_32bit)
+ {
+ max_number = 0xfffffffe;
+ }
+
+ for (i = 1;i <= max_number;i++)
+ {
+ if (GetSessionFromId(t, i) == NULL)
+ {
+ return i;
+ }
+ }
+
+ return 0;
+}
+UINT GenerateNewSessionIdForL2TPv3(L2TP_SERVER *l2tp)
+{
+ // Validate arguments
+ if (l2tp == NULL)
+ {
+ return 0;
+ }
+
+ while (true)
+ {
+ UINT id = Rand32();
+
+ if (id == 0 || id == 0xffffffff)
+ {
+ continue;
+ }
+
+ if (SearchL2TPSessionById(l2tp, true, id) == false)
+ {
+ return id;
+ }
+ }
+}
+
+// Release the session
+void FreeL2TPSession(L2TP_SESSION *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Free(s);
+}
+
+// Search a session from the session ID
+L2TP_SESSION *GetSessionFromId(L2TP_TUNNEL *t, UINT session_id)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || session_id == 0)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(t->SessionList);i++)
+ {
+ L2TP_SESSION *s = LIST_DATA(t->SessionList, i);
+
+ if (s->SessionId2 == session_id)
+ {
+ return s;
+ }
+ }
+
+ return NULL;
+}
+
+// Search a session from the session ID (Search by ID assigned from the client side)
+L2TP_SESSION *GetSessionFromIdAssignedByClient(L2TP_TUNNEL *t, UINT session_id)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || session_id == 0)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(t->SessionList);i++)
+ {
+ L2TP_SESSION *s = LIST_DATA(t->SessionList, i);
+
+ if (s->SessionId1 == session_id)
+ {
+ return s;
+ }
+ }
+
+ return NULL;
+}
+
+// Performs processing L2TP received packets.
+void ProcL2TPPacketRecv(L2TP_SERVER *l2tp, UDPPACKET *p)
+{
+ L2TP_PACKET *pp;
+ bool no_free = false;
+ // Validate arguments
+ if (l2tp == NULL || p == NULL)
+ {
+ return;
+ }
+
+ // Parse a packet.
+ pp = ParseL2TPPacket(p);
+ if (pp == NULL)
+ {
+ return;
+ }
+
+ if (pp->MessageType == L2TP_MESSAGE_TYPE_SCCRQ && pp->SessionId == 0 && pp->TunnelId == 0 &&
+ pp->Nr == 0 && pp->Ns == 0 && l2tp->Halt == false)
+ {
+ {
+ L2TP_AVP *a = GetAVPValue(pp, (pp->Ver == 3 ? L2TP_AVP_TYPE_V3_TUNNEL_ID : L2TP_AVP_TYPE_ASSIGNED_TUNNEL));
+ if (a != NULL && a->DataSize == (pp->Ver == 3 ? sizeof(UINT) : sizeof(USHORT)))
+ {
+ UINT client_assigned_id = (pp->Ver == 3 ? READ_UINT(a->Data) : READ_USHORT(a->Data));
+ if (GetTunnelFromIdOfAssignedByClient(l2tp, &p->SrcIP, client_assigned_id) == NULL)
+ {
+ char ipstr[MAX_SIZE];
+ L2TP_PACKET *pp2;
+ UCHAR protocol_version[2];
+ UCHAR caps_data[4];
+ USHORT us;
+ char hostname[MAX_SIZE];
+
+ // Begin Tunneling
+ L2TP_TUNNEL *t = NewL2TPTunnel(l2tp, pp, p);
+
+ if (t != NULL)
+ {
+ IPToStr(ipstr, sizeof(ipstr), &t->ClientIp);
+ Debug("L2TP New Tunnel From %s (%s, %s): New Tunnel ID = %u/%u\n", ipstr, t->HostName, t->VendorName,
+ t->TunnelId1, t->TunnelId2);
+
+ // Add the tunnel to the list
+ Add(l2tp->TunnelList, t);
+
+ // Respond with SCCEP to SCCRQ
+ pp2 = NewL2TPControlPacket(L2TP_MESSAGE_TYPE_SCCRP, t->IsV3);
+
+ // Protocol Version
+ protocol_version[0] = 1;
+ protocol_version[1] = 0;
+ Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_PROTOCOL_VERSION, true, 0, protocol_version, sizeof(protocol_version)));
+
+ // Framing Capabilities
+ Zero(caps_data, sizeof(caps_data));
+ if (t->IsV3 == false)
+ {
+ caps_data[3] = 3;
+ }
+ Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_FRAME_CAP, false, 0, caps_data, sizeof(caps_data)));
+
+ if (t->IsV3 == false)
+ {
+ // Bearer Capabilities
+ Zero(caps_data, sizeof(caps_data));
+ caps_data[3] = 3;
+ Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_BEARER_CAP, false, 0, caps_data, sizeof(caps_data)));
+ }
+
+ // Host Name
+ GetMachineHostName(hostname, sizeof(hostname));
+ if (IsEmptyStr(hostname))
+ {
+ StrCpy(hostname, sizeof(hostname), "vpn");
+ }
+ Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_HOST_NAME, true, 0, hostname, StrLen(hostname)));
+
+ // Vendor Name
+ Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_VENDOR_NAME, false, 0, L2TP_VENDOR_NAME, StrLen(L2TP_VENDOR_NAME)));
+
+ // Assigned Tunnel ID
+ if (t->IsV3 == false)
+ {
+ us = Endian16(t->TunnelId2);
+ Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_ASSIGNED_TUNNEL, true, 0, &us, sizeof(USHORT)));
+ }
+ else
+ {
+ UINT ui = Endian32(t->TunnelId2);
+ Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_V3_TUNNEL_ID, true, 0, &ui, sizeof(UINT)));
+
+ if (t->IsCiscoV3)
+ {
+ Add(pp2->AvpList, NewAVP(L2TPV3_CISCO_AVP_TUNNEL_ID, true, L2TP_AVP_VENDOR_ID_CISCO, &ui, sizeof(UINT)));
+ }
+ }
+
+ // Pseudowire Capabilities List
+ if (t->IsV3)
+ {
+ // Only Ethernet
+ USHORT cap_list[2];
+ cap_list[0] = Endian16(L2TPV3_PW_TYPE_ETHERNET);
+ cap_list[1] = Endian16(L2TPV3_PW_TYPE_ETHERNET_VLAN);
+ Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_V3_PW_CAP_LIST, true, 0, cap_list, sizeof(cap_list)));
+
+ if (t->IsCiscoV3)
+ {
+ Add(pp2->AvpList, NewAVP(L2TPV3_CISCO_AVP_PW_CAP_LIST, true, L2TP_AVP_VENDOR_ID_CISCO, cap_list, sizeof(cap_list)));
+ }
+ }
+
+ // Cisco AVP
+ if (t->IsCiscoV3)
+ {
+ USHORT us = Endian16(1);
+ Add(pp2->AvpList, NewAVP(L2TPV3_CISCO_AVP_DRAFT_AVP_VERSION, true, L2TP_AVP_VENDOR_ID_CISCO, &us, sizeof(USHORT)));
+ }
+
+ // Recv Window Size
+ us = Endian16(L2TP_WINDOW_SIZE);
+ Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_RECV_WINDOW_SIZE, false, 0, &us, sizeof(USHORT)));
+
+ SendL2TPControlPacket(l2tp, t, 0, pp2);
+
+ FreeL2TPPacket(pp2);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Process related to the existing tunnel
+ // Find the tunnel
+ L2TP_TUNNEL *t = NULL;
+ L2TP_SESSION *l2tpv3_session = NULL;
+
+ if (pp->Ver != 3 || pp->IsControl)
+ {
+ t = GetTunnelFromId(l2tp, &p->SrcIP, pp->TunnelId, pp->Ver == 3);
+ }
+ else
+ {
+ l2tpv3_session = SearchL2TPSessionById(l2tp, true, pp->SessionId);
+ if (l2tpv3_session != NULL)
+ {
+ t = l2tpv3_session->Tunnel;
+
+ pp->TunnelId = t->TunnelId2;
+ }
+ }
+
+ if (t == NULL)
+ {
+ char ipstr[MAX_SIZE];
+
+ IPToStr(ipstr, sizeof(ipstr), &p->SrcIP);
+ Debug("L2TP Tunnel From %s ID=%u Not Found on the Table.\n", ipstr, pp->TunnelId);
+ }
+ else
+ {
+ // Update last reception time
+ t->LastRecvTick = l2tp->Now;
+
+ if (pp->IsControl)
+ {
+ // Control packet
+ UINT i;
+ LIST *o = NULL;
+ L2TP_QUEUE *q;
+ L2TP_QUEUE tt;
+
+ // Delete the queue that the other party has already received from the retransmission queue
+ for (i = 0;i < LIST_NUM(t->SendQueue);i++)
+ {
+ L2TP_QUEUE *q = LIST_DATA(t->SendQueue, i);
+ if (L2TP_SEQ_LT(q->Ns, pp->Nr))
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Add(o, q);
+ }
+ }
+
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ L2TP_QUEUE *q = LIST_DATA(o, i);
+
+ Delete(t->SendQueue, q);
+
+ FreeL2TPQueue(q);
+ }
+
+ ReleaseList(o);
+ }
+
+ if ((!L2TP_SEQ_LT(pp->Ns, t->LastNr)) && (pp->Ns != t->LastNr))
+ {
+ // Add the packet received from the opposite to the queue
+ if (LIST_NUM(t->RecvQueue) < L2TP_WINDOW_SIZE)
+ {
+ Zero(&tt, sizeof(tt));
+ tt.Ns = pp->Ns;
+
+ if (Search(t->RecvQueue, &tt) == NULL)
+ {
+ q = ZeroMalloc(sizeof(L2TP_QUEUE));
+ q->Ns = pp->Ns;
+ q->L2TPPacket = pp;
+ no_free = true;
+ Insert(t->RecvQueue, q);
+
+ // Read to the end of completed part from the head of the queue
+ while (TRUE)
+ {
+ L2TP_QUEUE *q;
+ if (LIST_NUM(t->RecvQueue) == 0)
+ {
+ break;
+ }
+
+ q = LIST_DATA(t->RecvQueue, 0);
+ if (!L2TP_SEQ_EQ(q->Ns, t->LastNr + 1))
+ {
+ break;
+ }
+
+ if (q->L2TPPacket->IsZLB == false)
+ {
+ t->LastNr = q->Ns;
+
+ // The packet other than ZLB is treated
+ t->StateChanged = true;
+ }
+
+ Delete(t->RecvQueue, q);
+
+ // Process the received packet
+ L2TPProcessRecvControlPacket(l2tp, t, q->L2TPPacket);
+
+ FreeL2TPQueue(q);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Data packet
+ L2TP_SESSION *s = GetSessionFromId(t, pp->SessionId);
+
+ if (s != NULL && s->Established)
+ {
+ if (s->IsV3 == false)
+ {
+ // Start the L2TP thread (If not already started)
+ StartL2TPThread(l2tp, t, s);
+
+ // Pass the data
+ TubeSendEx(s->TubeRecv, pp->Data, pp->DataSize, NULL, true);
+ AddTubeToFlushList(l2tp->FlushList, s->TubeRecv);
+ }
+ else
+ {
+ BLOCK *b;
+
+ // Start the EtherIP session (If it's not have yet started)
+ L2TPSessionManageEtherIPServer(l2tp, s);
+
+ // Pass the data
+ b = NewBlock(pp->Data, pp->DataSize, 0);
+
+ EtherIPProcRecvPackets(s->EtherIP, b);
+
+ Free(b);
+ }
+ }
+ }
+ }
+ }
+
+ if (no_free == false)
+ {
+ FreeL2TPPacket(pp);
+ }
+}
+
+// Manage the EtherIP server that is associated with the L2TP session
+void L2TPSessionManageEtherIPServer(L2TP_SERVER *l2tp, L2TP_SESSION *s)
+{
+ IKE_SERVER *ike;
+ IKE_CLIENT *c;
+ // Validate arguments
+ if (l2tp == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (l2tp->IkeClient == NULL || l2tp->IkeServer == NULL)
+ {
+ return;
+ }
+
+ ike = l2tp->IkeServer;
+ c = l2tp->IkeClient;
+
+ if (s->EtherIP == NULL)
+ {
+ char crypt_name[MAX_SIZE];
+ UINT crypt_block_size = IKE_MAX_BLOCK_SIZE;
+
+ Zero(crypt_name, sizeof(crypt_name));
+
+ if (c->CurrentIpSecSaRecv != NULL)
+ {
+ Format(crypt_name, sizeof(crypt_name),
+ "IPsec - %s (%u bits)",
+ c->CurrentIpSecSaRecv->TransformSetting.Crypto->Name,
+ c->CurrentIpSecSaRecv->TransformSetting.CryptoKeySize * 8);
+
+ crypt_block_size = c->CurrentIpSecSaRecv->TransformSetting.Crypto->BlockSize;
+ }
+
+ s->EtherIP = NewEtherIPServer(ike->Cedar, ike->IPsec, ike,
+ &c->ClientIP, c->ClientPort,
+ &c->ServerIP, c->ServerPort, crypt_name,
+ c->IsL2TPOnIPsecTunnelMode, crypt_block_size, c->ClientId,
+ ++ike->CurrentEtherId);
+
+ StrCpy(s->EtherIP->VendorName, sizeof(s->EtherIP->VendorName), s->Tunnel->VendorName);
+
+ s->EtherIP->L2TPv3 = true;
+
+ Debug("IKE_CLIENT 0x%X: EtherIP Server Started.\n", c);
+
+ IPsecLog(ike, c, NULL, NULL, NULL, "LI_ETHERIP_SERVER_STARTED", ike->CurrentEtherId);
+ }
+ else
+ {
+ StrCpy(s->EtherIP->ClientId, sizeof(s->EtherIP->ClientId), c->ClientId);
+ }
+
+ if (s->EtherIP->Interrupts == NULL)
+ {
+ s->EtherIP->Interrupts = l2tp->Interrupts;
+ }
+
+ if (s->EtherIP->SockEvent == NULL)
+ {
+ SetEtherIPServerSockEvent(s->EtherIP, l2tp->SockEvent);
+ }
+
+ s->EtherIP->Now = l2tp->Now;
+}
+
+// Calculate the appropriate MSS of the L2TP
+UINT CalcL2TPMss(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s)
+{
+ UINT ret;
+ // Validate arguments
+ if (l2tp == NULL || t == NULL || s == NULL)
+ {
+ return 0;
+ }
+
+ ret = MTU_FOR_PPPOE;
+
+ if (l2tp->IkeServer != NULL)
+ {
+ // On IPsec
+ if (l2tp->IsIPsecIPv6)
+ {
+ ret -= 40;
+ }
+ else
+ {
+ ret -= 20;
+ }
+
+ // UDP
+ ret -= 8;
+
+ // ESP
+ ret -= 20 + l2tp->CryptBlockSize * 2;
+ }
+ else
+ {
+ // Raw L2TP
+ if (IsIP6(&t->ClientIp))
+ {
+ ret -= 40;
+ }
+ else
+ {
+ ret -= 20;
+ }
+ }
+
+ // L2TP UDP
+ ret -= 8;
+
+ // L2TP
+ ret -= 8;
+
+ // PPP
+ ret -= 4;
+
+ // Target communication
+ ret -= 20;
+
+ // TCP header
+ ret -= 20;
+
+ return ret;
+}
+
+// Start the L2TP thread
+void StartL2TPThread(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s)
+{
+ // Validate arguments
+ if (l2tp == NULL || t == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (s->HasThread == false)
+ {
+ char tmp[MAX_SIZE];
+
+ Debug("Thread Created for Session %u/%u on Tunnel %u/%u\n",
+ s->SessionId1, s->SessionId2, t->TunnelId1, t->TunnelId2);
+
+ s->HasThread = true;
+
+ NewTubePair(&s->TubeSend, &s->TubeRecv, 0);
+ SetTubeSockEvent(s->TubeSend, l2tp->SockEvent);
+
+ if (IsEmptyStr(t->VendorName) == false)
+ {
+ Format(tmp, sizeof(tmp), L2TP_IPC_CLIENT_NAME_TAG, t->VendorName);
+ }
+ else
+ {
+ StrCpy(tmp, sizeof(tmp), L2TP_IPC_CLIENT_NAME_NO_TAG);
+ }
+
+ // Create a PPP thread
+ s->Thread = NewPPPSession(l2tp->Cedar, &t->ClientIp, t->ClientPort, &t->ServerIp, t->ServerPort,
+ s->TubeSend, s->TubeRecv, L2TP_IPC_POSTFIX, tmp, t->HostName, l2tp->CryptName,
+ CalcL2TPMss(l2tp, t, s));
+ }
+}
+
+// Stop the L2TP thread
+void StopL2TPThread(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s)
+{
+ THREAD *thread;
+ // Validate arguments
+ if (l2tp == NULL || t == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (s->IsV3)
+ {
+ // Process the L2TPv3
+ if (s->EtherIP != NULL)
+ {
+ // Release the EtherIP server
+ ReleaseEtherIPServer(s->EtherIP);
+ s->EtherIP = NULL;
+ }
+ return;
+ }
+
+ if (s->HasThread == false)
+ {
+ return;
+ }
+ thread = s->Thread;
+ s->Thread = NULL;
+ s->HasThread = false;
+
+ // Disconnect the tube
+ TubeDisconnect(s->TubeRecv);
+ TubeDisconnect(s->TubeSend);
+
+ // Release the tube
+ ReleaseTube(s->TubeRecv);
+ ReleaseTube(s->TubeSend);
+
+ s->TubeRecv = NULL;
+ s->TubeSend = NULL;
+
+ // Pass the thread to termination list
+ if (l2tp->IkeServer == NULL)
+ {
+ AddThreadToThreadList(l2tp->ThreadList, thread);
+ }
+ else
+ {
+ AddThreadToThreadList(l2tp->IkeServer->ThreadList, thread);
+ }
+
+ Debug("Thread Stopped for Session %u/%u on Tunnel %u/%u\n",
+ s->SessionId1, s->SessionId2, t->TunnelId1, t->TunnelId2);
+
+ // Release the thread
+ ReleaseThread(thread);
+}
+
+// Interrupt processing of L2TP server
+void L2TPProcessInterrupts(L2TP_SERVER *l2tp)
+{
+ UINT i, j;
+ LIST *delete_tunnel_list = NULL;
+ // Validate arguments
+ if (l2tp == NULL)
+ {
+ return;
+ }
+
+ if (l2tp->Halt)
+ {
+ if (l2tp->Halting == false)
+ {
+ l2tp->Halting = true;
+
+ // Disconnect all tunnels
+ for (i = 0;i < LIST_NUM(l2tp->TunnelList);i++)
+ {
+ L2TP_TUNNEL *t = LIST_DATA(l2tp->TunnelList, i);
+
+ DisconnectL2TPTunnel(t);
+ }
+ }
+ }
+
+ // Flush
+ FlushTubeFlushList(l2tp->FlushList);
+
+ // Enumerate all tunnels
+ for (i = 0;i < LIST_NUM(l2tp->TunnelList);i++)
+ {
+ L2TP_TUNNEL *t = LIST_DATA(l2tp->TunnelList, i);
+ LIST *delete_session_list = NULL;
+
+ if ((l2tp->Now >= (t->LastRecvTick + (UINT64)L2TP_TUNNEL_TIMEOUT)) && t->Timedout == false)
+ {
+ // Disconnect the tunnel forcibly if data can not be received for a certain period of time
+ t->Timedout = true;
+
+ Debug("L2TP Tunnel %u/%u Timed out.\n", t->TunnelId1, t->TunnelId2);
+ DisconnectL2TPTunnel(t);
+ }
+
+ if (t->Established && (l2tp->Now >= (t->LastHelloSent + (UINT64)L2TP_HELLO_INTERVAL)))
+ {
+ if (LIST_NUM(t->SendQueue) <= L2TP_HELLO_SUPRESS_MAX_THRETHORD_NUM_SEND_QUEUE)
+ {
+ L2TP_PACKET *pp = NewL2TPControlPacket(L2TP_MESSAGE_TYPE_HELLO, t->IsV3);
+
+ // Send a Hello message
+ t->LastHelloSent = l2tp->Now;
+ //Debug("L2TP Sending Hello %u/%u: tick=%I64u\n", t->TunnelId1, t->TunnelId2, l2tp->Now);
+
+ SendL2TPControlPacket(l2tp, t, 0, pp);
+
+ FreeL2TPPacket(pp);
+
+ L2TPAddInterrupt(l2tp, t->LastHelloSent + (UINT64)L2TP_HELLO_INTERVAL);
+ }
+ }
+
+ // Enumerate all sessions
+ for (j = 0;j < LIST_NUM(t->SessionList);j++)
+ {
+ L2TP_SESSION *s = LIST_DATA(t->SessionList, j);
+
+ if (s->HasThread)
+ {
+ // Send packet data
+ while (true)
+ {
+ TUBEDATA *d = TubeRecvAsync(s->TubeSend);
+
+ if (d == NULL)
+ {
+ break;
+ }
+
+ SendL2TPDataPacket(l2tp, t, s, d->Data, d->DataSize);
+
+ FreeTubeData(d);
+ }
+
+ if (IsTubeConnected(s->TubeSend) == false)
+ {
+ // Disconnect the this session because the PPP thread ends
+ DisconnectL2TPSession(t, s);
+ }
+ }
+
+ if (s->IsV3)
+ {
+ if (s->EtherIP != NULL)
+ {
+ UINT k;
+
+ L2TPSessionManageEtherIPServer(l2tp, s);
+
+ // Notify an interrupt to the EtherIP module
+ EtherIPProcInterrupts(s->EtherIP);
+
+ // Send an EtherIP packet data
+ for (k = 0;k < LIST_NUM(s->EtherIP->SendPacketList);k++)
+ {
+ BLOCK *b = LIST_DATA(s->EtherIP->SendPacketList, k);
+
+ SendL2TPDataPacket(l2tp, t, s, b->Buf, b->Size);
+
+ FreeBlock(b);
+ }
+
+ DeleteAll(s->EtherIP->SendPacketList);
+ }
+ }
+
+ if (s->WantToDisconnect && s->Disconnecting == false)
+ {
+ // Disconnect the session
+ UCHAR error_data[4];
+ USHORT us;
+ UINT ui;
+ UINT ppp_error_1 = 0, ppp_error_2 = 0;
+
+ // Send the session disconnection response
+ L2TP_PACKET *pp = NewL2TPControlPacket(L2TP_MESSAGE_TYPE_CDN, s->IsV3);
+
+ if (s->TubeRecv != NULL)
+ {
+ ppp_error_1 = s->TubeRecv->IntParam1;
+ ppp_error_2 = s->TubeRecv->IntParam2;
+ }
+
+ // Assigned Session ID
+ if (s->IsV3 == false)
+ {
+ us = Endian16(s->SessionId2);
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_ASSIGNED_SESSION, true, 0,
+ &us, sizeof(USHORT)));
+ }
+ else
+ {
+ ui = Endian16(s->SessionId2);
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_V3_SESSION_ID_LOCAL, true, 0,
+ &ui, sizeof(UINT)));
+
+ if (t->IsCiscoV3)
+ {
+ Add(pp->AvpList, NewAVP(L2TPV3_CISCO_AVP_SESSION_ID_LOCAL, true, L2TP_AVP_VENDOR_ID_CISCO,
+ &ui, sizeof(UINT)));
+ }
+ }
+
+ // Result-Error Code
+ Zero(error_data, sizeof(error_data));
+ error_data[1] = 0x03;
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_RESULT_CODE, true, 0,
+ error_data, sizeof(error_data)));
+
+ if (ppp_error_1 != 0)
+ {
+ // PPP Disconnect Cause Code AVP
+ BUF *b = NewBuf();
+ UCHAR uc;
+ USHORT us;
+
+ // Disconnect Code
+ us = Endian16(ppp_error_1);
+ WriteBuf(b, &us, sizeof(USHORT));
+
+ // Control Protocol Number
+ us = Endian16(0xc021);
+ WriteBuf(b, &us, sizeof(USHORT));
+
+ // Direction
+ uc = (UCHAR)ppp_error_2;
+ WriteBuf(b, &uc, sizeof(UCHAR));
+
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_PPP_DISCONNECT_CAUSE, false, 0,
+ b->Buf, b->Size));
+
+ FreeBuf(b);
+ }
+
+ SendL2TPControlPacket(l2tp, t, s->SessionId1, pp);
+
+ FreeL2TPPacket(pp);
+
+ // Disconnect the session
+ Debug("L2TP Session %u/%u on Tunnel %u/%u Disconnected.\n", s->SessionId1, s->SessionId2,
+ t->TunnelId1, t->TunnelId2);
+ s->Disconnecting = true;
+ s->Established = false;
+ s->DisconnectTimeout = l2tp->Now + (UINT64)L2TP_TUNNEL_DISCONNECT_TIMEOUT;
+
+ // Stop the thread
+ StopL2TPThread(l2tp, t, s);
+
+ L2TPAddInterrupt(l2tp, s->DisconnectTimeout);
+ }
+
+ if (s->Disconnecting && ((l2tp->Now >= s->DisconnectTimeout) || LIST_NUM(t->SendQueue) == 0))
+ {
+ // Delete the session if synchronization between the client
+ // and the server is complete or a time-out occurs
+ if (delete_session_list == NULL)
+ {
+ delete_session_list = NewListFast(NULL);
+ }
+
+ Add(delete_session_list, s);
+ }
+ }
+
+ if (delete_session_list != NULL)
+ {
+ // Session deletion process
+ for (j = 0;j < LIST_NUM(delete_session_list);j++)
+ {
+ L2TP_SESSION *s = LIST_DATA(delete_session_list, j);
+
+ Debug("L2TP Session %u/%u on Tunnel %u/%u Cleaned up.\n", s->SessionId1, s->SessionId2,
+ t->TunnelId1, t->TunnelId2);
+
+ FreeL2TPSession(s);
+ Delete(t->SessionList, s);
+ }
+
+ ReleaseList(delete_session_list);
+ }
+
+ if (t->WantToDisconnect && t->Disconnecting == false)
+ {
+ // Disconnect the tunnel
+ USHORT error_data[4];
+ USHORT us;
+ UINT ui;
+ // Reply the tunnel disconnection response
+ L2TP_PACKET *pp = NewL2TPControlPacket(L2TP_MESSAGE_TYPE_STOPCCN, t->IsV3);
+
+ // Assigned Tunnel ID
+ if (t->IsV3 == false)
+ {
+ us = Endian16(t->TunnelId2);
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_ASSIGNED_TUNNEL, true, 0,
+ &us, sizeof(USHORT)));
+ }
+ else
+ {
+ ui = Endian32(t->TunnelId2);
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_V3_TUNNEL_ID, true, 0,
+ &ui, sizeof(UINT)));
+
+ if (t->IsCiscoV3)
+ {
+ Add(pp->AvpList, NewAVP(L2TPV3_CISCO_AVP_TUNNEL_ID, true, L2TP_AVP_VENDOR_ID_CISCO,
+ &ui, sizeof(UINT)));
+ }
+ }
+
+ // Result-Error Code
+ Zero(error_data, sizeof(error_data));
+ error_data[1] = 0x06;
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_RESULT_CODE, true, 0,
+ error_data, sizeof(error_data)));
+
+ SendL2TPControlPacket(l2tp, t, 0, pp);
+
+ FreeL2TPPacket(pp);
+
+ Debug("L2TP Tunnel %u/%u is Disconnected.\n", t->TunnelId1, t->TunnelId2);
+ t->Disconnecting = true;
+ t->Established = false;
+ t->DisconnectTimeout = l2tp->Now + (UINT64)L2TP_TUNNEL_DISCONNECT_TIMEOUT;
+ L2TPAddInterrupt(l2tp, t->DisconnectTimeout);
+ }
+
+ if (t->Disconnecting && (((LIST_NUM(t->SendQueue) == 0) && LIST_NUM(t->SessionList) == 0) || (l2tp->Now >= t->DisconnectTimeout)))
+ {
+ // Delete the tunnel if there is no session in the tunnel when synchronization
+ // between the client and the server has been completed or a time-out occurs
+ if (delete_tunnel_list == NULL)
+ {
+ delete_tunnel_list = NewListFast(NULL);
+ }
+
+ Add(delete_tunnel_list, t);
+ }
+ }
+
+ if (delete_tunnel_list != NULL)
+ {
+ for (i = 0;i < LIST_NUM(delete_tunnel_list);i++)
+ {
+ L2TP_TUNNEL *t = LIST_DATA(delete_tunnel_list, i);
+
+ Debug("L2TP Tunnel %u/%u Cleaned up.\n", t->TunnelId1, t->TunnelId2);
+
+ FreeL2TPTunnel(t);
+ Delete(l2tp->TunnelList, t);
+ }
+
+ ReleaseList(delete_tunnel_list);
+ }
+
+ // Re-transmit packets
+ for (i = 0;i < LIST_NUM(l2tp->TunnelList);i++)
+ {
+ L2TP_TUNNEL *t = LIST_DATA(l2tp->TunnelList, i);
+ UINT j;
+
+ if (LIST_NUM(t->SendQueue) >= 1)
+ {
+ // Packet to be transmitted exists one or more
+ for (j = 0;j < LIST_NUM(t->SendQueue);j++)
+ {
+ L2TP_QUEUE *q = LIST_DATA(t->SendQueue, j);
+
+ if (l2tp->Now >= q->NextSendTick)
+ {
+ q->NextSendTick = l2tp->Now + (UINT64)L2TP_PACKET_RESEND_INTERVAL;
+
+ L2TPAddInterrupt(l2tp, q->NextSendTick);
+
+ SendL2TPControlPacketMain(l2tp, t, q);
+ }
+ }
+ }
+ else
+ {
+ // There is no packet to be transmitted, but the state of the tunnel is changed
+ if (t->StateChanged)
+ {
+ // Send a ZLB
+ L2TP_QUEUE *q = ZeroMalloc(sizeof(L2TP_QUEUE));
+ L2TP_PACKET *pp = NewL2TPControlPacket(0, t->IsV3);
+
+ pp->TunnelId = t->TunnelId1;
+ pp->Ns = t->NextNs;
+ q->Buf = BuildL2TPPacketData(pp);
+
+ SendL2TPControlPacketMain(l2tp, t, q);
+
+ FreeL2TPQueue(q);
+ FreeL2TPPacket(pp);
+ }
+ }
+
+ t->StateChanged = false;
+ }
+
+ if (l2tp->Halting)
+ {
+ if (LIST_NUM(l2tp->TunnelList) == 0)
+ {
+ // Stop all the L2TP tunnel completed
+ if (l2tp->HaltCompleted == false)
+ {
+ l2tp->HaltCompleted = true;
+
+ Set(l2tp->HaltCompletedEvent);
+ }
+ }
+ }
+
+ // Maintenance the thread list
+ if (l2tp->IkeServer == NULL)
+ {
+ MainteThreadList(l2tp->ThreadList);
+ //Debug("l2tp->ThreadList: %u\n", LIST_NUM(l2tp->ThreadList));
+ }
+}
+
+// Create a new L2TP server
+L2TP_SERVER *NewL2TPServer(CEDAR *cedar)
+{
+ return NewL2TPServerEx(cedar, NULL, false, 0);
+}
+L2TP_SERVER *NewL2TPServerEx(CEDAR *cedar, IKE_SERVER *ike, bool is_ipv6, UINT crypt_block_size)
+{
+ L2TP_SERVER *l2tp;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ l2tp = ZeroMalloc(sizeof(L2TP_SERVER));
+
+ l2tp->FlushList = NewTubeFlushList();
+
+ l2tp->Cedar = cedar;
+ AddRef(l2tp->Cedar->ref);
+
+ l2tp->SendPacketList = NewList(NULL);
+ l2tp->TunnelList = NewList(NULL);
+
+ l2tp->HaltCompletedEvent = NewEvent();
+
+ l2tp->ThreadList = NewThreadList();
+
+ l2tp->IkeServer = ike;
+
+ l2tp->IsIPsecIPv6 = is_ipv6;
+ l2tp->CryptBlockSize = crypt_block_size;
+
+ return l2tp;
+}
+
+// Stop the L2TP server
+void StopL2TPServer(L2TP_SERVER *l2tp, bool no_wait)
+{
+ // Validate arguments
+ if (l2tp == NULL)
+ {
+ return;
+ }
+ if (l2tp->Halt)
+ {
+ return;
+ }
+
+ // Begin to shut down
+ l2tp->Halt = true;
+ Debug("Shutting down L2TP Server...\n");
+
+ // Hit the event
+ SetSockEvent(l2tp->SockEvent);
+
+ if (no_wait == false)
+ {
+ // Wait until complete stopping all tunnels
+ Wait(l2tp->HaltCompletedEvent, INFINITE);
+ }
+ else
+ {
+ UINT i, j;
+ // Kill the thread of all sessions
+ for (i = 0;i < LIST_NUM(l2tp->TunnelList);i++)
+ {
+ L2TP_TUNNEL *t = LIST_DATA(l2tp->TunnelList, i);
+
+ for (j = 0;j < LIST_NUM(t->SessionList);j++)
+ {
+ L2TP_SESSION *s = LIST_DATA(t->SessionList, j);
+
+ StopL2TPThread(l2tp, t, s);
+ }
+ }
+ }
+
+ // Thread stop
+ Debug("Stopping all L2TP PPP Threads...\n");
+ StopThreadList(l2tp->ThreadList);
+ Debug("L2TP Server Shutdown Completed.\n");
+}
+
+// Release the L2TP server
+void FreeL2TPServer(L2TP_SERVER *l2tp)
+{
+ UINT i;
+ // Validate arguments
+ if (l2tp == NULL)
+ {
+ return;
+ }
+
+ FreeThreadList(l2tp->ThreadList);
+
+ for (i = 0;i < LIST_NUM(l2tp->SendPacketList);i++)
+ {
+ UDPPACKET *p = LIST_DATA(l2tp->SendPacketList, i);
+
+ FreeUdpPacket(p);
+ }
+
+ ReleaseList(l2tp->SendPacketList);
+
+ for (i = 0;i < LIST_NUM(l2tp->TunnelList);i++)
+ {
+ L2TP_TUNNEL *t = LIST_DATA(l2tp->TunnelList, i);
+
+ FreeL2TPTunnel(t);
+ }
+
+ ReleaseList(l2tp->TunnelList);
+
+ ReleaseSockEvent(l2tp->SockEvent);
+
+ ReleaseEvent(l2tp->HaltCompletedEvent);
+
+ ReleaseCedar(l2tp->Cedar);
+
+ FreeTubeFlushList(l2tp->FlushList);
+
+ Free(l2tp);
+}
+
+// Set a SockEvent to the L2TP server
+void SetL2TPServerSockEvent(L2TP_SERVER *l2tp, SOCK_EVENT *e)
+{
+ // Validate arguments
+ if (l2tp == NULL)
+ {
+ return;
+ }
+
+ if (e != NULL)
+ {
+ AddRef(e->ref);
+ }
+
+ if (l2tp->SockEvent != NULL)
+ {
+ ReleaseSockEvent(l2tp->SockEvent);
+ l2tp->SockEvent = NULL;
+ }
+
+ l2tp->SockEvent = e;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_L2TP.h b/src/Cedar/IPsec_L2TP.h
new file mode 100644
index 00000000..1de1fe1d
--- /dev/null
+++ b/src/Cedar/IPsec_L2TP.h
@@ -0,0 +1,347 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_L2TP.h
+// Header of IPsec_L2TP.c
+
+#ifndef IPSEC_L2TP_H
+#define IPSEC_L2TP_H
+
+//// Macro
+
+// Check the sequence number
+#define L2TP_SEQ_LT(a, b) (((USHORT)(((USHORT)(a)) - ((USHORT)(b)))) & 0x8000)
+#define L2TP_SEQ_EQ(a, b) ((USHORT)(a) == (USHORT)(b))
+
+//// Constants
+
+// Client string
+#define L2TP_IPC_CLIENT_NAME_TAG "L2TP VPN Client - %s"
+#define L2TP_IPC_CLIENT_NAME_NO_TAG "L2TP VPN Client"
+#define L2TP_IPC_POSTFIX "L2TP"
+
+// L2TP vendor name
+#define L2TP_VENDOR_NAME "L2TP"
+
+// L2TP packet retransmission interval
+#define L2TP_PACKET_RESEND_INTERVAL 500
+
+// Timeout for L2TP tunnel disconnecting completion
+#define L2TP_TUNNEL_DISCONNECT_TIMEOUT 3000
+
+// Timeout for L2TP session disconnection completion
+#define L2TP_SESSION_DISCONNECT_TIMEOUT 3000
+
+// Time-out interval of L2TP tunnel
+#define L2TP_TUNNEL_TIMEOUT (60 * 1000)
+
+// Transmission interval of L2TP Hello
+#define L2TP_HELLO_INTERVAL (8801)
+
+// Threshold number of registered items in the transmission queue for suppressing the L2TP Hello transmission
+#define L2TP_HELLO_SUPRESS_MAX_THRETHORD_NUM_SEND_QUEUE 32
+
+// L2TP window size
+#define L2TP_WINDOW_SIZE 16
+
+// L2TP packet header bit mask
+#define L2TP_HEADER_BIT_TYPE 0x80 // Type
+#define L2TP_HEADER_BIT_LENGTH 0x40 // Length
+#define L2TP_HEADER_BIT_SEQUENCE 0x08 // Sequence
+#define L2TP_HEADER_BIT_OFFSET 0x02 // Offset
+#define L2TP_HEADER_BIT_PRIORITY 0x01 // Priority
+#define L2TP_HEADER_BIT_VER 0x0F // Version
+
+// L2TP AVP header bit mask
+#define L2TP_AVP_BIT_MANDATORY 0x80 // Mandatory
+#define L2TP_AVP_BIT_HIDDEN 0x40 // Hidden
+#define L2TP_AVP_LENGTH 0x3FF // Length
+
+// AVP value
+#define L2TP_AVP_TYPE_MESSAGE_TYPE 0 // Message Type
+#define L2TP_AVP_TYPE_RESULT_CODE 1 // Result Code
+#define L2TP_AVP_TYPE_PROTOCOL_VERSION 2 // Protocol Version
+#define L2TP_AVP_TYPE_FRAME_CAP 3 // Framing Capabilities
+#define L2TP_AVP_TYPE_BEARER_CAP 4 // Bearer Capabilities
+#define L2TP_AVP_TYPE_TIE_BREAKER 5 // Tie Breaker
+#define L2TP_AVP_TYPE_HOST_NAME 7 // Host Name
+#define L2TP_AVP_TYPE_VENDOR_NAME 8 // Vendor Name
+#define L2TP_AVP_TYPE_ASSIGNED_TUNNEL 9 // Assigned Tunnel
+#define L2TP_AVP_TYPE_RECV_WINDOW_SIZE 10 // Receive Window Size
+#define L2TP_AVP_TYPE_ASSIGNED_SESSION 14 // Assigned Session ID
+#define L2TP_AVP_TYPE_CALL_SERIAL 15 // Call Serial Number
+#define L2TP_AVP_TYPE_PPP_DISCONNECT_CAUSE 46 // PPP Disconnect Cause Code
+#define L2TP_AVP_TYPE_V3_ROUTER_ID 60 // Router ID
+#define L2TP_AVP_TYPE_V3_TUNNEL_ID 61 // Assigned Control Connection ID
+#define L2TP_AVP_TYPE_V3_PW_CAP_LIST 62 // Pseudowire Capabilities List
+#define L2TP_AVP_TYPE_V3_SESSION_ID_LOCAL 63 // Local Session ID
+#define L2TP_AVP_TYPE_V3_SESSION_ID_REMOTE 64 // Remote Session ID
+#define L2TP_AVP_TYPE_V3_PW_TYPE 68 // Pseudowire Type
+
+// Message Type value
+#define L2TP_MESSAGE_TYPE_SCCRQ 1 // Start-Control-Connection-Request
+#define L2TP_MESSAGE_TYPE_SCCRP 2 // Start-Control-Connection-Reply
+#define L2TP_MESSAGE_TYPE_SCCCN 3 // Start-Control-Connection-Connected
+#define L2TP_MESSAGE_TYPE_STOPCCN 4 // Stop-Control-Connection-Notification
+#define L2TP_MESSAGE_TYPE_HELLO 6 // Hello
+#define L2TP_MESSAGE_TYPE_ICRQ 10 // Incoming-Call-Request
+#define L2TP_MESSAGE_TYPE_ICRP 11 // Incoming-Call-Reply
+#define L2TP_MESSAGE_TYPE_ICCN 12 // Incoming-Call-Connected
+#define L2TP_MESSAGE_TYPE_CDN 14 // Call-Disconnect-Notify
+
+// Type of L2TPv3 virtual network
+#define L2TPV3_PW_TYPE_ETHERNET 5 // Ethernet
+#define L2TPV3_PW_TYPE_ETHERNET_VLAN 4 // Ethernet VLAN
+
+// L2TPv3 vendor unique value
+#define L2TP_AVP_VENDOR_ID_CISCO 9 // Cisco Systems
+#define L2TPV3_CISCO_AVP_TUNNEL_ID 1 // Assigned Connection ID
+#define L2TPV3_CISCO_AVP_PW_CAP_LIST 2 // Pseudowire Capabilities List
+#define L2TPV3_CISCO_AVP_SESSION_ID_LOCAL 3 // Local Session ID
+#define L2TPV3_CISCO_AVP_SESSION_ID_REMOTE 4 // Remote Session ID
+#define L2TPV3_CISCO_AVP_PW_TYPE 7 // Pseudowire Type
+#define L2TPV3_CISCO_AVP_DRAFT_AVP_VERSION 10 // Draft AVP Version
+
+
+
+//// Types
+
+// L2TP queue
+struct L2TP_QUEUE
+{
+ BUF *Buf; // Data
+ USHORT Ns; // Sequence number
+ UINT64 NextSendTick; // Scheduled time to be sent next
+ L2TP_PACKET *L2TPPacket; // L2TP packet data
+};
+
+// L2TP AVP value
+struct L2TP_AVP
+{
+ bool Mandatory; // Force bit
+ UINT Length; // Overall length
+ USHORT VendorID; // Vendor ID
+ USHORT Type; // Type
+ UINT DataSize; // Data size
+ void *Data; // Data body
+};
+
+// L2TP packet
+struct L2TP_PACKET
+{
+ bool IsControl; // Whether it's a control message
+ bool HasLength; // Whether there is length bit
+ bool HasSequence; // Whether there is sequence bit
+ bool HasOffset; // Whether there is offset bit
+ bool IsPriority; // Whether priority packet
+ bool IsZLB; // Zero Length Bit
+ UINT Ver; // Version
+ UINT Length; // Length
+ UINT TunnelId; // Tunnel ID
+ UINT SessionId; // Session ID
+ USHORT Ns, Nr; // Sequence number
+ UINT OffsetSize; // Offset size
+ UINT DataSize; // Data size
+ void *Data; // Data body
+ LIST *AvpList; // AVP list
+ UINT MessageType; // Message type
+};
+
+// L2TP session
+struct L2TP_SESSION
+{
+ L2TP_TUNNEL *Tunnel; // Parent L2TP tunnel
+ bool IsV3; // L2TPv3
+ bool IsCiscoV3; // L2TPv3 for Cisco
+ UINT SessionId1; // Session ID (server -> client direction)
+ UINT SessionId2; // Session ID (client -> server direction)
+ bool Established; // Established
+ bool WantToDisconnect; // Whether to want to disconnect
+ bool Disconnecting; // Whether disconnected
+ UINT64 DisconnectTimeout; // Disconnection completion time-out
+ bool HasThread; // Whether have a thread
+ THREAD *Thread; // Thread
+ TUBE *TubeSend; // Tube of PPP to L2TP direction
+ TUBE *TubeRecv; // Tube of L2TP to PPP direction
+ UINT PseudowireType; // Type of L2TPv3 virtual line
+ ETHERIP_SERVER *EtherIP; // EtherIP server
+};
+
+// L2TP tunnel
+struct L2TP_TUNNEL
+{
+ bool IsV3; // L2TPv3
+ bool IsCiscoV3; // L2TPv3 for Cisco
+ IP ClientIp; // Client IP address
+ UINT ClientPort; // Client port number
+ IP ServerIp; // Server IP address
+ UINT ServerPort; // Server port number
+ UINT TunnelId1; // Tunnel ID (server -> client direction)
+ UINT TunnelId2; // Tunnel ID (client -> server direction)
+ char HostName[MAX_SIZE]; // Destination host name
+ char VendorName[MAX_SIZE]; // Destination vendor name
+ LIST *SessionList; // L2TP session list
+ LIST *SendQueue; // Transmission queue
+ LIST *RecvQueue; // Reception queue
+ USHORT NextNs; // Value of Ns of the packet to be sent next
+ USHORT LastNr; // Value of NR received in the last
+ bool Established; // Whether the tunnel is established
+ bool StateChanged; // Whether the state have changed
+ bool WantToDisconnect; // Whether to want to disconnect
+ bool Disconnecting; // Whether disconnected
+ UINT64 DisconnectTimeout; // Disconnection completion time-out
+ UINT64 LastRecvTick; // Time which the data has been received at last
+ bool Timedout; // Whether the time-out
+ UINT64 LastHelloSent; // Time which the data has been sent at last
+};
+
+// L2TP server
+struct L2TP_SERVER
+{
+ CEDAR *Cedar;
+ UINT64 Now; // Current time
+ LIST *SendPacketList; // Transmission packet
+ LIST *TunnelList; // Tunnel list
+ INTERRUPT_MANAGER *Interrupts; // Interrupt manager
+ SOCK_EVENT *SockEvent; // SockEvent
+ bool Halt; // Start the shutdown
+ bool Halting; // During shutdown
+ bool HaltCompleted; // Shutdown is complete
+ EVENT *HaltCompletedEvent; // Stopping completion event
+ LIST *ThreadList; // Thread list
+ char CryptName[MAX_SIZE]; // Cipher algorithm name
+ IKE_SERVER *IkeServer; // IKE server (Only if associated)
+ IKE_CLIENT *IkeClient; // IKE client (Only if associated)
+ bool IsIPsecIPv6; // Whether it's IPv6
+ UINT CryptBlockSize; // Cipher block size of the upper layer
+ TUBE_FLUSH_LIST *FlushList; // Tube Flush List
+};
+
+
+//// Function prototype
+L2TP_SERVER *NewL2TPServer(CEDAR *cedar);
+L2TP_SERVER *NewL2TPServerEx(CEDAR *cedar, IKE_SERVER *ike, bool is_ipv6, UINT crypt_block_size);
+void SetL2TPServerSockEvent(L2TP_SERVER *l2tp, SOCK_EVENT *e);
+void FreeL2TPServer(L2TP_SERVER *l2tp);
+void StopL2TPServer(L2TP_SERVER *l2tp, bool no_wait);
+void ProcL2TPPacketRecv(L2TP_SERVER *l2tp, UDPPACKET *p);
+L2TP_PACKET *ParseL2TPPacket(UDPPACKET *p);
+BUF *BuildL2TPPacketData(L2TP_PACKET *pp);
+L2TP_AVP *GetAVPValue(L2TP_PACKET *p, UINT type);
+L2TP_AVP *GetAVPValueEx(L2TP_PACKET *p, UINT type, UINT vendor_id);
+L2TP_TUNNEL *NewL2TPTunnel(L2TP_SERVER *l2tp, L2TP_PACKET *p, UDPPACKET *udp);
+UINT GenerateNewTunnelId(L2TP_SERVER *l2tp, IP *client_ip);
+UINT GenerateNewTunnelIdEx(L2TP_SERVER *l2tp, IP *client_ip, bool is_32bit);
+void FreeL2TPTunnel(L2TP_TUNNEL *t);
+L2TP_TUNNEL *GetTunnelFromId(L2TP_SERVER *l2tp, IP *client_ip, UINT tunnel_id, bool is_v3);
+L2TP_TUNNEL *GetTunnelFromIdOfAssignedByClient(L2TP_SERVER *l2tp, IP *client_ip, UINT tunnel_id);
+void SendL2TPControlPacket(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, UINT session_id, L2TP_PACKET *p);
+void SendL2TPControlPacketMain(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_QUEUE *q);
+void SendL2TPDataPacket(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s, void *data, UINT size);
+void FreeL2TPQueue(L2TP_QUEUE *q);
+void L2TPAddInterrupt(L2TP_SERVER *l2tp, UINT64 next_tick);
+void L2TPSendUDP(L2TP_SERVER *l2tp, UDPPACKET *p);
+void L2TPProcessInterrupts(L2TP_SERVER *l2tp);
+L2TP_PACKET *NewL2TPControlPacket(UINT message_type, bool is_v3);
+L2TP_AVP *NewAVP(USHORT type, bool mandatory, USHORT vendor_id, void *data, UINT data_size);
+int CmpL2TPQueueForRecv(void *p1, void *p2);
+void L2TPProcessRecvControlPacket(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_PACKET *p);
+L2TP_SESSION *GetSessionFromId(L2TP_TUNNEL *t, UINT session_id);
+L2TP_SESSION *GetSessionFromIdAssignedByClient(L2TP_TUNNEL *t, UINT session_id);
+L2TP_SESSION *NewL2TPSession(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, UINT session_id_by_client);
+UINT GenerateNewSessionId(L2TP_TUNNEL *t);
+UINT GenerateNewSessionIdEx(L2TP_TUNNEL *t, bool is_32bit);
+void FreeL2TPSession(L2TP_SESSION *s);
+void DisconnectL2TPSession(L2TP_TUNNEL *t, L2TP_SESSION *s);
+void DisconnectL2TPTunnel(L2TP_TUNNEL *t);
+void StartL2TPThread(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s);
+void StopL2TPThread(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s);
+UINT CalcL2TPMss(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s);
+UINT GenerateNewSessionIdForL2TPv3(L2TP_SERVER *l2tp);
+L2TP_SESSION *SearchL2TPSessionById(L2TP_SERVER *l2tp, bool is_v3, UINT id);
+void L2TPSessionManageEtherIPServer(L2TP_SERVER *l2tp, L2TP_SESSION *s);
+
+#endif // IPSEC_L2TP_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_PPP.c b/src/Cedar/IPsec_PPP.c
new file mode 100644
index 00000000..26fa0d1d
--- /dev/null
+++ b/src/Cedar/IPsec_PPP.c
@@ -0,0 +1,2689 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_PPP.c
+// PPP protocol stack
+
+#include "CedarPch.h"
+
+// PPP thread
+void PPPThread(THREAD *thread, void *param)
+{
+ PPP_SESSION *p = (PPP_SESSION *)param;
+ UINT i;
+ PPP_LCP *c;
+ USHORT us;
+ UINT ui;
+ USHORT next_protocol = 0;
+ bool ret = false;
+ char ipstr1[128], ipstr2[128];
+ bool established = false;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Initialize
+ p->Mru1 = p->Mru2 = PPP_MRU_DEFAULT;
+ p->RecvPacketList = NewList(NULL);
+
+ //// Link establishment phase
+ IPToStr(ipstr1, sizeof(ipstr1), &p->ClientIP);
+ IPToStr(ipstr2, sizeof(ipstr2), &p->ServerIP);
+ PPPLog(p, "LP_CONNECTED", p->Postfix, ipstr1, p->ClientHostname, p->ClientPort, ipstr2, p->ServerPort,
+ p->ClientSoftwareName, p->AdjustMss);
+
+ // Request the use of PAP
+ c = NewPPPLCP(PPP_LCP_CODE_REQ, 0);
+ us = Endian16(PPP_LCP_AUTH_PAP);
+ Add(c->OptionList, NewPPPOption(PPP_LCP_OPTION_AUTH, &us, sizeof(USHORT)));
+ ret = PPPSendRequest(p, PPP_PROTOCOL_LCP, c);
+ FreePPPLCP(c);
+ if (ret == false)
+ {
+ if (IsTubeConnected(p->TubeRecv))
+ {
+ // PAP protocol is denied
+ p->DisconnectCauseCode = 15;
+ p->DisconnectCauseDirection = 1;
+ Debug("PPP: PAP Rejected.\n");
+
+ if (p->EnableMSCHAPv2)
+ {
+ // Try to request the use of MS-CHAPv2
+ UCHAR ms_chap_v2_code[3];
+ WRITE_USHORT(ms_chap_v2_code, PPP_LCP_AUTH_CHAP);
+ ms_chap_v2_code[2] = PPP_CHAP_ALG_MS_CHAP_V2;
+
+ c = NewPPPLCP(PPP_LCP_CODE_REQ, 0);
+ Add(c->OptionList, NewPPPOption(PPP_LCP_OPTION_AUTH, ms_chap_v2_code, sizeof(ms_chap_v2_code)));
+ ret = PPPSendRequest(p, PPP_PROTOCOL_LCP, c);
+ FreePPPLCP(c);
+
+ if (ret == false)
+ {
+ if (IsTubeConnected(p->TubeRecv))
+ {
+ // MS-CHAPv2 protocol was also rejected
+ p->DisconnectCauseCode = 15;
+ p->DisconnectCauseDirection = 1;
+ Debug("PPP: MS-CHAPv2 Rejected.\n");
+ PPPLog(p, "LP_PAP_MSCHAPV2_REJECTED");
+ }
+ }
+ else
+ {
+ // It is to be used for the MS-CHAPv2
+ p->AuthProtocol = PPP_PROTOCOL_CHAP;
+ }
+ }
+ else
+ {
+ PPPLog(p, "LP_PAP_REJECTED");
+ }
+ }
+
+ if (ret == false)
+ {
+ goto LABEL_CLEANUP;
+ }
+ }
+
+ //// Authentication phase
+
+ if (p->AuthProtocol == PPP_PROTOCOL_PAP)
+ {
+ // PAP
+ next_protocol = PPPContinueCurrentProtocolRequestListening(p, PPP_PROTOCOL_LCP);
+ if (next_protocol == 0)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ Debug("next_protocol = 0x%x\n", next_protocol);
+
+ if (next_protocol != PPP_PROTOCOL_PAP)
+ {
+ Debug("next_protocol is not PAP !!\n");
+ PPPLog(p, "LP_NEXT_PROTOCOL_IS_NOT_PAP", next_protocol);
+ goto LABEL_CLEANUP;
+ }
+
+ next_protocol = PPPContinueCurrentProtocolRequestListening(p, PPP_PROTOCOL_PAP);
+ if (next_protocol == 0 || p->AuthOk == false)
+ {
+ if (IsTubeConnected(p->TubeRecv))
+ {
+ // PAP authentication failed
+ p->DisconnectCauseCode = 15;
+ p->DisconnectCauseDirection = 1;
+ Debug("PPP: PAP Failed.\n");
+ PPPLog(p, "LP_PAP_FAILED");
+ }
+ goto LABEL_CLEANUP;
+ }
+ }
+ else
+ {
+ // MS-CHAP v2
+ PPP_PACKET *pp, *pp_ret;
+ BUF *b;
+ char machine_name[MAX_SIZE];
+ UINT64 start_tick = Tick64();
+ UINT64 timeout_tick = start_tick + (UINT64)PPP_PACKET_RECV_TIMEOUT;
+ UINT64 next_send_tick = 0;
+ USHORT pp_ret_protocol;
+
+ PPPContinueUntilFinishAllLCPOptionRequestsDetermined(p);
+
+ // Generate a Server Challenge packet of MS-CHAP v2
+ GetMachineHostName(machine_name, sizeof(machine_name));
+ MsChapV2Server_GenerateChallenge(p->MsChapV2_ServerChallenge);
+
+ pp = ZeroMalloc(sizeof(PPP_PACKET));
+ pp->Protocol = PPP_PROTOCOL_CHAP;
+ pp->IsControl = true;
+ pp->Lcp = NewPPPLCP(PPP_CHAP_CODE_CHALLENGE, 0);
+
+ b = NewBuf();
+ WriteBufChar(b, 16);
+ WriteBuf(b, p->MsChapV2_ServerChallenge, sizeof(p->MsChapV2_ServerChallenge));
+ WriteBuf(b, machine_name, StrLen(machine_name));
+ pp->Lcp->Data = Clone(b->Buf, b->Size);
+ pp->Lcp->DataSize = b->Size;
+ FreeBuf(b);
+
+ PPPSendPacket(p, pp);
+
+ pp_ret_protocol = 0;
+ pp_ret = PPPRecvResponsePacket(p, pp, 0, &pp_ret_protocol, false);
+
+ if (pp_ret != NULL)
+ {
+ FreePPPPacket(pp_ret);
+ }
+
+ FreePPPPacket(pp);
+
+ if (pp_ret_protocol == 0 || p->AuthOk == false)
+ {
+ if (IsTubeConnected(p->TubeRecv))
+ {
+ // MS-CHAPv2 authentication failed
+ p->DisconnectCauseCode = 15;
+ p->DisconnectCauseDirection = 1;
+ Debug("PPP: MS-CHAPv2 Failed.\n");
+ PPPLog(p, "LP_MSCHAPV2_FAILED");
+ }
+ goto LABEL_CLEANUP;
+ }
+
+ next_protocol = pp_ret_protocol;
+ }
+
+ Debug("next_protocol = 0x%x\n", next_protocol);
+
+ if (next_protocol != PPP_PROTOCOL_IPCP)
+ {
+ // Receive the protocol of non-IPCP
+ Debug("Not IPCP Protocol.\n");
+ PPPLog(p, "LP_NEXT_PROTOCOL_IS_NOT_IPCP", next_protocol);
+ goto LABEL_CLEANUP;
+ }
+
+ // Notify the IP address of the PPP server
+ c = NewPPPLCP(PPP_LCP_CODE_REQ, 0);
+ ui = Endian32(0x01000001); // 1.0.0.1
+ Add(c->OptionList, NewPPPOption(PPP_IPCP_OPTION_IP, &ui, sizeof(UINT)));
+ ret = PPPSendRequest(p, PPP_PROTOCOL_IPCP, c);
+ FreePPPLCP(c);
+ if (ret == false)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ next_protocol = PPPContinueCurrentProtocolRequestListening(p, PPP_PROTOCOL_IPCP);
+ Debug("next_protocol = 0x%x\n", next_protocol);
+
+ if (p->Ipc == NULL || IsZeroIP(&p->Ipc->ClientIPAddress))
+ {
+ // IP address is undetermined
+ PPPLog(p, "LP_IP_ADDRESS_NOT_DETERMIND");
+ goto LABEL_CLEANUP;
+ }
+
+ if (next_protocol == PPP_PROTOCOL_IP)
+ {
+ established = true;
+
+ // Do the IP communication
+ while (true)
+ {
+ TUBE *tubes[2];
+ UINT64 now = Tick64();
+ UINT r;
+
+ // Flush the ARP table of the IPC
+ IPCFlushArpTable(p->Ipc);
+
+ // Packet of client to server direction
+ while (true)
+ {
+ PPP_PACKET *pp = PPPRecvPacketForCommunication(p);
+ if (pp == NULL)
+ {
+ break;
+ }
+
+ if (pp->Protocol == PPP_PROTOCOL_IP)
+ {
+ // Since I want to send the IP packet, pass it to the IPC
+ IPCSendIPv4(p->Ipc, pp->Data, pp->DataSize);
+ }
+
+ FreePPPPacket(pp);
+ }
+
+ if (p->DhcpAllocated)
+ {
+ if (now >= p->DhcpNextRenewTime)
+ {
+ IP ip;
+
+ // DHCP renewal procedure
+ p->DhcpNextRenewTime = now + p->DhcpRenewInterval;
+
+ UINTToIP(&ip, p->ClientAddressOption.ServerAddress);
+
+ IPCDhcpRenewIP(p->Ipc, &ip);
+ }
+ }
+
+ // Happy procedure
+ IPCProcessL3Events(p->Ipc);
+
+ // Packet of server to client direction
+ while (true)
+ {
+ BLOCK *b = IPCRecvIPv4(p->Ipc);
+ PPP_PACKET *pp;
+ PPP_PACKET tmp;
+ if (b == NULL)
+ {
+ break;
+ }
+
+ // Since receiving the IP packet, send it to the client by PPP
+ pp = &tmp;
+ pp->IsControl = false;
+ pp->Protocol = PPP_PROTOCOL_IP;
+ pp->Lcp = NULL;
+ pp->Data = b->Buf;
+ pp->DataSize = b->Size;
+
+ PPPSendPacketEx(p, pp, true);
+
+ FreePPPPacketEx(pp, true);
+ Free(b);
+ }
+
+ FlushTubeFlushList(p->FlushList);
+
+ // PPP Echo Request
+ if (p->NextEchoSendTime == 0 || now >= p->NextEchoSendTime)
+ {
+ p->NextEchoSendTime = now + (UINT64)PPP_ECHO_SEND_INTERVAL;
+ AddInterrupt(p->Ipc->Interrupt, p->NextEchoSendTime);
+
+ PPPSendEchoRequest(p);
+ }
+
+ // Terminate if any tube is disconnected
+ if (IsTubeConnected(p->TubeRecv) == false || IsTubeConnected(p->TubeSend) == false)
+ {
+ // Higher-level protocol is disconnected
+ PPPLog(p, "LP_UPPER_PROTOCOL_DISCONNECTED", p->Postfix);
+ break;
+ }
+ if (IsIPCConnected(p->Ipc) == false)
+ {
+ // IPC VPN session is disconnected
+ PPPLog(p, "LP_VPN_SESSION_TERMINATED");
+ break;
+ }
+
+ // Time-out inspection
+ if ((p->LastRecvTime + (UINT64)PPP_DATA_TIMEOUT) <= now)
+ {
+ // Communication time-out occurs
+ PPPLog(p, "LP_DATA_TIMEOUT");
+ break;
+ }
+
+ // Terminate if the PPP disconnected
+ if (p->IsTerminateReceived)
+ {
+ PPPLog(p, "LP_NORMAL_TERMINATE");
+ break;
+ }
+
+ // Wait until the next packet arrives
+ tubes[0] = p->TubeRecv;
+ tubes[1] = p->Ipc->Sock->RecvTube;
+
+ r = GetNextIntervalForInterrupt(p->Ipc->Interrupt);
+ WaitForTubes(tubes, 2, MIN(r, 1234));
+ }
+
+ // Disconnected normally
+ PPPLog(p, "LP_DISCONNECTED");
+ }
+
+ if (p->DhcpAllocated)
+ {
+ // If any address is assigned from the DHCP, release it
+ IP ip;
+ char tmp[MAX_SIZE];
+
+ UINTToIP(&ip, p->ClientAddressOption.ServerAddress);
+
+ IPToStr(tmp, sizeof(tmp), &ip);
+ Debug("Releasing IP Address from DHCP Server %s...\n", tmp);
+
+ IPCDhcpFreeIP(p->Ipc, &ip);
+ IPCProcessL3Events(p->Ipc);
+
+ SleepThread(300);
+ }
+
+LABEL_CLEANUP:
+
+ if (established == false)
+ {
+ // Disconnected Abnormally
+ PPPLog(p, "LP_DISCONNECTED_ABNORMAL");
+ }
+
+ // Disconnection process
+ PPPCleanTerminate(p);
+
+ // Release the memory
+ for (i = 0;i < LIST_NUM(p->RecvPacketList);i++)
+ {
+ PPP_PACKET *pp = LIST_DATA(p->RecvPacketList, i);
+
+ FreePPPPacket(pp);
+ }
+ ReleaseList(p->RecvPacketList);
+
+ // Release the PPP session
+ FreePPPSession(p);
+}
+
+// Disconnect the PPP cleanly
+void PPPCleanTerminate(PPP_SESSION *p)
+{
+ PPP_PACKET *pp;
+ PPP_PACKET *res;
+ UINT64 giveup_tick = Tick64() + (UINT64)PPP_TERMINATE_TIMEOUT;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ // Send a Terminate Request
+ pp = ZeroMalloc(sizeof(PPP_PACKET));
+ pp->IsControl = true;
+ pp->Protocol = PPP_PROTOCOL_LCP;
+ pp->Lcp = NewPPPLCP(PPP_LCP_CODE_TERMINATE_REQ, p->NextId++);
+ Debug("PPP: Terminate Request is Sent.\n");
+ if (PPPSendPacket(p, pp) == false)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ // Wait for Terminate ACK
+ while (true)
+ {
+ UINT64 now = Tick64();
+ UINT interval;
+
+ if (now >= giveup_tick)
+ {
+ break;
+ }
+
+ while (true)
+ {
+ if (IsTubeConnected(p->TubeRecv) == false)
+ {
+ break;
+ }
+
+ res = PPPRecvPacket(p, true);
+
+ if (res == NULL)
+ {
+ break;
+ }
+
+ if (res->IsControl && res->Protocol == PPP_PROTOCOL_LCP && res->Lcp->Code == PPP_LCP_CODE_TERMINATE_ACK)
+ {
+ Debug("PPP: Terminate ACK is Received.\n");
+ FreePPPPacket(res);
+ goto LABEL_CLEANUP;
+ }
+
+ FreePPPPacket(res);
+ }
+
+ interval = (UINT)(giveup_tick - now);
+
+ Wait(p->TubeRecv->Event, interval);
+ }
+
+LABEL_CLEANUP:
+ FreePPPPacket(pp);
+}
+
+// Wait until all pending LCP option are determined
+bool PPPContinueUntilFinishAllLCPOptionRequestsDetermined(PPP_SESSION *p)
+{
+ USHORT received_protocol = 0;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return false;
+ }
+
+ PPPRecvResponsePacket(p, NULL, PPP_PROTOCOL_LCP, &received_protocol, true);
+
+ return p->ClientLCPOptionDetermined;
+}
+
+// Continue the processing of the request packet protocol on the current PPP
+USHORT PPPContinueCurrentProtocolRequestListening(PPP_SESSION *p, USHORT protocol)
+{
+ USHORT received_protocol = 0;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return 0;
+ }
+
+ PPPRecvResponsePacket(p, NULL, protocol, &received_protocol, false);
+
+ return received_protocol;
+}
+
+// Send the PPP Echo Request
+void PPPSendEchoRequest(PPP_SESSION *p)
+{
+ PPP_PACKET *pp;
+ char echo_data[]= "\0\0\0\0Aho Baka Manuke";
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ pp = ZeroMalloc(sizeof(PPP_PACKET));
+ pp->Protocol = PPP_PROTOCOL_LCP;
+ pp->IsControl = true;
+ pp->Lcp = NewPPPLCP(PPP_LCP_CODE_ECHO_REQUEST, p->NextId++);
+
+ pp->Lcp->Data = Clone(echo_data, sizeof(echo_data));
+ pp->Lcp->DataSize = sizeof(echo_data);
+
+ PPPSendPacket(p, pp);
+
+ FreePPPPacket(pp);
+}
+
+// Send a request packet in the PPP
+bool PPPSendRequest(PPP_SESSION *p, USHORT protocol, PPP_LCP *c)
+{
+ PPP_PACKET *pp;
+ PPP_PACKET *pp2;
+ bool ret = false;
+ // Validate arguments
+ if (p == NULL || c == NULL)
+ {
+ return false;
+ }
+
+ pp = ZeroMalloc(sizeof(PPP_PACKET));
+ pp->Protocol = protocol;
+ pp->IsControl = true;
+ pp->Lcp = c;
+ pp->Lcp->Id = p->NextId++;
+
+ // Send the PPP packet
+ if (PPPSendPacket(p, pp) == false)
+ {
+ goto LABEL_ERROR;
+ }
+
+ // Receive a corresponding PPP packet
+ pp2 = PPPRecvResponsePacket(p, pp, 0, NULL, false);
+
+ if (pp2 != NULL)
+ {
+ if (protocol == PPP_PROTOCOL_LCP || protocol == PPP_PROTOCOL_IPCP)
+ {
+ if (!PPP_LCP_CODE_IS_NEGATIVE(pp2->Lcp->Code))
+ {
+ // A positive response is received
+ ret = true;
+ }
+ }
+ }
+
+ FreePPPPacket(pp2);
+ Free(pp);
+
+ return ret;
+
+LABEL_ERROR:
+ Free(pp);
+ return false;
+}
+
+// Check whether the Virtual HUB with the specified name exist?
+bool IsHubExistsWithLock(CEDAR *cedar, char *hubname)
+{
+ bool ret = false;
+ // Validate arguments
+ if (cedar == NULL || hubname == NULL)
+ {
+ return false;
+ }
+
+ LockList(cedar->HubList);
+ {
+ ret = IsHub(cedar, hubname);
+ }
+ UnlockList(cedar->HubList);
+
+ return ret;
+}
+
+// Separate into the user name and the Virtual HUB name by analyzing the string
+bool PPPParseUsername(CEDAR *cedar, char *src_username, ETHERIP_ID *dst)
+{
+ UINT i, len, last_at, first_en;
+ char token1[MAX_SIZE]; // username
+ char token2[MAX_SIZE]; // hub_name
+ char src[MAX_SIZE];
+ // Validate arguments
+ Zero(dst, sizeof(ETHERIP_ID));
+ if (cedar == NULL || src == NULL || dst == NULL)
+ {
+ return false;
+ }
+
+ StrCpy(src, sizeof(src), src_username);
+ Trim(src);
+
+ // Search for the first "\\" in the string
+ len = StrLen(src);
+
+ first_en = SearchStrEx(src, "\\", 0, true);
+
+ if (first_en != INFINITE && first_en >= 1 && (first_en < (len - 1)))
+ {
+ StrCpy(token1, sizeof(token1), src + first_en + 1);
+ StrCpy(token2, sizeof(token2), src);
+ token2[first_en] = 0;
+
+ // Confirm whether the hubname exists if the virtual HUB name is
+ // specified like as hubname\username
+ if (IsHubExistsWithLock(cedar, token2) == false)
+ {
+ // If the hubname does not exist, restore to the original name
+ StrCpy(token1, sizeof(token1), src);
+ ClearStr(token2, sizeof(token2));
+ }
+ }
+ else
+ {
+ // Search for the last "@" in the string
+ len = StrLen(src);
+ last_at = INFINITE;
+ for (i = 0;i < len;i++)
+ {
+ char c = src[i];
+
+ if (c == '@')
+ {
+ last_at = i;
+ }
+ }
+
+ Zero(token1, sizeof(token1));
+ Zero(token2, sizeof(token2));
+
+ if (last_at == INFINITE)
+ {
+ // "@" is not specified
+ StrCpy(token1, sizeof(token1), src);
+ }
+ else
+ {
+ // Split with last "@"
+ StrCpy(token1, sizeof(token1), src);
+ token1[last_at] = 0;
+
+ StrCpy(token2, sizeof(token2), src + last_at + 1);
+ }
+
+ // Check whether such Virtual HUB exists If the virtual HUB name is specified
+ if (IsEmptyStr(token2) == false)
+ {
+ if (IsHubExistsWithLock(cedar, token2) == false)
+ {
+ // Because the specified virtual HUB name doesn't exist, it's considered to be a part of the user name
+ StrCpy(token1, sizeof(token1), src);
+
+ ClearStr(token2, sizeof(token2));
+ }
+ }
+ }
+
+ if (IsEmptyStr(token2))
+ {
+ // Select the default Virtual HUB if the Virtual HUB name is not specified
+ StrCpy(token2, sizeof(token2), SERVER_DEFAULT_HUB_NAME);
+ if (cedar->Server != NULL && cedar->Server->IPsecServer != NULL)
+ {
+ Lock(cedar->Server->IPsecServer->LockSettings);
+ {
+ IPsecNormalizeServiceSetting(cedar->Server->IPsecServer);
+
+ StrCpy(token2, sizeof(token2), cedar->Server->IPsecServer->Services.L2TP_DefaultHub);
+ }
+ Unlock(cedar->Server->IPsecServer->LockSettings);
+ }
+
+ }
+
+ // Return the results
+ StrCpy(dst->HubName, sizeof(dst->HubName), token2);
+ StrCpy(dst->UserName, sizeof(dst->UserName), token1);
+
+ return true;
+}
+
+// Process the PPP request packet
+PPP_PACKET *PPPProcessRequestPacket(PPP_SESSION *p, PPP_PACKET *req)
+{
+ UINT i;
+ PPP_PACKET *ret = NULL;
+ UINT num_not_supported = 0;
+ UINT num_not_accepted = 0;
+ bool no_return_option_list = false;
+ UINT return_code = 0;
+ BUF *lcp_ret_data = NULL;
+ // Validate arguments
+ if (p == NULL || req == NULL || req->Lcp == NULL)
+ {
+ return NULL;
+ }
+
+ // Initialize
+ for (i = 0;i < LIST_NUM(req->Lcp->OptionList);i++)
+ {
+ PPP_OPTION *t = LIST_DATA(req->Lcp->OptionList, i);
+
+ t->IsAccepted = false;
+ t->IsSupported = false;
+ t->AltDataSize = 0;
+ Zero(t->AltData, sizeof(t->AltData));
+ }
+
+ // Process by scanning the specified option value
+ if (req->Protocol == PPP_PROTOCOL_LCP)
+ {
+ // LCP
+ if (req->Lcp == NULL)
+ {
+ return NULL;
+ }
+ for (i = 0;i < LIST_NUM(req->Lcp->OptionList);i++)
+ {
+ PPP_OPTION *t = LIST_DATA(req->Lcp->OptionList, i);
+
+ switch (t->Type)
+ {
+ case PPP_LCP_OPTION_MRU:
+ // MRU
+ t->IsSupported = true;
+ if (t->DataSize == sizeof(USHORT))
+ {
+ UINT value = READ_USHORT(t->Data);
+ if (value < PPP_MRU_MIN || value > PPP_MRU_MAX)
+ {
+ t->IsAccepted = false;
+ value = MAKESURE(value, PPP_MRU_MIN, PPP_MRU_MAX);
+ WRITE_USHORT(t->AltData, value);
+ t->AltDataSize = sizeof(USHORT);
+ }
+ else
+ {
+ p->Mru1 = value;
+ Debug("PPP: Client set %u as MRU\n", p->Mru1);
+ t->IsAccepted = true;
+ }
+ }
+ break;
+ }
+ }
+ }
+ else if (req->Protocol == PPP_PROTOCOL_CHAP)
+ {
+ bool ok = false;
+ char ret_str[MAX_SIZE];
+
+ no_return_option_list = true;
+
+ if (p->Ipc == NULL)
+ {
+ // MS-CHAPv2
+ if (req->Lcp->DataSize >= 51)
+ {
+ BUF *b;
+
+ b = NewBuf();
+
+ WriteBuf(b, req->Lcp->Data, req->Lcp->DataSize);
+ SeekBuf(b, 0, 0);
+
+ if (ReadBufChar(b) == 49)
+ {
+ UCHAR client_response_buffer[49];
+ UCHAR *client_challenge_16;
+ UCHAR *client_response_24;
+ char username_tmp[MAX_SIZE];
+ IPC *ipc = NULL;
+ char id[MAX_SIZE];
+ char hub[MAX_SIZE];
+ char password[MAX_SIZE];
+ char server_challenge_hex[MAX_SIZE];
+ char client_challenge_hex[MAX_SIZE];
+ char client_response_hex[MAX_SIZE];
+ ETHERIP_ID d;
+ UINT error_code;
+
+ ReadBuf(b, client_response_buffer, 49);
+
+ Zero(username_tmp, sizeof(username_tmp));
+ ReadBuf(b, username_tmp, sizeof(username_tmp));
+
+ client_challenge_16 = client_response_buffer + 0;
+ client_response_24 = client_response_buffer + 16 + 8;
+
+ Copy(p->MsChapV2_ClientChallenge, client_challenge_16, 16);
+ Copy(p->MsChapV2_ClientResponse, client_response_24, 24);
+
+ Debug("MS-CHAPv2: id=%s\n", username_tmp);
+
+ Zero(id, sizeof(id));
+ Zero(hub, sizeof(hub));
+
+ // The user name is divided into the ID and the virtual HUB name
+ Zero(&d, sizeof(d));
+ PPPParseUsername(p->Cedar, username_tmp, &d);
+
+ StrCpy(id, sizeof(id), d.UserName);
+ StrCpy(hub, sizeof(hub), d.HubName);
+
+ // Convert the MS-CHAPv2 data to a password string
+ BinToStr(server_challenge_hex, sizeof(server_challenge_hex),
+ p->MsChapV2_ServerChallenge, sizeof(p->MsChapV2_ServerChallenge));
+ BinToStr(client_challenge_hex, sizeof(client_challenge_hex),
+ p->MsChapV2_ClientChallenge, sizeof(p->MsChapV2_ClientChallenge));
+ BinToStr(client_response_hex, sizeof(client_response_hex),
+ p->MsChapV2_ClientResponse, sizeof(p->MsChapV2_ClientResponse));
+
+ Format(password, sizeof(password), "%s%s:%s:%s:%s",
+ IPC_PASSWORD_MSCHAPV2_TAG,
+ username_tmp,
+ server_challenge_hex,
+ client_challenge_hex,
+ client_response_hex);
+
+ // Attempt to connect with IPC
+ ipc = NewIPC(p->Cedar, p->ClientSoftwareName, p->Postfix, hub, id, password,
+ &error_code, &p->ClientIP, p->ClientPort, &p->ServerIP, p->ServerPort,
+ p->ClientHostname, p->CryptName, false, p->AdjustMss);
+
+ if (ipc != NULL)
+ {
+ p->Ipc = ipc;
+
+ Copy(p->MsChapV2_ServerResponse, ipc->MsChapV2_ServerResponse, 20);
+
+ ok = true;
+ }
+ else
+ {
+ switch (error_code)
+ {
+ default:
+ // Normal authentication error
+ p->MsChapV2_ErrorCode = 691;
+ break;
+
+ case ERR_MSCHAP2_PASSWORD_NEED_RESET:
+ // Authentication errors due to compatibility issues of the password
+ p->MsChapV2_ErrorCode = 942;
+ break;
+ }
+ }
+ }
+
+ FreeBuf(b);
+ }
+ }
+ else
+ {
+ // Return success for a request from the second time when it is successfully authenticated once
+ ok = true;
+ }
+
+ // Generate a response options string
+ if (ok == false)
+ {
+ // In the case of failure
+ char hex[MAX_SIZE];
+ BinToStr(hex, sizeof(hex), p->MsChapV2_ServerChallenge, 16);
+
+ Format(ret_str, sizeof(ret_str),
+ "E=%u R=0 C=%s V=3", p->MsChapV2_ErrorCode, hex);
+
+ return_code = PPP_CHAP_CODE_FAILURE;
+ }
+ else
+ {
+ // In the case of success
+ char hex[MAX_SIZE];
+ BinToStr(hex, sizeof(hex), p->MsChapV2_ServerResponse, 20);
+
+ Format(ret_str, sizeof(ret_str),
+ "S=%s", hex);
+
+ return_code = PPP_CHAP_CODE_SUCCESS;
+
+ p->AuthOk = true;
+ }
+
+ lcp_ret_data = NewBuf();
+ WriteBuf(lcp_ret_data, ret_str, StrLen(ret_str));
+ }
+ else if (req->Protocol == PPP_PROTOCOL_PAP)
+ {
+ UCHAR *data;
+ UINT size;
+ bool ok = false;
+
+ no_return_option_list = true;
+
+ if (p->Ipc == NULL)
+ {
+ // PAP
+
+ // Extract the ID and the password
+ data = req->Lcp->Data;
+ size = req->Lcp->DataSize;
+
+ if (size >= 1)
+ {
+ UCHAR len_id = data[0];
+ data++;
+ size--;
+
+ if (size >= len_id)
+ {
+ char username[256];
+ char password[256];
+
+ Zero(username, sizeof(username));
+ Zero(password, sizeof(password));
+
+ Copy(username, data, len_id);
+ data += len_id;
+ size -= len_id;
+
+ if (size >= 1)
+ {
+ UCHAR len_pass = data[0];
+ data++;
+ size--;
+
+ if (size >= len_pass)
+ {
+ IPC *ipc;
+ char id[MAX_SIZE];
+ char hub[MAX_SIZE];
+ ETHERIP_ID d;
+
+ Zero(id, sizeof(id));
+ Zero(hub, sizeof(hub));
+
+ Copy(password, data, len_pass);
+
+ Debug("PPP: id=%s, pw=%s\n", username, password);
+
+ // The user name is divided into the ID and the virtual HUB name
+ Zero(&d, sizeof(d));
+ PPPParseUsername(p->Cedar, username, &d);
+
+ StrCpy(id, sizeof(id), d.UserName);
+ StrCpy(hub, sizeof(hub), d.HubName);
+
+ if (IsEmptyStr(id) == false)
+ {
+ // Attempt to connect with IPC
+ UINT error_code;
+
+ ipc = NewIPC(p->Cedar, p->ClientSoftwareName, p->Postfix, hub, id, password,
+ &error_code, &p->ClientIP, p->ClientPort, &p->ServerIP, p->ServerPort,
+ p->ClientHostname, p->CryptName, false, p->AdjustMss);
+
+ if (ipc != NULL)
+ {
+ p->Ipc = ipc;
+ ok = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Return success for a request from the second time when it is successfully authenticated once
+ ok = true;
+ }
+
+ if (ok == false)
+ {
+ // Authentication failure
+ return_code = PPP_PAP_CODE_NAK;
+ }
+ else
+ {
+ // Authentication success
+ return_code = PPP_PAP_CODE_ACK;
+
+ p->AuthOk = true;
+ }
+ }
+ else if (req->Protocol == PPP_PROTOCOL_IPCP)
+ {
+ PPP_IPOPTION o;
+ // Get the IP options data from the request data
+ if (PPPGetIPOptionFromLCP(&o, req->Lcp))
+ {
+ PPP_IPOPTION res;
+ IP subnet;
+ IP gw;
+
+ if (IsZeroIP(&o.IpAddress) == false)
+ {
+ if (p->Ipc->Policy->DHCPForce == false)
+ {
+ if (p->DhcpAllocated == false)
+ {
+ if (p->UseStaticIPAddress == false)
+ {
+ DHCP_OPTION_LIST cao;
+
+ // The client specify an IP address
+ Zero(&cao, sizeof(cao));
+
+ cao.ClientAddress = IPToUINT(&o.IpAddress);
+
+ Copy(&p->ClientAddressOption, &cao, sizeof(cao));
+
+ p->UseStaticIPAddress = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ p->UseStaticIPAddress = false;
+ }
+
+ if (p->UseStaticIPAddress)
+ {
+ if (p->DhcpIpInformTried == false)
+ {
+ // Get additional information such as the subnet mask from the DHCP server
+ DHCP_OPTION_LIST cao;
+ IP client_ip;
+
+ IP subnet;
+ IP zero;
+
+ SetIP(&subnet, 255, 0, 0, 0);
+ Zero(&zero, sizeof(zero));
+
+ UINTToIP(&client_ip, p->ClientAddressOption.ClientAddress);
+
+ Zero(&cao, sizeof(cao));
+
+ IPCSetIPv4Parameters(p->Ipc, &client_ip, &subnet, &zero);
+
+ p->DhcpIpInformTried = true;
+
+ PPPLog(p, "LP_DHCP_INFORM_TRYING");
+
+ if (IPCDhcpRequestInformIP(p->Ipc, &cao, p->TubeRecv, &client_ip))
+ {
+ Debug("IPCDhcpRequestInformIP ok.\n");
+ Copy(&p->ClientAddressOption, &cao, sizeof(cao));
+ p->ClientAddressOption.ClientAddress = IPToUINT(&client_ip);
+
+ if (true)
+ {
+ char server_ip_str[64];
+ char subnet_str[64], defgw_str[64];
+ char dns1_str[64], dns2_str[64];
+ char wins1_str[64], wins2_str[64];
+
+ IPToStr32(server_ip_str, sizeof(server_ip_str), cao.ServerAddress);
+ IPToStr32(subnet_str, sizeof(subnet_str), cao.SubnetMask);
+ IPToStr32(defgw_str, sizeof(defgw_str), cao.Gateway);
+ IPToStr32(dns1_str, sizeof(dns1_str), cao.DnsServer);
+ IPToStr32(dns2_str, sizeof(dns2_str), cao.DnsServer2);
+ IPToStr32(wins1_str, sizeof(wins1_str), cao.WinsServer);
+ IPToStr32(wins2_str, sizeof(wins2_str), cao.WinsServer2);
+
+ PPPLog(p, "LP_DHCP_INFORM_OK",
+ subnet_str, defgw_str, cao.DomainName,
+ dns1_str, dns2_str, wins1_str, wins2_str,
+ server_ip_str);
+ }
+ }
+ else
+ {
+ Debug("IPCDhcpRequestInformIP failed.\n");
+
+ PPPLog(p, "LP_DHCP_INFORM_NG");
+ }
+
+ IPCSetIPv4Parameters(p->Ipc, &zero, &zero, &zero);
+ }
+ }
+ else
+ {
+ // Get an IP address from a DHCP server
+ if (p->DhcpIpAllocTried == false)
+ {
+ DHCP_OPTION_LIST cao;
+
+ Zero(&cao, sizeof(cao));
+ p->DhcpIpAllocTried = true;
+
+ PPPLog(p, "LP_DHCP_REQUEST_TRYING");
+
+ if (IPCDhcpAllocateIP(p->Ipc, &cao, p->TubeRecv))
+ {
+ UINT t;
+
+ Debug("IPCDhcpAllocateIP ok.\n");
+
+ // IP address has been determined
+ Copy(&p->ClientAddressOption, &cao, sizeof(cao));
+
+ p->DhcpAllocated = true;
+
+ // Determine the DHCP update interval
+ t = cao.LeaseTime;
+ if (t == 0)
+ {
+ t = 600;
+ }
+
+ t = t / 3;
+
+ if (t == 0)
+ {
+ t = 1;
+ }
+
+ p->DhcpRenewInterval = (UINT64)(t * 1000);
+ p->DhcpNextRenewTime = Tick64() + p->DhcpRenewInterval;
+
+ if (true)
+ {
+ char client_ip_str[64], server_ip_str[64];
+ char subnet_str[64], defgw_str[64];
+ char dns1_str[64], dns2_str[64];
+ char wins1_str[64], wins2_str[64];
+
+ IPToStr32(client_ip_str, sizeof(client_ip_str), cao.ClientAddress);
+ IPToStr32(server_ip_str, sizeof(server_ip_str), cao.ServerAddress);
+ IPToStr32(subnet_str, sizeof(subnet_str), cao.SubnetMask);
+ IPToStr32(defgw_str, sizeof(defgw_str), cao.Gateway);
+ IPToStr32(dns1_str, sizeof(dns1_str), cao.DnsServer);
+ IPToStr32(dns2_str, sizeof(dns2_str), cao.DnsServer2);
+ IPToStr32(wins1_str, sizeof(wins1_str), cao.WinsServer);
+ IPToStr32(wins2_str, sizeof(wins2_str), cao.WinsServer2);
+
+ PPPLog(p, "LP_DHCP_REQUEST_OK",
+ client_ip_str, subnet_str, defgw_str, cao.DomainName,
+ dns1_str, dns2_str, wins1_str, wins2_str,
+ server_ip_str, cao.LeaseTime);
+ }
+ }
+ else
+ {
+ Debug("IPCDhcpAllocateIP failed.\n");
+
+ PPPLog(p, "LP_DHCP_REQUEST_NG");
+ }
+ }
+ }
+
+ if (IsValidUnicastIPAddressUINT4(p->ClientAddressOption.ClientAddress) &&
+ p->ClientAddressOption.SubnetMask != 0)
+ {
+ // Success to determine the address
+ UINTToIP(&subnet, p->ClientAddressOption.SubnetMask);
+ UINTToIP(&gw, p->ClientAddressOption.Gateway);
+
+ Zero(&res, sizeof(res));
+ UINTToIP(&res.IpAddress, p->ClientAddressOption.ClientAddress);
+ UINTToIP(&res.DnsServer1, p->ClientAddressOption.DnsServer);
+ UINTToIP(&res.DnsServer2, p->ClientAddressOption.DnsServer2);
+ UINTToIP(&res.WinsServer1, p->ClientAddressOption.WinsServer);
+ UINTToIP(&res.WinsServer2, p->ClientAddressOption.WinsServer2);
+
+ if (IPCSetIPv4Parameters(p->Ipc, &res.IpAddress, &subnet, &gw))
+ {
+ char client_ip_str[64];
+ char subnet_str[64], defgw_str[64];
+ char dns1_str[64], dns2_str[64];
+ char wins1_str[64], wins2_str[64];
+
+ // IPv4 parameters have been set for the first time
+ Debug("Param First Set.\n");
+
+ IPToStr(client_ip_str, sizeof(client_ip_str), &res.IpAddress);
+ IPToStr(subnet_str, sizeof(subnet_str), &subnet);
+ IPToStr(defgw_str, sizeof(defgw_str), &gw);
+ IPToStr(dns1_str, sizeof(dns1_str), &res.DnsServer1);
+ IPToStr(dns2_str, sizeof(dns2_str), &res.DnsServer2);
+ IPToStr(wins1_str, sizeof(wins1_str), &res.WinsServer1);
+ IPToStr(wins2_str, sizeof(wins2_str), &res.WinsServer2);
+
+ PPPLog(p, "LP_SET_IPV4_PARAM", client_ip_str, subnet_str,
+ defgw_str, dns1_str, dns2_str, wins1_str, wins2_str);
+ }
+
+ PPPSetIPOptionToLCP(&res, req->Lcp, true);
+ }
+ else
+ {
+ // Failed to determine the address
+ Debug("IP Address Determination Failed.\n");
+
+ Zero(&res, sizeof(res));
+
+ PPPSetIPOptionToLCP(&res, req->Lcp, true);
+ }
+ }
+ }
+
+ // Assemble the LCP response packet based on the results
+ for (i = 0;i < LIST_NUM(req->Lcp->OptionList);i++)
+ {
+ PPP_OPTION *t = LIST_DATA(req->Lcp->OptionList, i);
+
+ if (t->IsSupported == false)
+ {
+ num_not_supported++;
+ }
+
+ if (t->IsAccepted == false)
+ {
+ num_not_accepted++;
+ }
+ }
+
+ // Create a PPP response packet
+ ret = ZeroMalloc(sizeof(PPP_PACKET));
+ ret->IsControl = true;
+ ret->Protocol = req->Protocol;
+
+ if (no_return_option_list == false)
+ {
+ // Response by attaching an optional list
+ if (num_not_supported >= 1)
+ {
+ // Return a Reject if there are unsupported parameters
+ ret->Lcp = NewPPPLCP(PPP_LCP_CODE_REJECT, req->Lcp->Id);
+
+ for (i = 0;i < LIST_NUM(req->Lcp->OptionList);i++)
+ {
+ PPP_OPTION *t = LIST_DATA(req->Lcp->OptionList, i);
+
+ if (t->IsSupported == false)
+ {
+ // Attach the original option value as is
+ Add(ret->Lcp->OptionList, NewPPPOption(t->Type, t->Data, t->DataSize));
+ }
+ }
+ }
+ else if (num_not_accepted >= 1)
+ {
+ // Return a NAK if there are any unacceptable parameter
+ // even that all parameters are supported
+ ret->Lcp = NewPPPLCP(PPP_LCP_CODE_NAK, req->Lcp->Id);
+
+ for (i = 0;i < LIST_NUM(req->Lcp->OptionList);i++)
+ {
+ PPP_OPTION *t = LIST_DATA(req->Lcp->OptionList, i);
+
+ if (t->IsAccepted == false)
+ {
+ // Replace the original option value with an acceptable value
+ Add(ret->Lcp->OptionList, NewPPPOption(t->Type, t->AltData, t->AltDataSize));
+ }
+ }
+ }
+ else
+ {
+ // Return an ACK if all parameters are accepted
+ ret->Lcp = NewPPPLCP(PPP_LCP_CODE_ACK, req->Lcp->Id);
+
+ for (i = 0;i < LIST_NUM(req->Lcp->OptionList);i++)
+ {
+ PPP_OPTION *t = LIST_DATA(req->Lcp->OptionList, i);
+
+ // Attach the original option value as is
+ Add(ret->Lcp->OptionList, NewPPPOption(t->Type, t->Data, t->DataSize));
+ }
+
+ if (req->Protocol == PPP_PROTOCOL_LCP)
+ {
+ p->ClientLCPOptionDetermined = true;
+ }
+ }
+ }
+ else
+ {
+ // Response without attaching a list of options
+ ret->Lcp = NewPPPLCP(return_code, req->Lcp->Id);
+
+ if (lcp_ret_data != NULL && lcp_ret_data->Size >= 1)
+ {
+ ret->Lcp->Data = Clone(lcp_ret_data->Buf, lcp_ret_data->Size);
+ ret->Lcp->DataSize = lcp_ret_data->Size;
+ }
+ }
+
+ if (lcp_ret_data != NULL)
+ {
+ FreeBuf(lcp_ret_data);
+ }
+
+ return ret;
+}
+
+// Set the IP options of PPP to LCP
+bool PPPSetIPOptionToLCP(PPP_IPOPTION *o, PPP_LCP *c, bool only_modify)
+{
+ bool ret = false;
+ // Validate arguments
+ if (c == NULL || o == NULL)
+ {
+ return false;
+ }
+
+ ret = PPPSetIPAddressValueToLCP(c, PPP_IPCP_OPTION_IP, &o->IpAddress, only_modify);
+
+ PPPSetIPAddressValueToLCP(c, PPP_IPCP_OPTION_DNS1, &o->DnsServer1, only_modify);
+ PPPSetIPAddressValueToLCP(c, PPP_IPCP_OPTION_DNS2, &o->DnsServer2, only_modify);
+ PPPSetIPAddressValueToLCP(c, PPP_IPCP_OPTION_WINS1, &o->WinsServer1, only_modify);
+ PPPSetIPAddressValueToLCP(c, PPP_IPCP_OPTION_WINS2, &o->WinsServer2, only_modify);
+
+ return ret;
+}
+
+// Get the IP options of PPP from LCP
+bool PPPGetIPOptionFromLCP(PPP_IPOPTION *o, PPP_LCP *c)
+{
+ bool ret;
+ // Validate arguments
+ if (c == NULL || o == NULL)
+ {
+ return false;
+ }
+
+ Zero(o, sizeof(PPP_IPOPTION));
+
+ ret = PPPGetIPAddressValueFromLCP(c, PPP_IPCP_OPTION_IP, &o->IpAddress);
+
+ PPPGetIPAddressValueFromLCP(c, PPP_IPCP_OPTION_DNS1, &o->DnsServer1);
+ PPPGetIPAddressValueFromLCP(c, PPP_IPCP_OPTION_DNS2, &o->DnsServer2);
+ PPPGetIPAddressValueFromLCP(c, PPP_IPCP_OPTION_WINS1, &o->WinsServer1);
+ PPPGetIPAddressValueFromLCP(c, PPP_IPCP_OPTION_WINS2, &o->WinsServer2);
+
+ return ret;
+}
+
+// Set the IP address data to the option list of the LCP
+bool PPPSetIPAddressValueToLCP(PPP_LCP *c, UINT type, IP *ip, bool only_modify)
+{
+ IP ip2;
+ UINT ui;
+ // Validate arguments
+ if (c == NULL || ip == NULL)
+ {
+ return false;
+ }
+
+ ui = IPToUINT(ip);
+
+ if (PPPGetIPAddressValueFromLCP(c, type, &ip2))
+ {
+ PPP_OPTION *opt;
+ opt = GetOptionValue(c, type);
+
+ if (opt != NULL)
+ {
+ if (IsZeroIP(ip) == false)
+ {
+ if (CmpIpAddr(&ip2, ip) == 0)
+ {
+ // No change
+ opt->IsAccepted = true;
+ opt->IsSupported = true;
+ }
+ else
+ {
+ // Changed
+ opt->IsAccepted = false;
+ opt->IsSupported = true;
+ opt->AltDataSize = 4;
+ Copy(opt->AltData, &ui, 4);
+ }
+ }
+ else
+ {
+ // The parameter itself is not supported
+ // (if the IP address is 0.0.0.0)
+ opt->IsSupported = false;
+ opt->IsAccepted = false;
+ }
+ }
+
+ return true;
+ }
+ else
+ {
+ if (IsZeroIP(ip) == false)
+ {
+ // Add as a new item
+ if (only_modify != false)
+ {
+ return false;
+ }
+ else
+ {
+ PPP_OPTION *opt2 = NewPPPOption(type, &ui, 4);
+ opt2->IsAccepted = opt2->IsSupported = true;
+
+ Add(c->OptionList, opt2);
+
+ return true;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+}
+
+// Get the IP address data from the option list of the LCP
+bool PPPGetIPAddressValueFromLCP(PPP_LCP *c, UINT type, IP *ip)
+{
+ PPP_OPTION *opt;
+ UINT ui;
+ // Validate arguments
+ if (c == NULL || ip == NULL)
+ {
+ return false;
+ }
+
+ opt = GetOptionValue(c, type);
+ if (opt == NULL)
+ {
+ return false;
+ }
+
+ if (opt->DataSize != 4)
+ {
+ return false;
+ }
+
+ opt->IsSupported = true;
+
+ ui = *((UINT *)opt->Data);
+
+ UINTToIP(ip, ui);
+
+ return true;
+}
+
+// Process corresponding to the incoming request while receiving a PPP packet corresponding to the transmitted request.
+// (If req == NULL, process on that protocol while the protocol specified in expected_protocol have received.
+//If other protocols has arrived, without further processing, and then store that packet in the session context once,
+// return NULL by setting the received_protocol.)
+PPP_PACKET *PPPRecvResponsePacket(PPP_SESSION *p, PPP_PACKET *req, USHORT expected_protocol, USHORT *received_protocol, bool finish_when_all_lcp_acked)
+{
+ UINT64 giveup_tick = Tick64() + (UINT64)PPP_PACKET_RECV_TIMEOUT;
+ UINT64 next_resend = Tick64() + (UINT64)PPP_PACKET_RESEND_INTERVAL;
+ PPP_PACKET *ret = NULL;
+ USHORT tmp_us = 0;
+ // Validate arguments
+ if (p == NULL || req != NULL && req->Lcp == NULL)
+ {
+ return NULL;
+ }
+
+ if (received_protocol == NULL)
+ {
+ received_protocol = &tmp_us;
+ }
+
+ if (req != NULL)
+ {
+ expected_protocol = req->Protocol;
+ }
+
+ *received_protocol = 0;
+
+ // Receive the next packet (Retransmission repeatedly the last packet until the reception is completed)
+ while (true)
+ {
+ UINT64 now = Tick64();
+ UINT interval;
+
+ if (IsTubeConnected(p->TubeRecv) == false)
+ {
+ return NULL;
+ }
+
+ while (true)
+ {
+ PPP_PACKET *pp;
+ PPP_PACKET *response;
+
+ if (p->LastStoredPacket != NULL)
+ {
+ pp = p->LastStoredPacket;
+ p->LastStoredPacket = NULL;
+ }
+ else
+ {
+ pp = PPPRecvPacketWithLowLayerProcessing(p, true);
+ }
+
+ if (pp == NULL)
+ {
+ break;
+ }
+
+ if (req != NULL)
+ {
+ // Determine whether the packet is corresponding to the request that was sent at the last
+ if (pp->IsControl && pp->Protocol == req->Protocol && pp->Lcp->Id == req->Lcp->Id &&
+ PPP_CODE_IS_RESPONSE(pp->Protocol, pp->Lcp->Code))
+ {
+ return pp;
+ }
+ }
+
+ // Return a response immediately without processing if a protocol other than the expected received
+ if ((pp->IsControl && pp->Protocol != expected_protocol) || pp->IsControl == false)
+ {
+ if (PPP_IS_SUPPORTED_PROTOCOL(pp->Protocol))
+ {
+ // This is another supported protocol
+ // Store this packet
+ PPPStoreLastPacket(p, pp);
+
+ *received_protocol = pp->Protocol;
+ return NULL;
+ }
+ else
+ {
+ // Unsupported protocol
+ Debug("Unsupported Protocol: 0x%x\n", pp->Protocol);
+ FreePPPPacket(pp);
+
+ return NULL;
+ }
+ }
+
+ if (pp->IsControl && PPP_CODE_IS_REQUEST(pp->Protocol, pp->Lcp->Code))
+ {
+ // Process when the received packet is a request packet
+ response = PPPProcessRequestPacket(p, pp);
+ FreePPPPacket(pp);
+
+ if (response == NULL)
+ {
+ return NULL;
+ }
+ else
+ {
+ bool is_pap_and_disconnect_now = false;
+ bool is_chap_and_disconnect_now = false;
+
+ if (PPPSendPacket(p, response) == false)
+ {
+ FreePPPPacket(response);
+ return NULL;
+ }
+
+ if (response->Protocol == PPP_PROTOCOL_PAP && response->IsControl &&
+ response->Lcp->Code != PPP_PAP_CODE_ACK)
+ {
+ is_pap_and_disconnect_now = true;
+ }
+
+ if (response->Protocol == PPP_PROTOCOL_CHAP && response->IsControl &&
+ response->Lcp->Code == PPP_CHAP_CODE_FAILURE)
+ {
+ is_chap_and_disconnect_now = true;
+ }
+
+ FreePPPPacket(response);
+
+ if (is_pap_and_disconnect_now)
+ {
+ // Disconnect immediately if user authentication fails at least once in the PAP authentication protocol
+ Debug("Disconnecting because PAP failed.\n");
+ SleepThread(300);
+ return NULL;
+ }
+
+ if (is_chap_and_disconnect_now)
+ {
+ // Disconnect immediately if it fails to user authentication at least once in the CHAP authentication protocol
+ Debug("Disconnecting because CHAP failed.\n");
+ SleepThread(300);
+ return NULL;
+ }
+ }
+ }
+ else
+ {
+ // Ignore in the case of the other packets
+ FreePPPPacket(pp);
+ }
+ }
+
+ // Packet retransmission
+ if (req != NULL)
+ {
+ if (now >= next_resend)
+ {
+ next_resend = now + PPP_PACKET_RESEND_INTERVAL;
+
+ if (PPPSendPacket(p, req) == false)
+ {
+ return NULL;
+ }
+ }
+ }
+
+ if (req == NULL)
+ {
+ giveup_tick = now + (UINT64)PPP_PACKET_RECV_TIMEOUT;
+ }
+
+ // Time-out decision
+ if (now >= giveup_tick)
+ {
+ PPPLog(p, "LP_CONTROL_TIMEOUT");
+ return NULL;
+ }
+
+ // Wait
+ if (req != NULL)
+ {
+ interval = MIN((UINT)(giveup_tick - now), (UINT)(next_resend - now));
+ }
+ else
+ {
+ interval = (UINT)(giveup_tick - now);
+ }
+
+ if (finish_when_all_lcp_acked && p->ClientLCPOptionDetermined)
+ {
+ return NULL;
+ }
+
+ Wait(p->TubeRecv->Event, interval);
+ }
+}
+
+// Store the last packet in the session (to be read the next time)
+void PPPStoreLastPacket(PPP_SESSION *p, PPP_PACKET *pp)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ if (p->LastStoredPacket != NULL)
+ {
+ FreePPPPacket(p->LastStoredPacket);
+ }
+
+ p->LastStoredPacket = pp;
+}
+
+// Receive a PPP communication packet
+PPP_PACKET *PPPRecvPacketForCommunication(PPP_SESSION *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ if (p->LastStoredPacket != NULL)
+ {
+ PPP_PACKET *pp = p->LastStoredPacket;
+ p->LastStoredPacket = NULL;
+ return pp;
+ }
+
+ return PPPRecvPacketWithLowLayerProcessing(p, true);
+}
+
+// Receive a PPP packet (Also performs low layer processing)
+PPP_PACKET *PPPRecvPacketWithLowLayerProcessing(PPP_SESSION *p, bool async)
+{
+ PPP_PACKET *pp = NULL;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+LABEL_LOOP:
+ pp = PPPRecvPacket(p, async);
+ if (pp == NULL)
+ {
+ return NULL;
+ }
+
+ if (PPP_IS_SUPPORTED_PROTOCOL(pp->Protocol) == false)
+ {
+ // Unsupported algorithm
+ PPP_PACKET *pp2 = ZeroMalloc(sizeof(PPP_PACKET));
+ BUF *buf;
+ UCHAR c;
+ USHORT us;
+
+ pp2->Protocol = PPP_PROTOCOL_LCP;
+ pp2->IsControl = false;
+
+ buf = NewBuf();
+
+ // Code
+ c = PPP_LCP_CODE_PROTOCOL_REJECT;
+ WriteBuf(buf, &c, 1);
+
+ // ID
+ c = p->NextId++;
+ WriteBuf(buf, &c, 1);
+
+ // Length
+ us = Endian16(pp->DataSize + 6);
+ WriteBuf(buf, &us, 2);
+
+ // Rejected Protocol
+ us = Endian16(pp->Protocol);
+ WriteBuf(buf, &us, 2);
+
+ // Packet Data
+ WriteBuf(buf, pp->Data, pp->DataSize);
+
+ pp2->Data = Clone(buf->Buf, buf->Size);
+ pp2->DataSize = buf->Size;
+
+ FreePPPPacket(pp);
+
+ FreeBuf(buf);
+
+ if (PPPSendPacket(p, pp2) == false)
+ {
+ FreePPPPacket(pp2);
+ return NULL;
+ }
+
+ FreePPPPacket(pp2);
+ goto LABEL_LOOP;
+ }
+
+ if (pp->IsControl && pp->Protocol == PPP_PROTOCOL_LCP)
+ {
+ if (pp->Lcp->Code == PPP_LCP_CODE_ECHO_REQUEST)
+ {
+ // Immediately return the echo response to the echo request
+ PPP_PACKET *pp2 = ZeroMalloc(sizeof(PPP_PACKET));
+
+ pp2->IsControl = true;
+ pp2->Protocol = PPP_PROTOCOL_LCP;
+ pp2->Lcp = NewPPPLCP(PPP_LCP_CODE_ECHO_RESPONSE, pp->Lcp->Id);
+ pp2->Lcp->Data = Clone(pp->Lcp->Data, pp->Lcp->DataSize);
+ pp2->Lcp->DataSize = pp->Lcp->DataSize;
+
+ FreePPPPacket(pp);
+
+ if (PPPSendPacket(p, pp2) == false)
+ {
+ FreePPPPacket(pp2);
+ return NULL;
+ }
+
+ FreePPPPacket(pp2);
+ goto LABEL_LOOP;
+ }
+ else if (pp->Lcp->Code == PPP_LCP_CODE_ECHO_RESPONSE)
+ {
+ // Ignore the Echo response packet
+ FreePPPPacket(pp);
+ goto LABEL_LOOP;
+ }
+ else if (pp->Lcp->Code == PPP_LCP_CODE_DROP)
+ {
+ // Ignore the Drop packet
+ FreePPPPacket(pp);
+ goto LABEL_LOOP;
+ }
+ else if (pp->Lcp->Code == PPP_LCP_CODE_IDENTIFICATION)
+ {
+ // Ignore the Identification packet
+ FreePPPPacket(pp);
+ WHERE;
+ goto LABEL_LOOP;
+ }
+ else if (pp->Lcp->Code == PPP_LCP_CODE_TERMINATE_REQ)
+ {
+ // Return the Terminate ACK If a Terminate Request has been received
+ PPP_PACKET *pp2 = ZeroMalloc(sizeof(PPP_PACKET));
+
+ pp2->IsControl = true;
+ pp2->Protocol = PPP_PROTOCOL_LCP;
+ pp2->Lcp = NewPPPLCP(PPP_LCP_CODE_TERMINATE_ACK, pp->Lcp->Id);
+ pp2->Lcp->Data = Clone(pp->Lcp->Data, pp->Lcp->DataSize);
+ pp2->Lcp->DataSize = pp->Lcp->DataSize;
+
+ p->IsTerminateReceived = true;
+
+ FreePPPPacket(pp);
+
+ if (PPPSendPacket(p, pp2) == false)
+ {
+ FreePPPPacket(pp2);
+ return NULL;
+ }
+
+ SleepThread(100);
+
+ FreePPPPacket(pp2);
+ goto LABEL_LOOP;
+ }
+ }
+
+ return pp;
+}
+
+// Receive a PPP packet
+PPP_PACKET *PPPRecvPacket(PPP_SESSION *p, bool async)
+{
+ TUBEDATA *d;
+ PPP_PACKET *pp;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+LABEL_LOOP:
+
+ if (async == false)
+ {
+ d = TubeRecvSync(p->TubeRecv, PPP_PACKET_RECV_TIMEOUT);
+ }
+ else
+ {
+ d = TubeRecvAsync(p->TubeRecv);
+ }
+
+ if (d == NULL)
+ {
+ return NULL;
+ }
+
+ pp = ParsePPPPacket(d->Data, d->DataSize);
+ FreeTubeData(d);
+
+ if (pp == NULL)
+ {
+ // A broken packet is received
+ goto LABEL_LOOP;
+ }
+
+ p->LastRecvTime = Tick64();
+
+ return pp;
+}
+
+// Send the PPP packet
+bool PPPSendPacket(PPP_SESSION *p, PPP_PACKET *pp)
+{
+ return PPPSendPacketEx(p, pp, false);
+}
+bool PPPSendPacketEx(PPP_SESSION *p, PPP_PACKET *pp, bool no_flush)
+{
+ bool ret = false;
+ BUF *b;
+ // Validate arguments
+ if (p == NULL || pp == NULL)
+ {
+ return false;
+ }
+
+ b = BuildPPPPacketData(pp);
+ if (b == NULL)
+ {
+ return false;
+ }
+
+ ret = TubeSendEx(p->TubeSend, b->Buf, b->Size, NULL, no_flush);
+
+ if (no_flush)
+ {
+ AddTubeToFlushList(p->FlushList, p->TubeSend);
+ }
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Create a new PPP options
+PPP_OPTION *NewPPPOption(UCHAR type, void *data, UINT size)
+{
+ PPP_OPTION *o;
+ // Validate arguments
+ if (size != 0 && data == NULL)
+ {
+ return NULL;
+ }
+
+ o = ZeroMalloc(sizeof(PPP_OPTION));
+
+ o->Type = type;
+ Copy(o->Data, data, size);
+ o->DataSize = size;
+
+ return o;
+}
+
+// Analyse the PPP packet
+PPP_PACKET *ParsePPPPacket(void *data, UINT size)
+{
+ PPP_PACKET *pp;
+ UCHAR *buf;
+ // Validate arguments
+ if (data == NULL || size == 0)
+ {
+ return NULL;
+ }
+
+ pp = ZeroMalloc(sizeof(PPP_PACKET));
+
+ buf = (UCHAR *)data;
+
+ // Address
+ if (size < 1)
+ {
+ goto LABEL_ERROR;
+ }
+ if (buf[0] != 0xff)
+ {
+ goto LABEL_ERROR;
+ }
+ size--;
+ buf++;
+
+ // Control
+ if (size < 1)
+ {
+ goto LABEL_ERROR;
+ }
+ if (buf[0] != 0x03)
+ {
+ goto LABEL_ERROR;
+ }
+ size--;
+ buf++;
+
+ // Protocol
+ if (size < 2)
+ {
+ goto LABEL_ERROR;
+ }
+ pp->Protocol = READ_USHORT(buf);
+ size -= 2;
+ buf += 2;
+
+ if (pp->Protocol == PPP_PROTOCOL_LCP || pp->Protocol == PPP_PROTOCOL_PAP || pp->Protocol == PPP_PROTOCOL_CHAP || pp->Protocol == PPP_PROTOCOL_IPCP)
+ {
+ pp->IsControl = true;
+ }
+
+ pp->Data = Clone(buf, size);
+ pp->DataSize = size;
+
+ if (pp->IsControl)
+ {
+ pp->Lcp = ParseLCP(pp->Protocol, pp->Data, pp->DataSize);
+ if (pp->Lcp == NULL)
+ {
+ goto LABEL_ERROR;
+ }
+ }
+
+ return pp;
+
+LABEL_ERROR:
+ FreePPPPacket(pp);
+ return NULL;
+}
+
+// Build a PPP packet data
+BUF *BuildPPPPacketData(PPP_PACKET *pp)
+{
+ BUF *ret;
+ UCHAR c;
+ USHORT us;
+ // Validate arguments
+ if (pp == NULL)
+ {
+ return NULL;
+ }
+
+ ret = NewBuf();
+
+ // Address
+ c = 0xff;
+ WriteBuf(ret, &c, 1);
+
+ // Control
+ c = 0x03;
+ WriteBuf(ret, &c, 1);
+
+ // Protocol
+ us = Endian16(pp->Protocol);
+ WriteBuf(ret, &us, 2);
+
+ if (pp->IsControl)
+ {
+ // LCP
+ BUF *b = BuildLCPData(pp->Lcp);
+
+ WriteBufBuf(ret, b);
+
+ FreeBuf(b);
+ }
+ else
+ {
+ // Data
+ WriteBuf(ret, pp->Data, pp->DataSize);
+ }
+
+ SeekBuf(ret, 0, 0);
+
+ return ret;
+}
+
+// Build the LCP packet data
+BUF *BuildLCPData(PPP_LCP *c)
+{
+ BUF *b;
+ UCHAR zero = 0;
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+
+ // Code
+ WriteBuf(b, &c->Code, 1);
+
+ // ID
+ WriteBuf(b, &c->Id, 1);
+
+ // Length (to be updated later)
+ zero = 0;
+ WriteBuf(b, &zero, 1);
+ WriteBuf(b, &zero, 1);
+
+ if (c->Data == NULL)
+ {
+ // Option List
+ for (i = 0;i < LIST_NUM(c->OptionList);i++)
+ {
+ PPP_OPTION *o = LIST_DATA(c->OptionList, i);
+ UCHAR sz = o->DataSize + 2;
+
+ WriteBuf(b, &o->Type, 1);
+ WriteBuf(b, &sz, 1);
+
+ WriteBuf(b, o->Data, o->DataSize);
+ }
+ }
+ else
+ {
+ // Data
+ WriteBuf(b, c->Data, c->DataSize);
+ }
+
+ SeekBuf(b, 0, 0);
+
+ // Update Length
+ WRITE_USHORT(((UCHAR *)b->Buf) + 2, b->Size);
+
+ return b;
+}
+
+// Analyse the LCP data
+PPP_LCP *ParseLCP(USHORT protocol, void *data, UINT size)
+{
+ UCHAR *buf;
+ PPP_LCP *c;
+ USHORT len;
+ bool has_option_list = false;
+ // Validate arguments
+ if (data == NULL || size == 0)
+ {
+ return NULL;
+ }
+
+ buf = (UCHAR *)data;
+ c = ZeroMalloc(sizeof(PPP_LCP));
+
+ c->OptionList = NewListFast(NULL);
+
+ // Code
+ if (size < 1)
+ {
+ goto LABEL_ERROR;
+ }
+ c->Code = buf[0];
+ buf++;
+ size--;
+
+ // ID
+ if (size < 1)
+ {
+ goto LABEL_ERROR;
+ }
+ c->Id = buf[0];
+ buf++;
+ size--;
+
+ // Length
+ if (size < 2)
+ {
+ goto LABEL_ERROR;
+ }
+ len = READ_USHORT(buf);
+ if (len < 4)
+ {
+ goto LABEL_ERROR;
+ }
+ len -= 4;
+ buf += 2;
+ size -= 2;
+
+ // Options or Data
+ if (size < len)
+ {
+ goto LABEL_ERROR;
+ }
+
+ has_option_list = PPP_CODE_IS_WITH_OPTION_LIST(protocol, c->Code);
+
+ if (has_option_list == false)
+ {
+ c->Data = Clone(buf, size);
+ c->DataSize = size;
+ }
+ else
+ {
+ // Option List
+ while (len >= 1)
+ {
+ PPP_OPTION o;
+
+ Zero(&o, sizeof(o));
+
+ // Type
+ if (len < 1)
+ {
+ goto LABEL_ERROR;
+ }
+ o.Type = buf[0];
+ buf++;
+ len--;
+
+ // Length
+ if (len < 1)
+ {
+ goto LABEL_ERROR;
+ }
+ o.DataSize = buf[0];
+ if (o.DataSize < 2)
+ {
+ goto LABEL_ERROR;
+ }
+ o.DataSize -= 2;
+ buf++;
+ len--;
+
+ // Data
+ if (len < o.DataSize)
+ {
+ goto LABEL_ERROR;
+ }
+ Copy(o.Data, buf, o.DataSize);
+ buf += o.DataSize;
+ len -= o.DataSize;
+
+ Add(c->OptionList, Clone(&o, sizeof(o)));
+ }
+ }
+
+ return c;
+
+LABEL_ERROR:
+ FreePPPLCP(c);
+ return NULL;
+}
+
+// Release the PPP packet
+void FreePPPPacket(PPP_PACKET *pp)
+{
+ FreePPPPacketEx(pp, false);
+}
+void FreePPPPacketEx(PPP_PACKET *pp, bool no_free_struct)
+{
+ // Validate arguments
+ if (pp == NULL)
+ {
+ return;
+ }
+
+ FreePPPLCP(pp->Lcp);
+
+ Free(pp->Data);
+
+ if (no_free_struct == false)
+ {
+ Free(pp);
+ }
+}
+
+// Release the PPP session
+void FreePPPSession(PPP_SESSION *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ if (p->TubeRecv != NULL)
+ {
+ // Record the PPP disconnect reason code for L2TP
+ p->TubeRecv->IntParam1 = p->DisconnectCauseCode;
+ p->TubeRecv->IntParam2 = p->DisconnectCauseDirection;
+ }
+
+ FreeTubeFlushList(p->FlushList);
+
+ TubeDisconnect(p->TubeRecv);
+ TubeDisconnect(p->TubeSend);
+
+ ReleaseCedar(p->Cedar);
+
+ ReleaseTube(p->TubeRecv);
+ ReleaseTube(p->TubeSend);
+
+ PPPStoreLastPacket(p, NULL);
+
+ if (p->Ipc != NULL)
+ {
+ FreeIPC(p->Ipc);
+ }
+
+ Free(p);
+}
+
+// Get the option value
+PPP_OPTION *GetOptionValue(PPP_LCP *c, UCHAR type)
+{
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(c->OptionList);i++)
+ {
+ PPP_OPTION *t = LIST_DATA(c->OptionList, i);
+
+ if (t->Type == type)
+ {
+ return t;
+ }
+ }
+
+ return NULL;
+}
+
+// Create the LCP
+PPP_LCP *NewPPPLCP(UCHAR code, UCHAR id)
+{
+ PPP_LCP *c = ZeroMalloc(sizeof(PPP_LCP));
+
+ c->Code = code;
+ c->Id = id;
+ c->OptionList = NewListFast(NULL);
+
+ return c;
+}
+
+// Release the LCP
+void FreePPPLCP(PPP_LCP *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ FreePPPOptionList(c->OptionList);
+
+ Free(c->Data);
+
+ Free(c);
+}
+
+// Release the PPP options list
+void FreePPPOptionList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ PPP_OPTION *t = LIST_DATA(o, i);
+
+ Free(t);
+ }
+
+ ReleaseList(o);
+}
+
+// Create a new PPP session
+THREAD *NewPPPSession(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, TUBE *send_tube, TUBE *recv_tube, char *postfix, char *client_software_name, char *client_hostname, char *crypt_name, UINT adjust_mss)
+{
+ PPP_SESSION *p;
+ THREAD *t;
+ // Validate arguments
+ if (cedar == NULL || client_ip == NULL || server_ip == NULL || send_tube == NULL || recv_tube == NULL)
+ {
+ return NULL;
+ }
+ if (IsEmptyStr(postfix))
+ {
+ postfix = "PPP";
+ }
+ if (IsEmptyStr(crypt_name))
+ {
+ crypt_name = "";
+ }
+ if (IsEmptyStr(client_software_name))
+ {
+ client_software_name = "PPP VPN Client";
+ }
+
+ // Data structure initialization
+ p = ZeroMalloc(sizeof(PPP_SESSION));
+
+ p->EnableMSCHAPv2 = true;
+ p->AuthProtocol = PPP_PROTOCOL_PAP;
+ p->MsChapV2_ErrorCode = 691;
+
+ p->Cedar = cedar;
+ AddRef(cedar->ref);
+
+ p->AdjustMss = adjust_mss;
+
+ StrCpy(p->CryptName, sizeof(p->CryptName), crypt_name);
+
+ Copy(&p->ClientIP, client_ip, sizeof(IP));
+ p->ClientPort = client_port;
+
+ Copy(&p->ServerIP, server_ip, sizeof(IP));
+ p->ServerPort = server_port;
+
+ p->TubeRecv = recv_tube;
+ p->TubeSend = send_tube;
+
+ AddRef(p->TubeRecv->Ref);
+ AddRef(p->TubeSend->Ref);
+
+ StrCpy(p->Postfix, sizeof(p->Postfix), postfix);
+ StrCpy(p->ClientSoftwareName, sizeof(p->ClientSoftwareName), client_software_name);
+
+ if (IsEmptyStr(client_hostname))
+ {
+ IPToStr(p->ClientHostname, sizeof(p->ClientHostname), client_ip);
+ }
+ else
+ {
+ StrCpy(p->ClientHostname, sizeof(p->ClientHostname), client_hostname);
+ }
+
+ p->FlushList = NewTubeFlushList();
+
+ // Thread creation
+ t = NewThread(PPPThread, p);
+
+ return t;
+}
+
+// Generate the NT hash of the password
+void GenerateNtPasswordHash(UCHAR *dst, char *password)
+{
+ UCHAR *tmp;
+ UINT tmp_size;
+ UINT i, len;
+ // Validate arguments
+ if (dst == NULL || password == NULL)
+ {
+ return;
+ }
+
+ // Generate a Unicode password
+ len = StrLen(password);
+ tmp_size = len * 2;
+
+ tmp = ZeroMalloc(tmp_size);
+
+ for (i = 0;i < len;i++)
+ {
+ tmp[i * 2] = password[i];
+ }
+
+ // Hashing
+ HashMd4(dst, tmp, tmp_size);
+
+ Free(tmp);
+}
+
+// Generate the MS-CHAPv2 server-side challenge
+void MsChapV2Server_GenerateChallenge(UCHAR *dst)
+{
+ // Validate arguments
+ if (dst == NULL)
+ {
+ return;
+ }
+
+ Rand(dst, 16);
+}
+
+// Generate the MS-CHAPv2 client-side challenge
+void MsChapV2Client_GenerateChallenge(UCHAR *dst)
+{
+ // Validate arguments
+ if (dst == NULL)
+ {
+ return;
+ }
+
+ Rand(dst, 16);
+}
+
+// Generate a 8 bytes challenge
+void MsChapV2_GenerateChallenge8(UCHAR *dst, UCHAR *client_challenge, UCHAR *server_challenge, char *username)
+{
+ BUF *b;
+ UCHAR hash[SHA1_SIZE];
+ char username2[MAX_SIZE];
+ char domainname2[MAX_SIZE];
+ // Validate arguments
+ if (dst == NULL || client_challenge == NULL || server_challenge == NULL)
+ {
+ return;
+ }
+
+ b = NewBuf();
+
+ WriteBuf(b, client_challenge, 16);
+ WriteBuf(b, server_challenge, 16);
+
+ ParseNtUsername(username, username2, sizeof(username2), domainname2, sizeof(domainname2), true);
+
+ if (IsEmptyStr(username2) == false)
+ {
+ WriteBuf(b, username2, StrLen(username2));
+ }
+
+ HashSha1(hash, b->Buf, b->Size);
+
+ FreeBuf(b);
+
+ Copy(dst, hash, 8);
+}
+
+// Generate the MS-CHAPv2 client response
+void MsChapV2Client_GenerateResponse(UCHAR *dst, UCHAR *challenge8, UCHAR *nt_password_hash)
+{
+ UCHAR password_hash_2[21];
+ UCHAR key1[8], key2[8], key3[8];
+ // Validate arguments
+ if (dst == NULL || challenge8 == NULL || nt_password_hash == NULL)
+ {
+ return;
+ }
+
+ Zero(password_hash_2, sizeof(password_hash_2));
+ Copy(password_hash_2, nt_password_hash, 16);
+
+ Zero(key1, sizeof(key1));
+ Zero(key2, sizeof(key2));
+ Zero(key3, sizeof(key3));
+
+ Copy(key1, password_hash_2 + 0, 7);
+ Copy(key2, password_hash_2 + 7, 7);
+ Copy(key3, password_hash_2 + 14, 7);
+
+ DesEcbEncrypt(dst + 0, challenge8, key1);
+ DesEcbEncrypt(dst + 8, challenge8, key2);
+ DesEcbEncrypt(dst + 16, challenge8, key3);
+}
+
+// Generate a hash of the hash of the NT password
+void GenerateNtPasswordHashHash(UCHAR *dst_hash, UCHAR *src_hash)
+{
+ // Validate arguments
+ if (dst_hash == NULL || src_hash == NULL)
+ {
+ return;
+ }
+
+ HashMd4(dst_hash, src_hash, 16);
+}
+
+// Generate the MS-CHAPv2 server response
+void MsChapV2Server_GenerateResponse(UCHAR *dst, UCHAR *nt_password_hash_hash, UCHAR *client_response, UCHAR *challenge8)
+{
+ UCHAR digest[SHA1_SIZE];
+ BUF *b;
+ char *magic1 = "Magic server to client signing constant";
+ char *magic2 = "Pad to make it do more than one iteration";
+ // Validate arguments
+ if (dst == NULL || nt_password_hash_hash == NULL || client_response == NULL || challenge8 == NULL)
+ {
+ return;
+ }
+
+ b = NewBuf();
+ WriteBuf(b, nt_password_hash_hash, 16);
+ WriteBuf(b, client_response, 24);
+ WriteBuf(b, magic1, StrLen(magic1));
+ HashSha1(digest, b->Buf, b->Size);
+ FreeBuf(b);
+
+ b = NewBuf();
+ WriteBuf(b, digest, sizeof(digest));
+ WriteBuf(b, challenge8, 8);
+ WriteBuf(b, magic2, StrLen(magic2));
+ HashSha1(dst, b->Buf, b->Size);
+ FreeBuf(b);
+}
+
+// Verify whether the password matches one that is specified by the user in the MS-CHAPv2
+bool MsChapV2VerityPassword(IPC_MSCHAP_V2_AUTHINFO *d, char *password)
+{
+ UCHAR ntlm_hash[MD5_SIZE];
+ UCHAR challenge8[8];
+ UCHAR client_response[24];
+ // Validate arguments
+ if (d == NULL || password == NULL)
+ {
+ return false;
+ }
+
+ GenerateNtPasswordHash(ntlm_hash, password);
+ MsChapV2_GenerateChallenge8(challenge8, d->MsChapV2_ClientChallenge, d->MsChapV2_ServerChallenge, d->MsChapV2_PPPUsername);
+ MsChapV2Client_GenerateResponse(client_response, challenge8, ntlm_hash);
+
+ if (Cmp(client_response, d->MsChapV2_ClientResponse, 24) != 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Estimate the password in the brute force for the request packet of MS-CHAPv2
+char *MsChapV2DoBruteForce(IPC_MSCHAP_V2_AUTHINFO *d, LIST *password_list)
+{
+ UINT i;
+ // Validate arguments
+ if (d == NULL || password_list == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(password_list);i++)
+ {
+ char *s = LIST_DATA(password_list, i);
+ char tmp[MAX_SIZE];
+ UINT j, max;
+ UINT len;
+
+ StrCpy(tmp, sizeof(tmp), s);
+
+ len = StrLen(tmp);
+ max = Power(2, MIN(len, 9));
+
+ for (j = 0;j < max;j++)
+ {
+ SetStrCaseAccordingToBits(tmp, j);
+ if (MsChapV2VerityPassword(d, tmp))
+ {
+ return CopyStr(tmp);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_PPP.h b/src/Cedar/IPsec_PPP.h
new file mode 100644
index 00000000..1534f1de
--- /dev/null
+++ b/src/Cedar/IPsec_PPP.h
@@ -0,0 +1,311 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_PPP.h
+// Header of IPsec_PPP.c
+
+#ifndef IPSEC_PPP_H
+#define IPSEC_PPP_H
+
+
+//// Macro
+#define PPP_LCP_CODE_IS_NEGATIVE(c) ((c) == PPP_LCP_CODE_NAK || (c) == PPP_LCP_CODE_REJECT || (c) == PPP_LCP_CODE_CODE_REJECT || (c) == PPP_LCP_CODE_PROTOCOL_REJECT)
+#define PPP_LCP_CODE_IS_REQUEST(c) ((c) == PPP_LCP_CODE_REQ)
+#define PPP_LCP_CODE_IS_RESPONSE(c) ((c) == PPP_LCP_CODE_ACK || (c) == PPP_LCP_CODE_NAK || (c) == PPP_LCP_CODE_REJECT || (c) == PPP_LCP_CODE_PROTOCOL_REJECT)
+#define PPP_LCP_CODE_IS_WITH_OPTION_LIST(c) ((c) == PPP_LCP_CODE_REQ || (c) == PPP_LCP_CODE_ACK || (c) == PPP_LCP_CODE_NAK)
+
+#define PPP_PAP_CODE_IS_REQUEST(c) ((c) == PPP_PAP_CODE_REQ)
+#define PPP_PAP_CODE_IS_RESPONSE(c) ((c) == PPP_PAP_CODE_ACK || (c) == PPP_PAP_CODE_NAK)
+
+#define PPP_CODE_IS_RESPONSE(protocol, c) ((((protocol) == PPP_PROTOCOL_LCP || (protocol) == PPP_PROTOCOL_IPCP) && PPP_LCP_CODE_IS_RESPONSE(c)) || (((protocol) == PPP_PROTOCOL_PAP) && PPP_PAP_CODE_IS_RESPONSE(c)))
+#define PPP_CODE_IS_REQUEST(protocol, c) ((((protocol) == PPP_PROTOCOL_LCP || (protocol) == PPP_PROTOCOL_IPCP) && PPP_LCP_CODE_IS_REQUEST(c)) || (((protocol) == PPP_PROTOCOL_PAP) && PPP_PAP_CODE_IS_REQUEST(c)) || ((protocol) == PPP_PROTOCOL_CHAP))
+#define PPP_CODE_IS_WITH_OPTION_LIST(protocol, c) ((((protocol) == PPP_PROTOCOL_LCP || (protocol) == PPP_PROTOCOL_IPCP) && PPP_LCP_CODE_IS_WITH_OPTION_LIST(c)) || false)
+
+#define PPP_IS_SUPPORTED_PROTOCOL(p) ((p) == PPP_PROTOCOL_LCP || (p) == PPP_PROTOCOL_PAP || (p) == PPP_PROTOCOL_CHAP || (p) == PPP_PROTOCOL_IPCP || (p) == PPP_PROTOCOL_IP)
+
+
+//// Constants
+
+// Time-out value
+#define PPP_PACKET_RECV_TIMEOUT 10000 // Timeout until the next packet is received
+#define PPP_PACKET_RESEND_INTERVAL 1000 // Retransmission interval of the last packet
+#define PPP_TERMINATE_TIMEOUT 2000 // Timeout value to complete disconnection after requesting to disconnect in the PPP
+#define PPP_ECHO_SEND_INTERVAL 4792 // Transmission interval of PPP Echo Request
+#define PPP_DATA_TIMEOUT (20 * 1000) // Communication time-out
+
+// MRU
+#define PPP_MRU_DEFAULT 1500 // Default value
+#define PPP_MRU_MIN 100 // Minimum value
+#define PPP_MRU_MAX 1500 // Maximum value
+
+// PPP protocol (for control)
+#define PPP_PROTOCOL_LCP 0xc021
+#define PPP_PROTOCOL_PAP 0xc023
+#define PPP_PROTOCOL_IPCP 0x8021
+#define PPP_PROTOCOL_CHAP 0xc223
+
+// PPP protocol (for transfer)
+#define PPP_PROTOCOL_IP 0x0021
+
+// LCP code
+#define PPP_LCP_CODE_REQ 1
+#define PPP_LCP_CODE_ACK 2
+#define PPP_LCP_CODE_NAK 3
+#define PPP_LCP_CODE_REJECT 4
+#define PPP_LCP_CODE_TERMINATE_REQ 5
+#define PPP_LCP_CODE_TERMINATE_ACK 6
+#define PPP_LCP_CODE_CODE_REJECT 7
+#define PPP_LCP_CODE_PROTOCOL_REJECT 8
+#define PPP_LCP_CODE_ECHO_REQUEST 9
+#define PPP_LCP_CODE_ECHO_RESPONSE 10
+#define PPP_LCP_CODE_DROP 11
+#define PPP_LCP_CODE_IDENTIFICATION 12
+
+// PAP Code
+#define PPP_PAP_CODE_REQ 1
+#define PPP_PAP_CODE_ACK 2
+#define PPP_PAP_CODE_NAK 3
+
+// CHAP code
+#define PPP_CHAP_CODE_CHALLENGE 1
+#define PPP_CHAP_CODE_RESPONSE 2
+#define PPP_CHAP_CODE_SUCCESS 3
+#define PPP_CHAP_CODE_FAILURE 4
+
+// LCP Option Type
+#define PPP_LCP_OPTION_MRU 1
+#define PPP_LCP_OPTION_AUTH 3
+
+// IPCP option type
+#define PPP_IPCP_OPTION_IP 3
+#define PPP_IPCP_OPTION_DNS1 129
+#define PPP_IPCP_OPTION_DNS2 131
+#define PPP_IPCP_OPTION_WINS1 130
+#define PPP_IPCP_OPTION_WINS2 132
+
+// Authentication protocol
+#define PPP_LCP_AUTH_PAP PPP_PROTOCOL_PAP
+#define PPP_LCP_AUTH_CHAP PPP_PROTOCOL_CHAP
+
+// Algorithm of CHAP
+#define PPP_CHAP_ALG_MS_CHAP_V2 0x81
+
+
+//// Type
+
+// IP options used in the PPP
+struct PPP_IPOPTION
+{
+ IP IpAddress; // IP address
+ IP DnsServer1, DnsServer2; // DNS server address
+ IP WinsServer1, WinsServer2; // WINS server address
+};
+
+// PPP packet
+struct PPP_PACKET
+{
+ USHORT Protocol; // Protocol
+ bool IsControl; // Whether or not the control packet
+ PPP_LCP *Lcp; // LCP packet data
+ UINT DataSize; // Data size
+ void *Data; // Data body
+};
+
+// PPP LCP packet
+struct PPP_LCP
+{
+ UCHAR Code; // Code
+ UCHAR Id; // ID
+ UCHAR MagicNumber[4]; // Magic number
+ LIST *OptionList; // PPP options list
+ void *Data; // Data
+ UINT DataSize; // Data size
+};
+
+// PPP Options
+struct PPP_OPTION
+{
+ UCHAR Type; // Type of option
+ UINT DataSize; // Data size
+ UCHAR Data[254]; // Data
+ bool IsSupported; // Flag of whether it is supported
+ bool IsAccepted; // Flag for whether accepted
+ UCHAR AltData[254]; // Alternate data when it isn't accepted
+ UINT AltDataSize; // Alternate data size
+};
+
+// PPP session
+struct PPP_SESSION
+{
+ CEDAR *Cedar; // Cedar
+ IP ClientIP; // Client IP address
+ UINT ClientPort; // Client port
+ IP ServerIP; // Server IP address
+ UINT ServerPort; // Server port
+ TUBE *TubeSend; // Sending tube
+ TUBE *TubeRecv; // Receiving tube
+ UCHAR NextId; // ID to be used next
+ UINT Mru1; // MRU (server -> client)
+ UINT Mru2; // MRU (client -> server)
+ LIST *RecvPacketList; // Received packet list
+ PPP_PACKET *LastStoredPacket; // Packet that is stored at the last
+ bool IsTerminateReceived; // Whether a Terminate has been received
+ UINT DisconnectCauseCode; // L2TP disconnect cause code
+ UINT DisconnectCauseDirection; // L2TP disconnect cause direction code
+ IPC *Ipc; // IPC
+ bool ClientLCPOptionDetermined; // LCP option from the client has been determined
+ char Postfix[MAX_SIZE]; // Postfix of the session name
+ char ClientHostname[MAX_SIZE]; // Client host name
+ char ClientSoftwareName[MAX_SIZE]; // Client software name
+ UINT64 NextEchoSendTime; // Time to send Echo Request next
+ UINT64 LastRecvTime; // Time which the data has been received last
+ DHCP_OPTION_LIST ClientAddressOption; // Client address option
+ bool DhcpIpAllocTried; // Whether the request for an IP address is already attempted by DHCP
+ bool DhcpIpInformTried; // Whether the acquirement for an IP information is already attempted by DHCP
+ bool DhcpAllocated; // IP address is assigned by DHCP
+ bool UseStaticIPAddress; // Use a static IP address that is specified by the client
+ UINT64 DhcpRenewInterval; // DHCP update interval
+ UINT64 DhcpNextRenewTime; // DHCP renewal time of the next
+ char CryptName[MAX_SIZE]; // Cipher algorithm name
+ UINT AdjustMss; // MSS value
+ TUBE_FLUSH_LIST *FlushList; // Tube Flush List
+ bool EnableMSCHAPv2; // Enable the MS-CHAP v2
+ USHORT AuthProtocol; // Authentication protocol
+ bool AuthOk; // Flag for whether the authentication was successful
+ UCHAR MsChapV2_ServerChallenge[16]; // MS-CHAPv2 Server Challenge
+ UCHAR MsChapV2_ClientChallenge[16]; // MS-CHAPv2 Client Challenge
+ UCHAR MsChapV2_ClientResponse[24]; // MS-CHAPv2 Client Response
+ UCHAR MsChapV2_ServerResponse[20]; // MS-CHAPv2 Server Response
+ UINT MsChapV2_ErrorCode; // Authentication failure error code of MS-CHAPv2
+};
+
+// Function prototype
+THREAD *NewPPPSession(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, TUBE *send_tube, TUBE *recv_tube, char *postfix, char *client_software_name, char *client_hostname, char *crypt_name, UINT adjust_mss);
+void PPPThread(THREAD *thread, void *param);
+void FreePPPSession(PPP_SESSION *p);
+void FreePPPOptionList(LIST *o);
+void FreePPPLCP(PPP_LCP *c);
+PPP_LCP *NewPPPLCP(UCHAR code, UCHAR id);
+PPP_LCP *ParseLCP(USHORT protocol, void *data, UINT size);
+BUF *BuildLCPData(PPP_LCP *c);
+PPP_OPTION *GetOptionValue(PPP_LCP *c, UCHAR type);
+PPP_PACKET *ParsePPPPacket(void *data, UINT size);
+void FreePPPPacket(PPP_PACKET *pp);
+void FreePPPPacketEx(PPP_PACKET *pp, bool no_free_struct);
+BUF *BuildPPPPacketData(PPP_PACKET *pp);
+PPP_OPTION *NewPPPOption(UCHAR type, void *data, UINT size);
+bool PPPSendPacket(PPP_SESSION *p, PPP_PACKET *pp);
+bool PPPSendPacketEx(PPP_SESSION *p, PPP_PACKET *pp, bool no_flush);
+PPP_PACKET *PPPRecvPacket(PPP_SESSION *p, bool async);
+PPP_PACKET *PPPRecvPacketWithLowLayerProcessing(PPP_SESSION *p, bool async);
+PPP_PACKET *PPPRecvPacketForCommunication(PPP_SESSION *p);
+void PPPStoreLastPacket(PPP_SESSION *p, PPP_PACKET *pp);
+void PPPCleanTerminate(PPP_SESSION *p);
+bool PPPGetIPOptionFromLCP(PPP_IPOPTION *o, PPP_LCP *c);
+bool PPPSetIPOptionToLCP(PPP_IPOPTION *o, PPP_LCP *c, bool only_modify);
+bool PPPGetIPAddressValueFromLCP(PPP_LCP *c, UINT type, IP *ip);
+bool PPPSetIPAddressValueToLCP(PPP_LCP *c, UINT type, IP *ip, bool only_modify);
+
+bool PPPSendRequest(PPP_SESSION *p, USHORT protocol, PPP_LCP *c);
+USHORT PPPContinueCurrentProtocolRequestListening(PPP_SESSION *p, USHORT protocol);
+bool PPPContinueUntilFinishAllLCPOptionRequestsDetermined(PPP_SESSION *p);
+PPP_PACKET *PPPRecvResponsePacket(PPP_SESSION *p, PPP_PACKET *req, USHORT expected_protocol, USHORT *received_protocol, bool finish_when_all_lcp_acked);
+PPP_PACKET *PPPProcessRequestPacket(PPP_SESSION *p, PPP_PACKET *req);
+void PPPSendEchoRequest(PPP_SESSION *p);
+bool PPPParseUsername(CEDAR *cedar, char *src, ETHERIP_ID *dst);
+bool IsHubExistsWithLock(CEDAR *cedar, char *hubname);
+
+void GenerateNtPasswordHash(UCHAR *dst, char *password);
+void GenerateNtPasswordHashHash(UCHAR *dst_hash, UCHAR *src_hash);
+void MsChapV2Server_GenerateChallenge(UCHAR *dst);
+void MsChapV2Client_GenerateChallenge(UCHAR *dst);
+void MsChapV2_GenerateChallenge8(UCHAR *dst, UCHAR *client_challenge, UCHAR *server_challenge, char *username);
+void MsChapV2Client_GenerateResponse(UCHAR *dst, UCHAR *challenge8, UCHAR *nt_password_hash);
+void MsChapV2Server_GenerateResponse(UCHAR *dst, UCHAR *nt_password_hash_hash, UCHAR *client_response, UCHAR *challenge8);
+bool MsChapV2VerityPassword(IPC_MSCHAP_V2_AUTHINFO *d, char *password);
+char *MsChapV2DoBruteForce(IPC_MSCHAP_V2_AUTHINFO *d, LIST *password_list);
+
+#endif // IPSEC_PPP_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_Win7.c b/src/Cedar/IPsec_Win7.c
new file mode 100644
index 00000000..e04a81e2
--- /dev/null
+++ b/src/Cedar/IPsec_Win7.c
@@ -0,0 +1,530 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_Win7.c
+// Initialize the helper module for Windows 7 / Windows 8 / Windows Vista / Windows Server 2008 / Windows Server 2008 R2 / Windows Server 2012
+
+#include
+
+#ifdef WIN32
+
+#define _WIN32_WINNT 0x0600
+#define WINVER 0x0600
+#define INITGUID
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "IPsec_Win7Inner.h"
+#include
+
+static IPSEC_WIN7_FUNCTIONS *api = NULL;
+static HINSTANCE hDll = NULL;
+
+
+// Initialize the IPsec helper module for Windows 7
+IPSEC_WIN7 *IPsecWin7Init()
+{
+ IPSEC_WIN7 *w;
+ FWPM_SESSION0 session;
+ UINT ret;
+ FWPM_FILTER0 filter;
+ UINT64 weight = MAXUINT64;
+
+ Debug("IPsecWin7Init()\n");
+
+ if (MsIsVista() == false)
+ {
+ return NULL;
+ }
+
+ if (MsIsAdmin() == false)
+ {
+ return NULL;
+ }
+
+ if (IPsecWin7InitApi() == false)
+ {
+ return NULL;
+ }
+
+ // Driver Initialization
+ if (IPsecWin7InitDriver() == false)
+ {
+ return NULL;
+ }
+
+ // Open the WFP (Dynamic Session)
+ Zero(&session, sizeof(session));
+ session.flags = FWPM_SESSION_FLAG_DYNAMIC;
+
+ w = ZeroMalloc(sizeof(IPSEC_WIN7));
+ ret = api->FwpmEngineOpen0(NULL, RPC_C_AUTHN_DEFAULT, NULL, &session, &w->hEngine);
+ if (ret)
+ {
+ Debug("FwpmEngineOpen0 Failed.\n");
+ IPsecWin7Free(w);
+ return NULL;
+ }
+
+ // Create the Filter (IPv4)
+ Zero(&filter, sizeof(filter));
+ filter.flags = FWPM_FILTER_FLAG_PERMIT_IF_CALLOUT_UNREGISTERED;
+ filter.layerKey = FWPM_LAYER_INBOUND_IPPACKET_V4;
+ filter.weight.type = FWP_UINT64;
+ filter.weight.uint64 = &weight;
+ filter.action.type = FWP_ACTION_CALLOUT_UNKNOWN;
+ filter.action.calloutKey = GUID_WFP_CALLOUT_DRIVER_V4;
+ filter.displayData.name = IPSEC_WIN7_FILTER_TITLE_V4;
+ ret = api->FwpmFilterAdd0(w->hEngine, &filter, NULL, &w->FilterIPv4Id);
+ if (ret)
+ {
+ Debug("FwpmFilterAdd0 for IPv4 Failed: 0x%X\n", ret);
+ }
+ else
+ {
+ Debug("FwpmFilterAdd0 for IPv4 Ok.\n");
+ }
+
+ // Create the Filter (IPv6)
+ Zero(&filter, sizeof(filter));
+ filter.flags = FWPM_FILTER_FLAG_PERMIT_IF_CALLOUT_UNREGISTERED;
+ filter.layerKey = FWPM_LAYER_INBOUND_IPPACKET_V6;
+ filter.weight.type = FWP_UINT64;
+ filter.weight.uint64 = &weight;
+ filter.action.type = FWP_ACTION_CALLOUT_UNKNOWN;
+ filter.action.calloutKey = GUID_WFP_CALLOUT_DRIVER_V6;
+ filter.displayData.name = IPSEC_WIN7_FILTER_TITLE_V6;
+ ret = api->FwpmFilterAdd0(w->hEngine, &filter, NULL, &w->FilterIPv6Id);
+ if (ret)
+ {
+ Debug("FwpmFilterAdd0 for IPv6 Failed: 0x%X\n", ret);
+ }
+ else
+ {
+ Debug("FwpmFilterAdd0 for IPv6 Ok.\n");
+ }
+
+ // Open the device of the driver as a file
+ w->hDriverFile = CreateFileA(WFP_DEVICE_FILE_NAME, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (w->hDriverFile == NULL || w->hDriverFile == INVALID_HANDLE_VALUE)
+ {
+ Debug("CreateFileA(\"%s\") Failed.\n", WFP_DEVICE_FILE_NAME);
+ IPsecWin7Free(w);
+ return NULL;
+ }
+
+ IPsecWin7UpdateHostIPAddressList(w);
+
+ Debug("IPsecWin7Init() Ok.\n");
+
+ return w;
+}
+
+// Update the IP address list of the host
+void IPsecWin7UpdateHostIPAddressList(IPSEC_WIN7 *w)
+{
+ LIST *o;
+ UINT i;
+ BUF *buf;
+ UINT retsize;
+ // Validate arguments
+ if (w == NULL)
+ {
+ return;
+ }
+
+ o = GetHostIPAddressList();
+ if (o == NULL)
+ {
+ return;
+ }
+
+ buf = NewBuf();
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IP *ip = LIST_DATA(o, i);
+ WFP_LOCAL_IP a;
+
+ Zero(&a, sizeof(a));
+
+ // Exclude any IPs or localhost IP
+ if (IsZeroIP(ip) == false && IsLocalHostIP(ip) == false)
+ {
+ if (IsIP4(ip))
+ {
+ a.IpVersion = 4;
+ Copy(a.IpAddress.IPv4Address, ip->addr, 4);
+ }
+ else
+ {
+ a.IpVersion = 6;
+ Copy(a.IpAddress.IPv6Address, ip->ipv6_addr, 16);
+ }
+
+ WriteBuf(buf, &a, sizeof(WFP_LOCAL_IP));
+ }
+ }
+
+ if (WriteFile(w->hDriverFile, buf->Buf, buf->Size, &retsize, NULL) == false)
+ {
+ Debug("WriteFile to the driver failed. %u\n", GetLastError());
+ }
+
+ FreeHostIPAddressList(o);
+
+ FreeBuf(buf);
+}
+
+// Release the module
+void IPsecWin7Free(IPSEC_WIN7 *w)
+{
+ // Validate arguments
+ if (w == NULL)
+ {
+ return;
+ }
+
+ if (w->hEngine != NULL)
+ {
+ api->FwpmEngineClose0(w->hEngine);
+ }
+
+ if (w->hDriverFile != NULL && w->hDriverFile != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(w->hDriverFile);
+ }
+
+ Free(w);
+}
+
+// Initialize and start the driver
+bool IPsecWin7InitDriver()
+{
+ bool ret;
+ void *lock = MsInitGlobalLock("IPsecWin7InitDriver", false);
+ void *p = MsDisableWow64FileSystemRedirection();
+
+ MsGlobalLock(lock);
+ {
+ ret = IPsecWin7InitDriverInner();
+ }
+ MsGlobalUnlock(lock);
+
+ MsFreeGlobalLock(lock);
+
+ MsRestoreWow64FileSystemRedirection(p);
+
+ Debug("IPsecWin7InitDriver: %u\n", ret);
+
+ return ret;
+}
+bool IPsecWin7InitDriverInner()
+{
+ char sys_filename[MAX_PATH];
+ bool install_driver = true;
+ HANDLE hEngine;
+ UINT ret;
+ FWPM_SESSION0 session;
+ UINT id;
+ FWPM_CALLOUT0 callout;
+
+ Format(sys_filename, sizeof(sys_filename), IPSEC_WIN7_DST_SYS, MsGetSystem32Dir());
+
+ if (IsFileExists(sys_filename) && MsIsServiceInstalled(IPSEC_WIN7_DRIVER_NAME))
+ {
+ if (GetCurrentIPsecWin7DriverBuild() >= CEDAR_BUILD)
+ {
+ // Not to install since the latest version has been already installed
+ install_driver = false;
+ }
+ }
+
+ if (install_driver)
+ {
+ char *src_filename = IPSEC_WIN7_SRC_SYS_X86;
+ if (MsIsX64())
+ {
+ src_filename = IPSEC_WIN7_SRC_SYS_X64;
+ }
+
+ // Copy the driver
+ if (FileCopy(src_filename, sys_filename) == false)
+ {
+ Debug("%s copy failed.\n", sys_filename);
+ return false;
+ }
+ Debug("%s copied.\n", sys_filename);
+
+ // Set the build number
+ SetCurrentIPsecWin7DriverBuild();
+ }
+
+ // Get whether the device drivers is already installed
+ if (MsIsServiceInstalled(IPSEC_WIN7_DRIVER_NAME) == false)
+ {
+ wchar_t sys_filename_w[MAX_PATH];
+
+ StrToUni(sys_filename_w, sizeof(sys_filename_w), sys_filename);
+
+ // Run a new installation
+ if (MsInstallDeviceDriverW(IPSEC_WIN7_DRIVER_NAME, IPSEC_WIN7_DRIVER_TITLE,
+ sys_filename_w, NULL) == false)
+ {
+ // Installation failed
+ Debug("MsInstallDeviceDriverW failed.\n");
+ return false;
+ }
+ }
+
+ // Start if the device driver is stopped
+ if (MsIsServiceRunning(IPSEC_WIN7_DRIVER_NAME) == false)
+ {
+ if (MsStartService(IPSEC_WIN7_DRIVER_NAME) == false)
+ {
+ // Start failure
+ Debug("MsStartService failed.\n");
+ return false;
+ }
+
+ Debug("%s service started.\n", IPSEC_WIN7_DRIVER_NAME);
+ }
+ else
+ {
+ Debug("%s service was already started.\n", IPSEC_WIN7_DRIVER_NAME);
+ }
+
+ // Open the WFP
+ Zero(&session, sizeof(session));
+
+ ret = api->FwpmEngineOpen0(NULL, RPC_C_AUTHN_DEFAULT, NULL, &session, &hEngine);
+ if (ret)
+ {
+ Debug("FwpmEngineOpen0 failed.\n");
+ return false;
+ }
+
+ // Create the Callout Driver (IPv4)
+ Zero(&callout, sizeof(callout));
+ callout.calloutKey = GUID_WFP_CALLOUT_DRIVER_V4;
+ callout.applicableLayer = FWPM_LAYER_INBOUND_IPPACKET_V4;
+ callout.displayData.name = IPSEC_WIN7_DRIVER_TITLE_V4;
+ ret = api->FwpmCalloutAdd0(hEngine, &callout, NULL, &id);
+ if (ret)
+ {
+ Debug("FwpmCalloutAdd0 for IPv4 Failed: 0x%X\n", ret);
+ }
+ else
+ {
+ Debug("FwpmCalloutAdd0 for IPv4 Ok.\n");
+ }
+
+ // Create the Callout Driver (IPv6)
+ Zero(&callout, sizeof(callout));
+ callout.calloutKey = GUID_WFP_CALLOUT_DRIVER_V6;
+ callout.applicableLayer = FWPM_LAYER_INBOUND_IPPACKET_V6;
+ callout.displayData.name = IPSEC_WIN7_DRIVER_TITLE_V6;
+ ret = api->FwpmCalloutAdd0(hEngine, &callout, NULL, &id);
+ if (ret)
+ {
+ Debug("FwpmCalloutAdd0 for IPv6 Failed: 0x%X\n", ret);
+ }
+ else
+ {
+ Debug("FwpmCalloutAdd0 for IPv6 Ok.\n");
+ }
+
+ api->FwpmEngineClose0(hEngine);
+
+ return true;
+}
+
+// Write the build number of the current driver
+void SetCurrentIPsecWin7DriverBuild()
+{
+ MsRegWriteInt(REG_LOCAL_MACHINE, IPSEC_WIN7_DRIVER_REGKEY, IPSEC_WIN7_DRIVER_BUILDNUMBER, CEDAR_BUILD);
+}
+
+// Get the build number of the current driver
+UINT GetCurrentIPsecWin7DriverBuild()
+{
+ return MsRegReadInt(REG_LOCAL_MACHINE, IPSEC_WIN7_DRIVER_REGKEY, IPSEC_WIN7_DRIVER_BUILDNUMBER);
+}
+
+// Initialization of the API
+bool IPsecWin7InitApi()
+{
+ if (api != NULL)
+ {
+ return true;
+ }
+
+ if (hDll == NULL)
+ {
+ hDll = LoadLibraryA("FWPUCLNT.DLL");
+ }
+
+ if (hDll == NULL)
+ {
+ return false;
+ }
+
+ api = malloc(sizeof(IPSEC_WIN7_FUNCTIONS));
+ Zero(api, sizeof(IPSEC_WIN7_FUNCTIONS));
+
+ api->FwpmEngineOpen0 =
+ (DWORD (__stdcall *)(const wchar_t *,UINT32,SEC_WINNT_AUTH_IDENTITY_W *,const FWPM_SESSION0 *,HANDLE *))
+ GetProcAddress(hDll, "FwpmEngineOpen0");
+
+ api->FwpmEngineClose0 =
+ (DWORD (__stdcall *)(HANDLE))
+ GetProcAddress(hDll, "FwpmEngineClose0");
+
+ api->FwpmFreeMemory0 =
+ (void (__stdcall *)(void **))
+ GetProcAddress(hDll, "FwpmFreeMemory0");
+
+ api->FwpmFilterAdd0 =
+ (DWORD (__stdcall *)(HANDLE,const FWPM_FILTER0 *,PSECURITY_DESCRIPTOR,UINT64 *))
+ GetProcAddress(hDll, "FwpmFilterAdd0");
+
+ api->IPsecSaContextCreate0 =
+ (DWORD (__stdcall *)(HANDLE,const IPSEC_TRAFFIC0 *,UINT64 *,UINT64 *))
+ GetProcAddress(hDll, "IPsecSaContextCreate0");
+
+ api->IPsecSaContextGetSpi0 =
+ (DWORD (__stdcall *)(HANDLE,UINT64,const IPSEC_GETSPI0 *,IPSEC_SA_SPI *))
+ GetProcAddress(hDll, "IPsecSaContextGetSpi0");
+
+ api->IPsecSaContextAddInbound0 =
+ (DWORD (__stdcall *)(HANDLE,UINT64,const IPSEC_SA_BUNDLE0 *))
+ GetProcAddress(hDll, "IPsecSaContextAddInbound0");
+
+ api->IPsecSaContextAddOutbound0 =
+ (DWORD (__stdcall *)(HANDLE,UINT64,const IPSEC_SA_BUNDLE0 *))
+ GetProcAddress(hDll, "IPsecSaContextAddOutbound0");
+
+ api->FwpmCalloutAdd0 =
+ (DWORD (__stdcall *)(HANDLE,const FWPM_CALLOUT0 *,PSECURITY_DESCRIPTOR,UINT32 *))
+ GetProcAddress(hDll, "FwpmCalloutAdd0");
+
+ if (api->FwpmEngineOpen0 == NULL ||
+ api->FwpmEngineClose0 == NULL ||
+ api->FwpmFreeMemory0 == NULL ||
+ api->FwpmFilterAdd0 == NULL ||
+ api->IPsecSaContextCreate0 == NULL ||
+ api->IPsecSaContextGetSpi0 == NULL ||
+ api->IPsecSaContextAddInbound0 == NULL ||
+ api->IPsecSaContextAddOutbound0 == NULL ||
+ api->FwpmCalloutAdd0 == NULL)
+ {
+ free(api);
+ api = NULL;
+ return false;
+ }
+
+ return true;
+}
+
+#endif // WIN32
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_Win7.h b/src/Cedar/IPsec_Win7.h
new file mode 100644
index 00000000..35a8b664
--- /dev/null
+++ b/src/Cedar/IPsec_Win7.h
@@ -0,0 +1,121 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_Win7.h
+// Header of IPsec_Win7.c
+
+#ifndef IPSEC_WIN7_H
+#define IPSEC_WIN7_H
+
+// Constants
+#define IPSEC_WIN7_SRC_SYS_X86 "|pxwfp_x86.sys"
+#define IPSEC_WIN7_SRC_SYS_X64 "|pxwfp_x64.sys"
+#define IPSEC_WIN7_DST_SYS "%s\\drivers\\pxwfp.sys"
+
+#define IPSEC_WIN7_DRIVER_NAME "pxwfp"
+#define IPSEC_WIN7_DRIVER_TITLE L"SoftEther PacketiX VPN IPsec WFP Callout Driver"
+#define IPSEC_WIN7_DRIVER_TITLE_V4 L"SoftEther PacketiX VPN IPsec WFP Callout for IPv4"
+#define IPSEC_WIN7_DRIVER_TITLE_V6 L"SoftEther PacketiX VPN IPsec WFP Callout for IPv6"
+#define IPSEC_WIN7_FILTER_TITLE_V4 CEDAR_PRODUCT_STR_W L" VPN IPsec Filter for IPv4"
+#define IPSEC_WIN7_FILTER_TITLE_V6 CEDAR_PRODUCT_STR_W L" VPN IPsec Filter for IPv6"
+#define IPSEC_WIN7_DRIVER_REGKEY "SYSTEM\\CurrentControlSet\\services\\pxwfp"
+#define IPSEC_WIN7_DRIVER_BUILDNUMBER "CurrentInstalledBuild"
+
+
+// Function prototype
+IPSEC_WIN7 *IPsecWin7Init();
+void IPsecWin7Free(IPSEC_WIN7 *w);
+void IPsecWin7UpdateHostIPAddressList(IPSEC_WIN7 *w);
+
+bool IPsecWin7InitDriver();
+bool IPsecWin7InitDriverInner();
+UINT GetCurrentIPsecWin7DriverBuild();
+void SetCurrentIPsecWin7DriverBuild();
+bool IPsecWin7InitApi();
+
+
+#endif // IPSEC_WIN7_H
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_Win7Inner.h b/src/Cedar/IPsec_Win7Inner.h
new file mode 100644
index 00000000..b57054b1
--- /dev/null
+++ b/src/Cedar/IPsec_Win7Inner.h
@@ -0,0 +1,160 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_Win7.h
+// Internal header of IPsec_Win7.c
+
+#ifndef IPSEC_WIN7_INNER_H
+#define IPSEC_WIN7_INNER_H
+
+// API function
+typedef struct IPSEC_WIN7_FUNCTIONS
+{
+ DWORD (WINAPI *FwpmEngineOpen0)(
+ IN OPTIONAL const wchar_t* serverName,
+ IN UINT32 authnService,
+ IN OPTIONAL SEC_WINNT_AUTH_IDENTITY_W* authIdentity,
+ IN OPTIONAL const FWPM_SESSION0* session,
+ OUT HANDLE* engineHandle
+ );
+
+ DWORD (WINAPI *FwpmEngineClose0)(IN HANDLE engineHandle);
+
+ void (WINAPI *FwpmFreeMemory0)(IN OUT void** p);
+
+ DWORD (WINAPI *FwpmFilterAdd0)(
+ IN HANDLE engineHandle,
+ IN const FWPM_FILTER0* filter,
+ IN OPTIONAL PSECURITY_DESCRIPTOR sd,
+ OUT OPTIONAL UINT64* id
+ );
+
+ DWORD (WINAPI *IPsecSaContextCreate0)(
+ IN HANDLE engineHandle,
+ IN const IPSEC_TRAFFIC0* outboundTraffic,
+ OUT OPTIONAL UINT64* inboundFilterId,
+ OUT UINT64* id
+ );
+
+ DWORD (WINAPI *IPsecSaContextGetSpi0)(
+ IN HANDLE engineHandle,
+ IN UINT64 id,
+ IN const IPSEC_GETSPI0* getSpi,
+ OUT IPSEC_SA_SPI* inboundSpi
+ );
+
+ DWORD (WINAPI *IPsecSaContextAddInbound0)(
+ IN HANDLE engineHandle,
+ IN UINT64 id,
+ IN const IPSEC_SA_BUNDLE0* inboundBundle
+ );
+
+ DWORD (WINAPI *IPsecSaContextAddOutbound0)(
+ IN HANDLE engineHandle,
+ IN UINT64 id,
+ IN const IPSEC_SA_BUNDLE0* outboundBundle
+ );
+
+ DWORD (WINAPI *FwpmCalloutAdd0)(
+ IN HANDLE engineHandle,
+ IN const FWPM_CALLOUT0* callout,
+ IN OPTIONAL PSECURITY_DESCRIPTOR sd,
+ OUT OPTIONAL UINT32* id
+ );
+
+} IPSEC_WIN7_FUNCTIONS;
+
+// Instance
+struct IPSEC_WIN7
+{
+ HANDLE hEngine;
+ HANDLE hDriverFile;
+ UINT64 FilterIPv4Id, FilterIPv6Id;
+};
+
+
+#endif // IPSEC_WIN7_INNER_H
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Interop_OpenVPN.c b/src/Cedar/Interop_OpenVPN.c
new file mode 100644
index 00000000..48045333
--- /dev/null
+++ b/src/Cedar/Interop_OpenVPN.c
@@ -0,0 +1,2942 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Interop_OpenVPN.c
+// OpenVPN protocol stack
+
+#include "CedarPch.h"
+
+
+static bool g_no_openvpn_tcp = false;
+static bool g_no_openvpn_udp = false;
+
+// Ping signature of the OpenVPN protocol
+static UCHAR ping_signature[] =
+{
+ 0x2a, 0x18, 0x7b, 0xf3, 0x64, 0x1e, 0xb4, 0xcb,
+ 0x07, 0xed, 0x2d, 0x0a, 0x98, 0x1f, 0xc7, 0x48
+};
+
+// Set the OpenVPN over TCP disabling flag
+void OvsSetNoOpenVpnTcp(bool b)
+{
+ g_no_openvpn_tcp = b;
+}
+
+// Get the OpenVPN over TCP disabling flag
+bool OvsGetNoOpenVpnTcp()
+{
+ return g_no_openvpn_tcp;
+}
+
+// Set the OpenVPN over UDP disabling flag
+void OvsSetNoOpenVpnUdp(bool b)
+{
+ g_no_openvpn_udp = b;
+}
+
+// Get the OpenVPN over UDP disabling flag
+bool OvsGetNoOpenVpnUdp()
+{
+ return g_no_openvpn_udp;
+}
+
+
+// Write the OpenVPN log
+void OvsLog(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c, char *name, ...)
+{
+ wchar_t prefix[MAX_SIZE * 2];
+ wchar_t buf2[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+ if (se == NULL)
+ {
+ UniStrCpy(prefix, sizeof(prefix), _UU("LO_PREFIX_RAW"));
+ }
+ else
+ {
+ if (c == NULL)
+ {
+ UniFormat(prefix, sizeof(prefix), _UU("LO_PREFIX_SESSION"),
+ se->Id, &se->ClientIp, se->ClientPort, &se->ServerIp, se->ServerPort);
+ }
+ else
+ {
+ UniFormat(prefix, sizeof(prefix), _UU("LO_PREFIX_CHANNEL"),
+ se->Id, &se->ClientIp, se->ClientPort, &se->ServerIp, se->ServerPort,
+ c->KeyId);
+ }
+ }
+ va_start(args, name);
+ UniFormatArgs(buf2, sizeof(buf2), _UU(name), args);
+ va_end(args);
+
+ UniStrCat(prefix, sizeof(prefix), buf2);
+
+ WriteServerLog(s->Cedar, prefix);
+}
+
+// Process the received packet
+void OvsProceccRecvPacket(OPENVPN_SERVER *s, UDPPACKET *p, UINT protocol)
+{
+ OPENVPN_SESSION *se;
+ OPENVPN_PACKET *recv_packet;
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+
+ // Search for the session
+ se = OvsFindOrCreateSession(s, &p->DstIP, p->DestPort, &p->SrcIP, p->SrcPort, protocol);
+ if (se == NULL)
+ {
+ return;
+ }
+
+ // Parse the packet
+ recv_packet = OvsParsePacket(p->Data, p->Size);
+
+ if (recv_packet != NULL)
+ {
+ OPENVPN_CHANNEL *c = NULL;
+ if (recv_packet->OpCode != OPENVPN_P_DATA_V1 && recv_packet->MySessionId != 0)
+ {
+ Debug("RECV PACKET: %u %I64u\n", recv_packet->KeyId, recv_packet->MySessionId);
+ }
+ if (recv_packet->OpCode != OPENVPN_P_DATA_V1)
+ {
+ Debug(" PKT %u %u\n", recv_packet->OpCode, recv_packet->KeyId);
+ }
+
+ if (recv_packet->OpCode != OPENVPN_P_DATA_V1)
+ {
+ // Control packet
+ if (recv_packet->OpCode == OPENVPN_P_CONTROL_HARD_RESET_CLIENT_V2 ||
+ recv_packet->OpCode == OPENVPN_P_CONTROL_SOFT_RESET_V1)
+ {
+ // Connection request packet
+ if (se->Channels[recv_packet->KeyId] != NULL)
+ {
+ // Release when there is a channel data already
+ OvsFreeChannel(se->Channels[recv_packet->KeyId]);
+ se->Channels[recv_packet->KeyId] = NULL;
+ }
+
+ // Create a new channel
+ c = OvsNewChannel(se, recv_packet->KeyId);
+ if (se->ClientSessionId == 0)
+ {
+ se->ClientSessionId = recv_packet->MySessionId;
+ }
+ se->Channels[recv_packet->KeyId] = c;
+ Debug("OpenVPN New Channel :%u\n", recv_packet->KeyId);
+ OvsLog(s, se, c, "LO_NEW_CHANNEL");
+ }
+/* else if (recv_packet->OpCode == OPENVPN_P_CONTROL_SOFT_RESET_V1)
+ {
+ // Response to soft reset request packet
+ OPENVPN_PACKET *p;
+
+ p = OvsNewControlPacket(OPENVPN_P_CONTROL_SOFT_RESET_V1, recv_packet->KeyId, se->ServerSessionId,
+ 0, NULL, 0, 0, 0, NULL);
+
+ OvsSendPacketNow(s, se, p);
+
+ OvsFreePacket(p);
+ }*/
+ else
+ {
+ // Packet other than the connection request
+ if (se->Channels[recv_packet->KeyId] != NULL)
+ {
+ c = se->Channels[recv_packet->KeyId];
+ }
+ }
+
+ if (c != NULL)
+ {
+ // Delete the send packet list by looking the packet ID in the ACK list of arrived packet
+ OvsDeleteFromSendingControlPacketList(c, recv_packet->NumAck, recv_packet->AckPacketId);
+
+ if (recv_packet->OpCode != OPENVPN_P_ACK_V1)
+ {
+ // Add the Packet ID of arrived packet to the list
+ InsertIntDistinct(c->AckReplyList, recv_packet->PacketId);
+ Debug("Recv Packet ID (c=%u): %u\n", c->KeyId, recv_packet->PacketId);
+
+ if ((recv_packet->PacketId > c->MaxRecvPacketId)
+ || (recv_packet->OpCode == OPENVPN_P_CONTROL_HARD_RESET_CLIENT_V2)
+ || (recv_packet->OpCode == OPENVPN_P_CONTROL_SOFT_RESET_V1))
+ {
+ c->MaxRecvPacketId = recv_packet->PacketId;
+
+ // Process the received control packet
+ OvsProcessRecvControlPacket(s, se, c, recv_packet);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Data packet
+ if (se->Channels[recv_packet->KeyId] != NULL)
+ {
+ OPENVPN_CHANNEL *c = se->Channels[recv_packet->KeyId];
+ if (c->Status == OPENVPN_CHANNEL_STATUS_ESTABLISHED)
+ {
+ UCHAR *data;
+ UINT size;
+
+ data = recv_packet->Data;
+ size = recv_packet->DataSize;
+
+ if (size >= (c->MdRecv->Size + c->CipherDecrypt->IvSize + sizeof(UINT)))
+ {
+ UCHAR *hmac;
+ UCHAR *iv;
+ UCHAR hmac_test[128];
+
+ // HMAC
+ hmac = data;
+ data += c->MdRecv->Size;
+ size -= c->MdRecv->Size;
+
+ // Confirmation of HMAC
+ MdProcess(c->MdRecv, hmac_test, data, size);
+ if (Cmp(hmac_test, hmac, c->MdRecv->Size) == 0)
+ {
+ // Update of last communication time
+ se->LastCommTick = s->Now;
+
+ // IV
+ iv = data;
+ data += c->CipherDecrypt->IvSize;
+ size -= c->CipherDecrypt->IvSize;
+
+ // Payload
+ if (size >= 1 && (c->CipherDecrypt->BlockSize == 0 || (size % c->CipherDecrypt->BlockSize) == 0))
+ {
+ UINT data_packet_id;
+
+ // Decryption
+ size = CipherProcess(c->CipherDecrypt, iv, s->TmpBuf, data, size);
+
+ data = s->TmpBuf;
+
+ if (size >= sizeof(UINT))
+ {
+ data_packet_id = READ_UINT(data);
+
+ data += sizeof(UINT);
+ size -= sizeof(UINT);
+
+ if (size >= sizeof(ping_signature) &&
+ Cmp(data, ping_signature, sizeof(ping_signature)) == 0)
+ {
+ // Ignore since a ping packet has been received
+ DoNothing();
+ }
+ else
+ {
+ // Receive a packet!!
+ if (se->Ipc != NULL)
+ {
+ switch (se->Mode)
+ {
+ case OPENVPN_MODE_L2: // Send an Ethernet packet to a session
+ IPCSendL2(se->Ipc, data, size);
+ break;
+
+ case OPENVPN_MODE_L3: // Send an IPv4 packet to a session
+ IPCSendIPv4(se->Ipc, data, size);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+// Debug("HMAC Failed (c=%u)\n", c->KeyId);
+ }
+ }
+ }
+ }
+ }
+
+ OvsFreePacket(recv_packet);
+ }
+}
+
+// Remove a packet which the opponent has received from the transmission list
+void OvsDeleteFromSendingControlPacketList(OPENVPN_CHANNEL *c, UINT num_acks, UINT *acks)
+{
+ LIST *o;
+ UINT i;
+ // Validate arguments
+ if (c == NULL || num_acks == 0)
+ {
+ return;
+ }
+
+ o = NewListFast(NULL);
+ for (i = 0;i < num_acks;i++)
+ {
+ UINT ack = acks[i];
+ UINT j;
+
+ for (j = 0;j < LIST_NUM(c->SendControlPacketList);j++)
+ {
+ OPENVPN_CONTROL_PACKET *p = LIST_DATA(c->SendControlPacketList, j);
+
+ if (p->PacketId == ack)
+ {
+ AddDistinct(o, p);
+ }
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ OPENVPN_CONTROL_PACKET *p = LIST_DATA(o, i);
+
+ Delete(c->SendControlPacketList, p);
+
+ OvsFreeControlPacket(p);
+ }
+
+ ReleaseList(o);
+}
+
+// Process the received control packet
+void OvsProcessRecvControlPacket(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c, OPENVPN_PACKET *p)
+{
+ FIFO *recv_fifo = NULL;
+ FIFO *send_fifo = NULL;
+ // Validate arguments
+ if (s == NULL || se == NULL || c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (p->OpCode == OPENVPN_P_CONTROL_V1)
+ {
+ Debug("SSL (c=%u): %u\n", c->KeyId, p->DataSize);
+
+ if (c->SslPipe == NULL)
+ {
+ // Create an SSL pipe
+ Lock(s->Cedar->lock);
+ {
+ c->SslPipe = NewSslPipe(true, s->Cedar->ServerX, s->Cedar->ServerK, s->Dh);
+ }
+ Unlock(s->Cedar->lock);
+
+ Debug("SSL Pipe Created (c=%u).\n", c->KeyId);
+ }
+
+ if (c->SslPipe->IsDisconnected == false)
+ {
+ // Pour the physically received data into SSL pipe
+ if (FifoSize(c->SslPipe->RawIn->SendFifo) < OPENVPN_MAX_SSL_RECV_BUF_SIZE)
+ {
+ Debug("SSL_Write: %u\n", p->DataSize);
+ WriteFifo(c->SslPipe->RawIn->SendFifo, p->Data, p->DataSize);
+ }
+ SyncSslPipe(c->SslPipe);
+ }
+ }
+
+ if (c->SslPipe != NULL && c->SslPipe->IsDisconnected == false)
+ {
+ recv_fifo = c->SslPipe->SslInOut->RecvFifo;
+ send_fifo = c->SslPipe->SslInOut->SendFifo;
+ }
+
+ Debug("SIZE: recv_fifo = %u, send_fifo = %u\n", FifoSize(recv_fifo), FifoSize(send_fifo));
+
+ switch (c->Status)
+ {
+ case OPENVPN_CHANNEL_STATUS_INIT:
+ switch (p->OpCode)
+ {
+ case OPENVPN_P_CONTROL_SOFT_RESET_V1:
+ // Key update (soft reset)
+ if (se->Established)
+ {
+ if (c->IsInitiatorServer == false)
+ {
+ OvsSendControlPacket(c, OPENVPN_P_CONTROL_SOFT_RESET_V1, NULL, 0);
+ }
+
+ c->Status = OPENVPN_CHANNEL_STATUS_TLS_WAIT_CLIENT_KEY;
+ c->IsRekeyChannel = true;
+ }
+ break;
+
+ case OPENVPN_P_CONTROL_HARD_RESET_CLIENT_V2:
+ // New connection (hard reset)
+ OvsSendControlPacket(c, OPENVPN_P_CONTROL_HARD_RESET_SERVER_V2, NULL, 0);
+
+ c->Status = OPENVPN_CHANNEL_STATUS_TLS_WAIT_CLIENT_KEY;
+ break;
+ }
+ break;
+
+ case OPENVPN_CHANNEL_STATUS_TLS_WAIT_CLIENT_KEY:
+ if (FifoSize(recv_fifo) >= 1)
+ {
+ OPENVPN_KEY_METHOD_2 data;
+ UCHAR *ptr = FifoPtr(recv_fifo);
+
+ // Parse OPENVPN_KEY_METHOD_2
+ UINT read_size = OvsParseKeyMethod2(&data, ptr, FifoSize(recv_fifo), true);
+ if (read_size != 0)
+ {
+ BUF *b;
+
+ // Success in parsing key information
+ ReadFifo(recv_fifo, NULL, read_size);
+
+ // Set session parameters
+ OvsSetupSessionParameters(s, se, c, &data);
+
+ // Build OPENVPN_KEY_METHOD_2 to respond
+ b = OvsBuildKeyMethod2(&c->ServerKey);
+
+ // Transmission of the response data
+ if (b != NULL)
+ {
+ WriteFifo(send_fifo, b->Buf, b->Size);
+
+ FreeBuf(b);
+ }
+
+ // State transition
+ c->Status = OPENVPN_CHANNEL_STATUS_TLS_WAIT_CLIENT_PUSH_REQUEST;
+ if (c->IsRekeyChannel)
+ {
+ c->Status = OPENVPN_CHANNEL_STATUS_ESTABLISHED;
+ c->EstablishedTick = s->Now;
+ Debug("OpenVPN Channel %u Established (re-key).\n", c->KeyId);
+ OvsLog(s, se, c, "LO_CHANNEL_ESTABLISHED_NEWKEY");
+ }
+ }
+ }
+ break;
+
+ case OPENVPN_CHANNEL_STATUS_TLS_WAIT_CLIENT_PUSH_REQUEST:
+ if (FifoSize(recv_fifo) >= 1)
+ {
+ char tmp[MAX_SIZE];
+ UINT read_size = OvsPeekStringFromFifo(recv_fifo, tmp, sizeof(tmp));
+
+ if (read_size >= 1)
+ {
+ Debug("Client->Server (c=%u): %s\n", c->KeyId, tmp);
+
+ ReadFifo(recv_fifo, NULL, read_size);
+
+ if (StartWith(tmp, "PUSH_REQUEST"))
+ {
+ // Since connection requested, start VPN connection
+ // When the IPC VPN connection has not been started yet, start it
+ OvsBeginIPCAsyncConnectionIfEmpty(s, se, c);
+
+ // State transition
+ c->Status = OPENVPN_CHANNEL_STATUS_TLS_VPN_CONNECTING;
+ }
+ }
+ }
+ break;
+
+ case OPENVPN_CHANNEL_STATUS_TLS_VPN_CONNECTING:
+ case OPENVPN_CHANNEL_STATUS_ESTABLISHED:
+ if (FifoSize(recv_fifo) >= 1)
+ {
+ char tmp[MAX_SIZE];
+ UINT read_size = OvsPeekStringFromFifo(recv_fifo, tmp, sizeof(tmp));
+
+ if (read_size >= 1)
+ {
+ Debug("Client->Server (c=%u): %s\n", c->KeyId, tmp);
+
+ ReadFifo(recv_fifo, NULL, read_size);
+
+ if (StartWith(tmp, "PUSH_REQUEST"))
+ {
+ WriteFifo(send_fifo, se->PushReplyStr, StrLen(se->PushReplyStr));
+ }
+ }
+ }
+ break;
+ }
+}
+
+// Calculate the proper MSS
+UINT OvsCalcTcpMss(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c)
+{
+ UINT ret = MTU_FOR_PPPOE;
+ // Validate arguments
+ if (s == NULL || se == NULL || c == NULL)
+ {
+ return 0;
+ }
+
+ if (c->MdSend == NULL || c->CipherEncrypt == NULL)
+ {
+ return 0;
+ }
+
+ if (se->Protocol == OPENVPN_PROTOCOL_TCP)
+ {
+ // Calculation is not required for TCP mode
+ return 0;
+ }
+
+ // IPv4 / IPv6
+ if (IsIP4(&se->ClientIp))
+ {
+ ret -= 20;
+ }
+ else
+ {
+ ret -= 40;
+ }
+
+ // UDP
+ ret -= 8;
+
+ // opcode
+ ret -= 1;
+
+ // HMAC
+ ret -= c->MdSend->Size;
+
+ // IV
+ ret -= c->CipherEncrypt->IvSize;
+
+ // Packet ID
+ ret -= 4;
+
+ if (c->CipherEncrypt->IsNullCipher == false)
+ {
+ // block
+ ret -= c->CipherEncrypt->BlockSize;
+ }
+
+ if (se->Mode == OPENVPN_MODE_L2)
+ {
+ // Inner Ethernet Header
+ ret -= 14;
+ }
+
+ // Inner IPv4
+ ret -= 20;
+
+ // Inner TCP
+ ret -= 20;
+
+ return ret;
+}
+
+// When the IPC VPN connection has not been started yet, start it
+void OvsBeginIPCAsyncConnectionIfEmpty(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c)
+{
+ // Validate arguments
+ if (s == NULL || se == NULL || c == NULL)
+ {
+ return;
+ }
+
+ if (IsIPCConnected(se->Ipc) == false)
+ {
+ FreeIPC(se->Ipc);
+
+ se->Ipc = NULL;
+ }
+
+ if (se->IpcAsync == NULL)
+ {
+ IPC_PARAM p;
+ ETHERIP_ID id;
+
+ Zero(&p, sizeof(p));
+ Zero(&id, sizeof(id));
+
+ // Parse the user name
+ PPPParseUsername(s->Cedar, c->ClientKey.Username, &id);
+
+
+ // Build IPC connection parameters
+ StrCpy(p.ClientName, sizeof(p.ClientName), OPENVPN_IPC_CLIENT_NAME);
+ StrCpy(p.Postfix, sizeof(p.Postfix), (se->Mode == OPENVPN_MODE_L3 ? OPENVPN_IPC_POSTFIX_L3 : OPENVPN_IPC_POSTFIX_L2));
+
+ StrCpy(p.UserName, sizeof(p.UserName), id.UserName);
+ StrCpy(p.HubName, sizeof(p.HubName), id.HubName);
+ StrCpy(p.Password, sizeof(p.Password), c->ClientKey.Password);
+
+ Copy(&p.ClientIp, &se->ClientIp, sizeof(IP));
+ p.ClientPort = se->ClientPort;
+
+ Copy(&p.ServerIp, &se->ServerIp, sizeof(IP));
+ p.ServerPort = se->ServerPort;
+
+ if (c->CipherEncrypt->IsNullCipher == false)
+ {
+ StrCpy(p.CryptName, sizeof(p.CryptName), c->CipherEncrypt->Name);
+ }
+
+ if (se->Mode == OPENVPN_MODE_L3)
+ {
+ // L3 Mode
+ p.IsL3Mode = true;
+ }
+ else
+ {
+ // L2 Mode
+ p.BridgeMode = true;
+ }
+
+ p.IsOpenVPN = true;
+
+ // Calculate the MSS
+ p.Mss = OvsCalcTcpMss(s, se, c);
+ Debug("MSS=%u\n", p.Mss);
+
+ // Start an IPC connection
+ se->IpcAsync = NewIPCAsync(s->Cedar, &p, s->SockEvent);
+ }
+}
+
+// Peek a NULL-terminated string from the FIFO
+UINT OvsPeekStringFromFifo(FIFO *f, char *str, UINT str_size)
+{
+ UINT i;
+ bool ok = false;
+ // Validate arguments
+ if (f == NULL || str == NULL || str_size == 0)
+ {
+ return 0;
+ }
+
+ StrCpy(str, str_size, "");
+
+ for (i = 0;i < MIN(str_size, FifoSize(f));i++)
+ {
+ char c = *(((char *)FifoPtr(f)) + i);
+
+ if (c != 0)
+ {
+ str[i] = c;
+ }
+ else
+ {
+ str[i] = 0;
+ i++;
+ ok = true;
+ break;
+ }
+ }
+
+ if (ok == false)
+ {
+ return 0;
+ }
+
+ return i;
+}
+
+// Set session parameters
+void OvsSetupSessionParameters(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c, OPENVPN_KEY_METHOD_2 *data)
+{
+ LIST *o;
+ BUF *b;
+ // Validate arguments
+ if (s == NULL || se == NULL || c == NULL || data == NULL)
+ {
+ return;
+ }
+
+ Copy(&c->ClientKey, data, sizeof(OPENVPN_KEY_METHOD_2));
+
+ // Parse the parameter string
+ Debug("Parsing Option Str: %s\n", data->OptionString);
+
+ OvsLog(s, se, c, "LO_OPTION_STR_RECV", data->OptionString);
+
+ o = OvsParseOptions(data->OptionString);
+
+ if (se->Mode == OPENVPN_MODE_UNKNOWN)
+ {
+ UINT mtu;
+ // Layer
+ if (StrCmpi(IniStrValue(o, "dev-type"), "tun") == 0)
+ {
+ // L3
+ se->Mode = OPENVPN_MODE_L3;
+ }
+ else
+ {
+ // L2
+ se->Mode = OPENVPN_MODE_L2;
+ }
+
+ // Link MTU
+ mtu = IniIntValue(o, "link-mtu");
+ if (mtu == 0)
+ {
+ mtu = OPENVPN_MTU_LINK;
+ }
+ se->LinkMtu = mtu;
+
+ // Tun MTU
+ mtu = IniIntValue(o, "tun-mtu");
+ if (mtu == 0)
+ {
+ mtu = OPENVPN_MTU_TUN;
+ }
+ se->TunMtu = mtu;
+ }
+
+ // Protocol
+ if (se->Protocol == OPENVPN_PROTOCOL_TCP)
+ {
+ // TCP
+ // UDP
+ if (IsIP6(&se->ClientIp) == false)
+ {
+ StrCpy(c->Proto, sizeof(c->Proto), "TCPv4_SERVER");
+ }
+ else
+ {
+ StrCpy(c->Proto, sizeof(c->Proto), "TCPv6_SERVER");
+ }
+ }
+ else
+ {
+ // UDP
+ if (IsIP6(&se->ClientIp) == false)
+ {
+ StrCpy(c->Proto, sizeof(c->Proto), "UDPv4");
+ }
+ else
+ {
+ StrCpy(c->Proto, sizeof(c->Proto), "UDPv6");
+ }
+ }
+
+ // Encryption algorithm
+ c->CipherEncrypt = OvsGetCipher(IniStrValue(o, "cipher"));
+ c->CipherDecrypt = NewCipher(c->CipherEncrypt->Name);
+
+ // Hash algorithm
+ c->MdSend = OvsGetMd(IniStrValue(o, "auth"));
+ c->MdRecv = NewMd(c->MdSend->Name);
+
+ // Random number generation
+ Rand(c->ServerKey.Random1, sizeof(c->ServerKey.Random1));
+ Rand(c->ServerKey.Random2, sizeof(c->ServerKey.Random2));
+
+ // Generate the Master Secret
+ b = NewBuf();
+ WriteBuf(b, OPENVPN_PREMASTER_LABEL, StrLen(OPENVPN_PREMASTER_LABEL));
+ WriteBuf(b, c->ClientKey.Random1, sizeof(c->ClientKey.Random1));
+ WriteBuf(b, c->ServerKey.Random1, sizeof(c->ServerKey.Random1));
+ Enc_tls1_PRF(b->Buf, b->Size,
+ c->ClientKey.PreMasterSecret, sizeof(c->ClientKey.PreMasterSecret),
+ c->MasterSecret, sizeof(c->MasterSecret));
+ FreeBuf(b);
+
+ // Generate an Expansion Key
+ b = NewBuf();
+ WriteBuf(b, OPENVPN_EXPANSION_LABEL, StrLen(OPENVPN_EXPANSION_LABEL));
+ WriteBuf(b, c->ClientKey.Random2, sizeof(c->ClientKey.Random2));
+ WriteBuf(b, c->ServerKey.Random2, sizeof(c->ServerKey.Random2));
+ WriteBufInt64(b, se->ClientSessionId);
+ WriteBufInt64(b, se->ServerSessionId);
+ Enc_tls1_PRF(b->Buf, b->Size, c->MasterSecret, sizeof(c->MasterSecret),
+ c->ExpansionKey, sizeof(c->ExpansionKey));
+ FreeBuf(b);
+
+ // Set the key
+ SetCipherKey(c->CipherDecrypt, c->ExpansionKey + 0, false);
+ SetCipherKey(c->CipherEncrypt, c->ExpansionKey + 128, true);
+ SetMdKey(c->MdRecv, c->ExpansionKey + 64, c->MdRecv->Size);
+ SetMdKey(c->MdSend, c->ExpansionKey + 192, c->MdSend->Size);
+
+ OvsFreeOptions(o);
+
+ // Generate the response option string
+ Format(c->ServerKey.OptionString, sizeof(c->ServerKey.OptionString),
+ "V4,dev-type %s,link-mtu %u,tun-mtu %u,proto %s,"
+ "cipher %s,auth %s,keysize %u,key-method 2,tls-server",
+ (se->Mode == OPENVPN_MODE_L2 ? "tap" : "tun"),
+ se->LinkMtu,
+ se->TunMtu,
+ c->Proto,
+ c->CipherEncrypt->Name, c->MdSend->Name, c->CipherEncrypt->KeySize * 8);
+ Debug("Building OptionStr: %s\n", c->ServerKey.OptionString);
+
+ OvsLog(s, se, c, "LO_OPTION_STR_SEND", c->ServerKey.OptionString);
+}
+
+// Get the encryption algorithm
+CIPHER *OvsGetCipher(char *name)
+{
+ CIPHER *c = NULL;
+
+ if (IsEmptyStr(name) == false && IsStrInStrTokenList(OPENVPN_CIPHER_LIST, name, NULL, false))
+ {
+ c = NewCipher(name);
+ }
+
+ if (c == NULL)
+ {
+ c = NewCipher(OPENVPN_DEFAULT_CIPHER);
+ }
+
+ return c;
+}
+
+// Get the hash algorithm
+MD *OvsGetMd(char *name)
+{
+ MD *m = NULL;
+
+ if (IsEmptyStr(name) == false && IsStrInStrTokenList(OPENVPN_MD_LIST, name, NULL, false))
+ {
+ m = NewMd(name);
+ }
+
+ if (m == NULL)
+ {
+ m = NewMd(OPENVPN_DEFAULT_MD);
+ }
+
+ return m;
+}
+
+// Parse the option string
+LIST *OvsParseOptions(char *str)
+{
+ LIST *o = NewListFast(NULL);
+ TOKEN_LIST *t;
+
+ t = ParseTokenWithoutNullStr(str, ",");
+ if (t != NULL)
+ {
+ UINT i;
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ char key[MAX_SIZE];
+ char value[MAX_SIZE];
+ char *line = t->Token[i];
+ Trim(line);
+
+ if (GetKeyAndValue(line, key, sizeof(key), value, sizeof(value), " \t"))
+ {
+ INI_ENTRY *e = ZeroMalloc(sizeof(INI_ENTRY));
+
+ e->Key = CopyStr(key);
+ e->Value = CopyStr(value);
+
+ Add(o, e);
+ }
+ }
+
+ FreeToken(t);
+ }
+
+ return o;
+}
+
+// Release the option list
+void OvsFreeOptions(LIST *o)
+{
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ FreeIni(o);
+}
+
+// Create an Option List
+LIST *OvsNewOptions()
+{
+ return NewListFast(NULL);
+}
+
+// Add a value to the option list
+void OvsAddOption(LIST *o, char *key, char *value)
+{
+ INI_ENTRY *e;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ e = GetIniEntry(o, key);
+ if (e != NULL)
+ {
+ // Overwrite existing keys
+ Free(e->Key);
+ e->Key = CopyStr(key);
+
+ Free(e->Value);
+ e->Value = CopyStr(value);
+ }
+ else
+ {
+ // Create a new key
+ e = ZeroMalloc(sizeof(INI_ENTRY));
+
+ e->Key = CopyStr(key);
+ e->Value = CopyStr(value);
+
+ Add(o, e);
+ }
+}
+
+// Confirm whether there is specified option key string
+bool OvsHasOption(LIST *o, char *key)
+{
+ // Validate arguments
+ if (o == NULL || key == NULL)
+ {
+ return false;
+ }
+
+ if (GetIniEntry(o, key) != NULL)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Build the data from KEY_METHOD2
+BUF *OvsBuildKeyMethod2(OPENVPN_KEY_METHOD_2 *d)
+{
+ BUF *b;
+ UCHAR uc;
+ // Validate arguments
+ if (d == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+
+ // Reserved
+ WriteBufInt(b, 0);
+
+ // Method
+ uc = 2;
+ WriteBuf(b, &uc, sizeof(UCHAR));
+
+ // Random1
+ WriteBuf(b, d->Random1, sizeof(d->Random1));
+
+ // Random2
+ WriteBuf(b, d->Random2, sizeof(d->Random2));
+
+ // Option String
+ OvsWriteStringToBuf(b, d->OptionString, sizeof(d->OptionString));
+
+ // Username
+ OvsWriteStringToBuf(b, d->Username, sizeof(d->Username));
+
+ // Password
+ OvsWriteStringToBuf(b, d->Password, sizeof(d->Password));
+
+ // PeerInfo
+ OvsWriteStringToBuf(b, d->PeerInfo, sizeof(d->PeerInfo));
+
+ return b;
+}
+
+// Append a string to buf
+void OvsWriteStringToBuf(BUF *b, char *str, UINT max_size)
+{
+ USHORT us;
+ UINT i;
+ char *tmp;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return;
+ }
+ if (str == NULL)
+ {
+ str = "";
+ }
+
+ if (StrLen(str) == 0)
+ {
+ us = 0;
+ WriteBuf(b, &us, sizeof(USHORT));
+ return;
+ }
+
+ i = StrSize(str);
+ i = MIN(i, max_size);
+ us = Endian16((USHORT)i);
+ WriteBuf(b, &us, sizeof(USHORT));
+
+ tmp = Malloc(i);
+ Copy(tmp, str, i);
+ tmp[i - 1] = 0;
+ WriteBuf(b, tmp, i);
+
+ Free(tmp);
+}
+
+// Parse the KEY_METHOD2
+UINT OvsParseKeyMethod2(OPENVPN_KEY_METHOD_2 *ret, UCHAR *data, UINT size, bool client_mode)
+{
+ BUF *b;
+ UINT read_size = 0;
+ UINT ui;
+ UCHAR uc;
+ // Validate arguments
+ Zero(ret, sizeof(OPENVPN_KEY_METHOD_2));
+ if (ret == NULL || data == NULL || size == 0)
+ {
+ return 0;
+ }
+
+ b = NewBuf();
+ WriteBuf(b, data, size);
+ SeekBuf(b, 0, 0);
+
+ // Reserved
+ if (ReadBuf(b, &ui, sizeof(UINT)) == sizeof(UINT))
+ {
+ // Method
+ if (ReadBuf(b, &uc, sizeof(UCHAR)) == sizeof(UCHAR) && uc == 2)
+ {
+ // Pre Master Secret
+ if (client_mode == false || ReadBuf(b, ret->PreMasterSecret, sizeof(ret->PreMasterSecret)) == sizeof(ret->PreMasterSecret))
+ {
+ // Random1
+ if (ReadBuf(b, ret->Random1, sizeof(ret->Random1)) == sizeof(ret->Random1))
+ {
+ // Random2
+ if (ReadBuf(b, ret->Random2, sizeof(ret->Random2)) == sizeof(ret->Random2))
+ {
+ // String
+ if (OvsReadStringFromBuf(b, ret->OptionString, sizeof(ret->OptionString)) &&
+ OvsReadStringFromBuf(b, ret->Username, sizeof(ret->Username)) &&
+ OvsReadStringFromBuf(b, ret->Password, sizeof(ret->Password)) &&
+ OvsReadStringFromBuf(b, ret->PeerInfo, sizeof(ret->PeerInfo)))
+ {
+ read_size = b->Current;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ FreeBuf(b);
+
+ return read_size;
+}
+
+// Read a string from BUF
+bool OvsReadStringFromBuf(BUF *b, char *str, UINT str_size)
+{
+ USHORT us;
+ // Validate arguments
+ if (b == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ if (ReadBuf(b, &us, sizeof(USHORT)) != sizeof(USHORT))
+ {
+ return false;
+ }
+
+ us = Endian16(us);
+
+ if (us == 0)
+ {
+ StrCpy(str, str_size, "");
+ return true;
+ }
+
+ if (us > str_size)
+ {
+ return false;
+ }
+
+ if (ReadBuf(b, str, us) != us)
+ {
+ return false;
+ }
+
+ if (str[us - 1] != 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Transmission of control packet (Automatic segmentation with the maximum size)
+void OvsSendControlPacketWithAutoSplit(OPENVPN_CHANNEL *c, UCHAR opcode, UCHAR *data, UINT data_size)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || (data_size != 0 && data == NULL))
+ {
+ return;
+ }
+
+ b = NewBuf();
+ WriteBuf(b, data, data_size);
+ SeekBuf(b, 0, 0);
+
+ while (true)
+ {
+ UCHAR tmp[OPENVPN_CONTROL_PACKET_MAX_DATASIZE];
+ UINT size = ReadBuf(b, tmp, sizeof(tmp));
+
+ if (size == 0)
+ {
+ break;
+ }
+
+ OvsSendControlPacket(c, opcode, tmp, size);
+ //Debug(" *** CNT SEND %u\n", size);
+ }
+
+ FreeBuf(b);
+}
+
+// Send the control packet
+void OvsSendControlPacket(OPENVPN_CHANNEL *c, UCHAR opcode, UCHAR *data, UINT data_size)
+{
+ OPENVPN_CONTROL_PACKET *p;
+ // Validate arguments
+ if (c == NULL || (data_size != 0 && data == NULL))
+ {
+ return;
+ }
+
+ p = ZeroMalloc(sizeof(OPENVPN_CONTROL_PACKET));
+
+ p->OpCode = opcode;
+ p->PacketId = c->NextSendPacketId++;
+
+ if (data != NULL)
+ {
+ p->Data = Clone(data, data_size);
+ p->DataSize = data_size;
+ }
+
+ p->NextSendTime = 0;
+
+ Add(c->SendControlPacketList, p);
+}
+
+// Release the control packet being transmitted
+void OvsFreeControlPacket(OPENVPN_CONTROL_PACKET *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ if (p->Data != NULL)
+ {
+ Free(p->Data);
+ }
+
+ Free(p);
+}
+
+// Get a list of packet ID to be responded
+UINT OvsGetAckReplyList(OPENVPN_CHANNEL *c, UINT *ret)
+{
+ UINT i;
+ LIST *o = NULL;
+ UINT num;
+ // Validate arguments
+ if (c == NULL || ret == NULL)
+ {
+ return 0;
+ }
+
+ num = MIN(LIST_NUM(c->AckReplyList), OPENVPN_MAX_NUMACK);
+
+ for (i = 0;i < num;i++)
+ {
+ UINT *v = LIST_DATA(c->AckReplyList, i);
+
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Add(o, v);
+
+ ret[i] = *v;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ UINT *v = LIST_DATA(o, i);
+
+ Delete(c->AckReplyList, v);
+
+ Free(v);
+ }
+
+ ReleaseList(o);
+
+ return num;
+}
+
+// Release the channel
+void OvsFreeChannel(OPENVPN_CHANNEL *c)
+{
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ if (c->SslPipe != NULL)
+ {
+ FreeSslPipe(c->SslPipe);
+ }
+
+ ReleaseIntList(c->AckReplyList);
+
+ for (i = 0;i < LIST_NUM(c->SendControlPacketList);i++)
+ {
+ OPENVPN_CONTROL_PACKET *p = LIST_DATA(c->SendControlPacketList, i);
+
+ OvsFreeControlPacket(p);
+ }
+
+ ReleaseList(c->SendControlPacketList);
+
+ FreeCipher(c->CipherDecrypt);
+ FreeCipher(c->CipherEncrypt);
+
+ FreeMd(c->MdRecv);
+ FreeMd(c->MdSend);
+
+ Free(c);
+}
+
+// Create a new channel
+OPENVPN_CHANNEL *OvsNewChannel(OPENVPN_SESSION *se, UCHAR key_id)
+{
+ OPENVPN_CHANNEL *c;
+ // Validate arguments
+ if (se == NULL)
+ {
+ return NULL;
+ }
+
+ c = ZeroMalloc(sizeof(OPENVPN_CHANNEL));
+
+ c->Session = se;
+ c->Server = se->Server;
+
+ c->Status = OPENVPN_CHANNEL_STATUS_INIT;
+
+ c->AckReplyList = NewIntList(true);
+
+ c->SendControlPacketList = NewListFast(NULL);
+
+ c->KeyId = key_id;
+
+ Rand(c->NextIv, sizeof(c->NextIv));
+
+ //c->NextRekey = se->Server->Now + (UINT64)5000;
+
+ se->LastCreatedChannelIndex = key_id;
+
+ return c;
+}
+
+// Create a new server-side channel ID
+UINT64 OvsNewServerSessionId(OPENVPN_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return 0;
+ }
+
+ while (true)
+ {
+ UINT64 id = Rand64();
+ UINT i;
+ bool exists = false;
+
+ if (id == 0 || id == (UINT64)(0xFFFFFFFFFFFFFFFFULL))
+ {
+ continue;
+ }
+
+ for (i = 0;i < LIST_NUM(s->SessionList);i++)
+ {
+ OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
+ if (se->ServerSessionId == id)
+ {
+ exists = true;
+ }
+ }
+
+ if (exists == false)
+ {
+ return id;
+ }
+ }
+}
+
+// Build and submit the OpenVPN data packet
+void OvsSendDataPacket(OPENVPN_CHANNEL *c, UCHAR key_id, UINT data_packet_id, void *data, UINT data_size)
+{
+ UCHAR uc;
+ UCHAR *encrypted_data;
+ UINT encrypted_size;
+ UCHAR *dest_data;
+ UINT dest_size;
+ UINT r;
+
+ // Validate arguments
+ if (c == NULL || data == NULL || data_size == 0)
+ {
+ return;
+ }
+
+ uc = ((OPENVPN_P_DATA_V1 << 3) & 0xF8) | (key_id & 0x07);
+
+ // Generate the data to be encrypted
+
+ encrypted_size = sizeof(UINT) + data_size;
+ encrypted_data = ZeroMalloc(encrypted_size);
+
+ WRITE_UINT(encrypted_data, data_packet_id);
+ Copy(encrypted_data + sizeof(UINT), data, data_size);
+
+ // Prepare a buffer to store the results
+ dest_data = Malloc(sizeof(UCHAR) + c->MdSend->Size + c->CipherEncrypt->IvSize + encrypted_size + 256);
+
+ // Encrypt
+ r = CipherProcess(c->CipherEncrypt, c->NextIv, dest_data + sizeof(UCHAR) + c->MdSend->Size + c->CipherEncrypt->IvSize,
+ encrypted_data, encrypted_size);
+ dest_size = sizeof(UCHAR) + c->MdSend->Size + c->CipherEncrypt->IvSize + r;
+
+ // Copy the IV
+ Copy(dest_data + sizeof(UCHAR) + c->MdSend->Size, c->NextIv, c->CipherEncrypt->IvSize);
+
+ // Calculate the HMAC
+ MdProcess(c->MdSend, dest_data + sizeof(UCHAR), dest_data + sizeof(UCHAR) + c->MdSend->Size,
+ dest_size - sizeof(UCHAR) - c->MdSend->Size);
+
+ // Update the NextIV
+ Copy(c->NextIv, dest_data + dest_size - c->CipherEncrypt->IvSize, c->CipherEncrypt->IvSize);
+
+ // Op-code
+ dest_data[0] = uc;
+
+ OvsSendPacketRawNow(c->Server, c->Session, dest_data, dest_size);
+
+ Free(encrypted_data);
+}
+
+// Build an OpenVPN control packet
+BUF *OvsBuildPacket(OPENVPN_PACKET *p)
+{
+ BUF *b;
+ UCHAR uc;
+ UINT num_ack;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+
+ // OpCode + KeyID
+ uc = ((p->OpCode << 3) & 0xF8) | (p->KeyId & 0x07);
+ WriteBufChar(b, uc);
+
+ if (p->OpCode == OPENVPN_P_DATA_V1)
+ {
+ // Data Packet
+ WriteBuf(b, p->Data, p->DataSize);
+ SeekBuf(b, 0, 0);
+ return b;
+ }
+
+ // Sender Channel ID
+ WriteBufInt64(b, p->MySessionId);
+
+ // NumAck
+ num_ack = MIN(p->NumAck, OPENVPN_MAX_NUMACK);
+ WriteBufChar(b, (UCHAR)num_ack);
+
+ if (p->NumAck >= 1)
+ {
+ UINT i;
+
+ for (i = 0;i < num_ack;i++)
+ {
+ WriteBufInt(b, (UCHAR)p->AckPacketId[i]);
+ }
+
+ // Received Channel ID
+ WriteBufInt64(b, p->YourSessionId);
+ }
+
+ if (p->OpCode != OPENVPN_P_ACK_V1)
+ {
+ // Packet ID
+ WriteBufInt(b, p->PacketId);
+
+ // Payload
+ if (p->DataSize >= 1 && p->Data != NULL)
+ {
+ WriteBuf(b, p->Data, p->DataSize);
+ }
+ }
+
+ SeekBuf(b, 0, 0);
+
+ return b;
+}
+
+// Parse the OpenVPN packet
+OPENVPN_PACKET *OvsParsePacket(UCHAR *data, UINT size)
+{
+ UCHAR uc;
+ OPENVPN_PACKET *ret = NULL;
+ // Validate arguments
+ if (data == NULL || size == 0)
+ {
+ return NULL;
+ }
+
+ ret = ZeroMalloc(sizeof(OPENVPN_PACKET));
+
+ // OpCode + KeyID
+ if (size < 1)
+ {
+ goto LABEL_ERROR;
+ }
+ uc = *((UCHAR *)data);
+ data++;
+ size--;
+
+ ret->OpCode = ((uc & 0xF8) >> 3) & 0x1F;
+ ret->KeyId = uc & 0x07;
+
+ if (ret->OpCode == OPENVPN_P_DATA_V1)
+ {
+ // Data packet
+ ret->DataSize = size;
+ ret->Data = Clone(data, size);
+ return ret;
+ }
+
+ // Sender Channel ID
+ if (size < sizeof(UINT64))
+ {
+ goto LABEL_ERROR;
+ }
+ ret->MySessionId = READ_UINT64(data);
+ data += sizeof(UINT64);
+ size -= sizeof(UINT64);
+
+ // ACK
+ if (size < 1)
+ {
+ goto LABEL_ERROR;
+ }
+ uc = *((UCHAR *)data);
+ data++;
+ size--;
+
+ ret->NumAck = uc;
+
+ if (ret->NumAck > 4)
+ {
+ goto LABEL_ERROR;
+ }
+
+ if (ret->NumAck >= 1)
+ {
+ UINT i;
+
+ if (size < (sizeof(UINT) * (UINT)ret->NumAck + sizeof(UINT64)))
+ {
+ goto LABEL_ERROR;
+ }
+
+ for (i = 0;i < ret->NumAck;i++)
+ {
+ UINT ui;
+
+ ui = READ_UINT(data);
+
+ ret->AckPacketId[i] = ui;
+
+ data += sizeof(UINT);
+ size -= sizeof(UINT);
+ }
+
+ ret->YourSessionId = READ_UINT64(data);
+ data += sizeof(UINT64);
+ size -= sizeof(UINT64);
+ }
+
+ if (ret->OpCode != OPENVPN_P_ACK_V1)
+ {
+ // Read the Packet ID Because in the case of other than ACK
+ if (size < sizeof(UINT))
+ {
+ goto LABEL_ERROR;
+ }
+
+ ret->PacketId = READ_UINT(data);
+ data += sizeof(UINT);
+ size -= sizeof(UINT);
+
+ // Payload
+ ret->DataSize = size;
+ if (size >= 1)
+ {
+ ret->Data = Clone(data, size);
+ }
+ }
+
+ return ret;
+
+LABEL_ERROR:
+ Debug("OvsParsePacket Error.\n");
+ if (ret != NULL)
+ {
+ OvsFreePacket(ret);
+ }
+ return NULL;
+}
+
+// Release the OpenVPN packet
+void OvsFreePacket(OPENVPN_PACKET *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ if (p->Data != NULL)
+ {
+ Free(p->Data);
+ }
+
+ Free(p);
+}
+
+// If the session does not exist, create a session
+OPENVPN_SESSION *OvsFindOrCreateSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, UINT protocol)
+{
+ OPENVPN_SESSION *se;
+ // Validate arguments
+ if (s == NULL || server_ip == NULL || server_port == 0 || client_ip == NULL || client_port == 0)
+ {
+ return NULL;
+ }
+
+ se = OvsSearchSession(s, server_ip, server_port, client_ip, client_port, protocol);
+ if (se == NULL)
+ {
+ se = OvsNewSession(s, server_ip, server_port, client_ip, client_port, protocol);
+
+ if (se != NULL)
+ {
+ Insert(s->SessionList, se);
+ }
+ }
+
+ return se;
+}
+
+// Get the number of sessions currently connected from the IP address of the client
+UINT OvsGetNumSessionByClientIp(OPENVPN_SERVER *s, IP *ip)
+{
+ UINT i;
+ UINT ret = 0;
+ // Validate arguments
+ if (s == NULL || ip == NULL)
+ {
+ return 0;
+ }
+
+ for (i = 0;i < LIST_NUM(s->SessionList);i++)
+ {
+ OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
+
+ if (CmpIpAddr(&se->ClientIp, ip) == 0)
+ {
+ ret++;
+ }
+ }
+
+ return ret;
+}
+
+// Create a new session
+OPENVPN_SESSION *OvsNewSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, UINT protocol)
+{
+ OPENVPN_SESSION *se;
+ char server_ip_str[MAX_SIZE];
+ char client_ip_str[MAX_SIZE];
+ // Validate arguments
+ if (s == NULL || server_ip == NULL || server_port == 0 || client_ip == NULL || client_port == 0)
+ {
+ return NULL;
+ }
+
+
+ if (OvsGetNumSessionByClientIp(s, client_ip) > OPENVPN_QUOTA_MAX_NUM_SESSIONS_PER_IP)
+ {
+ // Number of sessions from the same IP address too many
+ return NULL;
+ }
+
+ if (LIST_NUM(s->SessionList) > OPENVPN_QUOTA_MAX_NUM_SESSIONS)
+ {
+ // Too many OpenVPN sessions
+ return NULL;
+ }
+
+ se = ZeroMalloc(sizeof(OPENVPN_SESSION));
+
+ se->Server = s;
+
+ Copy(&se->ClientIp, client_ip, sizeof(IP));
+ se->ClientPort = client_port;
+
+ Copy(&se->ServerIp, server_ip, sizeof(IP));
+ se->ServerPort = server_port;
+
+ se->LastCommTick = s->Now;
+
+ se->Protocol = protocol;
+
+ se->ServerSessionId = OvsNewServerSessionId(se->Server);
+
+ se->CreatedTick = s->Now;
+
+ se->Id = s->NextSessionId;
+ s->NextSessionId++;
+
+ IPToStr(server_ip_str, sizeof(server_ip_str), server_ip);
+ IPToStr(client_ip_str, sizeof(client_ip_str), client_ip);
+ Debug("OpenVPN New Session: %s:%u -> %s:%u Proto=%u\n", server_ip_str, server_port,
+ client_ip_str, client_port, protocol);
+
+ OvsLog(s, se, NULL, "LO_NEW_SESSION", (protocol == OPENVPN_PROTOCOL_UDP ? "UDP" : "TCP"));
+
+ return se;
+}
+
+// Release the session
+void OvsFreeSession(OPENVPN_SESSION *se)
+{
+ UINT i;
+ // Validate arguments
+ if (se == NULL)
+ {
+ return;
+ }
+
+ // If there is IP addresses which is got from a DHCP server in the session, release it
+ if (se->Ipc != NULL)
+ {
+ if (se->Mode == OPENVPN_MODE_L3)
+ {
+ if (se->IpcAsync != NULL)
+ {
+ IP dhcp_ip;
+
+ UINTToIP(&dhcp_ip, se->IpcAsync->L3ClientAddressOption.ServerAddress);
+
+ IPCDhcpFreeIP(se->Ipc, &dhcp_ip);
+ IPCProcessL3Events(se->Ipc);
+ }
+ }
+ }
+
+ // Release the channel
+ for (i = 0;i < OPENVPN_NUM_CHANNELS;i++)
+ {
+ OPENVPN_CHANNEL *c = se->Channels[i];
+
+ if (c != NULL)
+ {
+ OvsFreeChannel(c);
+ }
+ }
+
+ // Release the IPC
+ if (se->Ipc != NULL)
+ {
+ FreeIPC(se->Ipc);
+ }
+
+ if (se->IpcAsync != NULL)
+ {
+ FreeIPCAsync(se->IpcAsync);
+ }
+
+ Free(se);
+}
+
+// Search the session from the endpoint information
+OPENVPN_SESSION *OvsSearchSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, UINT protocol)
+{
+ OPENVPN_SESSION *se;
+ OPENVPN_SESSION t;
+ // Validate arguments
+ if (s == NULL || server_ip == NULL || server_port == 0 || client_ip == NULL || client_port == 0)
+ {
+ return NULL;
+ }
+
+ Copy(&t.ClientIp, client_ip, sizeof(IP));
+ t.ClientPort = client_port;
+ Copy(&t.ServerIp, server_ip, sizeof(IP));
+ t.ServerPort = server_port;
+ t.Protocol = protocol;
+
+ se = Search(s->SessionList, &t);
+
+ return se;
+}
+
+// Receive packets in the OpenVPN server
+void OvsRecvPacket(OPENVPN_SERVER *s, LIST *recv_packet_list, UINT protocol)
+{
+ UINT i, j;
+ LIST *delete_session_list = NULL;
+ // Validate arguments
+ if (s == NULL || recv_packet_list == NULL)
+ {
+ return;
+ }
+
+ s->Now = Tick64();
+
+ // Process for all sessions
+ for (i = 0;i < LIST_NUM(s->SessionList);i++)
+ {
+ OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
+
+ if (se->Ipc != NULL)
+ {
+ if (se->Mode == OPENVPN_MODE_L3)
+ {
+ // Flush the ARP table of the IPC
+ IPCFlushArpTableEx(se->Ipc, s->Now);
+ }
+ }
+ }
+
+ // Process received packets
+ for (i = 0;i < LIST_NUM(recv_packet_list);i++)
+ {
+ UDPPACKET *p = LIST_DATA(recv_packet_list, i);
+
+ OvsProceccRecvPacket(s, p, protocol);
+ }
+
+ // Treat for all sessions and all channels
+ for (i = 0;i < LIST_NUM(s->SessionList);i++)
+ {
+ OPENVPN_CHANNEL *latest_channel = NULL;
+ UINT64 max_tick = 0;
+ OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
+ bool is_disconnected = false;
+
+ if (se->Ipc != NULL)
+ {
+ if (se->Mode == OPENVPN_MODE_L3)
+ {
+ IPCProcessL3Events(se->Ipc);
+ }
+ }
+
+ for (j = 0;j < OPENVPN_NUM_CHANNELS;j++)
+ {
+ OPENVPN_CHANNEL *c = se->Channels[j];
+
+ if (c != NULL)
+ {
+ if (c->RekeyInitiated == false && ((c->NextRekey <= s->Now && c->NextRekey != 0) || (c->LastDataPacketId >= OPENVPN_MAX_PACKET_ID_FOR_TRIGGER_REKEY)))
+ {
+ OPENVPN_CHANNEL *c2;
+ // Send a soft reset by creating a new channel
+ UINT next_channel_id = se->LastCreatedChannelIndex + 1;
+ if (next_channel_id >= OPENVPN_NUM_CHANNELS)
+ {
+ next_channel_id = 1;
+ }
+ if (se->Channels[next_channel_id] != NULL)
+ {
+ // Release when there is a channel data already
+ OvsFreeChannel(se->Channels[next_channel_id]);
+ se->Channels[next_channel_id] = NULL;
+ }
+
+ // Create a new channel
+ c2 = OvsNewChannel(se, (UCHAR)next_channel_id);
+ c2->IsInitiatorServer = true;
+ se->Channels[next_channel_id] = c2;
+ Debug("OpenVPN New Channel for Re-Keying :%u\n", next_channel_id);
+ OvsLog(s, se, c, "LO_INITIATE_REKEY");
+
+ // Send a soft reset
+ OvsSendControlPacket(c2, OPENVPN_P_CONTROL_SOFT_RESET_V1, NULL, 0);
+
+ c->RekeyInitiated = true;
+ }
+ }
+
+ if (c != NULL)
+ {
+ switch (c->Status)
+ {
+ case OPENVPN_CHANNEL_STATUS_TLS_VPN_CONNECTING:
+ // Check whether the connection process completed if there is a channel running a VPN connection process
+ if (se->IpcAsync != NULL)
+ {
+ if (se->IpcAsync->Done)
+ {
+ if (se->IpcAsync->Ipc != NULL)
+ {
+ char option_str[MAX_SIZE];
+ char l3_options[MAX_SIZE];
+
+ // Successful in VPN connection
+ Debug("OpenVPN Channel %u Established (new key).\n", j);
+ OvsLog(s, se, c, "LO_CHANNEL_ESTABLISHED");
+
+ // Return the PUSH_REPLY
+ Format(option_str, sizeof(option_str),
+ "PUSH_REPLY,ping %u,ping-restart %u",
+ (OPENVPN_PING_SEND_INTERVAL / 1000),
+ (OPENVPN_RECV_TIMEOUT / 1000));
+
+ if (se->Mode == OPENVPN_MODE_L3)
+ {
+ // Add such as the IP address that was acquired from the DHCP server
+ // if the L3 mode to the option character string
+ DHCP_OPTION_LIST *cao = &se->IpcAsync->L3ClientAddressOption;
+ char ip_client[64];
+ char ip_tunnel_endpoint[64];
+ UINT ip_tunnel_endpoint_32;
+ char ip_network[64];
+ char ip_subnet_mask[64];
+ char ip_dns1[64];
+ char ip_dns2[64];
+ char ip_wins1[64];
+ char ip_wins2[64];
+ char ip_defgw[64];
+
+ ClearStr(ip_dns1, sizeof(ip_dns1));
+ ClearStr(ip_dns2, sizeof(ip_dns2));
+ ClearStr(ip_wins1, sizeof(ip_wins1));
+ ClearStr(ip_wins2, sizeof(ip_wins2));
+ ClearStr(ip_defgw, sizeof(ip_defgw));
+
+ IPToStr32(ip_client, sizeof(ip_client),
+ cao->ClientAddress);
+
+ // Generate a virtual gateway address to be passed to the OpenVPN
+ ip_tunnel_endpoint_32 = Endian32(cao->ClientAddress);
+ ip_tunnel_endpoint_32++;
+ ip_tunnel_endpoint_32 = Endian32(ip_tunnel_endpoint_32);
+ IPToStr32(ip_tunnel_endpoint, sizeof(ip_tunnel_endpoint), ip_tunnel_endpoint_32);
+
+ // Create a subnet information for the LAN
+ IPToStr32(ip_network, sizeof(ip_network),
+ GetNetworkAddress(cao->ClientAddress,
+ cao->SubnetMask));
+
+ IPToStr32(ip_subnet_mask, sizeof(ip_subnet_mask),
+ cao->SubnetMask);
+
+ Format(l3_options, sizeof(l3_options),
+ ",ifconfig %s %s",
+// ",ifconfig %s %s,route %s %s %s 1",
+ ip_client, ip_tunnel_endpoint, ip_network, ip_subnet_mask,
+ ip_tunnel_endpoint);
+ StrCat(option_str, sizeof(option_str), l3_options);
+
+ // Domain name
+ if (IsEmptyStr(cao->DomainName) == false)
+ {
+ Format(l3_options, sizeof(l3_options),
+ ",dhcp-option DOMAIN %s", cao->DomainName);
+ StrCat(option_str, sizeof(option_str), l3_options);
+ }
+
+ // DNS server address 1
+ if (cao->DnsServer != 0)
+ {
+ char ip_str[64];
+ IPToStr32(ip_str, sizeof(ip_str), cao->DnsServer);
+ Format(l3_options, sizeof(l3_options),
+ ",dhcp-option DNS %s", ip_str);
+ StrCat(option_str, sizeof(option_str), l3_options);
+
+ StrCpy(ip_dns1, sizeof(ip_dns1), ip_str);
+ }
+
+ // DNS server address 2
+ if (cao->DnsServer2 != 0)
+ {
+ char ip_str[64];
+ IPToStr32(ip_str, sizeof(ip_str), cao->DnsServer2);
+ Format(l3_options, sizeof(l3_options),
+ ",dhcp-option DNS %s", ip_str);
+ StrCat(option_str, sizeof(option_str), l3_options);
+
+ StrCpy(ip_dns2, sizeof(ip_dns2), ip_str);
+ }
+
+ // WINS address 1
+ if (cao->WinsServer != 0)
+ {
+ char ip_str[64];
+ IPToStr32(ip_str, sizeof(ip_str), cao->WinsServer);
+ Format(l3_options, sizeof(l3_options),
+ ",dhcp-option WINS %s", ip_str);
+ StrCat(option_str, sizeof(option_str), l3_options);
+
+ StrCpy(ip_wins1, sizeof(ip_wins1), ip_str);
+ }
+
+ // WINS address 2
+ if (cao->WinsServer2 != 0)
+ {
+ char ip_str[64];
+ IPToStr32(ip_str, sizeof(ip_str), cao->WinsServer2);
+ Format(l3_options, sizeof(l3_options),
+ ",dhcp-option WINS %s", ip_str);
+ StrCat(option_str, sizeof(option_str), l3_options);
+
+ StrCpy(ip_wins2, sizeof(ip_wins2), ip_str);
+ }
+
+ // Default gateway
+ if (cao->Gateway != 0)
+ {
+ Format(l3_options, sizeof(l3_options),
+ ",route-gateway %s,redirect-gateway def1", ip_tunnel_endpoint);
+ StrCat(option_str, sizeof(option_str), l3_options);
+
+ IPToStr32(ip_defgw, sizeof(ip_defgw), cao->Gateway);
+ }
+
+ OvsLog(s, se, c, "LP_SET_IPV4_PARAM",
+ ip_client, ip_subnet_mask, ip_defgw, ip_dns1, ip_dns2, ip_wins1, ip_wins2);
+ }
+
+ WriteFifo(c->SslPipe->SslInOut->SendFifo, option_str, StrSize(option_str));
+
+ Debug("Push Str: %s\n", option_str);
+ OvsLog(s, se, c, "LO_PUSH_REPLY", option_str);
+
+ StrCpy(se->PushReplyStr, sizeof(se->PushReplyStr), option_str);
+
+ se->Ipc = se->IpcAsync->Ipc;
+ se->IpcAsync->Ipc = NULL;
+
+ s->SessionEstablishedCount++;
+
+ // Set a Sock Event of IPC to Sock Event of the UDP Listener
+ IPCSetSockEventWhenRecvL2Packet(se->Ipc, s->SockEvent);
+
+ // State transition
+ c->Status = OPENVPN_CHANNEL_STATUS_ESTABLISHED;
+ c->EstablishedTick = s->Now;
+ se->Established = true;
+ se->LastCommTick = Tick64();
+ }
+ else
+ {
+ char *str;
+
+ if (se->IpcAsync->DhcpAllocFailed)
+ {
+ OvsLog(s, se, c, "LP_DHCP_REQUEST_NG");
+ }
+
+ // Failed to connect VPN
+ Debug("OpenVPN Channel %u Failed.\n", j);
+ OvsLog(s, se, c, "LO_CHANNEL_FAILED");
+
+ // Return the AUTH_FAILED
+ str = "AUTH_FAILED";
+ WriteFifo(c->SslPipe->SslInOut->SendFifo, str, StrSize(str));
+
+ s->SessionEstablishedCount++;
+
+ // State transition
+ c->Status = OPENVPN_CHANNEL_STATUS_DISCONNECTED;
+
+ FreeIPCAsync(se->IpcAsync);
+ se->IpcAsync = NULL;
+ }
+ }
+ }
+ break;
+
+ case OPENVPN_CHANNEL_STATUS_ESTABLISHED:
+ // Monitor the IPC whether not disconnected when there is a VPN connection completed channel
+ if (IsIPCConnected(se->Ipc) == false)
+ {
+ // Send the RESTART since IPC is disconnected
+ char *str = "RESTART";
+ Debug("OpenVPN Channel %u Disconnected by HUB.\n", j);
+
+ OvsLog(s, se, c, "LO_CHANNEL_DISCONNECTED_BY_HUB");
+
+ WriteFifo(c->SslPipe->SslInOut->SendFifo, str, StrSize(str));
+
+ // State transition
+ c->Status = OPENVPN_CHANNEL_STATUS_DISCONNECTED;
+
+ // Set the session to disconnected state
+ se->Established = false;
+ se->LastCommTick = s->Now;
+ }
+ break;
+ }
+ }
+
+ if (c != NULL)
+ {
+ // If there is a packet to be transmitted physically in SSL, send it
+ if (c->SslPipe != NULL && SyncSslPipe(c->SslPipe))
+ {
+ if (FifoSize(c->SslPipe->RawOut->RecvFifo) >= 1)
+ {
+ Debug("RawOut Fifo Size (c=%u): %u\n", c->KeyId, FifoSize(c->SslPipe->RawOut->RecvFifo));
+
+ OvsSendControlPacketWithAutoSplit(c, OPENVPN_P_CONTROL_V1,
+ FifoPtr(c->SslPipe->RawOut->RecvFifo),
+ FifoSize(c->SslPipe->RawOut->RecvFifo));
+
+ ReadFifo(c->SslPipe->RawOut->RecvFifo, NULL, FifoSize(c->SslPipe->RawOut->RecvFifo));
+ }
+ }
+ }
+
+ if (c != NULL)
+ {
+ UINT num;
+ UINT acks[OPENVPN_MAX_NUMACK];
+ UINT k;
+
+ // Packet transmission
+ for (k = 0;k < LIST_NUM(c->SendControlPacketList);k++)
+ {
+ OPENVPN_CONTROL_PACKET *cp = LIST_DATA(c->SendControlPacketList, k);
+
+ if (cp->NextSendTime <= s->Now)
+ {
+ OPENVPN_PACKET *p;
+
+ num = OvsGetAckReplyList(c, acks);
+
+ p = OvsNewControlPacket(cp->OpCode, j, se->ServerSessionId, num, acks,
+ se->ClientSessionId, cp->PacketId, cp->DataSize, cp->Data);
+
+ OvsSendPacketNow(s, se, p);
+
+ OvsFreePacket(p);
+
+ cp->NextSendTime = s->Now + (UINT64)OPENVPN_CONTROL_PACKET_RESEND_INTERVAL;
+
+ AddInterrupt(s->Interrupt, cp->NextSendTime);
+ }
+ }
+
+ // If the response with an ACK-only packet is required, respond such that
+ num = OvsGetAckReplyList(c, acks);
+
+ if (num >= 1)
+ {
+ OPENVPN_PACKET *p = OvsNewControlPacket(OPENVPN_P_ACK_V1, j, se->ServerSessionId,
+ num, acks, se->ClientSessionId, 0, 0, NULL);
+
+ OvsSendPacketNow(s, se, p);
+
+ OvsFreePacket(p);
+ }
+ }
+ }
+
+ if (se->Ipc != NULL)
+ {
+ if (se->Mode == OPENVPN_MODE_L3)
+ {
+ if (se->IpcAsync != NULL)
+ {
+ // Update DHCP address
+ if (se->IpcAsync->L3NextDhcpRenewTick <= s->Now)
+ {
+ IP ip;
+
+ se->IpcAsync->L3NextDhcpRenewTick = s->Now + se->IpcAsync->L3DhcpRenewInterval;
+
+ UINTToIP(&ip, se->IpcAsync->L3ClientAddressOption.ServerAddress);
+
+ IPCDhcpRenewIP(se->Ipc, &ip);
+ }
+ }
+
+ IPCProcessL3Events(se->Ipc);
+ }
+
+ IPCProcessInterrupts(se->Ipc);
+ }
+
+ // Choose the latest channel in all established channels
+ for (j = 0;j < OPENVPN_NUM_CHANNELS;j++)
+ {
+ OPENVPN_CHANNEL *c = se->Channels[j];
+
+ if (c != NULL)
+ {
+ if (c->Status == OPENVPN_CHANNEL_STATUS_ESTABLISHED)
+ {
+ if (max_tick <= c->EstablishedTick)
+ {
+ max_tick = c->EstablishedTick;
+ latest_channel = c;
+ }
+ }
+ }
+ }
+
+ if (se->Established == false)
+ {
+ latest_channel = NULL;
+ }
+
+ // Send the data using the latest channel (when there is no transmission channel, suck out the queue simply)
+ if (se->Mode == OPENVPN_MODE_L2)
+ {
+ // Get an Ethernet frame from IPC
+ while (true)
+ {
+ BLOCK *b = IPCRecvL2(se->Ipc);
+ if (b == NULL)
+ {
+ break;
+ }
+
+ if (latest_channel != NULL && s->SupressSendPacket == false)
+ {
+ OvsSendDataPacket(latest_channel, latest_channel->KeyId, ++latest_channel->LastDataPacketId, b->Buf, b->Size);
+ }
+
+ FreeBlock(b);
+ }
+ }
+ else
+ {
+ // Get an IPv4 packet from IPC
+ while (true)
+ {
+ BLOCK *b = IPCRecvIPv4(se->Ipc);
+ if (b == NULL)
+ {
+ break;
+ }
+
+ if (latest_channel != NULL && s->SupressSendPacket == false)
+ {
+ OvsSendDataPacket(latest_channel, latest_channel->KeyId, ++latest_channel->LastDataPacketId, b->Buf, b->Size);
+ }
+
+ FreeBlock(b);
+ }
+ }
+
+ // Send a Ping
+ if (latest_channel != NULL)
+ {
+ if ((se->NextPingSendTick == 0) || (se->NextPingSendTick <= s->Now))
+ {
+ se->NextPingSendTick = s->Now + (UINT64)(OPENVPN_PING_SEND_INTERVAL);
+
+ OvsSendDataPacket(latest_channel, latest_channel->KeyId, ++latest_channel->LastDataPacketId,
+ ping_signature, sizeof(ping_signature));
+ //Debug(".");
+
+ AddInterrupt(s->Interrupt, se->NextPingSendTick);
+ }
+ }
+
+ if ((se->Established == false) && (s->Now >= (se->CreatedTick + (UINT64)OPENVPN_NEW_SESSION_DEADLINE_TIMEOUT)))
+ {
+ is_disconnected = true;
+ }
+
+ if (se->Established && (s->Now >= (se->LastCommTick + (UINT64)OPENVPN_RECV_TIMEOUT)))
+ {
+ is_disconnected = true;
+ }
+
+ if (is_disconnected)
+ {
+ if (delete_session_list == NULL)
+ {
+ delete_session_list = NewListFast(NULL);
+ }
+
+ Add(delete_session_list, se);
+ }
+ }
+
+ if (delete_session_list != NULL)
+ {
+ UINT i;
+
+ for (i = 0;i < LIST_NUM(delete_session_list);i++)
+ {
+ OPENVPN_SESSION *se = LIST_DATA(delete_session_list, i);
+
+ Debug("Deleting Session %p\n", se);
+ OvsLog(s, se, NULL, "LO_DELETE_SESSION");
+
+ OvsFreeSession(se);
+
+ s->DisconnectCount++;
+
+ Delete(s->SessionList, se);
+ }
+
+ ReleaseList(delete_session_list);
+ }
+}
+
+// Send the packet now
+void OvsSendPacketNow(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_PACKET *p)
+{
+ BUF *b;
+ UINT i;
+ // Validate arguments
+ if (s == NULL || se == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Debug("Sending Opcode=%u ", p->OpCode);
+ if (p->NumAck >= 1)
+ {
+ Debug("Sending ACK Packet IDs (c=%u): ", p->KeyId);
+ for (i = 0;i < p->NumAck;i++)
+ {
+ Debug("%u ", p->AckPacketId[i]);
+ }
+ }
+ Debug("\n");
+
+ b = OvsBuildPacket(p);
+
+ OvsSendPacketRawNow(s, se, b->Buf, b->Size);
+
+ Free(b);
+}
+void OvsSendPacketRawNow(OPENVPN_SERVER *s, OPENVPN_SESSION *se, void *data, UINT size)
+{
+ UDPPACKET *u;
+
+ // Validate arguments
+ if (s == NULL || se == NULL || data == NULL || size == 0)
+ {
+ Free(data);
+ return;
+ }
+
+ u = NewUdpPacket(&se->ServerIp, se->ServerPort, &se->ClientIp, se->ClientPort,
+ data, size);
+
+ Add(s->SendPacketList, u);
+}
+// Create a new OpenVPN control packet
+OPENVPN_PACKET *OvsNewControlPacket(UCHAR opcode, UCHAR key_id, UINT64 my_channel_id, UINT num_ack,
+ UINT *ack_packet_ids, UINT64 your_channel_id, UINT packet_id,
+ UINT data_size, UCHAR *data)
+{
+ OPENVPN_PACKET *p = ZeroMalloc(sizeof(OPENVPN_PACKET));
+ UINT i;
+
+ p->OpCode = opcode;
+ p->KeyId = key_id;
+ p->MySessionId = my_channel_id;
+ p->NumAck = num_ack;
+
+ for (i = 0;i < MIN(num_ack, OPENVPN_MAX_NUMACK);i++)
+ {
+ p->AckPacketId[i] = ack_packet_ids[i];
+ }
+
+ p->YourSessionId = your_channel_id;
+ p->PacketId = packet_id;
+
+ if (data_size != 0 && data != NULL)
+ {
+ p->Data = Clone(data, data_size);
+ p->DataSize = data_size;
+ }
+
+ return p;
+}
+
+// Comparison function of the entries in the session list
+int OvsCompareSessionList(void *p1, void *p2)
+{
+ OPENVPN_SESSION *s1, *s2;
+ int i;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ s1 = *(OPENVPN_SESSION **)p1;
+ s2 = *(OPENVPN_SESSION **)p2;
+ if (s1 == NULL || s2 == NULL)
+ {
+ return 0;
+ }
+
+ i = CmpIpAddr(&s1->Protocol, &s2->Protocol);
+ if (i != 0)
+ {
+ return i;
+ }
+
+ i = CmpIpAddr(&s1->ClientIp, &s2->ClientIp);
+ if (i != 0)
+ {
+ return i;
+ }
+
+ i = COMPARE_RET(s1->ClientPort, s2->ClientPort);
+ if (i != 0)
+ {
+ return i;
+ }
+
+ i = CmpIpAddr(&s1->ServerIp, &s2->ServerIp);
+ if (i != 0)
+ {
+ return i;
+ }
+
+ i = COMPARE_RET(s1->ServerPort, s2->ServerPort);
+ if (i != 0)
+ {
+ return i;
+ }
+
+ return 0;
+}
+
+// Identify whether the IP address is compatible to the tun device of OpenVPN
+bool OvsIsCompatibleL3IP(UINT ip)
+{
+ IP p;
+
+ UINTToIP(&p, ip);
+ if ((p.addr[3] % 4) == 1)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Get an IP address that is compatible to tun device of the OpenVPN after the specified IP address
+UINT OvsGetCompatibleL3IPNext(UINT ip)
+{
+ ip = Endian32(ip);
+
+ while (true)
+ {
+ if (OvsIsCompatibleL3IP(Endian32(ip)))
+ {
+ return Endian32(ip);
+ }
+
+ ip++;
+ }
+}
+
+// Create a new OpenVPN server
+OPENVPN_SERVER *NewOpenVpnServer(CEDAR *cedar, INTERRUPT_MANAGER *interrupt, SOCK_EVENT *sock_event)
+{
+ OPENVPN_SERVER *s;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ s = ZeroMalloc(sizeof(OPENVPN_SERVER));
+
+ s->Cedar = cedar;
+
+ AddRef(s->Cedar->ref);
+
+ s->Interrupt = interrupt;
+
+ s->SessionList = NewList(OvsCompareSessionList);
+ s->SendPacketList = NewListFast(NULL);
+
+ s->Now = Tick64();
+
+ s->NextSessionId = 1;
+
+ if (sock_event != NULL)
+ {
+ s->SockEvent = sock_event;
+ AddRef(s->SockEvent->ref);
+ }
+
+ OvsLog(s, NULL, NULL, "LO_START");
+
+ s->Dh = DhNewGroup2();
+
+ return s;
+}
+
+// Release the OpenVPN server
+void FreeOpenVpnServer(OPENVPN_SERVER *s)
+{
+ UINT i;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ OvsLog(s, NULL, NULL, "LO_STOP");
+
+ // Release the session list
+ for (i = 0;i < LIST_NUM(s->SessionList);i++)
+ {
+ OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
+
+ OvsFreeSession(se);
+ }
+
+ ReleaseList(s->SessionList);
+
+ // Release the packet which is attempting to send
+ for (i = 0;i < LIST_NUM(s->SendPacketList);i++)
+ {
+ UDPPACKET *p = LIST_DATA(s->SendPacketList, i);
+
+ FreeUdpPacket(p);
+ }
+
+ ReleaseList(s->SendPacketList);
+
+ ReleaseCedar(s->Cedar);
+
+ if (s->SockEvent != NULL)
+ {
+ ReleaseSockEvent(s->SockEvent);
+ }
+
+ DhFree(s->Dh);
+
+ Free(s);
+}
+
+// UDP reception procedure
+void OpenVpnServerUdpListenerProc(UDPLISTENER *u, LIST *packet_list)
+{
+ OPENVPN_SERVER_UDP *us;
+ UINT64 now = Tick64();
+ // Validate arguments
+ if (u == NULL || packet_list == NULL)
+ {
+ return;
+ }
+
+ us = (OPENVPN_SERVER_UDP *)u->Param;
+
+ if (OvsGetNoOpenVpnUdp())
+ {
+ // OpenVPN over UDP is disabled
+ return;
+ }
+
+ if (us->OpenVpnServer != NULL)
+ {
+ {
+ u->PollMyIpAndPort = false;
+
+ ClearStr(us->Cedar->OpenVPNPublicPorts, sizeof(us->Cedar->OpenVPNPublicPorts));
+ }
+
+ OvsRecvPacket(us->OpenVpnServer, packet_list, OPENVPN_PROTOCOL_UDP);
+
+ UdpListenerSendPackets(u, us->OpenVpnServer->SendPacketList);
+ DeleteAll(us->OpenVpnServer->SendPacketList);
+ }
+}
+
+// Create an OpenVPN server (UDP mode)
+OPENVPN_SERVER_UDP *NewOpenVpnServerUdp(CEDAR *cedar)
+{
+ OPENVPN_SERVER_UDP *u;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ u = ZeroMalloc(sizeof(OPENVPN_SERVER_UDP));
+
+ u->Cedar = cedar;
+
+ AddRef(u->Cedar->ref);
+
+ // Create a UDP listener
+ u->UdpListener = NewUdpListener(OpenVpnServerUdpListenerProc, u);
+
+ // Create an OpenVPN server
+ u->OpenVpnServer = NewOpenVpnServer(cedar, u->UdpListener->Interrupts, u->UdpListener->Event);
+
+ return u;
+}
+
+// Apply the port list to the OpenVPN server
+void OvsApplyUdpPortList(OPENVPN_SERVER_UDP *u, char *port_list)
+{
+ LIST *o;
+ UINT i;
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+
+ DeleteAllPortFromUdpListener(u->UdpListener);
+
+ o = StrToIntList(port_list, true);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ UINT port = *((UINT *)LIST_DATA(o, i));
+
+ if (port >= 1 && port <= 65535)
+ {
+ AddPortToUdpListener(u->UdpListener, port);
+ }
+ }
+
+ ReleaseIntList(o);
+}
+
+// Release the OpenVPN server (UDP mode)
+void FreeOpenVpnServerUdp(OPENVPN_SERVER_UDP *u)
+{
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+
+ // Stop the UDP listener
+ FreeUdpListener(u->UdpListener);
+
+ // Release the OpenVPN server
+ FreeOpenVpnServer(u->OpenVpnServer);
+
+ ReleaseCedar(u->Cedar);
+
+ Free(u);
+}
+
+// Check whether it's OpenSSL protocol by looking the first receive buffer of the TCP
+bool OvsCheckTcpRecvBufIfOpenVPNProtocol(UCHAR *buf, UINT size)
+{
+ if (buf == NULL || size != 2)
+ {
+ return false;
+ }
+
+ if (buf[0] == 0x00 && buf[1] == 0x0E)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Run the OpenVPN server in TCP mode
+bool OvsPerformTcpServer(CEDAR *cedar, SOCK *sock)
+{
+ OPENVPN_SERVER *s;
+ INTERRUPT_MANAGER *im;
+ SOCK_EVENT *se;
+ FIFO *tcp_recv_fifo;
+ FIFO *tcp_send_fifo;
+ UINT buf_size = (128 * 1024);
+ UCHAR *buf;
+ UINT64 giveup_time = Tick64() + (UINT64)OPENVPN_NEW_SESSION_DEADLINE_TIMEOUT;
+ LIST *ovs_recv_packet;
+ UINT i;
+ bool ret = false;
+ // Validate arguments
+ if (cedar == NULL || sock == NULL)
+ {
+ return false;
+ }
+
+ // Initialize
+ buf = Malloc(buf_size);
+ im = NewInterruptManager();
+ se = NewSockEvent();
+ SetTimeout(sock, TIMEOUT_INFINITE);
+ JoinSockToSockEvent(sock, se);
+
+ tcp_recv_fifo = NewFifoFast();
+ tcp_send_fifo = NewFifoFast();
+
+ ovs_recv_packet = NewListFast(NULL);
+
+ // Create an OpenVPN server
+ s = NewOpenVpnServer(cedar, im, se);
+
+ // Main loop
+ Debug("Entering OpenVPN TCP Server Main Loop.\n");
+ while (true)
+ {
+ UINT next_interval;
+ bool disconnected = false;
+ UINT64 now = Tick64();
+
+ // Receive data from a TCP socket
+ while (true)
+ {
+ UINT r = Recv(sock, buf, buf_size, false);
+ if (r == SOCK_LATER)
+ {
+ // Can not read any more
+ break;
+ }
+ else if (r == 0)
+ {
+ // Disconnected
+ disconnected = true;
+ break;
+ }
+ else
+ {
+ // Read
+ WriteFifo(tcp_recv_fifo, buf, r);
+ }
+ }
+
+ // Separate to a list of datagrams by interpreting the data received from the TCP socket
+ while (true)
+ {
+ UINT r = FifoSize(tcp_recv_fifo);
+ if (r >= sizeof(USHORT))
+ {
+ void *ptr = FifoPtr(tcp_recv_fifo);
+ USHORT packet_size = READ_USHORT(ptr);
+ if (packet_size <= OPENVPN_TCP_MAX_PACKET_SIZE)
+ {
+ UINT total_len = (UINT)packet_size + sizeof(USHORT);
+ if (r >= total_len)
+ {
+ if (ReadFifo(tcp_recv_fifo, buf, total_len) != total_len)
+ {
+ // Mismatch
+ disconnected = true;
+ break;
+ }
+ else
+ {
+ // Read one packet
+ UINT payload_len = packet_size;
+ UCHAR *payload_ptr = buf + sizeof(USHORT);
+
+ // Pass the packet to the OpenVPN server
+ Add(ovs_recv_packet, NewUdpPacket(&sock->RemoteIP, sock->RemotePort,
+ &sock->LocalIP, sock->LocalPort,
+ Clone(payload_ptr, payload_len), payload_len));
+ }
+ }
+ else
+ {
+ // Non-arrival
+ break;
+ }
+ }
+ else
+ {
+ // Invalid packet size
+ disconnected = true;
+ break;
+ }
+ }
+ else
+ {
+ // Non-arrival
+ break;
+ }
+ }
+
+ // Pass a list of received datagrams to the OpenVPN server
+ OvsRecvPacket(s, ovs_recv_packet, OPENVPN_PROTOCOL_TCP);
+
+ // Release the received packet list
+ for (i = 0;i < LIST_NUM(ovs_recv_packet);i++)
+ {
+ UDPPACKET *p = LIST_DATA(ovs_recv_packet, i);
+
+ FreeUdpPacket(p);
+ }
+
+ DeleteAll(ovs_recv_packet);
+
+ // Store in the queue by getting a list of the datagrams to be transmitted from the OpenVPN server
+ for (i = 0;i < LIST_NUM(s->SendPacketList);i++)
+ {
+ UDPPACKET *p = LIST_DATA(s->SendPacketList, i);
+ // Store the size to the TCP send queue first
+ USHORT us = (USHORT)p->Size;
+ //Debug(" *** TCP SEND %u\n", us);
+ us = Endian16(us);
+ WriteFifo(tcp_send_fifo, &us, sizeof(USHORT));
+
+ // Write the data body
+ WriteFifo(tcp_send_fifo, p->Data, p->Size);
+
+ // Packet release
+ FreeUdpPacket(p);
+ }
+ DeleteAll(s->SendPacketList);
+
+ // Send data to the TCP socket
+ while (FifoSize(tcp_send_fifo) >= 1)
+ {
+ UINT r = Send(sock, FifoPtr(tcp_send_fifo), FifoSize(tcp_send_fifo), false);
+
+ if (r == SOCK_LATER)
+ {
+ // Can not write any more
+ break;
+ }
+ else if (r == 0)
+ {
+ // Disconnected
+ disconnected = true;
+ break;
+ }
+ else
+ {
+ // Wrote out
+ ReadFifo(tcp_send_fifo, NULL, r);
+ }
+ }
+
+ if (FifoSize(tcp_send_fifo) > MAX_BUFFERING_PACKET_SIZE)
+ {
+ s->SupressSendPacket = true;
+ }
+ else
+ {
+ s->SupressSendPacket = false;
+ }
+
+ if (s->DisconnectCount >= 1)
+ {
+ // Session disconnection has occurred on OpenVPN server-side
+ disconnected = true;
+ }
+
+ if (giveup_time <= now)
+ {
+ UINT i;
+ UINT num_established_sessions = 0;
+ for (i = 0;i < LIST_NUM(s->SessionList);i++)
+ {
+ OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
+
+ if (se->Established)
+ {
+ num_established_sessions++;
+ }
+ }
+
+ if (num_established_sessions == 0)
+ {
+ // If the number of sessions is 0 even if wait a certain period of time after the start of server, abort
+ disconnected = true;
+ }
+ }
+
+ if (disconnected)
+ {
+ // Error or disconnect occurs
+ Debug("Breaking OpenVPN TCP Server Main Loop.\n");
+ break;
+ }
+
+ // Wait until the next event occurs
+ next_interval = GetNextIntervalForInterrupt(im);
+ next_interval = MIN(next_interval, UDPLISTENER_WAIT_INTERVAL);
+ WaitSockEvent(se, next_interval);
+ }
+
+ if (s != NULL && s->SessionEstablishedCount != 0)
+ {
+ ret = true;
+ }
+
+ // Release the OpenVPN server
+ FreeOpenVpnServer(s);
+
+ // Release object
+ FreeInterruptManager(im);
+ ReleaseSockEvent(se);
+ ReleaseFifo(tcp_recv_fifo);
+ ReleaseFifo(tcp_send_fifo);
+ Free(buf);
+
+ // Release the received packet list
+ for (i = 0;i < LIST_NUM(ovs_recv_packet);i++)
+ {
+ UDPPACKET *p = LIST_DATA(ovs_recv_packet, i);
+
+ FreeUdpPacket(p);
+ }
+
+ ReleaseList(ovs_recv_packet);
+
+ return ret;
+}
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Interop_OpenVPN.h b/src/Cedar/Interop_OpenVPN.h
new file mode 100644
index 00000000..c60b6a60
--- /dev/null
+++ b/src/Cedar/Interop_OpenVPN.h
@@ -0,0 +1,362 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Interop_OpenVPN.h
+// Header of Interop_OpenVPN.c
+
+#ifndef INTEROP_OPENVPN_H
+#define INTEROP_OPENVPN_H
+
+
+//// Constants
+#define OPENVPN_UDP_PORT 1194 // OpenVPN default UDP port number
+#define OPENVPN_UDP_PORT_INCLUDE 1195 // OpenVPN default UDP port number (Operating within the client)
+
+#define OPENVPN_MAX_NUMACK 4 // The maximum number of ACKs
+#define OPENVPN_NUM_CHANNELS 8 // Maximum number of channels during a session
+#define OPENVPN_CONTROL_PACKET_RESEND_INTERVAL 500 // Control packet retransmission interval
+#define OPENVPN_CONTROL_PACKET_MAX_DATASIZE 1200 // Maximum data size that can be stored in one control packet
+
+#define OPENVPN_MAX_SSL_RECV_BUF_SIZE (256 * 1024) // SSL receive buffer maximum length
+
+#define OPENVPN_MAX_KEY_SIZE 64 // Maximum key size
+
+#define OPENVPN_TMP_BUFFER_SIZE (65536 + 256) // Temporary buffer size
+
+#define OPENVPN_PING_SEND_INTERVAL 3000 // Transmission interval of Ping
+#define OPENVPN_RECV_TIMEOUT 10000 // Communication time-out
+#define OPENVPN_NEW_SESSION_DEADLINE_TIMEOUT 30000 // Grace time to complete new VPN session connection since it was created
+
+#define OPENVPN_MAX_PACKET_ID_FOR_TRIGGER_REKEY 0xFF000000 // Packet ID that is a trigger to start the re-key
+#define OPENVPN_TCP_MAX_PACKET_SIZE 2000 // The maximum packet size allowed in TCP mode
+
+
+// The default algorithm
+#define OPENVPN_DEFAULT_CIPHER "AES-128-CBC"
+#define OPENVPN_DEFAULT_MD "SHA1"
+
+// Encryption related
+#define OPENVPN_PREMASTER_LABEL "OpenVPN master secret"
+#define OPENVPN_EXPANSION_LABEL "OpenVPN key expansion"
+
+// IPC related
+#define OPENVPN_IPC_CLIENT_NAME "OpenVPN Client"
+#define OPENVPN_IPC_POSTFIX_L2 "OPENVPN_L2"
+#define OPENVPN_IPC_POSTFIX_L3 "OPENVPN_L3"
+
+// List of supported encryption algorithms
+#define OPENVPN_CIPHER_LIST "[NULL-CIPHER] NULL AES-128-CBC AES-192-CBC AES-256-CBC BF-CBC CAST-CBC CAST5-CBC DES-CBC DES-EDE-CBC DES-EDE3-CBC DESX-CBC RC2-40-CBC RC2-64-CBC RC2-CBC"
+
+// List of the supported hash algorithm
+#define OPENVPN_MD_LIST "SHA SHA1 MD5 MD4 RMD160"
+
+// MTU
+#define OPENVPN_MTU_LINK 1514 // Ethernet MTU
+#define OPENVPN_MTU_TUN 1500 // Tun MTU
+
+// Protocol
+#define OPENVPN_PROTOCOL_UDP 0 // UDP
+#define OPENVPN_PROTOCOL_TCP 1 // TCP
+
+// Op-code
+#define OPENVPN_P_CONTROL_SOFT_RESET_V1 3 // Soft reset request
+#define OPENVPN_P_CONTROL_V1 4 // SSL negotiation packet
+#define OPENVPN_P_ACK_V1 5 // Acknowledgment
+#define OPENVPN_P_DATA_V1 6 // Data packet
+#define OPENVPN_P_CONTROL_HARD_RESET_CLIENT_V2 7 // Connection request from client
+#define OPENVPN_P_CONTROL_HARD_RESET_SERVER_V2 8 // Connection response from server
+
+// State of OpenVPN channel
+#define OPENVPN_CHANNEL_STATUS_INIT 0 // Initialization phase
+#define OPENVPN_CHANNEL_STATUS_TLS_WAIT_CLIENT_KEY 1 // Waiting for the key information from the client
+#define OPENVPN_CHANNEL_STATUS_TLS_WAIT_CLIENT_PUSH_REQUEST 2 // Waiting for PUSH_REQUEST from the client
+#define OPENVPN_CHANNEL_STATUS_TLS_VPN_CONNECTING 3 // VPN connecting process is running
+#define OPENVPN_CHANNEL_STATUS_ESTABLISHED 4 // VPN connection established
+#define OPENVPN_CHANNEL_STATUS_DISCONNECTED 5 // Disconnected
+
+// Quota
+#define OPENVPN_QUOTA_MAX_NUM_SESSIONS_PER_IP 1000 // Number of OpenVPN sessions per IP address
+#define OPENVPN_QUOTA_MAX_NUM_SESSIONS 30000 // Limit of the number of sessions
+
+// Mode
+#define OPENVPN_MODE_UNKNOWN 0 // Unknown
+#define OPENVPN_MODE_L2 1 // TAP (Ethernet)
+#define OPENVPN_MODE_L3 2 // TUN (IP)
+
+
+//// Type
+
+// Data of OpenVPN Key Method 2
+struct OPENVPN_KEY_METHOD_2
+{
+ UCHAR PreMasterSecret[48]; // Pre Master Secret (client only)
+ UCHAR Random1[32]; // Random 1
+ UCHAR Random2[32]; // Random 2
+ char OptionString[512]; // Option string
+ char Username[512]; // User name
+ char Password[512]; // Password
+ char PeerInfo[1536]; // PeerInfo
+};
+
+// OpenVPN sending control packet
+struct OPENVPN_CONTROL_PACKET
+{
+ UCHAR OpCode; // Op-code
+ UINT PacketId; // Packet ID
+ UINT DataSize; // Data size
+ UCHAR *Data; // Data body
+ UINT64 NextSendTime; // Scheduled next transmission time
+};
+
+// OpenVPN packet
+struct OPENVPN_PACKET
+{
+ UCHAR OpCode; // Op-code
+ UCHAR KeyId; // Key ID
+ UINT64 MySessionId; // Channel ID of the sender
+ UCHAR NumAck; // Number of ACK
+ UINT AckPacketId[OPENVPN_MAX_NUMACK]; // ACK packet ID list
+ UINT64 YourSessionId; // Destination Channel ID (If there are one or more ACK)
+ UINT PacketId; // Packet ID
+ UINT DataSize; // Data size
+ UCHAR *Data; // Data body
+};
+
+// OpenVPN channel
+struct OPENVPN_CHANNEL
+{
+ OPENVPN_SERVER *Server;
+ OPENVPN_SESSION *Session;
+ UINT Status; // State
+ LIST *AckReplyList; // Response ACK list
+ UINT MaxRecvPacketId; // The maximum value of the arrived packet ID
+ UINT NextSendPacketId; // The value of a packet ID to be transmitted next
+ LIST *SendControlPacketList; // Sending control packet list
+ SSL_PIPE *SslPipe; // SSL pipe
+ OPENVPN_KEY_METHOD_2 ClientKey; // Key sent from the client
+ OPENVPN_KEY_METHOD_2 ServerKey; // Key sent from the server
+ char Proto[64]; // Protocol
+ CIPHER *CipherEncrypt; // Encryption algorithm
+ CIPHER *CipherDecrypt; // Decryption algorithm
+ MD *MdSend; // Transmission MD algorithm
+ MD *MdRecv; // Reception MD algorithm
+ UCHAR MasterSecret[48]; // Master Secret
+ UCHAR ExpansionKey[256]; // Expansion Key
+ UCHAR NextIv[64]; // Next IV
+ UINT LastDataPacketId; // Previous Data Packet ID
+ UINT64 EstablishedTick; // Established time
+ UCHAR KeyId; // KEY ID
+ bool IsRekeyChannel; // Whether it is a channel for key update
+ bool IsInitiatorServer; // Whether the channel was started from the server side
+ bool RekeyInitiated; // Whether re-keying has already started
+ UINT64 NextRekey;
+};
+
+// OpenVPN session
+struct OPENVPN_SESSION
+{
+ UINT Id; // ID
+ OPENVPN_SERVER *Server;
+ UINT64 ServerSessionId; // The session ID of the server-side
+ UINT64 ClientSessionId; // Session ID of the client side
+ UINT Protocol; // Protocol
+ IP ClientIp; // Client IP address
+ UINT ClientPort; // Client port number
+ IP ServerIp; // Server IP address
+ UINT ServerPort; // Server port number
+ OPENVPN_CHANNEL *Channels[OPENVPN_NUM_CHANNELS]; // Channels (up to 8)
+ UINT LastCreatedChannelIndex; // Channel number that is created in the last
+ UINT Mode; // Mode (L3 or L2)
+ UINT LinkMtu; // link-mtu
+ UINT TunMtu; // tun-mtu
+ IPC_ASYNC *IpcAsync; // Asynchronous IPC connection
+ IPC *Ipc; // Connected IPC connection
+ char PushReplyStr[MAX_SIZE]; // PUSH_REPLY string
+ UINT64 NextPingSendTick; // Next time to send a Ping
+ bool Established; // VPN communication established flag
+ UINT64 CreatedTick; // Creation date and time
+ UINT64 LastCommTick; // Last communication date and time
+};
+
+// OpenVPN server
+struct OPENVPN_SERVER
+{
+ CEDAR *Cedar;
+ INTERRUPT_MANAGER *Interrupt; // Interrupt manager
+ LIST *SendPacketList; // Transmission packet list
+ LIST *SessionList; // Session list
+ UINT64 Now; // Current time
+ SOCK_EVENT *SockEvent; // Socket event
+ UCHAR TmpBuf[OPENVPN_TMP_BUFFER_SIZE]; // Temporary buffer
+ UINT DisconnectCount; // The number of session lost that have occurred so far
+ bool SupressSendPacket; // Packet transmission suppression flag
+ UINT NextSessionId; // Next session ID
+ DH_CTX *Dh; // DH key
+ UINT SessionEstablishedCount; // Number of session establishment
+};
+
+// OpenVPN server (UDP mode)
+struct OPENVPN_SERVER_UDP
+{
+ CEDAR *Cedar;
+ UDPLISTENER *UdpListener; // UDP listener
+ OPENVPN_SERVER *OpenVpnServer; // OpenVPN server
+ UINT64 VgsNextGetPublicPortsTick;
+};
+
+
+//// Function prototype
+OPENVPN_SERVER_UDP *NewOpenVpnServerUdp(CEDAR *cedar);
+void FreeOpenVpnServerUdp(OPENVPN_SERVER_UDP *u);
+void OpenVpnServerUdpListenerProc(UDPLISTENER *u, LIST *packet_list);
+void OvsApplyUdpPortList(OPENVPN_SERVER_UDP *u, char *port_list);
+
+OPENVPN_SERVER *NewOpenVpnServer(CEDAR *cedar, INTERRUPT_MANAGER *interrupt, SOCK_EVENT *sock_event);
+void FreeOpenVpnServer(OPENVPN_SERVER *s);
+void OvsRecvPacket(OPENVPN_SERVER *s, LIST *recv_packet_list, UINT protocol);
+void OvsProceccRecvPacket(OPENVPN_SERVER *s, UDPPACKET *p, UINT protocol);
+int OvsCompareSessionList(void *p1, void *p2);
+OPENVPN_SESSION *OvsSearchSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, UINT protocol);
+OPENVPN_SESSION *OvsNewSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, UINT protocol);
+OPENVPN_SESSION *OvsFindOrCreateSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, UINT protocol);
+void OvsFreeSession(OPENVPN_SESSION *se);
+UINT OvsGetNumSessionByClientIp(OPENVPN_SERVER *s, IP *ip);
+
+OPENVPN_PACKET *OvsParsePacket(UCHAR *data, UINT size);
+void OvsFreePacket(OPENVPN_PACKET *p);
+BUF *OvsBuildPacket(OPENVPN_PACKET *p);
+OPENVPN_PACKET *OvsNewControlPacket(UCHAR opcode, UCHAR key_id, UINT64 my_channel_id, UINT num_ack,
+ UINT *ack_packet_ids, UINT64 your_channel_id, UINT packet_id,
+ UINT data_size, UCHAR *data);
+void OvsSendDataPacket(OPENVPN_CHANNEL *c, UCHAR key_id, UINT data_packet_id, void *data, UINT data_size);
+
+
+OPENVPN_CHANNEL *OvsNewChannel(OPENVPN_SESSION *se, UCHAR key_id);
+void OvsFreeChannel(OPENVPN_CHANNEL *c);
+UINT64 OvsNewServerSessionId(OPENVPN_SERVER *s);
+UINT OvsGetAckReplyList(OPENVPN_CHANNEL *c, UINT *ret);
+
+void OvsSendPacketNow(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_PACKET *p);
+void OvsSendPacketRawNow(OPENVPN_SERVER *s, OPENVPN_SESSION *se, void *data, UINT size);
+
+void OvsProcessRecvControlPacket(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c, OPENVPN_PACKET *p);
+void OvsSendControlPacket(OPENVPN_CHANNEL *c, UCHAR opcode, UCHAR *data, UINT data_size);
+void OvsSendControlPacketWithAutoSplit(OPENVPN_CHANNEL *c, UCHAR opcode, UCHAR *data, UINT data_size);
+void OvsFreeControlPacket(OPENVPN_CONTROL_PACKET *p);
+void OvsDeleteFromSendingControlPacketList(OPENVPN_CHANNEL *c, UINT num_acks, UINT *acks);
+UINT OvsParseKeyMethod2(OPENVPN_KEY_METHOD_2 *ret, UCHAR *data, UINT size, bool client_mode);
+bool OvsReadStringFromBuf(BUF *b, char *str, UINT str_size);
+void OvsSetupSessionParameters(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c, OPENVPN_KEY_METHOD_2 *data);
+BUF *OvsBuildKeyMethod2(OPENVPN_KEY_METHOD_2 *d);
+void OvsWriteStringToBuf(BUF *b, char *str, UINT max_size);
+
+LIST *OvsParseOptions(char *str);
+void OvsFreeOptions(LIST *o);
+LIST *OvsNewOptions();
+void OvsAddOption(LIST *o, char *key, char *value);
+bool OvsHasOption(LIST *o, char *key);
+UINT OvsPeekStringFromFifo(FIFO *f, char *str, UINT str_size);
+void OvsBeginIPCAsyncConnectionIfEmpty(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c);
+bool OvsIsCompatibleL3IP(UINT ip);
+UINT OvsGetCompatibleL3IPNext(UINT ip);
+UINT OvsCalcTcpMss(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c);
+
+CIPHER *OvsGetCipher(char *name);
+MD *OvsGetMd(char *name);
+bool OvsCheckTcpRecvBufIfOpenVPNProtocol(UCHAR *buf, UINT size);
+
+bool OvsPerformTcpServer(CEDAR *cedar, SOCK *sock);
+
+void OvsSetReplyForVgsPollEnable(bool b);
+
+void OvsSetNoOpenVpnTcp(bool b);
+bool OvsGetNoOpenVpnTcp();
+
+void OvsSetNoOpenVpnUdp(bool b);
+
+
+
+#endif // INTEROP_OPENVPN_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Interop_SSTP.c b/src/Cedar/Interop_SSTP.c
new file mode 100644
index 00000000..18065fae
--- /dev/null
+++ b/src/Cedar/Interop_SSTP.c
@@ -0,0 +1,1222 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Interop_SSTP.c
+// SSTP (Microsoft Secure Socket Tunneling Protocol) protocol stack
+
+#include "CedarPch.h"
+
+static bool g_no_sstp = false;
+
+// Get the SSTP disabling flag
+bool GetNoSstp()
+{
+ return g_no_sstp;
+}
+
+// Set the SSTP disabling flag
+void SetNoSstp(bool b)
+{
+ g_no_sstp = b;
+}
+
+// Process the SSTP control packet reception
+void SstpProcessControlPacket(SSTP_SERVER *s, SSTP_PACKET *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL || p->IsControl == false)
+ {
+ return;
+ }
+
+ Debug("SSTP Control Packet Recv: Msg = %u, Num = %u\n", p->MessageType, LIST_NUM(p->AttibuteList));
+
+ switch (p->MessageType)
+ {
+ case SSTP_MSG_CALL_CONNECT_REQUEST: // Receive a connection request from a client
+ if (s->Aborting == false && s->Disconnecting == false)
+ {
+ if (s->Status == SSTP_SERVER_STATUS_REQUEST_PENGING)
+ {
+ SSTP_ATTRIBUTE *protocol_id = SstpFindAttribute(p, SSTP_ATTRIB_ENCAPSULATED_PROTOCOL_ID);
+ if (protocol_id != NULL && protocol_id->DataSize == 2 &&
+ READ_USHORT(protocol_id->Data) == SSTP_ENCAPSULATED_PROTOCOL_PPP)
+ {
+ // Accept the connection request by the PPP protocol
+ SSTP_PACKET *ret;
+
+ // Generation of random numbers
+ Rand(s->SentNonce, SSTP_NONCE_SIZE);
+
+ ret = SstpNewControlPacketWithAnAttribute(SSTP_MSG_CALL_CONNECT_ACK,
+ SstpNewCryptoBindingRequestAttribute(CERT_HASH_PROTOCOL_SHA256, s->SentNonce));
+
+ SstpSendPacket(s, ret);
+
+ SstpFreePacket(ret);
+
+ s->Status = SSTP_SERVER_STATUS_CONNECTED_PENDING;
+
+ s->EstablishedCount++;
+ }
+ else
+ {
+ // Refuse to accept for a connection request other than the PPP protocol
+ SSTP_PACKET *ret = SstpNewControlPacketWithAnAttribute(SSTP_MSG_CALL_CONNECT_NAK,
+ SstpNewStatusInfoAttribute(SSTP_ATTRIB_ENCAPSULATED_PROTOCOL_ID, ATTRIB_STATUS_VALUE_NOT_SUPPORTED));
+
+ SstpSendPacket(s, ret);
+
+ SstpFreePacket(ret);
+ }
+ }
+ }
+ break;
+
+ case SSTP_MSG_CALL_CONNECTED: // Connection from the client complete
+ if (s->Aborting == false && s->Disconnecting == false)
+ {
+ if (s->Status == SSTP_SERVER_STATUS_CONNECTED_PENDING)
+ {
+ s->Status = SSTP_SERVER_STATUS_ESTABLISHED;
+
+ Debug("SSTP Connected.\n");
+ }
+ }
+ break;
+
+ case SSTP_MSG_CALL_DISCONNECT: // Receive a disconnect request from the client
+ case SSTP_MSG_CALL_DISCONNECT_ACK:
+ s->DisconnectRecved = true;
+ SstpDisconnect(s);
+ break;
+
+ case SSTP_MSG_CALL_ABORT: // Receive a disconnect request from the client
+ s->AbortReceived = true;
+ SstpAbort(s);
+ break;
+ }
+}
+
+// Process the SSTP received data packet
+void SstpProcessDataPacket(SSTP_SERVER *s, SSTP_PACKET *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL || p->IsControl)
+ {
+ return;
+ }
+
+ //Debug("SSTP Data Packet Recv: Size = %u\n", p->DataSize);
+
+ if (s->PPPThread == NULL)
+ {
+ // Create a thread to initialize the new PPP module
+ s->PPPThread = NewPPPSession(s->Cedar, &s->ClientIp, s->ClientPort, &s->ServerIp, s->ServerPort,
+ s->TubeSend, s->TubeRecv, SSTP_IPC_POSTFIX, SSTP_IPC_CLIENT_NAME,
+ s->ClientHostName, s->ClientCipherName, 0);
+ }
+
+ // Pass the received data to the PPP module
+ TubeSendEx(s->TubeRecv, p->Data, p->DataSize, NULL, true);
+ s->FlushRecvTube = true;
+}
+
+// Process the SSTP received packet
+void SstpProcessPacket(SSTP_SERVER *s, SSTP_PACKET *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ s->LastRecvTick = s->Now;
+
+ if (p->IsControl)
+ {
+ // Control packet
+ SstpProcessControlPacket(s, p);
+ }
+ else
+ {
+ // Data packet
+ SstpProcessDataPacket(s, p);
+ }
+}
+
+// Send a SSTP packet
+void SstpSendPacket(SSTP_SERVER *s, SSTP_PACKET *p)
+{
+ BUF *b;
+ BLOCK *block;
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (p->IsControl)
+ {
+ Debug("SSTP Control Packet Send: Msg = %u, Num = %u\n", p->MessageType, LIST_NUM(p->AttibuteList));
+ }
+ else
+ {
+ //Debug("SSTP Data Packet Send: Size=%u\n", p->DataSize);
+ }
+
+ b = SstpBuildPacket(p);
+ if (b == NULL)
+ {
+ return;
+ }
+
+ block = NewBlock(b->Buf, b->Size, 0);
+ block->PriorityQoS = p->IsControl;
+ Free(b);
+
+ InsertQueue(s->SendQueue, block);
+}
+
+// Process the timer interrupt
+void SstpProcessInterrupt(SSTP_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ s->Now = Tick64();
+
+ s->FlushRecvTube = false;
+
+ // Process the received packet
+ while (true)
+ {
+ BLOCK *b = GetNext(s->RecvQueue);
+ SSTP_PACKET *p;
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ p = SstpParsePacket(b->Buf, b->Size);
+ if (p == NULL)
+ {
+ // Disconnect the SSTP since a bad packet received
+ SstpAbort(s);
+ }
+ else
+ {
+ // Process the received packet
+ SstpProcessPacket(s, p);
+
+ SstpFreePacket(p);
+ }
+
+ FreeBlock(b);
+ }
+
+ if (s->FlushRecvTube)
+ {
+ TubeFlush(s->TubeRecv);
+ }
+
+ // Transmit a packet that the PPP module is trying to send via the SSTP
+ while (true)
+ {
+ TUBEDATA *d = TubeRecvAsync(s->TubeSend);
+ SSTP_PACKET *p;
+ if (d == NULL)
+ {
+ break;
+ }
+
+ p = SstpNewDataPacket(d->Data, d->DataSize);
+
+ SstpSendPacket(s, p);
+
+ SstpFreePacket(p);
+
+ FreeTubeData(d);
+ }
+
+ if (s->Status == SSTP_SERVER_STATUS_ESTABLISHED)
+ {
+ if (s->Disconnecting == false && s->Aborting == false)
+ {
+ // Periodic transmission of Echo Request
+ if (s->NextSendEchoRequestTick == 0 || s->NextSendEchoRequestTick <= s->Now)
+ {
+ UINT64 next_interval = (UINT64)(SSTP_ECHO_SEND_INTERVAL_MIN + Rand32() % (SSTP_ECHO_SEND_INTERVAL_MAX - SSTP_ECHO_SEND_INTERVAL_MIN));
+ SSTP_PACKET *p;
+
+ s->NextSendEchoRequestTick = s->Now + next_interval;
+ AddInterrupt(s->Interrupt, s->NextSendEchoRequestTick);
+
+ p = SstpNewControlPacket(SSTP_MSG_ECHO_REQUEST);
+
+ SstpSendPacket(s, p);
+
+ SstpFreePacket(p);
+ }
+ }
+ }
+
+ if ((s->LastRecvTick + (UINT64)SSTP_TIMEOUT) <= s->Now)
+ {
+ // Disconnect the SSTP because a timeout occurred
+ SstpAbort(s);
+ s->Disconnected = true;
+ }
+
+ if (IsTubeConnected(s->TubeRecv) == false || IsTubeConnected(s->TubeSend) == false)
+ {
+ // Disconnect the SSTP since the PPP module is disconnected
+ SstpDisconnect(s);
+ }
+
+ if (s->Disconnecting)
+ {
+ // Normal disconnection process
+ if (s->DisconnectSent == false)
+ {
+ // Send a Disconnect
+ SSTP_PACKET *ret = SstpNewControlPacket(s->DisconnectRecved ? SSTP_MSG_CALL_DISCONNECT_ACK : SSTP_MSG_CALL_DISCONNECT);
+
+ SstpSendPacket(s, ret);
+
+ SstpFreePacket(ret);
+
+ s->DisconnectSent = true;
+ }
+ }
+
+ if (s->Aborting)
+ {
+ // Abnormal disconnection processing
+ if (s->AbortSent == false)
+ {
+ // Send the Abort
+ SSTP_PACKET *ret = SstpNewControlPacket(SSTP_MSG_CALL_ABORT);
+
+ SstpSendPacket(s, ret);
+
+ SstpFreePacket(ret);
+
+ s->AbortSent = true;
+ }
+ }
+
+ if (s->DisconnectSent && s->DisconnectRecved)
+ {
+ // Disconnect after exchanging the Disconnect each other
+ s->Disconnected = true;
+ }
+
+ if (s->AbortSent && s->AbortReceived)
+ {
+ // Disconnect after exchanging the Abort each other
+ s->Disconnected = true;
+ }
+}
+
+// Create a new SSTP control packet with an Attribute
+SSTP_PACKET *SstpNewControlPacketWithAnAttribute(USHORT message_type, SSTP_ATTRIBUTE *a)
+{
+ SSTP_PACKET *p = SstpNewControlPacket(message_type);
+
+ if (a != NULL)
+ {
+ Add(p->AttibuteList, a);
+ }
+
+ return p;
+}
+
+// Create a new SSTP control packet
+SSTP_PACKET *SstpNewControlPacket(USHORT message_type)
+{
+ SSTP_PACKET *p = ZeroMalloc(sizeof(SSTP_PACKET));
+
+ p->IsControl = true;
+ p->MessageType = message_type;
+ p->Version = SSTP_VERSION_1;
+ p->AttibuteList = NewListFast(NULL);
+
+ return p;
+}
+
+// Create a new SSTP data packet
+SSTP_PACKET *SstpNewDataPacket(UCHAR *data, UINT size)
+{
+ SSTP_PACKET *p = ZeroMalloc(sizeof(SSTP_PACKET));
+
+ p->IsControl = false;
+ p->Data = Clone(data, size);
+ p->DataSize = size;
+
+ return p;
+}
+
+// Get the Attibute with the specified ID from SSTP packet
+SSTP_ATTRIBUTE *SstpFindAttribute(SSTP_PACKET *p, UCHAR attribute_id)
+{
+ UINT i;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(p->AttibuteList);i++)
+ {
+ SSTP_ATTRIBUTE *a = LIST_DATA(p->AttibuteList, i);
+
+ if (a->AttributeId == attribute_id)
+ {
+ return a;
+ }
+ }
+
+ return NULL;
+}
+
+// Disconnect the SSTP normally
+void SstpDisconnect(SSTP_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ s->Disconnecting = true;
+}
+
+// Disconnect the SSTP abnormally
+void SstpAbort(SSTP_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ s->Aborting = true;
+}
+
+// Create a Crypto Binding Request Attribute
+SSTP_ATTRIBUTE *SstpNewCryptoBindingRequestAttribute(UCHAR hash_protocol_bitmask, UCHAR *nonce_32bytes)
+{
+ SSTP_ATTRIBUTE *a;
+ UCHAR uc;
+ BUF *b = NewBuf();
+
+ uc = 0;
+ WriteBuf(b, &uc, 1);
+ WriteBuf(b, &uc, 1);
+ WriteBuf(b, &uc, 1);
+ WriteBuf(b, &hash_protocol_bitmask, 1);
+
+ WriteBuf(b, nonce_32bytes, SSTP_NONCE_SIZE);
+
+ a = SstpNewAttribute(SSTP_ATTRIB_CRYPTO_BINDING_REQ, b->Buf, b->Size);
+
+ FreeBuf(b);
+
+ return a;
+}
+
+// Create a Status Info Attribute
+SSTP_ATTRIBUTE *SstpNewStatusInfoAttribute(UCHAR attrib_id, UINT status)
+{
+ SSTP_ATTRIBUTE *a;
+ UCHAR uc;
+ BUF *b = NewBuf();
+
+ uc = 0;
+ WriteBuf(b, &uc, 1);
+ WriteBuf(b, &uc, 1);
+ WriteBuf(b, &uc, 1);
+ WriteBuf(b, &attrib_id, 1);
+
+ WriteBufInt(b, status);
+
+ a = SstpNewAttribute(SSTP_ATTRIB_STATUS_INFO, b->Buf, b->Size);
+
+ FreeBuf(b);
+
+ return a;
+}
+
+// Create a New Attribute
+SSTP_ATTRIBUTE *SstpNewAttribute(UCHAR attribute_id, UCHAR *data, UINT data_size)
+{
+ SSTP_ATTRIBUTE *a = ZeroMalloc(sizeof(SSTP_ATTRIBUTE));
+
+ a->AttributeId = attribute_id;
+ a->Data = Clone(data, data_size);
+ a->DataSize = data_size;
+
+ return a;
+}
+
+// Build the Attribute
+BUF *SstpBuildAttribute(SSTP_ATTRIBUTE *a)
+{
+ UCHAR uc;
+ USHORT us;
+ BUF *b;
+ // Validate arguments
+ if (a == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+
+ // Reserved
+ uc = 0;
+ WriteBuf(b, &uc, sizeof(UCHAR));
+
+ // Attribute ID
+ uc = a->AttributeId;
+ WriteBuf(b, &uc, sizeof(UCHAR));
+
+ // LengthPacket
+ a->TotalLength = a->DataSize + 4;
+ us = (USHORT)a->TotalLength;
+ us = Endian16(us);
+ WriteBuf(b, &us, sizeof(USHORT));
+
+ // Data
+ WriteBuf(b, a->Data, a->DataSize);
+
+ return b;
+}
+
+// Build the Attribute list
+BUF *SstpBuildAttributeList(LIST *o, USHORT message_type)
+{
+ UINT i;
+ BUF *b;
+ USHORT us;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+
+ us = Endian16(message_type);
+ WriteBuf(b, &us, sizeof(USHORT));
+
+ us = Endian16((USHORT)LIST_NUM(o));
+ WriteBuf(b, &us, sizeof(USHORT));
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ SSTP_ATTRIBUTE *a = LIST_DATA(o, i);
+ BUF *ab = SstpBuildAttribute(a);
+
+ if (ab != NULL)
+ {
+ WriteBufBuf(b, ab);
+
+ FreeBuf(ab);
+ }
+ }
+
+ return b;
+}
+
+// Building the SSTP packet
+BUF *SstpBuildPacket(SSTP_PACKET *p)
+{
+ BUF *b;
+ UCHAR uc;
+ USHORT us;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+
+ if (p->IsControl)
+ {
+ BUF *ab;
+
+ if (p->Data != NULL)
+ {
+ Free(p->Data);
+ }
+
+ ab = SstpBuildAttributeList(p->AttibuteList, p->MessageType);
+ p->Data = ab->Buf;
+ p->DataSize = ab->Size;
+ Free(ab);
+ }
+
+ // Version
+ uc = SSTP_VERSION_1;
+ WriteBuf(b, &uc, sizeof(UCHAR));
+
+ // Flag
+ uc = p->IsControl ? 1 : 0;
+ WriteBuf(b, &uc, sizeof(UCHAR));
+
+ // Length Packet
+ us = Endian16(p->DataSize + 4);
+ WriteBuf(b, &us, sizeof(USHORT));
+
+ // Data
+ WriteBuf(b, p->Data, p->DataSize);
+
+ return b;
+}
+
+// Parse the SSTP packet
+SSTP_PACKET *SstpParsePacket(UCHAR *data, UINT size)
+{
+ SSTP_PACKET *p;
+ USHORT len;
+ // Validate arguments
+ if (data == NULL || size == 0)
+ {
+ return NULL;
+ }
+
+ if (size < 4)
+ {
+ return NULL;
+ }
+
+ p = ZeroMalloc(sizeof(SSTP_PACKET));
+
+ // Version
+ p->Version = *((UCHAR *)data);
+ data++;
+ size--;
+
+ if (p->Version != SSTP_VERSION_1)
+ {
+ // Invalid version
+ SstpFreePacket(p);
+ return NULL;
+ }
+
+ // Flag
+ if ((*((UCHAR *)data)) & 0x01)
+ {
+ p->IsControl = true;
+ }
+ data++;
+ size--;
+
+ // Length
+ len = READ_USHORT(data) & 0xFFF;
+ data += sizeof(USHORT);
+ size -= sizeof(USHORT);
+
+ if (len < 4)
+ {
+ // Invalid size
+ SstpFreePacket(p);
+ return NULL;
+ }
+
+ if (((UINT)(len - 4)) > size)
+ {
+ // Oversized
+ SstpFreePacket(p);
+ return NULL;
+ }
+
+ // Data
+ p->DataSize = len - 4;
+ p->Data = Clone(data, p->DataSize);
+
+ if (p->IsControl)
+ {
+ // Parse the Attribute list
+ p->AttibuteList = SstpParseAttributeList(p->Data, p->DataSize, p);
+
+ if (p->AttibuteList == NULL)
+ {
+ // Failure of parsing list
+ SstpFreePacket(p);
+ return NULL;
+ }
+ }
+
+ return p;
+}
+
+// Parse the Attribute list
+LIST *SstpParseAttributeList(UCHAR *data, UINT size, SSTP_PACKET *p)
+{
+ LIST *o;
+ USHORT us;
+ UINT num;
+ // Validate arguments
+ if (size == 0 || data == NULL || p == NULL)
+ {
+ return NULL;
+ }
+
+ if (size < 4)
+ {
+ return NULL;
+ }
+
+ // Message Type
+ us = READ_USHORT(data);
+ p->MessageType = us;
+ data += sizeof(USHORT);
+ size -= sizeof(USHORT);
+
+ // Num Attributes
+ num = READ_USHORT(data);
+ data += sizeof(USHORT);
+ size -= sizeof(USHORT);
+
+ // Attibutes List
+ o = NewListFast(NULL);
+
+ while (LIST_NUM(o) < num)
+ {
+ SSTP_ATTRIBUTE *a = SstpParseAttribute(data, size);
+
+ if (a == NULL)
+ {
+ SstpFreeAttributeList(o);
+ return NULL;
+ }
+
+ if (a->TotalLength > size)
+ {
+ SstpFreeAttribute(a);
+ SstpFreeAttributeList(o);
+ return NULL;
+ }
+
+ Add(o, a);
+
+ data += a->TotalLength;
+ size -= a->TotalLength;
+ }
+
+ return o;
+}
+
+// Parse the Attribute
+SSTP_ATTRIBUTE *SstpParseAttribute(UCHAR *data, UINT size)
+{
+ SSTP_ATTRIBUTE *a;
+ // Validate arguments
+ if (data == NULL || size == 0)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(SSTP_ATTRIBUTE));
+
+ if (size < 4)
+ {
+ SstpFreeAttribute(a);
+ return NULL;
+ }
+
+ data++;
+ size--;
+
+ // Attribute ID
+ a->AttributeId = *((UCHAR *)data);
+ data++;
+ size--;
+
+ // Length
+ a->TotalLength = READ_USHORT(data) & 0xFFF;
+ data += sizeof(USHORT);
+ size -= sizeof(USHORT);
+
+ if (a->TotalLength < 4)
+ {
+ // Length fraud
+ SstpFreeAttribute(a);
+ return NULL;
+ }
+
+ a->DataSize = a->TotalLength - 4;
+ if (a->DataSize > size)
+ {
+ // Length excess
+ SstpFreeAttribute(a);
+ return NULL;
+ }
+
+ a->Data = Clone(data, a->DataSize);
+
+ return a;
+}
+
+// Release the Attibute
+void SstpFreeAttribute(SSTP_ATTRIBUTE *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ Free(a->Data);
+
+ Free(a);
+}
+
+// Release the Attribute list
+void SstpFreeAttributeList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ SSTP_ATTRIBUTE *a = LIST_DATA(o, i);
+
+ SstpFreeAttribute(a);
+ }
+
+ ReleaseList(o);
+}
+
+// Release the SSTP packet
+void SstpFreePacket(SSTP_PACKET *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ if (p->AttibuteList != NULL)
+ {
+ SstpFreeAttributeList(p->AttibuteList);
+ }
+
+ if (p->Data != NULL)
+ {
+ Free(p->Data);
+ }
+
+ Free(p);
+}
+
+// Create a SSTP server
+SSTP_SERVER *NewSstpServer(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ip,
+ UINT server_port, SOCK_EVENT *se,
+ char *client_host_name, char *crypt_name)
+{
+ SSTP_SERVER *s = ZeroMalloc(sizeof(SSTP_SERVER));
+
+ s->LastRecvTick = Tick64();
+
+ StrCpy(s->ClientHostName, sizeof(s->ClientHostName), client_host_name);
+ StrCpy(s->ClientCipherName, sizeof(s->ClientCipherName), crypt_name);
+
+ s->Cedar = cedar;
+ AddRef(s->Cedar->ref);
+
+ NewTubePair(&s->TubeSend, &s->TubeRecv, 0);
+ SetTubeSockEvent(s->TubeSend, se);
+
+ s->Now = Tick64();
+
+ Copy(&s->ClientIp, client_ip, sizeof(IP));
+ s->ClientPort = client_port;
+ Copy(&s->ServerIp, server_ip, sizeof(IP));
+ s->ServerPort = server_port;
+
+ s->SockEvent = se;
+
+ AddRef(s->SockEvent->ref);
+
+ s->RecvQueue = NewQueueFast();
+ s->SendQueue = NewQueueFast();
+
+ s->Interrupt = NewInterruptManager();
+
+ return s;
+}
+
+// Release the SSTP server
+void FreeSstpServer(SSTP_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ TubeDisconnect(s->TubeRecv);
+ TubeDisconnect(s->TubeSend);
+
+ WaitThread(s->PPPThread, INFINITE);
+ ReleaseThread(s->PPPThread);
+
+ while (true)
+ {
+ BLOCK *b = GetNext(s->RecvQueue);
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ FreeBlock(b);
+ }
+
+ while (true)
+ {
+ BLOCK *b = GetNext(s->SendQueue);
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ FreeBlock(b);
+ }
+
+ ReleaseQueue(s->RecvQueue);
+ ReleaseQueue(s->SendQueue);
+
+ ReleaseSockEvent(s->SockEvent);
+
+ FreeInterruptManager(s->Interrupt);
+
+ ReleaseCedar(s->Cedar);
+
+ ReleaseTube(s->TubeSend);
+ ReleaseTube(s->TubeRecv);
+
+ Free(s);
+}
+
+// Handle the communication of SSTP protocol
+bool ProcessSstpHttps(CEDAR *cedar, SOCK *s, SOCK_EVENT *se)
+{
+ UINT tmp_size = 65536;
+ UCHAR *tmp_buf;
+ FIFO *recv_fifo;
+ FIFO *send_fifo;
+ SSTP_SERVER *sstp;
+ bool ret = false;
+ // Validate arguments
+ if (cedar == NULL || s == NULL || se == NULL)
+ {
+ return false;
+ }
+
+ tmp_buf = Malloc(tmp_size);
+ recv_fifo = NewFifo();
+ send_fifo = NewFifo();
+
+ sstp = NewSstpServer(cedar, &s->RemoteIP, s->RemotePort, &s->LocalIP, s->LocalPort, se,
+ s->RemoteHostname, s->CipherName);
+
+ while (true)
+ {
+ UINT r;
+ bool is_disconnected = false;
+ bool state_changed = false;
+
+ // Receive data over SSL
+ while (true)
+ {
+ r = Recv(s, tmp_buf, tmp_size, true);
+ if (r == 0)
+ {
+ // SSL is disconnected
+ is_disconnected = true;
+ break;
+ }
+ else if (r == SOCK_LATER)
+ {
+ // Data is not received any more
+ break;
+ }
+ else
+ {
+ // Queue the received data
+ WriteFifo(recv_fifo, tmp_buf, r);
+ state_changed = true;
+ }
+ }
+
+ while (recv_fifo->size >= 4)
+ {
+ UCHAR *first4;
+ UINT read_size = 0;
+ bool ok = false;
+ // Read 4 bytes from the beginning of the receive queue
+ first4 = ((UCHAR *)recv_fifo->p) + recv_fifo->pos;
+ if (first4[0] == SSTP_VERSION_1)
+ {
+ USHORT len = READ_USHORT(first4 + 2) & 0xFFF;
+ if (len >= 4)
+ {
+ ok = true;
+
+ if (recv_fifo->size >= len)
+ {
+ UCHAR *data;
+ BLOCK *b;
+
+ read_size = len;
+ data = Malloc(read_size);
+
+ ReadFifo(recv_fifo, data, read_size);
+
+ b = NewBlock(data, read_size, 0);
+
+ InsertQueue(sstp->RecvQueue, b);
+ }
+ }
+ }
+
+ if (read_size == 0)
+ {
+ break;
+ }
+
+ if (ok == false)
+ {
+ // Disconnect the connection since a bad packet received
+ is_disconnected = true;
+ break;
+ }
+ }
+
+ // Process the timer interrupt
+ SstpProcessInterrupt(sstp);
+
+ if (sstp->Disconnected)
+ {
+ is_disconnected = true;
+ }
+
+ // Put the transmission data that SSTP module has generated into the transmission queue
+ while (true)
+ {
+ BLOCK *b = GetNext(sstp->SendQueue);
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ // When transmit a data packet, If there are packets of more than about
+ // 2.5 MB in the transmission queue of the TCP, discard without transmission
+ if (b->PriorityQoS || (send_fifo->size <= MAX_BUFFERING_PACKET_SIZE))
+ {
+ WriteFifo(send_fifo, b->Buf, b->Size);
+ }
+
+ FreeBlock(b);
+ }
+
+ // Data is transmitted over SSL
+ while (send_fifo->size != 0)
+ {
+ r = Send(s, ((UCHAR *)send_fifo->p) + send_fifo->pos, send_fifo->size, true);
+ if (r == 0)
+ {
+ // SSL is disconnected
+ is_disconnected = true;
+ break;
+ }
+ else if (r == SOCK_LATER)
+ {
+ // Can not send any more
+ break;
+ }
+ else
+ {
+ // Advance the transmission queue by the amount of the transmitted
+ ReadFifo(send_fifo, NULL, r);
+ state_changed = true;
+ }
+ }
+
+ if (is_disconnected)
+ {
+ // Disconnected
+ break;
+ }
+
+ // Wait for the next state change
+ if (state_changed == false)
+ {
+ UINT r = GetNextIntervalForInterrupt(sstp->Interrupt);
+ WaitSockEvent(se, MIN(r, SELECT_TIME));
+ }
+ }
+
+ if (sstp != NULL && sstp->EstablishedCount >= 1)
+ {
+ ret = true;
+ }
+
+ FreeSstpServer(sstp);
+
+ ReleaseFifo(recv_fifo);
+ ReleaseFifo(send_fifo);
+ Free(tmp_buf);
+
+ YieldCpu();
+ Disconnect(s);
+
+ return ret;
+}
+
+// Accept the SSTP connection
+bool AcceptSstp(CONNECTION *c)
+{
+ SOCK *s;
+ HTTP_HEADER *h;
+ char date_str[MAX_SIZE];
+ bool ret;
+ bool ret2 = false;
+ SOCK_EVENT *se;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ s = c->FirstSock;
+
+ GetHttpDateStr(date_str, sizeof(date_str), SystemTime64());
+
+ // Return a response
+ h = NewHttpHeader("HTTP/1.1", "200", "OK");
+ AddHttpValue(h, NewHttpValue("Content-Length", "18446744073709551615"));
+ AddHttpValue(h, NewHttpValue("Server", "Microsoft-HTTPAPI/2.0"));
+ AddHttpValue(h, NewHttpValue("Date", date_str));
+
+ ret = PostHttp(s, h, NULL, 0);
+
+ FreeHttpHeader(h);
+
+ if (ret)
+ {
+ SetTimeout(s, INFINITE);
+
+ se = NewSockEvent();
+
+ JoinSockToSockEvent(s, se);
+
+ Debug("ProcessSstpHttps Start.\n");
+ ret2 = ProcessSstpHttps(c->Cedar, s, se);
+ Debug("ProcessSstpHttps End.\n");
+
+ ReleaseSockEvent(se);
+ }
+
+ Disconnect(s);
+
+ return ret2;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Interop_SSTP.h b/src/Cedar/Interop_SSTP.h
new file mode 100644
index 00000000..dbf2d50c
--- /dev/null
+++ b/src/Cedar/Interop_SSTP.h
@@ -0,0 +1,238 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Interop_SSTP.h
+// Header of Interop_SSTP.c
+
+#ifndef INTEROP_SSTP_H
+#define INTEROP_SSTP_H
+
+//// Constants
+#define SSTP_URI "/sra_{BA195980-CD49-458b-9E23-C84EE0ADCD75}/" // SSTP HTTPS URI
+#define SSTP_VERSION_1 0x10 // SSTP Version 1.0
+#define MAX_SSTP_PACKET_SIZE 4096 // Maximum packet size
+#define SSTP_IPC_CLIENT_NAME "Microsoft SSTP VPN Client"
+#define SSTP_IPC_POSTFIX "SSTP"
+#define SSTP_ECHO_SEND_INTERVAL_MIN 2500 // Transmission interval of Echo Request (minimum)
+#define SSTP_ECHO_SEND_INTERVAL_MAX 4792 // Transmission interval of Echo Request (maximum)
+#define SSTP_TIMEOUT 10000 // Communication time-out of SSTP
+
+// SSTP Message Type
+#define SSTP_MSG_CALL_CONNECT_REQUEST 0x0001
+#define SSTP_MSG_CALL_CONNECT_ACK 0x0002
+#define SSTP_MSG_CALL_CONNECT_NAK 0x0003
+#define SSTP_MSG_CALL_CONNECTED 0x0004
+#define SSTP_MSG_CALL_ABORT 0x0005
+#define SSTP_MSG_CALL_DISCONNECT 0x0006
+#define SSTP_MSG_CALL_DISCONNECT_ACK 0x0007
+#define SSTP_MSG_ECHO_REQUEST 0x0008
+#define SSTP_MSG_ECHO_RESPONSE 0x0009
+
+// SSTP Attribute ID
+#define SSTP_ATTRIB_NO_ERROR 0x00
+#define SSTP_ATTRIB_ENCAPSULATED_PROTOCOL_ID 0x01
+#define SSTP_ATTRIB_STATUS_INFO 0x02
+#define SSTP_ATTRIB_CRYPTO_BINDING 0x03
+#define SSTP_ATTRIB_CRYPTO_BINDING_REQ 0x04
+
+// Protocol ID
+#define SSTP_ENCAPSULATED_PROTOCOL_PPP 0x0001
+
+// Hash Protocol Bitmask
+#define CERT_HASH_PROTOCOL_SHA1 0x01
+#define CERT_HASH_PROTOCOL_SHA256 0x02
+
+// Status
+#define ATTRIB_STATUS_NO_ERROR 0x00000000
+#define ATTRIB_STATUS_DUPLICATE_ATTRIBUTE 0x00000001
+#define ATTRIB_STATUS_UNRECOGNIZED_ATTRIBUTE 0x00000002
+#define ATTRIB_STATUS_INVALID_ATTRIB_VALUE_LENGTH 0x00000003
+#define ATTRIB_STATUS_VALUE_NOT_SUPPORTED 0x00000004
+#define ATTRIB_STATUS_UNACCEPTED_FRAME_RECEIVED 0x00000005
+#define ATTRIB_STATUS_RETRY_COUNT_EXCEEDED 0x00000006
+#define ATTRIB_STATUS_INVALID_FRAME_RECEIVED 0x00000007
+#define ATTRIB_STATUS_NEGOTIATION_TIMEOUT 0x00000008
+#define ATTRIB_STATUS_ATTRIB_NOT_SUPPORTED_IN_MSG 0x00000009
+#define ATTRIB_STATUS_REQUIRED_ATTRIBUTE_MISSING 0x0000000A
+#define ATTRIB_STATUS_STATUS_INFO_NOT_SUPPORTED_IN_MSG 0x0000000B
+
+// State of SSTP Server
+#define SSTP_SERVER_STATUS_REQUEST_PENGING 0 // Connection incomplete
+#define SSTP_SERVER_STATUS_CONNECTED_PENDING 1 // Connection completed. Authentication incomplete
+#define SSTP_SERVER_STATUS_ESTABLISHED 2 // Connection completed. Communication available
+
+// Length of Nonce
+#define SSTP_NONCE_SIZE 32 // 256 bits
+
+
+//// Type
+
+// SSTP Attibute
+struct SSTP_ATTRIBUTE
+{
+ UCHAR AttributeId;
+ UCHAR *Data;
+ UINT DataSize;
+ UINT TotalLength;
+};
+
+// SSTP Packet
+struct SSTP_PACKET
+{
+ UCHAR Version;
+ bool IsControl;
+ UCHAR *Data;
+ UINT DataSize;
+ USHORT MessageType;
+ LIST *AttibuteList;
+};
+
+// SSTP Server
+struct SSTP_SERVER
+{
+ CEDAR *Cedar;
+ UINT64 Now;
+ IP ClientIp, ServerIp;
+ UINT ClientPort, ServerPort;
+ char ClientHostName[MAX_HOST_NAME_LEN + 1];
+ char ClientCipherName[MAX_SIZE];
+ SOCK_EVENT *SockEvent;
+ QUEUE *RecvQueue; // Receive queue
+ QUEUE *SendQueue; // Transmission queue
+ INTERRUPT_MANAGER *Interrupt; // Interrupt manager
+ bool Aborting; // Forced disconnection flag
+ bool AbortSent; // Flag of whether to send the Abort
+ bool AbortReceived; // Flag of whether the Abort has been received
+ bool Disconnecting; // Disconnecting flag
+ bool DisconnectSent; // Flag of whether to send a Disconnect
+ bool DisconnectRecved; // Flag of whether a Disconnect has been received
+ bool Disconnected; // Flag as to disconnect
+ UINT Status; // State
+ UCHAR SentNonce[SSTP_NONCE_SIZE]; // Random data sent
+ TUBE *TubeRecv, *TubeSend; // Delivery tube of packets to PPP module
+ THREAD *PPPThread; // PPP module thread
+ UINT64 NextSendEchoRequestTick; // Time to send the next Echo Request
+ UINT64 LastRecvTick; // Tick when some data has received at the end
+ bool FlushRecvTube; // Flag whether to flush the reception tube
+ UINT EstablishedCount; // Number of session establishment
+};
+
+
+//// Function prototype
+bool AcceptSstp(CONNECTION *c);
+bool ProcessSstpHttps(CEDAR *cedar, SOCK *s, SOCK_EVENT *se);
+
+SSTP_SERVER *NewSstpServer(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ip,
+ UINT server_port, SOCK_EVENT *se,
+ char *client_host_name, char *crypt_name);
+void FreeSstpServer(SSTP_SERVER *s);
+void SstpProcessInterrupt(SSTP_SERVER *s);
+SSTP_PACKET *SstpParsePacket(UCHAR *data, UINT size);
+LIST *SstpParseAttributeList(UCHAR *data, UINT size, SSTP_PACKET *p);
+SSTP_ATTRIBUTE *SstpParseAttribute(UCHAR *data, UINT size);
+void SstpFreeAttribute(SSTP_ATTRIBUTE *a);
+void SstpFreeAttributeList(LIST *o);
+void SstpFreePacket(SSTP_PACKET *p);
+BUF *SstpBuildPacket(SSTP_PACKET *p);
+BUF *SstpBuildAttributeList(LIST *o, USHORT message_type);
+BUF *SstpBuildAttribute(SSTP_ATTRIBUTE *a);
+void SstpAbort(SSTP_SERVER *s);
+void SstpDisconnect(SSTP_SERVER *s);
+void SstpProcessPacket(SSTP_SERVER *s, SSTP_PACKET *p);
+void SstpProcessControlPacket(SSTP_SERVER *s, SSTP_PACKET *p);
+void SstpProcessDataPacket(SSTP_SERVER *s, SSTP_PACKET *p);
+SSTP_ATTRIBUTE *SstpFindAttribute(SSTP_PACKET *p, UCHAR attribute_id);
+SSTP_ATTRIBUTE *SstpNewAttribute(UCHAR attribute_id, UCHAR *data, UINT data_size);
+SSTP_ATTRIBUTE *SstpNewStatusInfoAttribute(UCHAR attrib_id, UINT status);
+SSTP_ATTRIBUTE *SstpNewCryptoBindingRequestAttribute(UCHAR hash_protocol_bitmask, UCHAR *nonce_32bytes);
+SSTP_PACKET *SstpNewDataPacket(UCHAR *data, UINT size);
+SSTP_PACKET *SstpNewControlPacket(USHORT message_type);
+SSTP_PACKET *SstpNewControlPacketWithAnAttribute(USHORT message_type, SSTP_ATTRIBUTE *a);
+void SstpSendPacket(SSTP_SERVER *s, SSTP_PACKET *p);
+bool GetNoSstp();
+void SetNoSstp(bool b);
+
+#endif // INTEROP_SSTP_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Layer3.c b/src/Cedar/Layer3.c
new file mode 100644
index 00000000..3bb8ecbe
--- /dev/null
+++ b/src/Cedar/Layer3.c
@@ -0,0 +1,2173 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Layer3.c
+// Layer-3 switch module
+
+#include "CedarPch.h"
+
+static UCHAR broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+// Process the IP queue
+void L3PollingIpQueue(L3IF *f)
+{
+ L3PACKET *p;
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ // Process the packet came from another session
+ while (p = GetNext(f->IpPacketQueue))
+ {
+ PKT *pkt = p->Packet;
+
+ // Send as an IP packet
+ L3SendIp(f, p);
+ }
+}
+
+// Process IP packets
+void L3RecvIp(L3IF *f, PKT *p, bool self)
+{
+ IPV4_HEADER *ip;
+ UINT header_size;
+ UINT next_hop = 0;
+ L3IF *dst;
+ L3PACKET *packet;
+ UINT new_ttl = 0;
+ // Validate arguments
+ if (f == NULL || p == NULL)
+ {
+ return;
+ }
+
+ ip = p->L3.IPv4Header;
+ header_size = IPV4_GET_HEADER_LEN(p->L3.IPv4Header) * 4;
+
+ // Calculate the checksum
+ if (IpCheckChecksum(ip) == false)
+ {
+ // The checksum does not match
+ goto FREE_PACKET;
+ }
+
+ // Register in the ARP table
+ L3KnownArp(f, ip->SrcIP, p->MacAddressSrc);
+
+ if (p->BroadcastPacket)
+ {
+ // Not to route in the case of broadcast packet
+ goto FREE_PACKET;
+ }
+
+ // Calculate the TTL
+ if (ip->TimeToLive >= 1)
+ {
+ new_ttl = ip->TimeToLive - 1;
+ }
+ else
+ {
+ new_ttl = 0;
+ }
+
+ if (new_ttl == 0)
+ {
+ if (ip->DstIP != f->IpAddress)
+ {
+ UINT src_packet_size = p->PacketSize - sizeof(MAC_HEADER);
+ UINT icmp_packet_total_size = sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4 + header_size + 8;
+ UCHAR *buf;
+ IPV4_HEADER *ipv4;
+ ICMP_HEADER *icmpv4;
+ UCHAR *data;
+ PKT *pkt;
+ UINT data_size = MIN(p->PacketSize - header_size, header_size + 8);
+
+ // Generate an ICMP message that means that the TTL has expired
+ buf = ZeroMalloc(icmp_packet_total_size);
+ ipv4 = (IPV4_HEADER *)(buf + sizeof(MAC_HEADER));
+ icmpv4 = (ICMP_HEADER *)(buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER));
+ data = buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4;
+
+ IPV4_SET_VERSION(ipv4, 4);
+ IPV4_SET_HEADER_LEN(ipv4, sizeof(IPV4_HEADER) / 4);
+ ipv4->TotalLength = Endian16((USHORT)(icmp_packet_total_size - sizeof(MAC_HEADER)));
+ ipv4->TimeToLive = 0xff;
+ ipv4->Protocol = IP_PROTO_ICMPV4;
+ ipv4->SrcIP = f->IpAddress;
+ ipv4->DstIP = ip->SrcIP;
+ ipv4->Checksum = IpChecksum(ipv4, sizeof(IPV4_HEADER));
+
+ icmpv4->Type = 11;
+ Copy(data, ip, data_size);
+ icmpv4->Checksum = IpChecksum(icmpv4, sizeof(ICMP_HEADER) + data_size + 4);
+
+ buf[12] = 0x08;
+ buf[13] = 0x00;
+
+ pkt = ParsePacket(buf, icmp_packet_total_size);
+ if (pkt == NULL)
+ {
+ Free(buf);
+ }
+ else
+ {
+ L3RecvIp(f, pkt, true);
+ }
+
+ // Discard the packet body whose the TTL has expired
+ goto FREE_PACKET;
+ }
+ }
+
+ // Rewrite the TTL
+ p->L3.IPv4Header->TimeToLive = (UCHAR)new_ttl;
+
+ // Get the interface corresponding to the destination IP address
+ dst = L3GetNextIf(f->Switch, ip->DstIP, &next_hop);
+
+ if (dst == NULL && self == false)
+ {
+ UINT src_packet_size = p->PacketSize - sizeof(MAC_HEADER);
+ UINT icmp_packet_total_size = sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4 + header_size + 8;
+ UCHAR *buf;
+ IPV4_HEADER *ipv4;
+ ICMP_HEADER *icmpv4;
+ UCHAR *data;
+ PKT *pkt;
+ UINT data_size = MIN(p->PacketSize - header_size, header_size + 8);
+
+ // Respond with ICMP that indicates that no route can be found
+ buf = ZeroMalloc(icmp_packet_total_size);
+ ipv4 = (IPV4_HEADER *)(buf + sizeof(MAC_HEADER));
+ icmpv4 = (ICMP_HEADER *)(buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER));
+ data = buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4;
+
+ IPV4_SET_VERSION(ipv4, 4);
+ IPV4_SET_HEADER_LEN(ipv4, sizeof(IPV4_HEADER) / 4);
+ ipv4->TotalLength = Endian16((USHORT)(icmp_packet_total_size - sizeof(MAC_HEADER)));
+ ipv4->TimeToLive = 0xff;
+ ipv4->Protocol = IP_PROTO_ICMPV4;
+ ipv4->SrcIP = f->IpAddress;
+ ipv4->DstIP = ip->SrcIP;
+ ipv4->Checksum = IpChecksum(ipv4, sizeof(IPV4_HEADER));
+
+ icmpv4->Type = 3;
+ Copy(data, ip, data_size);
+ icmpv4->Checksum = IpChecksum(icmpv4, sizeof(ICMP_HEADER) + data_size + 4);
+
+ buf[12] = 0x08;
+ buf[13] = 0x00;
+
+ pkt = ParsePacket(buf, icmp_packet_total_size);
+ if (pkt == NULL)
+ {
+ Free(buf);
+ }
+ else
+ {
+ L3RecvIp(f, pkt, true);
+ }
+
+ // Discard the packet body whose route can not be found
+ goto FREE_PACKET;
+ }
+
+ if (dst != NULL && ip->DstIP == dst->IpAddress)
+ {
+ bool free_packet = true;
+ // IP packet addressed to myself has arrived
+ if (p->TypeL4 == L4_ICMPV4)
+ {
+ ICMP_HEADER *icmp = p->L4.ICMPHeader;
+ if (icmp->Type == ICMP_TYPE_ECHO_REQUEST)
+ {
+ // Reply by rewriting the source and destination of the IP packet
+ UINT src_ip, dst_ip;
+ src_ip = p->L3.IPv4Header->DstIP;
+ dst_ip = p->L3.IPv4Header->SrcIP;
+
+ p->L3.IPv4Header->DstIP = dst_ip;
+ p->L3.IPv4Header->SrcIP = src_ip;
+
+ ip->TimeToLive = 0xff;
+
+ // Recalculates the checksum
+ ip->FlagsAndFlagmentOffset[0] = ip->FlagsAndFlagmentOffset[1] = 0;
+ icmp->Checksum = 0;
+ icmp->Type = ICMP_TYPE_ECHO_RESPONSE;
+ icmp->Checksum = IpChecksum(icmp, p->PacketSize - sizeof(MAC_HEADER) - header_size);
+
+ dst = L3GetNextIf(f->Switch, ip->DstIP, &next_hop);
+
+ free_packet = false;
+ }
+ }
+
+ if (free_packet)
+ {
+ goto FREE_PACKET;
+ }
+ }
+
+ if (dst == NULL)
+ {
+ // The destination does not exist
+ goto FREE_PACKET;
+ }
+
+ // Recalculate the IP checksum
+ ip->Checksum = 0;
+ ip->Checksum = IpChecksum(ip, header_size);
+
+ // Treat as a Layer-3 packet
+ packet = ZeroMalloc(sizeof(L3PACKET));
+ packet->Expire = Tick64() + IP_WAIT_FOR_ARP_TIMEOUT;
+ packet->NextHopIp = next_hop;
+ packet->Packet = p;
+
+ // Store to the destination session
+ L3StoreIpPacketToIf(f, dst, packet);
+
+ return;
+
+FREE_PACKET:
+ // Release the packet
+ Free(p->PacketData);
+ FreePacket(p);
+ return;
+}
+
+// Process the Layer 2 packet
+void L3RecvL2(L3IF *f, PKT *p)
+{
+ // Validate arguments
+ if (f == NULL || p == NULL)
+ {
+ return;
+ }
+
+ // Ignore any packets except a unicast packet which is destinated other
+ // or a packet which I sent
+ if (Cmp(p->MacAddressSrc, f->MacAddress, 6) == 0 ||
+ (p->BroadcastPacket == false && Cmp(p->MacAddressDest, f->MacAddress, 6) != 0))
+ {
+ // Release the packet
+ Free(p->PacketData);
+ FreePacket(p);
+ return;
+ }
+
+ if (p->TypeL3 == L3_ARPV4)
+ {
+ // Received an ARP packet
+ L3RecvArp(f, p);
+
+ // Release the packet
+ Free(p->PacketData);
+ FreePacket(p);
+ }
+ else if (p->TypeL3 == L3_IPV4)
+ {
+ // Received an IP packet
+ L3RecvIp(f, p, false);
+ }
+ else
+ {
+ // Release the packet
+ Free(p->PacketData);
+ FreePacket(p);
+ }
+}
+
+// Store the IP packet to a different interface
+void L3StoreIpPacketToIf(L3IF *src_if, L3IF *dst_if, L3PACKET *p)
+{
+ // Validate arguments
+ if (src_if == NULL || p == NULL || dst_if == NULL)
+ {
+ return;
+ }
+
+ // Add to the queue of store-destination session
+ InsertQueue(dst_if->IpPacketQueue, p);
+
+ // Hit the Cancel object of the store-destination session
+ AddCancelList(src_if->CancelList, dst_if->Session->Cancel1);
+}
+
+// Write the packet (Process because the packet was received)
+void L3PutPacket(L3IF *f, void *data, UINT size)
+{
+ PKT *p;
+ L3SW *s;
+ if (f == NULL)
+ {
+ return;
+ }
+
+ s = f->Switch;
+
+ if (data != NULL)
+ {
+ // Handle the next packet
+ if (f->CancelList == NULL)
+ {
+ f->CancelList = NewCancelList();
+ }
+
+ // Packet analysis
+ p = ParsePacket(data, size);
+
+ if (p == NULL)
+ {
+ // Packet analysis failure
+ Free(data);
+ }
+ else
+ {
+ // Packet analysis success
+ Lock(s->lock);
+ {
+ L3RecvL2(f, p);
+ }
+ Unlock(s->lock);
+ }
+ }
+ else
+ {
+ // Cancel for the cancellation list after all packet processing has been finished
+ if (f->CancelList != NULL)
+ {
+ CancelList(f->CancelList);
+ ReleaseCancelList(f->CancelList);
+ f->CancelList = NULL;
+ }
+ }
+}
+
+// Send the waiting IP packets whose destination MAC address has been resolved
+void L3SendWaitingIp(L3IF *f, UCHAR *mac, UINT ip, L3ARPENTRY *a)
+{
+ UINT i;
+ LIST *o = NULL;
+ // Validate arguments
+ if (f == NULL || mac == NULL || a == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(f->IpWaitList);i++)
+ {
+ L3PACKET *p = LIST_DATA(f->IpWaitList, i);
+
+ if (p->NextHopIp == ip)
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+ Add(o, p);
+ }
+ }
+
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ L3PACKET *p = LIST_DATA(o, i);
+
+ // Transmission
+ L3SendIpNow(f, a, p);
+
+ Delete(f->IpWaitList, p);
+ Free(p->Packet->PacketData);
+ FreePacket(p->Packet);
+ Free(p);
+ }
+
+ ReleaseList(o);
+ }
+}
+
+// Register in the ARP table
+void L3InsertArpTable(L3IF *f, UINT ip, UCHAR *mac)
+{
+ L3ARPENTRY *a, t;
+ // Validate arguments
+ if (f == NULL || ip == 0 || ip == 0xffffffff || mac == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ t.IpAddress = ip;
+
+ a = Search(f->ArpTable, &t);
+
+ if (a == NULL)
+ {
+ // Since this is not registered, register this
+ a = ZeroMalloc(sizeof(L3ARPENTRY));
+ a->IpAddress = ip;
+ Copy(a->MacAddress, mac, 6);
+ Insert(f->ArpTable, a);
+ }
+
+ // Extend the expiration date
+ a->Expire = Tick64() + ARP_ENTRY_EXPIRES;
+
+ // Send waiting IP packets
+ L3SendWaitingIp(f, mac, ip, a);
+}
+
+// Function to be called when the ARP resolved
+void L3KnownArp(L3IF *f, UINT ip, UCHAR *mac)
+{
+ L3ARPWAIT t, *w;
+ // Validate arguments
+ if (f == NULL || ip == 0 || ip == 0xffffffff || mac == NULL)
+ {
+ return;
+ }
+
+ // Delete an ARP query entry to this IP address
+ Zero(&t, sizeof(t));
+ t.IpAddress = ip;
+ w = Search(f->IpWaitList, &t);
+ if (w != NULL)
+ {
+ Delete(f->IpWaitList, w);
+ Free(w);
+ }
+
+ // Register in the ARP table
+ L3InsertArpTable(f, ip, mac);
+}
+
+// Issue an ARP query
+void L3SendArp(L3IF *f, UINT ip)
+{
+ L3ARPWAIT t, *w;
+ // Validate arguments
+ if (f == NULL || ip == 0 || ip == 0xffffffff)
+ {
+ return;
+ }
+
+ // Examine whether it has not already registered
+ Zero(&t, sizeof(t));
+ t.IpAddress = ip;
+ w = Search(f->ArpWaitTable, &t);
+
+ if (w != NULL)
+ {
+ // Do not do anything because it is already registered in the waiting list
+ return;
+ }
+ else
+ {
+ // Register in the waiting list newly
+ w = ZeroMalloc(sizeof(L3ARPWAIT));
+ w->Expire = Tick64() + ARP_REQUEST_GIVEUP;
+ w->IpAddress = ip;
+ Insert(f->ArpWaitTable, w);
+ }
+}
+
+// Received an ARP request
+void L3RecvArpRequest(L3IF *f, PKT *p)
+{
+ ARPV4_HEADER *a;
+ // Validate arguments
+ if (f == NULL || p == NULL)
+ {
+ return;
+ }
+
+ a = p->L3.ARPv4Header;
+
+ L3KnownArp(f, a->SrcIP, a->SrcAddress);
+
+ if (a->TargetIP == f->IpAddress)
+ {
+ // Respond only if the ARP packet addressed to myself
+ L3SendArpResponseNow(f, a->SrcAddress, a->SrcIP, f->IpAddress);
+ }
+}
+
+// Received an ARP response
+void L3RecvArpResponse(L3IF *f, PKT *p)
+{
+ ARPV4_HEADER *a;
+ // Validate arguments
+ if (f == NULL || p == NULL)
+ {
+ return;
+ }
+
+ a = p->L3.ARPv4Header;
+
+ L3KnownArp(f, a->SrcIP, a->SrcAddress);
+}
+
+// Received an ARP packet
+void L3RecvArp(L3IF *f, PKT *p)
+{
+ ARPV4_HEADER *a;
+ // Validate arguments
+ if (f == NULL || p == NULL)
+ {
+ return;
+ }
+
+ a = p->L3.ARPv4Header;
+
+ if (Endian16(a->HardwareType) != ARP_HARDWARE_TYPE_ETHERNET ||
+ Endian16(a->ProtocolType) != MAC_PROTO_IPV4 ||
+ a->HardwareSize != 6 || a->ProtocolSize != 4)
+ {
+ return;
+ }
+ if (Cmp(a->SrcAddress, p->MacAddressSrc, 6) != 0)
+ {
+ return;
+ }
+
+ switch (Endian16(a->Operation))
+ {
+ case ARP_OPERATION_REQUEST:
+ // ARP request arrives
+ L3RecvArpRequest(f, p);
+ break;
+
+ case ARP_OPERATION_RESPONSE:
+ // ARP response arrives
+ L3RecvArpResponse(f, p);
+ break;
+ }
+}
+
+// Send an IP packet
+void L3SendIp(L3IF *f, L3PACKET *p)
+{
+ L3ARPENTRY *a = NULL;
+ bool broadcast = false;
+ IPV4_HEADER *ip;
+ bool for_me = false;
+ // Validate arguments
+ if (f == NULL || p == NULL)
+ {
+ return;
+ }
+ if (p->Packet->TypeL3 != L3_IPV4)
+ {
+ return;
+ }
+
+ ip = p->Packet->L3.IPv4Header;
+
+ // Determining whether it's a broadcast
+ if (p->NextHopIp == 0xffffffff ||
+ ((p->NextHopIp & f->SubnetMask) == (f->IpAddress & f->SubnetMask)) &&
+ ((p->NextHopIp & (~f->SubnetMask)) == (~f->SubnetMask)))
+ {
+ broadcast = true;
+ }
+
+ if (broadcast == false && ip->DstIP == f->IpAddress)
+ {
+ // me?
+ }
+ else if (broadcast == false)
+ {
+ // Examine whether the ARP entry contains this in the case of unicast
+ a = L3SearchArpTable(f, p->NextHopIp);
+
+ if (a == NULL)
+ {
+ // Since It is not in the ARP table,
+ // insert it into the IP waiting list without sending immediately
+ p->Expire = Tick64() + IP_WAIT_FOR_ARP_TIMEOUT;
+
+ Insert(f->IpWaitList, p);
+
+ // Issue an ARP query
+ L3SendArp(f, p->NextHopIp);
+ return;
+ }
+ }
+
+ if (for_me == false)
+ {
+ // Send the IP packet
+ L3SendIpNow(f, a, p);
+ }
+
+ // Release the packet
+ Free(p->Packet->PacketData);
+ FreePacket(p->Packet);
+ Free(p);
+}
+
+// Send the IP packet immediately
+void L3SendIpNow(L3IF *f, L3ARPENTRY *a, L3PACKET *p)
+{
+ // Validate arguments
+ if (f == NULL || p == NULL)
+ {
+ return;
+ }
+
+ L3SendL2Now(f, a != NULL ? a->MacAddress : broadcast, f->MacAddress, Endian16(p->Packet->MacHeader->Protocol),
+ p->Packet->L3.PointerL3, p->Packet->PacketSize - sizeof(MAC_HEADER));
+}
+
+// Search in the ARP table
+L3ARPENTRY *L3SearchArpTable(L3IF *f, UINT ip)
+{
+ L3ARPENTRY *e, t;
+ // Validate arguments
+ if (f == NULL || ip == 0 || ip == 0xffffffff)
+ {
+ return NULL;
+ }
+
+ Zero(&t, sizeof(t));
+ t.IpAddress = ip;
+
+ e = Search(f->ArpTable, &t);
+
+ return e;
+}
+
+// Send an ARP request packet
+void L3SendArpRequestNow(L3IF *f, UINT dest_ip)
+{
+ ARPV4_HEADER arp;
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ // Build an ARP header
+ arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+ arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
+ arp.HardwareSize = 6;
+ arp.ProtocolSize = 4;
+ arp.Operation = Endian16(ARP_OPERATION_REQUEST);
+ Copy(arp.SrcAddress, f->MacAddress, 6);
+ arp.SrcIP = f->IpAddress;
+ Zero(&arp.TargetAddress, 6);
+ arp.TargetIP = dest_ip;
+
+ // Transmission
+ L3SendL2Now(f, broadcast, f->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
+}
+
+// Send an ARP response packet
+void L3SendArpResponseNow(L3IF *f, UCHAR *dest_mac, UINT dest_ip, UINT src_ip)
+{
+ ARPV4_HEADER arp;
+ // Validate arguments
+ if (f == NULL || dest_mac == NULL)
+ {
+ return;
+ }
+
+ // Build a header
+ arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+ arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
+ arp.HardwareSize = 6;
+ arp.ProtocolSize = 4;
+ arp.Operation = Endian16(ARP_OPERATION_RESPONSE);
+ Copy(arp.SrcAddress, f->MacAddress, 6);
+ Copy(arp.TargetAddress, dest_mac, 6);
+ arp.SrcIP = src_ip;
+ arp.TargetIP = dest_ip;
+
+ // Transmission
+ L3SendL2Now(f, dest_mac, f->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
+}
+
+// Generate a MAC address of the interface
+void L3GenerateMacAddress(L3IF *f)
+{
+ BUF *b;
+ UCHAR hash[SHA1_SIZE];
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ b = NewBuf();
+ WriteBuf(b, f->Switch->Name, StrLen(f->Switch->Name));
+ WriteBuf(b, f->HubName, StrLen(f->HubName));
+ WriteBuf(b, &f->IpAddress, sizeof(f->IpAddress));
+
+ GenMacAddress(f->MacAddress);
+ Hash(hash, b->Buf, b->Size, true);
+ Copy(f->MacAddress + 2, hash, 4);
+ f->MacAddress[1] = 0xA3;
+ FreeBuf(b);
+}
+
+// Send an L2 packet immediately
+void L3SendL2Now(L3IF *f, UCHAR *dest_mac, UCHAR *src_mac, USHORT protocol, void *data, UINT size)
+{
+ UCHAR *buf;
+ MAC_HEADER *mac_header;
+ PKT *p;
+ // Validate arguments
+ if (f == NULL || dest_mac == NULL || src_mac == NULL || data == NULL)
+ {
+ return;
+ }
+
+ // Buffer creation
+ buf = Malloc(MAC_HEADER_SIZE + size);
+
+ // MAC header
+ mac_header = (MAC_HEADER *)&buf[0];
+ Copy(mac_header->DestAddress, dest_mac, 6);
+ Copy(mac_header->SrcAddress, src_mac, 6);
+ mac_header->Protocol = Endian16(protocol);
+
+ // Copy data
+ Copy(&buf[sizeof(MAC_HEADER)], data, size);
+
+ // Size
+ size += sizeof(MAC_HEADER);
+
+ // Packet generation
+ p = ZeroMalloc(sizeof(PKT));
+ p->PacketData = buf;
+ p->PacketSize = size;
+
+ // Add to the queue
+ InsertQueue(f->SendQueue, p);
+}
+
+// Polling for the ARP resolution waiting list
+void L3PollingArpWaitTable(L3IF *f)
+{
+ UINT i;
+ LIST *o = NULL;
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(f->ArpWaitTable);i++)
+ {
+ L3ARPWAIT *w = LIST_DATA(f->ArpWaitTable, i);
+
+ if (w->Expire <= Tick64())
+ {
+ // The ARP request entry is expired
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Insert(o, w);
+ }
+ else if ((w->LastSentTime + ARP_REQUEST_TIMEOUT) <= Tick64())
+ {
+ // Send a next ARP request packet
+ w->LastSentTime = Tick64();
+
+ L3SendArpRequestNow(f, w->IpAddress);
+ }
+ }
+
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ L3ARPWAIT *w = LIST_DATA(o, i);
+
+ Delete(f->ArpWaitTable, w);
+ Free(w);
+ }
+
+ ReleaseList(o);
+ }
+}
+
+// Clear old ARP table entries
+void L3DeleteOldArpTable(L3IF *f)
+{
+ UINT i;
+ LIST *o = NULL;
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ if ((f->LastDeleteOldArpTable + ARP_ENTRY_POLLING_TIME) > Tick64())
+ {
+ return;
+ }
+ f->LastDeleteOldArpTable = Tick64();
+
+ for (i = 0;i < LIST_NUM(f->ArpTable);i++)
+ {
+ L3ARPENTRY *a = LIST_DATA(f->ArpTable, i);
+
+ if (a->Expire <= Tick64())
+ {
+ // Expired
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Insert(o, a);
+ }
+ }
+
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ L3ARPENTRY *a = LIST_DATA(o, i);
+
+ Delete(f->ArpTable, a);
+ Free(a);
+ }
+
+ ReleaseList(o);
+ }
+}
+
+// Clear the IP waiting list
+void L3DeleteOldIpWaitList(L3IF *f)
+{
+ UINT i;
+ LIST *o = NULL;
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(f->IpWaitList);i++)
+ {
+ L3PACKET *p = LIST_DATA(f->IpWaitList, i);
+
+ if (p->Expire <= Tick64())
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Insert(o, p);
+ }
+ }
+
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ L3PACKET *p = LIST_DATA(o, i);
+
+ Delete(f->IpWaitList, p);
+
+ Free(p->Packet->PacketData);
+ FreePacket(p->Packet);
+ Free(p);
+ }
+
+ ReleaseList(o);
+ }
+}
+
+// Beacon transmission
+void L3PollingBeacon(L3IF *f)
+{
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ if (f->LastBeaconSent == 0 ||
+ (f->LastBeaconSent + BEACON_SEND_INTERVAL) <= Tick64())
+ {
+ UINT dest_ip;
+ UCHAR *udp_buf;
+ UINT udp_buf_size;
+ ARPV4_HEADER arp;
+ IPV4_HEADER *ip;
+ UDP_HEADER *udp;
+ static char beacon_str[] =
+ "PacketiX VPN Virtual Layer-3 Switch Beacon";
+
+ // Send an UDP
+ dest_ip = (f->IpAddress & f->SubnetMask) | (~f->SubnetMask);
+ udp_buf_size = sizeof(IPV4_HEADER) + sizeof(UDP_HEADER) + sizeof(beacon_str);
+ udp_buf = ZeroMalloc(udp_buf_size);
+
+ ip = (IPV4_HEADER *)udp_buf;
+ udp = (UDP_HEADER *)(udp_buf + sizeof(IPV4_HEADER));
+ udp->DstPort = Endian16(7);
+ udp->SrcPort = Endian16(7);
+ udp->PacketLength = Endian16(sizeof(UDP_HEADER) + sizeof(beacon_str));
+
+ Copy(udp_buf + sizeof(IPV4_HEADER) + sizeof(UDP_HEADER), beacon_str, sizeof(beacon_str));
+
+ udp->Checksum = IpChecksum(udp, sizeof(UDP_HEADER) + sizeof(beacon_str));
+
+ ip->DstIP = dest_ip;
+ IPV4_SET_VERSION(ip, 4);
+ IPV4_SET_HEADER_LEN(ip, (IP_HEADER_SIZE / 4));
+ ip->TypeOfService = DEFAULT_IP_TOS;
+ ip->TotalLength = Endian16((USHORT)(udp_buf_size));
+ ip->TimeToLive = DEFAULT_IP_TTL;
+ ip->Protocol = IP_PROTO_UDP;
+ ip->SrcIP = f->IpAddress;
+ ip->Checksum = IpChecksum(ip, IP_HEADER_SIZE);
+
+ L3SendL2Now(f, broadcast, f->MacAddress, MAC_PROTO_IPV4, udp_buf, udp_buf_size);
+
+ Free(udp_buf);
+
+ // Build the ARP header
+ arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+ arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
+ arp.HardwareSize = 6;
+ arp.ProtocolSize = 4;
+ arp.Operation = Endian16(ARP_OPERATION_RESPONSE);
+ Copy(arp.SrcAddress, f->MacAddress, 6);
+ arp.SrcIP = f->IpAddress;
+ arp.TargetAddress[0] =
+ arp.TargetAddress[1] =
+ arp.TargetAddress[2] =
+ arp.TargetAddress[3] =
+ arp.TargetAddress[4] =
+ arp.TargetAddress[5] = 0xff;
+ arp.TargetIP = dest_ip;
+
+ // Transmission
+ L3SendL2Now(f, broadcast, f->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
+
+ f->LastBeaconSent = Tick64();
+ }
+}
+
+// Polling process
+void L3Polling(L3IF *f)
+{
+ L3SW *s;
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ s = f->Switch;
+
+ // Lock the entire switch in the middle of the polling process
+ Lock(s->lock);
+ {
+ // Beacon transmission
+ L3PollingBeacon(f);
+
+ // Process the IP queue
+ L3PollingIpQueue(f);
+
+ // Clear old ARP table entries
+ L3DeleteOldArpTable(f);
+
+ // Polling ARP resolution waiting list
+ L3PollingArpWaitTable(f);
+
+ // Clear the IP waiting list
+ L3DeleteOldIpWaitList(f);
+ }
+ Unlock(s->lock);
+}
+
+// Get the next packet
+UINT L3GetNextPacket(L3IF *f, void **data)
+{
+ UINT ret = 0;
+ // Validate arguments
+ if (f == NULL || data == NULL)
+ {
+ return 0;
+ }
+
+START:
+ // Examine the send queue
+ LockQueue(f->SendQueue);
+ {
+ PKT *p = GetNext(f->SendQueue);
+
+ if (p != NULL)
+ {
+ // There is a packet
+ ret = p->PacketSize;
+ *data = p->PacketData;
+ // Packet structure may be discarded
+ Free(p);
+ }
+ }
+ UnlockQueue(f->SendQueue);
+
+ if (ret == 0)
+ {
+ // Polling process
+ L3Polling(f);
+
+ // Examine whether a new packet is queued for results of the polling process
+ if (f->SendQueue->num_item != 0)
+ {
+ // Get the packet immediately if it's in the queue
+ goto START;
+ }
+ }
+
+ return ret;
+}
+
+// Determine the packet destined for the specified IP address should be sent to which interface
+L3IF *L3GetNextIf(L3SW *s, UINT ip, UINT *next_hop)
+{
+ UINT i;
+ L3IF *f;
+ UINT next_hop_ip = 0;
+ // Validate arguments
+ if (s == NULL || ip == 0 || ip == 0xffffffff)
+ {
+ return NULL;
+ }
+
+ f = NULL;
+
+ // Examine whether the specified IP address is contained
+ // in the networks which each interfaces belong to
+ for (i = 0;i < LIST_NUM(s->IfList);i++)
+ {
+ L3IF *ff = LIST_DATA(s->IfList, i);
+
+ if ((ff->IpAddress & ff->SubnetMask) == (ip & ff->SubnetMask))
+ {
+ f = ff;
+ next_hop_ip = ip;
+ break;
+ }
+ }
+
+ if (f == NULL)
+ {
+ // Find the routing table if it's not found
+ L3TABLE *t = L3GetBestRoute(s, ip);
+
+ if (t == NULL)
+ {
+ // Still not found
+ return NULL;
+ }
+ else
+ {
+ // Find the interface with the IP address of the router of
+ // NextHop of the found route
+ for (i = 0;i < LIST_NUM(s->IfList);i++)
+ {
+ L3IF *ff = LIST_DATA(s->IfList, i);
+
+ if ((ff->IpAddress & ff->SubnetMask) == (t->GatewayAddress & ff->SubnetMask))
+ {
+ f = ff;
+ next_hop_ip = t->GatewayAddress;
+ break;
+ }
+ }
+ }
+ }
+
+ if (f == NULL)
+ {
+ // Destination interface was unknown after all
+ return NULL;
+ }
+
+ if (next_hop != NULL)
+ {
+ *next_hop = next_hop_ip;
+ }
+
+ return f;
+}
+
+// Get the best routing table entry for the specified IP address
+L3TABLE *L3GetBestRoute(L3SW *s, UINT ip)
+{
+ UINT i;
+ UINT max_mask = 0;
+ UINT min_metric = INFINITE;
+ L3TABLE *ret = NULL;
+ // Validate arguments
+ if (s == NULL || ip == 0)
+ {
+ return NULL;
+ }
+
+ // 1st condition: Choose the one which have the largest subnet mask
+ // 2nd condition: Choose the one which have the smallest metric
+ for (i = 0;i < LIST_NUM(s->TableList);i++)
+ {
+ L3TABLE *t = LIST_DATA(s->TableList, i);
+
+ if ((t->NetworkAddress & t->SubnetMask) == (ip & t->SubnetMask))
+ {
+ if (t->SubnetMask >= max_mask)
+ {
+ max_mask = t->SubnetMask;
+ if (min_metric >= t->Metric)
+ {
+ min_metric = t->Metric;
+ ret = t;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+// Initialize the Layer-3 interface
+void L3InitInterface(L3IF *f)
+{
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ // MAC address generation
+ L3GenerateMacAddress(f);
+
+ // List generation
+ f->ArpTable = NewList(CmpL3ArpEntry);
+ f->ArpWaitTable = NewList(CmpL3ArpWaitTable);
+ f->IpPacketQueue = NewQueue();
+ f->IpWaitList = NewList(NULL);
+ f->SendQueue = NewQueue();
+}
+
+// Release the Layer-3 interface
+void L3FreeInterface(L3IF *f)
+{
+ UINT i;
+ L3PACKET *p;
+ PKT *pkt;
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(f->ArpTable);i++)
+ {
+ L3ARPENTRY *a = LIST_DATA(f->ArpTable, i);
+ Free(a);
+ }
+ ReleaseList(f->ArpTable);
+ f->ArpTable = NULL;
+
+ for (i = 0;i < LIST_NUM(f->ArpWaitTable);i++)
+ {
+ L3ARPWAIT *w = LIST_DATA(f->ArpWaitTable, i);
+ Free(w);
+ }
+ ReleaseList(f->ArpWaitTable);
+ f->ArpWaitTable = NULL;
+
+ while (p = GetNext(f->IpPacketQueue))
+ {
+ Free(p->Packet->PacketData);
+ FreePacket(p->Packet);
+ Free(p);
+ }
+ ReleaseQueue(f->IpPacketQueue);
+ f->IpPacketQueue = NULL;
+
+ for (i = 0;i < LIST_NUM(f->IpWaitList);i++)
+ {
+ L3PACKET *p = LIST_DATA(f->IpWaitList, i);
+ Free(p->Packet->PacketData);
+ FreePacket(p->Packet);
+ Free(p);
+ }
+ ReleaseList(f->IpWaitList);
+ f->IpWaitList = NULL;
+
+ while (pkt = GetNext(f->SendQueue))
+ {
+ Free(pkt->PacketData);
+ FreePacket(pkt);
+ }
+ ReleaseQueue(f->SendQueue);
+ f->SendQueue = NULL;
+}
+
+// Layer-3 interface thread
+void L3IfThread(THREAD *t, void *param)
+{
+ L3IF *f;
+ CONNECTION *c;
+ SESSION *s;
+ POLICY *policy;
+ char tmp[MAX_SIZE];
+ char name[MAX_SIZE];
+ char username[MAX_SIZE];
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ f = (L3IF *)param;
+
+ StrCpy(username, sizeof(username), L3_USERNAME);
+ if (f->Switch != NULL)
+ {
+ StrCat(username, sizeof(username), f->Switch->Name);
+ }
+
+ // Create a connection
+ c = NewServerConnection(f->Switch->Cedar, NULL, t);
+ c->Protocol = CONNECTION_HUB_LAYER3;
+
+ // Create a Session
+ policy = ClonePolicy(GetDefaultPolicy());
+ // Not to limit the number of broadcast by policy
+ policy->NoBroadcastLimiter = true;
+ s = NewServerSession(f->Switch->Cedar, c, f->Hub, username, policy);
+ c->Session = s;
+
+ ReleaseConnection(c);
+
+ // Determine the name of the session
+ GetMachineHostName(tmp, sizeof(tmp));
+ if (f->Switch->Cedar->Server->ServerType == SERVER_TYPE_STANDALONE)
+ {
+ Format(name, sizeof(name), "SID-L3-%s-%u", f->Switch->Name, Inc(f->Hub->SessionCounter));
+ }
+ else
+ {
+ Format(name, sizeof(name), "SID-L3-%s-%s-%u", tmp, f->Switch->Name, Inc(f->Hub->SessionCounter));
+ }
+ ConvertSafeFileName(name, sizeof(name), name);
+ StrUpper(name);
+
+ Free(s->Name);
+ s->Name = CopyStr(name);
+
+ s->L3SwitchMode = true;
+ s->L3If = f;
+
+ if (s->Username != NULL)
+ {
+ Free(s->Username);
+ }
+ s->Username = CopyStr(username);
+
+ StrCpy(s->UserNameReal, sizeof(s->UserNameReal), username);
+
+ f->Session = s;
+ AddRef(s->ref);
+
+ // Notify the initialization completion
+ NoticeThreadInit(t);
+
+ // Session main process
+ SessionMain(s);
+
+ // Release the session
+ ReleaseSession(s);
+}
+
+// Initialize all Layer-3 interfaces
+void L3InitAllInterfaces(L3SW *s)
+{
+ UINT i;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(s->IfList);i++)
+ {
+ L3IF *f = LIST_DATA(s->IfList, i);
+ THREAD *t;
+
+ L3InitInterface(f);
+
+ f->Hub = GetHub(s->Cedar, f->HubName);
+ t = NewThread(L3IfThread, f);
+ WaitThreadInit(t);
+ ReleaseThread(t);
+ }
+}
+
+// Release all Layer-3 interfaces
+void L3FreeAllInterfaces(L3SW *s)
+{
+ UINT i;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(s->IfList);i++)
+ {
+ L3IF *f = LIST_DATA(s->IfList, i);
+
+ ReleaseHub(f->Hub);
+ f->Hub = NULL;
+ ReleaseSession(f->Session);
+ f->Session = NULL;
+
+ L3FreeInterface(f);
+ }
+}
+
+// Layer-3 test
+void L3Test(SERVER *s)
+{
+ L3SW *ss = L3AddSw(s->Cedar, "TEST");
+ L3AddIf(ss, "DEFAULT", 0x0101a8c0, 0x00ffffff);
+ L3AddIf(ss, "DEFAULT2", 0x0102a8c0, 0x00ffffff);
+ L3SwStart(ss);
+ ReleaseL3Sw(ss);
+}
+
+// Layer-3 switch thread
+void L3SwThread(THREAD *t, void *param)
+{
+ L3SW *s;
+ bool shutdown_now = false;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ s = (L3SW *)param;
+
+ s->Active = true;
+
+ NoticeThreadInit(t);
+
+ // Operation start
+ SLog(s->Cedar, "L3_SWITCH_START", s->Name);
+
+ while (s->Halt == false)
+ {
+ if (s->Online == false)
+ {
+ // Because the L3 switch is off-line now,
+ // attempt to make it on-line periodically
+ LockList(s->Cedar->HubList);
+ {
+ Lock(s->lock);
+ {
+ UINT i;
+ UINT n = 0;
+ bool all_exists = true;
+ if (LIST_NUM(s->IfList) == 0)
+ {
+ // Don't operate if there is no interface
+ all_exists = false;
+ }
+ for (i = 0;i < LIST_NUM(s->IfList);i++)
+ {
+ L3IF *f = LIST_DATA(s->IfList, i);
+ HUB *h = GetHub(s->Cedar, f->HubName);
+
+ if (h != NULL)
+ {
+ if (h->Offline || h->Type == HUB_TYPE_FARM_DYNAMIC)
+ {
+ all_exists = false;
+ }
+ else
+ {
+ n++;
+ }
+ ReleaseHub(h);
+ }
+ else
+ {
+ all_exists = false;
+ }
+ }
+
+ if (all_exists && n >= 1)
+ {
+ // Start the operation because all Virtual HUBs for
+ // interfaces are enabled
+ SLog(s->Cedar, "L3_SWITCH_ONLINE", s->Name);
+ L3InitAllInterfaces(s);
+ s->Online = true;
+ }
+ }
+ Unlock(s->lock);
+ }
+ UnlockList(s->Cedar->HubList);
+ }
+ else
+ {
+ // Examine periodically whether all sessions terminated
+ UINT i;
+ bool any_halted = false;
+ LIST *o = NULL;
+
+SHUTDOWN:
+
+ Lock(s->lock);
+ {
+ for (i = 0;i < LIST_NUM(s->IfList);i++)
+ {
+ L3IF *f = LIST_DATA(s->IfList, i);
+ if (f->Session->Halt || f->Hub->Offline != false)
+ {
+ any_halted = true;
+ break;
+ }
+ }
+
+ if (shutdown_now)
+ {
+ any_halted = true;
+ }
+
+ if (any_halted)
+ {
+ SLog(s->Cedar, "L3_SWITCH_OFFLINE", s->Name);
+ o = NewListFast(NULL);
+ // If there is any terminated session, terminate all sessions
+ for (i = 0;i < LIST_NUM(s->IfList);i++)
+ {
+ L3IF *f = LIST_DATA(s->IfList, i);
+ Insert(o, f->Session);
+ }
+
+ // Restore to the offline
+ s->Online = false;
+ }
+ }
+ Unlock(s->lock);
+
+ if (o != NULL)
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ SESSION *s = LIST_DATA(o, i);
+ StopSession(s);
+ }
+ L3FreeAllInterfaces(s);
+ ReleaseList(o);
+ o = NULL;
+ }
+ }
+
+ SleepThread(50);
+ }
+
+ if (s->Online != false)
+ {
+ shutdown_now = true;
+ goto SHUTDOWN;
+ }
+
+ // Stop the operation
+ SLog(s->Cedar, "L3_SWITCH_STOP", s->Name);
+}
+
+// Start a Layer-3 switch
+void L3SwStart(L3SW *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Lock(s->lock);
+ {
+ if (s->Active == false)
+ {
+ // Start if there is registered interface
+ if (LIST_NUM(s->IfList) >= 1)
+ {
+ s->Halt = false;
+
+ // Create a thread
+ s->Thread = NewThread(L3SwThread, s);
+ WaitThreadInit(s->Thread);
+ }
+ }
+ }
+ Unlock(s->lock);
+}
+
+// Stop the Layer-3 switch
+void L3SwStop(L3SW *s)
+{
+ THREAD *t = NULL;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Lock(s->lock);
+ {
+ if (s->Active == false)
+ {
+ Unlock(s->lock);
+ return;
+ }
+
+ s->Halt = true;
+
+ t = s->Thread;
+
+ s->Active = false;
+ }
+ Unlock(s->lock);
+
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+}
+
+// Add a Layer-3 switch
+L3SW *L3AddSw(CEDAR *c, char *name)
+{
+ L3SW *s = NULL;
+ // Validate arguments
+ if (c == NULL || name == NULL)
+ {
+ return NULL;
+ }
+
+ LockList(c->L3SwList);
+ {
+ s = L3GetSw(c, name);
+
+ if (s == NULL)
+ {
+ s = NewL3Sw(c, name);
+
+ Insert(c->L3SwList, s);
+
+ AddRef(s->ref);
+ }
+ else
+ {
+ ReleaseL3Sw(s);
+ s = NULL;
+ }
+ }
+ UnlockList(c->L3SwList);
+
+ return s;
+}
+
+// Delete the Layer-3 switch
+bool L3DelSw(CEDAR *c, char *name)
+{
+ L3SW *s;
+ bool ret = false;
+ // Validate arguments
+ if (c == NULL || name == NULL)
+ {
+ return false;
+ }
+
+ LockList(c->L3SwList);
+ {
+ s = L3GetSw(c, name);
+
+ if (s != NULL)
+ {
+ // Stop and delete
+ L3SwStop(s);
+ Delete(c->L3SwList, s);
+ ReleaseL3Sw(s);
+ ReleaseL3Sw(s);
+
+ ret = true;
+ }
+ }
+ UnlockList(c->L3SwList);
+
+ return ret;
+}
+
+
+// Delete the routing table
+bool L3DelTable(L3SW *s, L3TABLE *tbl)
+{
+ bool ret = false;
+ // Validate arguments
+ if (s == NULL || tbl == NULL)
+ {
+ return false;
+ }
+
+ Lock(s->lock);
+ {
+ if (s->Active == false)
+ {
+ L3TABLE *t = Search(s->TableList, tbl);
+
+ if (t != NULL)
+ {
+ Delete(s->TableList, t);
+ Free(t);
+
+ ret = true;
+ }
+ }
+ }
+ Unlock(s->lock);
+
+ return ret;
+}
+
+// Add to the routing table
+bool L3AddTable(L3SW *s, L3TABLE *tbl)
+{
+ bool ret = false;
+ // Validate arguments
+ if (s == NULL || tbl == NULL)
+ {
+ return false;
+ }
+
+ if (tbl->Metric == 0 || tbl->GatewayAddress == 0 || tbl->GatewayAddress == 0xffffffff)
+ {
+ return false;
+ }
+
+ Lock(s->lock);
+ {
+ if (LIST_NUM(s->TableList) >= GetServerCapsInt(s->Cedar->Server, "i_max_l3_table"))
+ {
+ // Too many
+ }
+ else
+ {
+ // Create
+ if (s->Active == false)
+ {
+ if (Search(s->TableList, tbl) == NULL)
+ {
+ L3TABLE *t = ZeroMalloc(sizeof(L3TABLE));
+
+ Copy(t, tbl, sizeof(L3TABLE));
+
+ Insert(s->TableList, t);
+
+ ret = true;
+ }
+ }
+ }
+ }
+ Unlock(s->lock);
+
+ return ret;
+}
+
+// Get the L3 switch
+L3SW *L3GetSw(CEDAR *c, char *name)
+{
+ L3SW t, *s;
+ // Validate arguments
+ if (c == NULL || name == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), name);
+
+ LockList(c->L3SwList);
+ {
+ s = Search(c->L3SwList, &t);
+ }
+ UnlockList(c->L3SwList);
+
+ if (s != NULL)
+ {
+ AddRef(s->ref);
+ }
+
+ return s;
+}
+
+// Get the interface that is connected to the specified Virtual HUB from the L3 switch
+L3IF *L3SearchIf(L3SW *s, char *hubname)
+{
+ L3IF t, *f;
+ // Validate arguments
+ if (s == NULL || hubname == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+ f = Search(s->IfList, &t);
+
+ return f;
+}
+
+// Delete the interface
+bool L3DelIf(L3SW *s, char *hubname)
+{
+ L3IF *f;
+ bool ret = false;
+ // Validate arguments
+ if (s == NULL || hubname == NULL)
+ {
+ return false;
+ }
+
+ Lock(s->lock);
+ {
+ if (s->Active == false)
+ {
+ f = L3SearchIf(s, hubname);
+
+ if (f != NULL)
+ {
+ // Remove
+ Delete(s->IfList, f);
+ Free(f);
+
+ ret = true;
+ }
+ }
+ }
+ Unlock(s->lock);
+
+ return ret;
+}
+
+// Add an interface
+bool L3AddIf(L3SW *s, char *hubname, UINT ip, UINT subnet)
+{
+ L3IF *f;
+ bool ret = false;
+ // Validate arguments
+ if (s == NULL || hubname == NULL || IsSafeStr(hubname) == false ||
+ ip == 0 || ip == 0xffffffff)
+ {
+ return false;
+ }
+
+ Lock(s->lock);
+ {
+ if (LIST_NUM(s->TableList) >= GetServerCapsInt(s->Cedar->Server, "i_max_l3_if"))
+ {
+ // Too many
+ }
+ else
+ {
+ if (s->Active == false)
+ {
+ // Examine whether the interface is already in the same Virtual HUB
+ if (L3SearchIf(s, hubname) == NULL)
+ {
+ // Add
+ f = ZeroMalloc(sizeof(L3IF));
+
+ f->Switch = s;
+ StrCpy(f->HubName, sizeof(f->HubName), hubname);
+ f->IpAddress = ip;
+ f->SubnetMask = subnet;
+
+ Insert(s->IfList, f);
+
+ ret = true;
+ }
+ }
+ }
+ }
+ Unlock(s->lock);
+
+ return ret;
+}
+
+// Clean-up the L3 switch
+void CleanupL3Sw(L3SW *s)
+{
+ UINT i;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(s->IfList);i++)
+ {
+ L3IF *f = LIST_DATA(s->IfList, i);
+ Free(f);
+ }
+ ReleaseList(s->IfList);
+
+ for (i = 0;i < LIST_NUM(s->TableList);i++)
+ {
+ L3TABLE *t = LIST_DATA(s->TableList, i);
+ Free(t);
+ }
+ ReleaseList(s->TableList);
+
+ DeleteLock(s->lock);
+ Free(s);
+}
+
+// Release the L3 switch
+void ReleaseL3Sw(L3SW *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ if (Release(s->ref) == 0)
+ {
+ CleanupL3Sw(s);
+ }
+}
+
+// Create a new L3 switch
+L3SW *NewL3Sw(CEDAR *c, char *name)
+{
+ L3SW *o;
+ // Validate arguments
+ if (c == NULL || name == NULL)
+ {
+ return NULL;
+ }
+
+ o = ZeroMalloc(sizeof(L3SW));
+
+ StrCpy(o->Name, sizeof(o->Name), name);
+
+ o->lock = NewLock();
+ o->ref = NewRef();
+ o->Cedar = c;
+ o->Active = false;
+
+ o->IfList = NewList(CmpL3If);
+ o->TableList = NewList(CmpL3Table);
+
+ return o;
+}
+
+// Stop all L3 switches in the Cedar
+void L3FreeAllSw(CEDAR *c)
+{
+ LIST *o;
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ o = NewListFast(NULL);
+
+ LockList(c->L3SwList);
+ {
+ for (i = 0;i < LIST_NUM(c->L3SwList);i++)
+ {
+ L3SW *s = LIST_DATA(c->L3SwList, i);
+ Insert(o, CopyStr(s->Name));
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ char *name = LIST_DATA(o, i);
+
+ L3DelSw(c, name);
+
+ Free(name);
+ }
+
+ ReleaseList(o);
+ }
+ UnlockList(c->L3SwList);
+}
+
+// Stop the L3 switch function of the Cedar
+void FreeCedarLayer3(CEDAR *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ ReleaseList(c->L3SwList);
+ c->L3SwList = NULL;
+}
+
+// Start the L3 switch function of the Cedar
+void InitCedarLayer3(CEDAR *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->L3SwList = NewList(CmpL3Sw);
+}
+
+// Interface comparison function
+int CmpL3If(void *p1, void *p2)
+{
+ L3IF *f1, *f2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ f1 = *(L3IF **)p1;
+ f2 = *(L3IF **)p2;
+ if (f1 == NULL || f2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(f1->HubName, f2->HubName);
+}
+
+// Routing table entry comparison function
+int CmpL3Table(void *p1, void *p2)
+{
+ L3TABLE *t1, *t2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ t1 = *(L3TABLE **)p1;
+ t2 = *(L3TABLE **)p2;
+ if (t1 == NULL || t2 == NULL)
+ {
+ return 0;
+ }
+
+ if (t1->NetworkAddress > t2->NetworkAddress)
+ {
+ return 1;
+ }
+ else if (t1->NetworkAddress < t2->NetworkAddress)
+ {
+ return -1;
+ }
+ else if (t1->SubnetMask > t2->SubnetMask)
+ {
+ return 1;
+ }
+ else if (t1->SubnetMask < t2->SubnetMask)
+ {
+ return -1;
+ }
+ else if (t1->GatewayAddress > t2->GatewayAddress)
+ {
+ return 1;
+ }
+ else if (t1->GatewayAddress < t2->GatewayAddress)
+ {
+ return -1;
+ }
+ else if (t1->Metric > t2->Metric)
+ {
+ return 1;
+ }
+ else if (t1->Metric < t2->Metric)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// L3SW comparison function
+int CmpL3Sw(void *p1, void *p2)
+{
+ L3SW *s1, *s2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ s1 = *(L3SW **)p1;
+ s2 = *(L3SW **)p2;
+ if (s1 == NULL || s2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(s1->Name, s2->Name);
+}
+
+// ARP waiting entry comparison function
+int CmpL3ArpWaitTable(void *p1, void *p2)
+{
+ L3ARPWAIT *w1, *w2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ w1 = *(L3ARPWAIT **)p1;
+ w2 = *(L3ARPWAIT **)p2;
+ if (w1 == NULL || w2 == NULL)
+ {
+ return 0;
+ }
+ if (w1->IpAddress > w2->IpAddress)
+ {
+ return 1;
+ }
+ else if (w1->IpAddress < w2->IpAddress)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// ARP entries comparison function
+int CmpL3ArpEntry(void *p1, void *p2)
+{
+ L3ARPENTRY *e1, *e2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ e1 = *(L3ARPENTRY **)p1;
+ e2 = *(L3ARPENTRY **)p2;
+ if (e1 == NULL || e2 == NULL)
+ {
+ return 0;
+ }
+ if (e1->IpAddress > e2->IpAddress)
+ {
+ return 1;
+ }
+ else if (e1->IpAddress < e2->IpAddress)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Layer3.h b/src/Cedar/Layer3.h
new file mode 100644
index 00000000..eca95c5e
--- /dev/null
+++ b/src/Cedar/Layer3.h
@@ -0,0 +1,229 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Layer3.h
+// Header of Layer3.c
+
+#ifndef LAYER3_H
+#define LAYER3_H
+
+// Constants
+#define L3_USERNAME "L3SW_"
+
+
+// L3 ARP table entry
+struct L3ARPENTRY
+{
+ UINT IpAddress; // IP address
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2];
+ UINT64 Expire; // Expiration date
+};
+
+// L3 ARP resolution waiting list entry
+struct L3ARPWAIT
+{
+ UINT IpAddress; // IP address
+ UINT64 LastSentTime; // Time which the data has been sent last
+ UINT64 Expire; // Expiration date
+};
+
+// L3 IP packet table
+struct L3PACKET
+{
+ PKT *Packet; // Packet data body
+ UINT64 Expire; // Expiration date
+ UINT NextHopIp; // Local delivery destination IP address
+};
+
+// L3 routing table definition
+struct L3TABLE
+{
+ UINT NetworkAddress; // Network address
+ UINT SubnetMask; // Subnet mask
+ UINT GatewayAddress; // Gateway address
+ UINT Metric; // Metric
+};
+
+// L3 interface definition
+struct L3IF
+{
+ L3SW *Switch; // Layer-3 switch
+ char HubName[MAX_HUBNAME_LEN + 1]; // Virtual HUB name
+ UINT IpAddress; // IP address
+ UINT SubnetMask; // Subnet mask
+
+ HUB *Hub; // Virtual HUB
+ SESSION *Session; // Session
+ LIST *ArpTable; // ARP table
+ LIST *ArpWaitTable; // ARP waiting table
+ QUEUE *IpPacketQueue; // IP packet queue (for reception from other interfaces)
+ LIST *IpWaitList; // IP waiting list
+ QUEUE *SendQueue; // Transmission queue
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2];
+ UINT64 LastDeleteOldArpTable; // Time that old ARP table entries are cleared
+ LIST *CancelList; // Cancellation list
+ UINT64 LastBeaconSent; // Time which the beacon has been sent last
+};
+
+// L3 switch definition
+struct L3SW
+{
+ char Name[MAX_HUBNAME_LEN + 1]; // Name
+ LOCK *lock; // Lock
+ REF *ref; // Reference counter
+ CEDAR *Cedar; // Cedar
+ bool Active; // During operation flag
+ bool Online; // Online flag
+ volatile bool Halt; // Halting flag
+ LIST *IfList; // Interface list
+ LIST *TableList; // Routing table list
+ THREAD *Thread; // Thread
+};
+
+
+
+// Function prototype
+int CmpL3Sw(void *p1, void *p2);
+int CmpL3ArpEntry(void *p1, void *p2);
+int CmpL3ArpWaitTable(void *p1, void *p2);
+int CmpL3Table(void *p1, void *p2);
+int CmpL3If(void *p1, void *p2);
+void InitCedarLayer3(CEDAR *c);
+void FreeCedarLayer3(CEDAR *c);
+L3SW *NewL3Sw(CEDAR *c, char *name);
+void ReleaseL3Sw(L3SW *s);
+void CleanupL3Sw(L3SW *s);
+bool L3AddIf(L3SW *s, char *hubname, UINT ip, UINT subnet);
+bool L3DelIf(L3SW *s, char *hubname);
+bool L3AddTable(L3SW *s, L3TABLE *tbl);
+bool L3DelTable(L3SW *s, L3TABLE *tbl);
+L3IF *L3SearchIf(L3SW *s, char *hubname);
+L3SW *L3GetSw(CEDAR *c, char *name);
+L3SW *L3AddSw(CEDAR *c, char *name);
+bool L3DelSw(CEDAR *c, char *name);
+void L3FreeAllSw(CEDAR *c);
+void L3SwStart(L3SW *s);
+void L3SwStop(L3SW *s);
+void L3SwThread(THREAD *t, void *param);
+void L3Test(SERVER *s);
+void L3InitAllInterfaces(L3SW *s);
+void L3FreeAllInterfaces(L3SW *s);
+void L3IfThread(THREAD *t, void *param);
+void L3InitInterface(L3IF *f);
+void L3FreeInterface(L3IF *f);
+L3IF *L3GetNextIf(L3SW *s, UINT ip, UINT *next_hop);
+L3TABLE *L3GetBestRoute(L3SW *s, UINT ip);
+UINT L3GetNextPacket(L3IF *f, void **data);
+void L3Polling(L3IF *f);
+void L3PollingBeacon(L3IF *f);
+void L3DeleteOldArpTable(L3IF *f);
+void L3DeleteOldIpWaitList(L3IF *f);
+void L3PollingArpWaitTable(L3IF *f);
+void L3SendL2Now(L3IF *f, UCHAR *dest_mac, UCHAR *src_mac, USHORT protocol, void *data, UINT size);
+void L3SendArpRequestNow(L3IF *f, UINT dest_ip);
+void L3SendArpResponseNow(L3IF *f, UCHAR *dest_mac, UINT dest_ip, UINT src_ip);
+void L3GenerateMacAddress(L3IF *f);
+L3ARPENTRY *L3SearchArpTable(L3IF *f, UINT ip);
+void L3SendIpNow(L3IF *f, L3ARPENTRY *a, L3PACKET *p);
+void L3SendIp(L3IF *f, L3PACKET *p);
+void L3RecvArp(L3IF *f, PKT *p);
+void L3RecvArpRequest(L3IF *f, PKT *p);
+void L3RecvArpResponse(L3IF *f, PKT *p);
+void L3KnownArp(L3IF *f, UINT ip, UCHAR *mac);
+void L3SendArp(L3IF *f, UINT ip);
+void L3InsertArpTable(L3IF *f, UINT ip, UCHAR *mac);
+void L3SendWaitingIp(L3IF *f, UCHAR *mac, UINT ip, L3ARPENTRY *a);
+void L3PutPacket(L3IF *f, void *data, UINT size);
+void L3RecvL2(L3IF *f, PKT *p);
+void L3StoreIpPacketToIf(L3IF *src_if, L3IF *dst_if, L3PACKET *p);
+void L3RecvIp(L3IF *f, PKT *p, bool self);
+void L3PollingIpQueue(L3IF *f);
+
+
+#endif // LAYER3_H
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Link.c b/src/Cedar/Link.c
new file mode 100644
index 00000000..13f001d2
--- /dev/null
+++ b/src/Cedar/Link.c
@@ -0,0 +1,655 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Link.c
+// Inter-HUB Link
+
+#include "CedarPch.h"
+
+// Link server thread
+void LinkServerSessionThread(THREAD *t, void *param)
+{
+ LINK *k = (LINK *)param;
+ CONNECTION *c;
+ SESSION *s;
+ POLICY *policy;
+ wchar_t name[MAX_SIZE];
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Create a server connection
+ c = NewServerConnection(k->Cedar, NULL, t);
+ c->Protocol = CONNECTION_HUB_LINK_SERVER;
+
+ // Create a policy
+ policy = ZeroMalloc(sizeof(POLICY));
+ Copy(policy, k->Policy, sizeof(POLICY));
+
+ // Create a server session
+ s = NewServerSession(k->Cedar, c, k->Hub, LINK_USER_NAME, policy);
+ s->LinkModeServer = true;
+ s->Link = k;
+ c->Session = s;
+ ReleaseConnection(c);
+
+ // User name
+ s->Username = CopyStr(LINK_USER_NAME_PRINT);
+
+ k->ServerSession = s;
+ AddRef(k->ServerSession->ref);
+
+ // Notify the initialization completion
+ NoticeThreadInit(t);
+
+ UniStrCpy(name, sizeof(name), k->Option->AccountName);
+ HLog(s->Hub, "LH_LINK_START", name, s->Name);
+
+ // Main function of session
+ SessionMain(s);
+
+ HLog(s->Hub, "LH_LINK_STOP", name);
+
+ ReleaseSession(s);
+}
+
+// Initialize the packet adapter
+bool LinkPaInit(SESSION *s)
+{
+ LINK *k;
+ THREAD *t;
+ // Validate arguments
+ if (s == NULL || (k = (LINK *)s->PacketAdapter->Param) == NULL)
+ {
+ return false;
+ }
+
+ // Create a transmission packet queue
+ k->SendPacketQueue = NewQueue();
+
+ // Creat a link server thread
+ t = NewThread(LinkServerSessionThread, (void *)k);
+ WaitThreadInit(t);
+
+ ReleaseThread(t);
+
+ return true;
+}
+
+// Get the cancel object
+CANCEL *LinkPaGetCancel(SESSION *s)
+{
+ LINK *k;
+ // Validate arguments
+ if (s == NULL || (k = (LINK *)s->PacketAdapter->Param) == NULL)
+ {
+ return NULL;
+ }
+
+ return NULL;
+}
+
+// Get the next packet
+UINT LinkPaGetNextPacket(SESSION *s, void **data)
+{
+ LINK *k;
+ UINT ret = 0;
+ // Validate arguments
+ if (s == NULL || data == NULL || (k = (LINK *)s->PacketAdapter->Param) == NULL)
+ {
+ return INFINITE;
+ }
+
+ // Examine whether there are packets in the queue
+ LockQueue(k->SendPacketQueue);
+ {
+ BLOCK *block = GetNext(k->SendPacketQueue);
+
+ if (block != NULL)
+ {
+ // There was a packet
+ *data = block->Buf;
+ ret = block->Size;
+ // Discard the memory for the structure
+ Free(block);
+ }
+ }
+ UnlockQueue(k->SendPacketQueue);
+
+ return ret;
+}
+
+// Write the received packet
+bool LinkPaPutPacket(SESSION *s, void *data, UINT size)
+{
+ LINK *k;
+ BLOCK *block;
+ SESSION *server_session;
+ CONNECTION *server_connection;
+ // Validate arguments
+ if (s == NULL || (k = (LINK *)s->PacketAdapter->Param) == NULL)
+ {
+ return false;
+ }
+
+ server_session = k->ServerSession;
+ server_connection = server_session->Connection;
+
+ // Since the packet arrives from the HUB of the link destination,
+ // deliver it to the ReceivedBlocks of the server session
+ if (data != NULL)
+ {
+ block = NewBlock(data, size, 0);
+
+ LockQueue(server_connection->ReceivedBlocks);
+ {
+ InsertQueue(server_connection->ReceivedBlocks, block);
+ }
+ UnlockQueue(server_connection->ReceivedBlocks);
+ }
+ else
+ {
+ // Issue the Cancel, since finished store all packets when the data == NULL
+ Cancel(server_session->Cancel1);
+
+ if (k->Hub != NULL && k->Hub->Option != NULL && k->Hub->Option->YieldAfterStorePacket)
+ {
+ YieldCpu();
+ }
+ }
+
+ return true;
+}
+
+// Release the packet adapter
+void LinkPaFree(SESSION *s)
+{
+ LINK *k;
+ // Validate arguments
+ if (s == NULL || (k = (LINK *)s->PacketAdapter->Param) == NULL)
+ {
+ return;
+ }
+
+ // Stop the server session
+ StopSession(k->ServerSession);
+ ReleaseSession(k->ServerSession);
+
+ // Release the transmission packet queue
+ LockQueue(k->SendPacketQueue);
+ {
+ BLOCK *block;
+ while (block = GetNext(k->SendPacketQueue))
+ {
+ FreeBlock(block);
+ }
+ }
+ UnlockQueue(k->SendPacketQueue);
+
+ ReleaseQueue(k->SendPacketQueue);
+}
+
+// Packet adapter
+PACKET_ADAPTER *LinkGetPacketAdapter()
+{
+ return NewPacketAdapter(LinkPaInit, LinkPaGetCancel, LinkPaGetNextPacket,
+ LinkPaPutPacket, LinkPaFree);
+}
+
+// Release all links
+void ReleaseAllLink(HUB *h)
+{
+ LINK **kk;
+ UINT num, i;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ LockList(h->LinkList);
+ {
+ num = LIST_NUM(h->LinkList);
+ kk = ToArray(h->LinkList);
+ DeleteAll(h->LinkList);
+ }
+ UnlockList(h->LinkList);
+
+ for (i = 0;i < num;i++)
+ {
+ LINK *k = kk[i];
+
+ ReleaseLink(k);
+ }
+
+ Free(kk);
+}
+
+// Release the link
+void ReleaseLink(LINK *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ if (Release(k->ref) == 0)
+ {
+ CleanupLink(k);
+ }
+}
+
+// Clean-up the link
+void CleanupLink(LINK *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ DeleteLock(k->lock);
+ if (k->ClientSession)
+ {
+ ReleaseSession(k->ClientSession);
+ }
+ Free(k->Option);
+ CiFreeClientAuth(k->Auth);
+ Free(k->Policy);
+
+ if (k->ServerCert != NULL)
+ {
+ FreeX(k->ServerCert);
+ }
+
+ Free(k);
+}
+
+// Make the link on-line
+void SetLinkOnline(LINK *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ if (k->Offline == false)
+ {
+ return;
+ }
+
+ k->Offline = false;
+ StartLink(k);
+}
+
+// Make the link off-line
+void SetLinkOffline(LINK *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ if (k->Offline)
+ {
+ return;
+ }
+
+ StopLink(k);
+ k->Offline = true;
+}
+
+// Delete the link
+void DelLink(HUB *hub, LINK *k)
+{
+ // Validate arguments
+ if (hub == NULL || k == NULL)
+ {
+ return;
+ }
+
+ LockList(hub->LinkList);
+ {
+ if (Delete(hub->LinkList, k))
+ {
+ ReleaseLink(k);
+ }
+ }
+ UnlockList(hub->LinkList);
+}
+
+// Start all links
+void StartAllLink(HUB *h)
+{
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ LockList(h->LinkList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *k = (LINK *)LIST_DATA(h->LinkList, i);
+
+ if (k->Offline == false)
+ {
+ StartLink(k);
+ }
+ }
+ }
+ UnlockList(h->LinkList);
+}
+
+// Stop all links
+void StopAllLink(HUB *h)
+{
+ LINK **link_list;
+ UINT num_link;
+ UINT i;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ LockList(h->LinkList);
+ {
+ link_list = ToArray(h->LinkList);
+ num_link = LIST_NUM(h->LinkList);
+ for (i = 0;i < num_link;i++)
+ {
+ AddRef(link_list[i]->ref);
+ }
+ }
+ UnlockList(h->LinkList);
+
+ for (i = 0;i < num_link;i++)
+ {
+ StopLink(link_list[i]);
+ ReleaseLink(link_list[i]);
+ }
+
+ Free(link_list);
+}
+
+// Start the link
+void StartLink(LINK *k)
+{
+ PACKET_ADAPTER *pa;
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ LockLink(k);
+ {
+ if (k->Started || k->Halting)
+ {
+ UnlockLink(k);
+ return;
+ }
+ k->Started = true;
+ }
+ UnlockLink(k);
+
+ // Connect the client session
+ pa = LinkGetPacketAdapter();
+ pa->Param = (void *)k;
+ LockLink(k);
+ {
+ k->ClientSession = NewClientSession(k->Cedar, k->Option, k->Auth, pa);
+ }
+ UnlockLink(k);
+}
+
+// Stop the link
+void StopLink(LINK *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ LockLink(k);
+ {
+ if (k->Started == false)
+ {
+ UnlockLink(k);
+ return;
+ }
+ k->Started = false;
+ k->Halting = true;
+ }
+ UnlockLink(k);
+
+ if (k->ClientSession != NULL)
+ {
+ // Disconnect the client session
+ StopSession(k->ClientSession);
+
+ LockLink(k);
+ {
+ ReleaseSession(k->ClientSession);
+ k->ClientSession = NULL;
+ }
+ UnlockLink(k);
+ }
+
+ LockLink(k);
+ {
+ k->Halting = false;
+ }
+ UnlockLink(k);
+}
+
+// Lock the link
+void LockLink(LINK *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ Lock(k->lock);
+}
+
+// Unlock the link
+void UnlockLink(LINK *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ Unlock(k->lock);
+}
+
+// Normalize the policy for the link
+void NormalizeLinkPolicy(POLICY *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ p->Access = true;
+ p->NoBridge = p->NoRouting = p->PrivacyFilter =
+ p->MonitorPort = false;
+ p->MaxConnection = 32;
+ p->TimeOut = 20;
+ p->FixPassword = false;
+}
+
+// Create a Link
+LINK *NewLink(CEDAR *cedar, HUB *hub, CLIENT_OPTION *option, CLIENT_AUTH *auth, POLICY *policy)
+{
+ CLIENT_OPTION *o;
+ LINK *k;
+ CLIENT_AUTH *a;
+ // Validate arguments
+ if (cedar == NULL || hub == NULL || option == NULL || auth == NULL || policy == NULL)
+ {
+ return NULL;
+ }
+ if (hub->Halt)
+ {
+ return NULL;
+ }
+
+ if (LIST_NUM(hub->LinkList) >= MAX_HUB_LINKS)
+ {
+ return NULL;
+ }
+
+ if (UniIsEmptyStr(option->AccountName))
+ {
+ return NULL;
+ }
+
+ // Limitation of authentication method
+ if (auth->AuthType != CLIENT_AUTHTYPE_ANONYMOUS && auth->AuthType != CLIENT_AUTHTYPE_PASSWORD &&
+ auth->AuthType != CLIENT_AUTHTYPE_PLAIN_PASSWORD && auth->AuthType != CLIENT_AUTHTYPE_CERT)
+ {
+ // Authentication method other than anonymous authentication, password authentication, plain password, certificate authentication cannot be used
+ return NULL;
+ }
+
+ // Copy of the client options (for modification)
+ o = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(o, option, sizeof(CLIENT_OPTION));
+ StrCpy(o->DeviceName, sizeof(o->DeviceName), LINK_DEVICE_NAME);
+
+ o->RequireBridgeRoutingMode = true; // Request the bridge mode
+ o->RequireMonitorMode = false; // Not to require the monitor mode
+
+ o->NumRetry = INFINITE; // Retry the connection infinitely
+ o->RetryInterval = 10; // Retry interval is 10 seconds
+ o->NoRoutingTracking = true; // Stop the routing tracking
+
+ // Copy the authentication data
+ a = CopyClientAuth(auth);
+ a->SecureSignProc = NULL;
+ a->CheckCertProc = NULL;
+
+ // Link object
+ k = ZeroMalloc(sizeof(LINK));
+ k->lock = NewLock();
+ k->ref = NewRef();
+
+ k->Cedar = cedar;
+ k->Option = o;
+ k->Auth = a;
+ k->Hub = hub;
+
+ // Copy the policy
+ k->Policy = ZeroMalloc(sizeof(POLICY));
+ Copy(k->Policy, policy, sizeof(POLICY));
+
+ // Normalize the policy
+ NormalizeLinkPolicy(k->Policy);
+
+ // Register in the link list of the HUB
+ LockList(hub->LinkList);
+ {
+ Add(hub->LinkList, k);
+ AddRef(k->ref);
+ }
+ UnlockList(hub->LinkList);
+
+ return k;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Link.h b/src/Cedar/Link.h
new file mode 100644
index 00000000..c2e4bf95
--- /dev/null
+++ b/src/Cedar/Link.h
@@ -0,0 +1,139 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Link.h
+// Header of Link.c
+
+#ifndef LINK_H
+#define LINK_H
+
+struct LINK
+{
+ bool Started; // Running flag
+ volatile bool Halting; // Halting flag
+ bool Offline; // Offline
+ REF *ref; // Reference counter
+ LOCK *lock; // Lock
+ CEDAR *Cedar; // Cedar
+ HUB *Hub; // HUB
+ SESSION *ClientSession; // Client session
+ SESSION *ServerSession; // Server session
+ CLIENT_OPTION *Option; // Client Option
+ CLIENT_AUTH *Auth; // Authentication data
+ POLICY *Policy; // Policy
+ QUEUE *SendPacketQueue; // Transmission packet queue
+ UINT LastError; // Last error
+ bool CheckServerCert; // To check the server certificate
+ X *ServerCert; // Server certificate
+};
+
+
+PACKET_ADAPTER *LinkGetPacketAdapter();
+bool LinkPaInit(SESSION *s);
+CANCEL *LinkPaGetCancel(SESSION *s);
+UINT LinkPaGetNextPacket(SESSION *s, void **data);
+bool LinkPaPutPacket(SESSION *s, void *data, UINT size);
+void LinkPaFree(SESSION *s);
+
+void LinkServerSessionThread(THREAD *t, void *param);
+LINK *NewLink(CEDAR *cedar, HUB *hub, CLIENT_OPTION *option, CLIENT_AUTH *auth, POLICY *policy);
+void StartLink(LINK *k);
+void StopLink(LINK *k);
+void DelLink(HUB *hub, LINK *k);
+void LockLink(LINK *k);
+void UnlockLink(LINK *k);
+void StopAllLink(HUB *h);
+void StartAllLink(HUB *h);
+void SetLinkOnline(LINK *k);
+void SetLinkOffline(LINK *k);
+void ReleaseLink(LINK *k);
+void CleanupLink(LINK *k);
+void ReleaseAllLink(HUB *h);
+void NormalizeLinkPolicy(POLICY *p);
+
+#endif // LINK_H
+
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Listener.c b/src/Cedar/Listener.c
new file mode 100644
index 00000000..0babfac2
--- /dev/null
+++ b/src/Cedar/Listener.c
@@ -0,0 +1,1079 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Listener.c
+// Listener module
+
+#include "CedarPch.h"
+
+static bool disable_dos = false;
+static UINT max_connections_per_ip = DEFAULT_MAX_CONNECTIONS_PER_IP;
+static UINT max_unestablished_connections = DEFAULT_MAX_UNESTABLISHED_CONNECTIONS;
+static bool listener_proc_recv_rpc = false;
+
+// Set the flag of whether to response to the RPC of RUDP
+void ListenerSetProcRecvRpcEnable(bool b)
+{
+ listener_proc_recv_rpc = b;
+}
+
+// Get the number of allowed outstanding connections
+UINT GetMaxUnestablishedConnections()
+{
+ return max_unestablished_connections;
+}
+
+// Set the number of allowed outstanding connections
+void SetMaxUnestablishedConnections(UINT num)
+{
+ if (num == 0)
+ {
+ num = DEFAULT_MAX_UNESTABLISHED_CONNECTIONS;
+ }
+
+ max_unestablished_connections = MAX(num, max_connections_per_ip);
+}
+
+// Get the maximum number of connections per IP address
+UINT GetMaxConnectionsPerIp()
+{
+ return max_connections_per_ip;
+}
+
+// Set the maximum number of connections per IP address
+void SetMaxConnectionsPerIp(UINT num)
+{
+ if (num == 0)
+ {
+ num = DEFAULT_MAX_CONNECTIONS_PER_IP;
+ }
+ max_connections_per_ip = MAX(num, MIN_MAX_CONNECTIONS_PER_IP);
+}
+
+// Enable the DoS defense
+void EnableDosProtect()
+{
+ disable_dos = false;
+}
+
+// Disable the DoS defense
+void DisableDosProtect()
+{
+ disable_dos = true;
+}
+
+// An UDP packet has been received
+void UDPReceivedPacket(CEDAR *cedar, SOCK *s, IP *ip, UINT port, void *data, UINT size)
+{
+ SESSION *session;
+ UINT *key32;
+ UCHAR *buf;
+ CONNECTION *c;
+ // Validate arguments
+ if (s == NULL || ip == NULL || data == NULL || size == 0 || cedar == NULL)
+ {
+ return;
+ }
+
+ if (size < 16)
+ {
+ // Ignore since the packet size is not enough
+ return;
+ }
+ buf = (UCHAR *)data;
+ key32 = (UINT *)(buf + 4);
+
+
+ // Get the session from the Key32 value
+ session = GetSessionFromUDPEntry(cedar, Endian32(*key32));
+ if (session == NULL)
+ {
+ Debug("Invalid UDP Session Key 32: 0x%X\n", *key32);
+ return;
+ }
+
+ c = session->Connection;
+
+ // Write the data
+ PutUDPPacketData(c, buf, size);
+
+ // Rewrite the UDP socket associated with the connection
+ Lock(c->lock);
+ {
+ if (c->Protocol == CONNECTION_UDP)
+ {
+ if (c->Udp->s != s)
+ {
+ if (c->Udp->s != NULL)
+ {
+ ReleaseSock(c->Udp->s);
+ }
+ AddRef(s->ref);
+ c->Udp->s = s;
+ }
+ Copy(&c->Udp->ip, ip, sizeof(UINT));
+ c->Udp->port = port;
+ }
+ }
+ Unlock(c->lock);
+
+ // Invoke the Cancel
+ Cancel(session->Cancel1);
+
+ // Release the session
+ ReleaseSession(session);
+}
+
+// Thread that processes the accepted TCP connection
+void TCPAcceptedThread(THREAD *t, void *param)
+{
+ TCP_ACCEPTED_PARAM *data;
+ LISTENER *r;
+ SOCK *s;
+ CONNECTION *c;
+ bool flag1;
+ char tmp[128];
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Initialize
+ data = (TCP_ACCEPTED_PARAM *)param;
+ r = data->r;
+ s = data->s;
+ AddRef(r->ref);
+ AddRef(s->ref);
+
+ // Create a connection
+ c = NewServerConnection(r->Cedar, s, t);
+
+ // Register to Cedar as a transient connection
+ AddConnection(c->Cedar, c);
+
+ NoticeThreadInit(t);
+
+ AcceptInit(s);
+ StrCpy(c->ClientHostname, sizeof(c->ClientHostname), s->RemoteHostname);
+ IPToStr(tmp, sizeof(tmp), &s->RemoteIP);
+ if (IS_SPECIAL_PORT(s->RemotePort) == false)
+ {
+ SLog(r->Cedar, "LS_LISTENER_ACCEPT", r->Port, tmp, s->RemoteHostname, s->RemotePort);
+ }
+
+ // Reception
+ ConnectionAccept(c);
+ flag1 = c->flag1;
+
+ // Release
+ SLog(r->Cedar, "LS_CONNECTION_END_1", c->Name);
+ ReleaseConnection(c);
+
+ // Release
+ if (flag1 == false)
+ {
+ Debug("%s %u flag1 == false\n", __FILE__, __LINE__);
+ IPToStr(tmp, sizeof(tmp), &s->RemoteIP);
+
+ if (IS_SPECIAL_PORT(s->RemotePort) == false)
+ {
+ SLog(r->Cedar, "LS_LISTENER_DISCONNECT", tmp, s->RemotePort);
+ }
+ Disconnect(s);
+ }
+ ReleaseSock(s);
+ ReleaseListener(r);
+}
+
+// Jump here if there is accepted connection in the TCP
+void TCPAccepted(LISTENER *r, SOCK *s)
+{
+ TCP_ACCEPTED_PARAM *data;
+ THREAD *t;
+ char tmp[MAX_SIZE];
+ UINT num_clients_from_this_ip = 0;
+ CEDAR *cedar;
+ // Validate arguments
+ if (r == NULL || s == NULL)
+ {
+ return;
+ }
+
+ cedar = r->Cedar;
+
+ num_clients_from_this_ip = GetNumIpClient(&s->RemoteIP);
+
+
+ IPToStr(tmp, sizeof(tmp), &s->RemoteIP);
+
+ data = ZeroMalloc(sizeof(TCP_ACCEPTED_PARAM));
+ data->r = r;
+ data->s = s;
+
+ if (r->ThreadProc == TCPAcceptedThread)
+ {
+ Inc(cedar->AcceptingSockets);
+ }
+
+ t = NewThread(r->ThreadProc, data);
+ WaitThreadInit(t);
+ Free(data);
+ ReleaseThread(t);
+}
+
+
+// UDP listener main loop
+void ListenerUDPMainLoop(LISTENER *r)
+{
+ UCHAR *data;
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+ Debug("ListenerUDPMainLoop Starts.\n");
+ r->Status = LISTENER_STATUS_TRYING;
+
+ while (true)
+ {
+ // Try to listen on the UDP port
+ while (true)
+ {
+ // Stop flag inspection
+ if (r->Halt)
+ {
+ // Stop
+ return;
+ }
+
+ Debug("NewUDP()\n");
+ r->Sock = NewUDP(r->Port);
+ if (r->Sock != NULL)
+ {
+ // Wait success
+ break;
+ }
+
+ // Wait failure
+ Debug("Failed to NewUDP.\n");
+ Wait(r->Event, LISTEN_RETRY_TIME);
+
+ // Stop flag inspection
+ if (r->Halt)
+ {
+ Debug("UDP Halt.\n");
+ return;
+ }
+ }
+
+ r->Status = LISTENER_STATUS_LISTENING;
+ Debug("Start Listening at UDP Port %u.\n", r->Sock->LocalPort);
+
+ // Stop flag inspection
+ if (r->Halt)
+ {
+ // Stop
+ goto STOP;
+ }
+
+ // Allocate the buffer area
+ data = Malloc(UDP_PACKET_SIZE);
+
+ // Read the next packet
+ while (true)
+ {
+ IP src_ip;
+ UINT src_port;
+ UINT size;
+ SOCKSET set;
+
+ InitSockSet(&set);
+ AddSockSet(&set, r->Sock);
+ Select(&set, SELECT_TIME, NULL, NULL);
+
+ size = RecvFrom(r->Sock, &src_ip, &src_port, data, UDP_PACKET_SIZE);
+ if (((size == 0) && (r->Sock->IgnoreRecvErr == false)) || r->Halt)
+ {
+ // Error has occurred
+STOP:
+ Disconnect(r->Sock);
+ ReleaseSock(r->Sock);
+ r->Sock = NULL;
+ Debug("UDP Listen Stopped.\n");
+ Free(data);
+ break;
+ }
+
+ // Received an UDP packet
+ if (size != SOCK_LATER)
+ {
+ UDPReceivedPacket(r->Cedar, r->Sock, &src_ip, src_port, data, size);
+ }
+ }
+ }
+}
+
+// RPC reception procedure
+bool ListenerRUDPRpcRecvProc(RUDP_STACK *r, UDPPACKET *p)
+{
+ return false;
+}
+
+// TCP listener main loop
+void ListenerTCPMainLoop(LISTENER *r)
+{
+ SOCK *new_sock;
+ SOCK *s;
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+ Debug("ListenerTCPMainLoop Starts.\n");
+ r->Status = LISTENER_STATUS_TRYING;
+
+ while (true)
+ {
+ bool first_failed = true;
+ Debug("Status = LISTENER_STATUS_TRYING\n");
+ r->Status = LISTENER_STATUS_TRYING;
+
+ // Try to Listen
+ while (true)
+ {
+ UINT interval;
+ // Stop flag inspection
+ if (r->Halt)
+ {
+ // Stop
+ return;
+ }
+
+ s = NULL;
+
+ if (r->Protocol == LISTENER_TCP)
+ {
+ if (r->ShadowIPv6 == false)
+ {
+ s = ListenEx2(r->Port, r->LocalOnly, r->EnableConditionalAccept);
+ }
+ else
+ {
+ s = ListenEx6(r->Port, r->LocalOnly);
+ }
+ }
+ else if (r->Protocol == LISTENER_INPROC)
+ {
+ s = ListenInProc();
+ }
+ else if (r->Protocol == LISTENER_RUDP)
+ {
+ s = ListenRUDPEx(VPN_RUDP_SVC_NAME, NULL, ListenerRUDPRpcRecvProc, NULL, 0, false, false, r->NatTGlobalUdpPort, r->RandPortId);
+ }
+ else if (r->Protocol == LISTENER_ICMP)
+ {
+ s = ListenRUDP(VPN_RUDP_SVC_NAME, NULL, ListenerRUDPRpcRecvProc, NULL, MAKE_SPECIAL_PORT(IP_PROTO_ICMPV4),
+ true, false);
+ }
+ else if (r->Protocol == LISTENER_DNS)
+ {
+ s = ListenRUDP(VPN_RUDP_SVC_NAME, NULL, ListenerRUDPRpcRecvProc, NULL, 53, true, true);
+ }
+ else if (r->Protocol == LISTENER_REVERSE)
+ {
+ s = ListenReverse();
+ }
+
+ if (s != NULL)
+ {
+ // Listen success
+ AddRef(s->ref);
+
+ Lock(r->lock);
+ {
+ r->Sock = s;
+ }
+ Unlock(r->lock);
+
+ if (r->ShadowIPv6 == false && r->Protocol == LISTENER_TCP)
+ {
+ SLog(r->Cedar, "LS_LISTENER_START_2", r->Port);
+ }
+ break;
+ }
+
+ // Listen failure
+ if (first_failed)
+ {
+ first_failed = false;
+ if (r->ShadowIPv6 == false && r->Protocol == LISTENER_TCP)
+ {
+ SLog(r->Cedar, "LS_LISTENER_START_3", r->Port, LISTEN_RETRY_TIME / 1000);
+ }
+ }
+
+ interval = LISTEN_RETRY_TIME;
+
+ if (r->ShadowIPv6)
+ {
+ if (IsIPv6Supported() == false)
+ {
+ interval = LISTEN_RETRY_TIME_NOIPV6;
+
+ Debug("IPv6 is not supported.\n");
+ }
+ }
+
+ Wait(r->Event, interval);
+
+ // Stop flag inspection
+ if (r->Halt)
+ {
+ // Stop
+ Debug("Listener Halt.\n");
+ return;
+ }
+ }
+
+ r->Status = LISTENER_STATUS_LISTENING;
+ Debug("Status = LISTENER_STATUS_LISTENING\n");
+
+ // Stop flag inspection
+ if (r->Halt)
+ {
+ // Stop
+ goto STOP;
+ }
+
+ // Accpet loop
+ while (true)
+ {
+ // Accept
+ Debug("Accept()\n");
+ new_sock = Accept(s);
+ if (new_sock != NULL)
+ {
+ // Accept success
+ Debug("Accepted.\n");
+ TCPAccepted(r, new_sock);
+ ReleaseSock(new_sock);
+ }
+ else
+ {
+STOP:
+ Debug("Accept Canceled.\n");
+ // Failed to accept (socket is destroyed)
+ // Close the listening socket
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+
+ Lock(r->lock);
+ {
+ if (r->Sock != NULL)
+ {
+ s = r->Sock;
+ r->Sock = NULL;
+ }
+ }
+ Unlock(r->lock);
+
+ if (s != NULL)
+ {
+ ReleaseSock(s);
+ }
+
+ s = NULL;
+
+ break;
+ }
+ }
+
+ // Stop flag inspection
+ if (r->Halt)
+ {
+ // Stop
+ Debug("Listener Halt.\n");
+ return;
+ }
+ }
+}
+
+// Listener Thread
+void ListenerThread(THREAD *thread, void *param)
+{
+ LISTENER *r;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Initialize
+ r = (LISTENER *)param;
+ AddRef(r->ref);
+ r->Thread = thread;
+ AddRef(thread->ref);
+ NoticeThreadInit(thread);
+
+ // Main loop
+ switch (r->Protocol)
+ {
+ case LISTENER_TCP:
+ case LISTENER_INPROC:
+ case LISTENER_RUDP:
+ case LISTENER_DNS:
+ case LISTENER_ICMP:
+ case LISTENER_REVERSE:
+ // TCP or other stream-based protocol
+ ListenerTCPMainLoop(r);
+ break;
+
+ case LISTENER_UDP:
+ // UDP protocol
+ ListenerUDPMainLoop(r);
+ break;
+ }
+
+ // Release
+ ReleaseListener(r);
+}
+
+// Shutdown the Listener
+void StopListener(LISTENER *r)
+{
+ UINT port;
+ SOCK *s = NULL;
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+ Lock(r->lock);
+ if (r->Halt)
+ {
+ Unlock(r->lock);
+ return;
+ }
+
+ // Stop flag set
+ r->Halt = true;
+
+ if (r->Sock != NULL)
+ {
+ s = r->Sock;
+
+ AddRef(s->ref);
+ }
+
+ Unlock(r->lock);
+
+ port = r->Port;
+
+ if (r->ShadowIPv6 == false && r->Protocol == LISTENER_TCP)
+ {
+ SLog(r->Cedar, "LS_LISTENER_STOP_1", port);
+ }
+
+ // Close the socket
+ if (s != NULL)
+ {
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ }
+
+ // Set the event
+ Set(r->Event);
+
+ // Wait for stopping the thread
+ WaitThread(r->Thread, INFINITE);
+
+ // Stop the shadow listener
+ if (r->ShadowIPv6 == false)
+ {
+ if (r->ShadowListener != NULL)
+ {
+ StopListener(r->ShadowListener);
+
+ ReleaseListener(r->ShadowListener);
+
+ r->ShadowListener = NULL;
+ }
+ }
+
+ if (r->ShadowIPv6 == false && r->Protocol == LISTENER_TCP)
+ {
+ SLog(r->Cedar, "LS_LISTENER_STOP_2", port);
+ }
+}
+
+// Cleanup the listener
+void CleanupListener(LISTENER *r)
+{
+ UINT i = 0;
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+
+ if (r->Sock != NULL)
+ {
+ ReleaseSock(r->Sock);
+ }
+
+ DeleteLock(r->lock);
+ ReleaseThread(r->Thread);
+ ReleaseEvent(r->Event);
+
+ ReleaseCedar(r->Cedar);
+
+ Free(r);
+}
+
+// Release the listener
+void ReleaseListener(LISTENER *r)
+{
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+ if (Release(r->ref) == 0)
+ {
+ CleanupListener(r);
+ }
+}
+
+// Comparison function of UDP entry list
+int CompareUDPEntry(void *p1, void *p2)
+{
+ UDP_ENTRY *e1, *e2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ e1 = *(UDP_ENTRY **)p1;
+ e2 = *(UDP_ENTRY **)p2;
+ if (e1 == NULL || e2 == NULL)
+ {
+ return 0;
+ }
+
+ if (e1->SessionKey32 > e2->SessionKey32)
+ {
+ return 1;
+ }
+ else if (e1->SessionKey32 == e2->SessionKey32)
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+// Comparison function of the listener
+int CompareListener(void *p1, void *p2)
+{
+ LISTENER *r1, *r2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ r1 = *(LISTENER **)p1;
+ r2 = *(LISTENER **)p2;
+ if (r1 == NULL || r2 == NULL)
+ {
+ return 0;
+ }
+
+ if (r1->Protocol > r2->Protocol)
+ {
+ return 1;
+ }
+ else if (r1->Protocol < r2->Protocol)
+ {
+ return -1;
+ }
+ else if (r1->Port > r2->Port)
+ {
+ return 1;
+ }
+ else if (r1->Port < r2->Port)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// Create a New Listener
+LISTENER *NewListener(CEDAR *cedar, UINT proto, UINT port)
+{
+ return NewListenerEx(cedar, proto, port, TCPAcceptedThread, NULL);
+}
+LISTENER *NewListenerEx(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param)
+{
+ return NewListenerEx2(cedar, proto, port, proc, thread_param, false);
+}
+LISTENER *NewListenerEx2(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only)
+{
+ return NewListenerEx3(cedar, proto, port, proc, thread_param, local_only, false);
+}
+LISTENER *NewListenerEx3(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only, bool shadow_ipv6)
+{
+ return NewListenerEx4(cedar, proto, port, proc, thread_param, local_only, shadow_ipv6, NULL, 0);
+}
+LISTENER *NewListenerEx4(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only, bool shadow_ipv6,
+ volatile UINT *natt_global_udp_port, UCHAR rand_port_id)
+{
+ return NewListenerEx5(cedar, proto, port, proc, thread_param,
+ local_only, shadow_ipv6, natt_global_udp_port, rand_port_id, false);
+}
+LISTENER *NewListenerEx5(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only, bool shadow_ipv6,
+ volatile UINT *natt_global_udp_port, UCHAR rand_port_id, bool enable_ca)
+{
+ LISTENER *r;
+ THREAD *t;
+ // Validate arguments
+ if ((proto == LISTENER_TCP && port == 0) || cedar == NULL)
+ {
+ return NULL;
+ }
+ // Check the protocol number
+ if (proto != LISTENER_TCP && proto != LISTENER_INPROC &&
+ proto != LISTENER_RUDP && proto != LISTENER_ICMP && proto != LISTENER_DNS &&
+ proto != LISTENER_REVERSE)
+ {
+ return NULL;
+ }
+
+ r = ZeroMalloc(sizeof(LISTENER));
+
+ r->ThreadProc = proc;
+ r->ThreadParam = thread_param;
+ r->Cedar = cedar;
+ AddRef(r->Cedar->ref);
+ r->lock = NewLock();
+ r->ref = NewRef();
+ r->Protocol = proto;
+ r->Port = port;
+ r->Event = NewEvent();
+
+
+ r->LocalOnly = local_only;
+ r->ShadowIPv6 = shadow_ipv6;
+ r->NatTGlobalUdpPort = natt_global_udp_port;
+ r->RandPortId = rand_port_id;
+ r->EnableConditionalAccept = enable_ca;
+
+ if (r->ShadowIPv6 == false)
+ {
+ if (proto == LISTENER_TCP)
+ {
+ SLog(cedar, "LS_LISTENER_START_1", port);
+ }
+ }
+
+ // Creating a thread
+ t = NewThread(ListenerThread, r);
+ WaitThreadInit(t);
+ ReleaseThread(t);
+
+ if (r->ShadowIPv6 == false && proto == LISTENER_TCP)
+ {
+ if (r->Cedar->DisableIPv6Listener == false)
+ {
+ // Add a shadow listener
+ r->ShadowListener = NewListenerEx3(cedar, proto, port, proc, thread_param,
+ local_only, true);
+ }
+ }
+
+ if (r->ShadowIPv6 == false)
+ {
+ // Add to the Cedar
+ AddListener(cedar, r);
+ }
+
+ return r;
+}
+
+// Get the session from the session key
+SESSION *GetSessionFromUDPEntry(CEDAR *cedar, UINT key32)
+{
+ UDP_ENTRY *e, t;
+ SESSION *s;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ t.SessionKey32 = key32;
+
+ LockList(cedar->UDPEntryList);
+ {
+ e = Search(cedar->UDPEntryList, &t);
+ if (e == NULL)
+ {
+ UnlockList(cedar->UDPEntryList);
+ return NULL;
+ }
+ s = e->Session;
+ AddRef(s->ref);
+ }
+ UnlockList(cedar->UDPEntryList);
+
+ return s;
+}
+
+// Delete the UDP session from the UDP entry
+void DelUDPEntry(CEDAR *cedar, SESSION *session)
+{
+ UINT num, i;
+ // Validate arguments
+ if (cedar == NULL || session == NULL)
+ {
+ return;
+ }
+
+ LockList(cedar->UDPEntryList);
+ {
+ num = LIST_NUM(cedar->UDPEntryList);
+ for (i = 0;i < num;i++)
+ {
+ UDP_ENTRY *e = LIST_DATA(cedar->UDPEntryList, i);
+ if (e->Session == session)
+ {
+ ReleaseSession(e->Session);
+ Delete(cedar->UDPEntryList, e);
+ Free(e);
+ UnlockList(cedar->UDPEntryList);
+ Debug("UDP_Entry Deleted.\n");
+ return;
+ }
+ }
+ }
+ UnlockList(cedar->UDPEntryList);
+}
+
+// Add an UDP session to the UDP entry
+void AddUDPEntry(CEDAR *cedar, SESSION *session)
+{
+ UDP_ENTRY *e;
+ // Validate arguments
+ if (cedar == NULL || session == NULL)
+ {
+ return;
+ }
+
+ e = ZeroMalloc(sizeof(UDP_ENTRY));
+ e->Session = session;
+ e->SessionKey32 = session->SessionKey32;
+ AddRef(session->ref);
+
+ LockList(cedar->UDPEntryList);
+ {
+ Add(cedar->UDPEntryList, e);
+ }
+ UnlockList(cedar->UDPEntryList);
+
+ Debug("UDP_Entry Added.\n");
+}
+
+// Clear the UDP entry
+void CleanupUDPEntry(CEDAR *cedar)
+{
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return;
+ }
+}
+
+// Create a new dynamic listener
+DYNAMIC_LISTENER *NewDynamicListener(CEDAR *c, bool *enable_ptr, UINT protocol, UINT port)
+{
+ DYNAMIC_LISTENER *d;
+ // Validate arguments
+ if (c == NULL || enable_ptr == NULL)
+ {
+ return NULL;
+ }
+
+ d = ZeroMalloc(sizeof(DYNAMIC_LISTENER));
+
+ d->Cedar = c;
+ AddRef(d->Cedar->ref);
+
+ d->Lock = NewLock();
+
+ d->EnablePtr = enable_ptr;
+
+ d->Listener = NULL;
+
+ d->Protocol = protocol;
+ d->Port = port;
+
+ ApplyDynamicListener(d);
+
+ return d;
+}
+
+// Release the dynamic listener
+void FreeDynamicListener(DYNAMIC_LISTENER *d)
+{
+ // Validate arguments
+ if (d == NULL)
+ {
+ return;
+ }
+
+ Lock(d->Lock);
+ {
+ if (d->Listener != NULL)
+ {
+ StopListener(d->Listener);
+ ReleaseListener(d->Listener);
+ d->Listener = NULL;
+ }
+ }
+ Unlock(d->Lock);
+
+ ReleaseCedar(d->Cedar);
+
+ DeleteLock(d->Lock);
+
+ Free(d);
+}
+
+// Set the state to dynamic listener
+void ApplyDynamicListener(DYNAMIC_LISTENER *d)
+{
+ // Validate arguments
+ if (d == NULL)
+ {
+ return;
+ }
+
+ Lock(d->Lock);
+ {
+ // Change the state
+ if (*d->EnablePtr)
+ {
+ if (d->Listener == NULL)
+ {
+ // Create a listener
+ WHERE;
+ d->Listener = NewListener(d->Cedar, d->Protocol, d->Port);
+ }
+ }
+ else
+ {
+ // Stop the listener
+ if (d->Listener != NULL)
+ {
+ WHERE;
+ StopListener(d->Listener);
+ ReleaseListener(d->Listener);
+ d->Listener = NULL;
+ }
+ }
+ }
+ Unlock(d->Lock);
+}
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Listener.h b/src/Cedar/Listener.h
new file mode 100644
index 00000000..454b5f87
--- /dev/null
+++ b/src/Cedar/Listener.h
@@ -0,0 +1,188 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Listener.h
+// Header of Listener.c
+
+#ifndef LISTENER_H
+#define LISTENER_H
+
+
+// Function to call when receiving a new connection
+typedef void (NEW_CONNECTION_PROC)(CONNECTION *c);
+
+
+
+// Listener structure
+struct LISTENER
+{
+ LOCK *lock; // Lock
+ REF *ref; // Reference counter
+ CEDAR *Cedar; // Cedar
+ UINT Protocol; // Protocol
+ UINT Port; // Port number
+ THREAD *Thread; // Operating thread
+ SOCK *Sock; // Socket
+ EVENT *Event; // Event
+ volatile bool Halt; // Halting flag
+ UINT Status; // State
+
+
+ THREAD_PROC *ThreadProc; // Thread procedure
+ void *ThreadParam; // Thread parameters
+ bool LocalOnly; // Can be connected only from localhost
+ bool ShadowIPv6; // Flag indicating that the shadow IPv6 listener
+ LISTENER *ShadowListener; // Reference to managing shadow IPv6 listener
+ bool DisableDos; // Disable the DoS attack detection
+ volatile UINT *NatTGlobalUdpPort; // NAT-T global UDP port number
+ UCHAR RandPortId; // NAT-T UDP random port ID
+ bool EnableConditionalAccept; // The flag of whether to enable the Conditional Accept
+};
+
+// Parameters of TCPAcceptedThread
+struct TCP_ACCEPTED_PARAM
+{
+ LISTENER *r;
+ SOCK *s;
+};
+
+// UDP entry
+struct UDP_ENTRY
+{
+ UINT SessionKey32; // 32bit session key
+ SESSION *Session; // Reference to the session
+};
+
+// Dynamic listener
+struct DYNAMIC_LISTENER
+{
+ UINT Protocol; // Protocol
+ UINT Port; // Port
+ LOCK *Lock; // Lock
+ CEDAR *Cedar; // Cedar
+ bool *EnablePtr; // A pointer to the flag of the valid / invalid state
+ LISTENER *Listener; // Listener
+};
+
+
+// Function prototype
+LISTENER *NewListener(CEDAR *cedar, UINT proto, UINT port);
+LISTENER *NewListenerEx(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param);
+LISTENER *NewListenerEx2(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only);
+LISTENER *NewListenerEx3(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only, bool shadow_ipv6);
+LISTENER *NewListenerEx4(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only, bool shadow_ipv6,
+ volatile UINT *natt_global_udp_port, UCHAR rand_port_id);
+LISTENER *NewListenerEx5(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only, bool shadow_ipv6,
+ volatile UINT *natt_global_udp_port, UCHAR rand_port_id, bool enable_ca);
+void ReleaseListener(LISTENER *r);
+void CleanupListener(LISTENER *r);
+void ListenerThread(THREAD *thread, void *param);
+void ListenerTCPMainLoop(LISTENER *r);
+void StopListener(LISTENER *r);
+int CompareListener(void *p1, void *p2);
+void TCPAccepted(LISTENER *r, SOCK *s);
+void EnableDosProtect();
+void DisableDosProtect();
+void TCPAcceptedThread(THREAD *t, void *param);
+void ListenerUDPMainLoop(LISTENER *r);
+void UDPReceivedPacket(CEDAR *cedar, SOCK *s, IP *ip, UINT port, void *data, UINT size);
+int CompareUDPEntry(void *p1, void *p2);
+void CleanupUDPEntry(CEDAR *cedar);
+void AddUDPEntry(CEDAR *cedar, SESSION *session);
+void DelUDPEntry(CEDAR *cedar, SESSION *session);
+SESSION *GetSessionFromUDPEntry(CEDAR *cedar, UINT key32);
+UINT GetMaxConnectionsPerIp();
+void SetMaxConnectionsPerIp(UINT num);
+UINT GetMaxUnestablishedConnections();
+void SetMaxUnestablishedConnections(UINT num);
+DYNAMIC_LISTENER *NewDynamicListener(CEDAR *c, bool *enable_ptr, UINT protocol, UINT port);
+void ApplyDynamicListener(DYNAMIC_LISTENER *d);
+void FreeDynamicListener(DYNAMIC_LISTENER *d);
+bool ListenerRUDPRpcRecvProc(RUDP_STACK *r, UDPPACKET *p);
+void ListenerSetProcRecvRpcEnable(bool b);
+
+
+#endif // LISTENER_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Logging.c b/src/Cedar/Logging.c
new file mode 100644
index 00000000..a5bcf2d8
--- /dev/null
+++ b/src/Cedar/Logging.c
@@ -0,0 +1,2054 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Logging.c
+// Log storaging module
+
+#include "CedarPch.h"
+
+static char *delete_targets[] =
+{
+ "backup.vpn_bridge.config",
+ "backup.vpn_client.config",
+ "backup.vpn_server.config",
+ "backup.vpn_gate_svc.config",
+ "backup.etherlogger.config",
+ "packet_log",
+ "etherlogger_log",
+ "secure_nat_log",
+ "security_log",
+ "server_log",
+ "bridge_log",
+ "packet_log_archive",
+};
+
+// Send with syslog
+void SendSysLog(SLOG *g, wchar_t *str)
+{
+}
+
+// Release the syslog client
+void FreeSysLog(SLOG *g)
+{
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ DeleteLock(g->lock);
+ ReleaseSock(g->Udp);
+ Free(g);
+}
+
+// Configure the syslog client
+void SetSysLog(SLOG *g, char *hostname, UINT port)
+{
+ IP ip;
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+ if (port == 0)
+ {
+ port = SYSLOG_PORT;
+ }
+
+ if (hostname == NULL)
+ {
+ hostname = "";
+ }
+
+ Zero(&ip, sizeof(IP));
+ GetIP(&ip, hostname);
+
+ Lock(g->lock);
+ {
+ Copy(&g->DestIp, &ip, sizeof(IP));
+ g->DestPort = port;
+ StrCpy(g->HostName, sizeof(g->HostName), hostname);
+ g->NextPollIp = Tick64() + IsZeroIp(&ip) ? SYSLOG_POLL_IP_INTERVAL_NG : SYSLOG_POLL_IP_INTERVAL;
+ }
+ Unlock(g->lock);
+}
+
+// Create a syslog client
+SLOG *NewSysLog(char *hostname, UINT port)
+{
+ // Validate arguments
+ SLOG *g = ZeroMalloc(sizeof(SLOG));
+
+ g->lock = NewLock();
+ g->Udp = NewUDP(0);
+
+ SetSysLog(g, hostname, port);
+
+ return g;
+}
+
+// Check if there is enough free space on the disk
+bool CheckEraserDiskFreeSpace(ERASER *e)
+{
+ UINT64 s;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return true;
+ }
+
+ // Get the free disk space
+ if (GetDiskFree(e->DirName, &s, NULL, NULL) == false)
+ {
+ // Acquisition failure
+ return true;
+ }
+
+ if (e->MinFreeSpace > s)
+ {
+ // The free space is smaller than specified bytes
+ return false;
+ }
+
+ // Vacant enough
+ return true;
+}
+
+// Release the deleting file list
+void FreeEraseFileList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ ERASE_FILE *f = LIST_DATA(o, i);
+ Free(f->FullPath);
+ Free(f);
+ }
+
+ ReleaseList(o);
+}
+
+// Show the deleting file list
+void PrintEraseFileList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ ERASE_FILE *f = LIST_DATA(o, i);
+ Print("%I64u - %s\n", f->UpdateTime, f->FullPath);
+ }
+}
+
+// Generate a deleting file list of the specified directory
+void EnumEraseFile(LIST *o, char *dirname)
+{
+ DIRLIST *dir;
+ UINT i;
+ char tmp[MAX_PATH];
+ // Validate arguments
+ if (o == NULL || dirname == NULL)
+ {
+ return;
+ }
+
+ // Enumeration
+ dir = EnumDir(dirname);
+
+ for (i = 0;i < dir->NumFiles;i++)
+ {
+ DIRENT *e = dir->File[i];
+ Format(tmp, sizeof(tmp), "%s/%s", dirname, e->FileName);
+ NormalizePath(tmp, sizeof(tmp), tmp);
+
+ if (e->Folder == false)
+ {
+ // File
+ ERASE_FILE *f;
+
+ if (EndWith(tmp, ".log") || EndWith(tmp, ".config") || EndWith(tmp, ".old"))
+ {
+ // Target only .config files and .log files
+ f = ZeroMalloc(sizeof(ERASE_FILE));
+ f->FullPath = CopyStr(tmp);
+ f->UpdateTime = e->UpdateDate;
+
+ Add(o, f);
+ }
+ }
+ else
+ {
+ // Folder
+ EnumEraseFile(o, tmp);
+ }
+ }
+
+ FreeDir(dir);
+}
+
+// Generate a deleting file list
+LIST *GenerateEraseFileList(ERASER *e)
+{
+ LIST *o;
+ UINT i;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return NULL;
+ }
+
+ o = NewListFast(CompareEraseFile);
+
+ // Scan for each directory
+ for (i = 0;i < sizeof(delete_targets) / sizeof(delete_targets[0]);i++)
+ {
+ char dirname[MAX_PATH];
+ Format(dirname, sizeof(dirname), "%s/%s", e->DirName, delete_targets[i]);
+
+ EnumEraseFile(o, dirname);
+ }
+
+ // Sort
+ Sort(o);
+
+ return o;
+}
+
+// Process of erasing unnecessary files
+void EraserMain(ERASER *e)
+{
+ LIST *o;
+ UINT i;
+ bool ok = false;
+ char bs[64];
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ // Check the free space first
+ if (CheckEraserDiskFreeSpace(e))
+ {
+ // Vacant enough
+ return;
+ }
+
+ ToStrByte(bs, sizeof(bs), e->MinFreeSpace);
+
+ // Generate the file list
+ o = GenerateEraseFileList(e);
+
+ // Try to delete one by one in order from oldest file
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ ERASE_FILE *f = LIST_DATA(o, i);
+
+ // Delete the file
+ if (FileDelete(f->FullPath))
+ {
+ ELog(e, "LE_DELETE", bs, f->FullPath);
+ }
+
+ // Check the free space after the deleted
+ if (CheckEraserDiskFreeSpace(e))
+ {
+ // Free space has been restored
+ ok = true;
+ break;
+ }
+ }
+
+ // Release the file list
+ FreeEraseFileList(o);
+
+ if (e->LastFailed == false && ok == false)
+ {
+ // Free space is not enough, but can not delete the file any more
+ ELog(e, "LE_NOT_ENOUGH_FREE", bs);
+ }
+
+ e->LastFailed = ok ? false : true;
+}
+
+// Comparison of the deleting file entries
+int CompareEraseFile(void *p1, void *p2)
+{
+ ERASE_FILE *f1, *f2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ f1 = *(ERASE_FILE **)p1;
+ f2 = *(ERASE_FILE **)p2;
+ if (f1 == NULL || f2 == NULL)
+ {
+ return 0;
+ }
+ if (f1->UpdateTime > f2->UpdateTime)
+ {
+ return 1;
+ }
+ else if (f1->UpdateTime == f2->UpdateTime)
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+// Eraser thread
+void EraserThread(THREAD *t, void *p)
+{
+ ERASER *e = (ERASER *)p;
+ char bs[64];
+ // Validate arguments
+ if (t == NULL || e == NULL)
+ {
+ return;
+ }
+
+ // Start monitoring
+ ToStrByte(bs, sizeof(bs), e->MinFreeSpace);
+ ELog(e, "LE_START", e->DirName, bs);
+
+ while (e->Halt == false)
+ {
+ // Check the amount of free space on the disk periodically
+ EraserMain(e);
+
+ Wait(e->HaltEvent, DISK_FREE_CHECK_INTERVAL);
+ }
+}
+
+// Create a new eraser
+ERASER *NewEraser(LOG *log, UINT64 min_size)
+{
+ ERASER *e;
+ char dir[MAX_PATH];
+
+ if (min_size == 0)
+ {
+ if (OS_IS_WINDOWS(GetOsInfo()->OsType))
+ {
+ min_size = DISK_FREE_SPACE_DEFAULT_WINDOWS;
+ }
+ else
+ {
+ min_size = DISK_FREE_SPACE_DEFAULT;
+ }
+ }
+
+ if (min_size < DISK_FREE_SPACE_MIN)
+ {
+ min_size = DISK_FREE_SPACE_MIN;
+ }
+
+ e = ZeroMalloc(sizeof(ERASER));
+
+ GetExeDir(dir, sizeof(dir));
+
+ e->Log = log;
+ e->MinFreeSpace = min_size;
+ e->DirName = CopyStr(dir);
+ e->HaltEvent = NewEvent();
+
+ e->Thread = NewThread(EraserThread, e);
+
+ return e;
+}
+
+// Release the eraser
+void FreeEraser(ERASER *e)
+{
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ e->Halt = true;
+ Set(e->HaltEvent);
+ WaitThread(e->Thread, INFINITE);
+ ReleaseThread(e->Thread);
+ ReleaseEvent(e->HaltEvent);
+
+ Free(e->DirName);
+ Free(e);
+}
+
+// Take the debug log (variable-length argument)
+void DebugLog(CEDAR *c, char *fmt, ...)
+{
+ char buf[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (fmt == NULL)
+ {
+ return;
+ }
+ if (c->DebugLog == NULL)
+ {
+ return;
+ }
+
+ va_start(args, fmt);
+ FormatArgs(buf, sizeof(buf), fmt, args);
+
+ InsertStringRecord(c->DebugLog, buf);
+ va_end(args);
+}
+
+// Take the log of eraser
+void ELog(ERASER *e, char *name, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return;
+ }
+
+ va_start(args, name);
+ UniFormatArgs(buf, sizeof(buf), _UU(name), args);
+
+ InsertUnicodeRecord(e->Log, buf);
+
+ if (IsDebug())
+ {
+ UniPrint(L"LOG: %s\n", buf);
+ }
+ va_end(args);
+}
+
+// Take the log of the server
+void ServerLog(CEDAR *c, wchar_t *fmt, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (fmt == NULL)
+ {
+ return;
+ }
+
+ va_start(args, fmt);
+ UniFormatArgs(buf, sizeof(buf), fmt, args);
+
+ WriteServerLog(c, buf);
+ va_end(args);
+}
+void SLog(CEDAR *c, char *name, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return;
+ }
+
+ va_start(args, name);
+ UniFormatArgs(buf, sizeof(buf), _UU(name), args);
+
+ WriteServerLog(c, buf);
+ va_end(args);
+}
+
+// Client log
+void CLog(CLIENT *c, char *name, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return;
+ }
+
+ if (c == NULL || c->NoSaveLog)
+ {
+ return;
+ }
+
+ va_start(args, name);
+ UniFormatArgs(buf, sizeof(buf), _UU(name), args);
+
+ WriteClientLog(c, buf);
+ va_end(args);
+}
+
+// Take the security log of the HUB
+void HubLog(HUB *h, wchar_t *fmt, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (fmt == NULL)
+ {
+ return;
+ }
+
+ va_start(args, fmt);
+ UniFormatArgs(buf, sizeof(buf), fmt, args);
+
+ WriteHubLog(h, buf);
+ va_end(args);
+}
+void ALog(ADMIN *a, HUB *h, char *name, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ wchar_t tmp[MAX_SIZE * 2];
+ va_list args;
+ RPC *r;
+ // Validate arguments
+ if (a == NULL || name == NULL)
+ {
+ return;
+ }
+
+ r = a->Rpc;
+
+ va_start(args, name);
+ UniFormatArgs(buf, sizeof(buf), _UU(name), args);
+
+ if (h == NULL)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("LA_TAG_1"), r->Name);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("LA_TAG_2"), r->Name, h->Name);
+ }
+
+ UniStrCat(tmp, sizeof(tmp), buf);
+
+ if (h == NULL)
+ {
+ WriteServerLog(((ADMIN *)r->Param)->Server->Cedar, tmp);
+ }
+ else
+ {
+ WriteHubLog(h, tmp);
+ }
+ va_end(args);
+}
+void HLog(HUB *h, char *name, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return;
+ }
+
+ va_start(args, name);
+ UniFormatArgs(buf, sizeof(buf), _UU(name), args);
+
+ WriteHubLog(h, buf);
+ va_end(args);
+}
+void NLog(VH *v, char *name, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ static wchar_t snat_prefix[] = L"SecureNAT: ";
+ va_list args;
+ // Validate arguments
+ if (name == NULL || v == NULL || v->nat == NULL || v->nat->SecureNAT == NULL || v->SaveLog == false)
+ {
+ return;
+ }
+
+ va_start(args, name);
+ Copy(buf, snat_prefix, sizeof(snat_prefix));
+ UniFormatArgs(&buf[11], sizeof(buf) - 12 * sizeof(wchar_t), _UU(name), args);
+
+ WriteHubLog(v->nat->SecureNAT->Hub, buf);
+ va_end(args);
+}
+
+// Writing EtherIP log
+void EtherIPLog(ETHERIP_SERVER *s, char *name, ...)
+{
+ wchar_t prefix[MAX_SIZE * 2];
+ wchar_t buf2[MAX_SIZE * 2];
+ char server_ip[64];
+ char client_ip[64];
+ va_list args;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ IPToStr(server_ip, sizeof(server_ip), &s->ServerIP);
+ IPToStr(client_ip, sizeof(client_ip), &s->ClientIP);
+
+ UniFormat(prefix, sizeof(prefix), _UU("LE_PREFIX"), s->Id,
+ server_ip, s->ServerPort, client_ip, s->ClientPort);
+
+ va_start(args, name);
+ UniFormatArgs(buf2, sizeof(buf2), _UU(name), args);
+ va_end(args);
+
+ UniStrCat(prefix, sizeof(prefix), buf2);
+
+ WriteServerLog(s->Cedar, prefix);
+}
+
+// Write an IPsec log
+void IPsecLog(IKE_SERVER *ike, IKE_CLIENT *c, IKE_SA *ike_sa, IPSECSA *ipsec_sa, char *name, ...)
+{
+ wchar_t prefix[MAX_SIZE * 2];
+ wchar_t buf2[MAX_SIZE * 2];
+ char server_ip[64];
+ char client_ip[64];
+ va_list args;
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return;
+ }
+ if (ipsec_sa != NULL)
+ {
+ c = ipsec_sa->IkeClient;
+ }
+ else if (ike_sa != NULL)
+ {
+ c = ike_sa->IkeClient;
+ }
+
+ if (c == NULL)
+ {
+ UniStrCpy(prefix, sizeof(prefix), _UU("LI_PREFIX_RAW"));
+ }
+ else
+ {
+ IPToStr(server_ip, sizeof(server_ip), &c->ServerIP);
+ IPToStr(client_ip, sizeof(client_ip), &c->ClientIP);
+
+ if (ipsec_sa != NULL)
+ {
+ UniFormat(prefix, sizeof(prefix), _UU("LI_PREFIX_IPSEC"),
+ ipsec_sa->Id, c->Id, client_ip, c->ClientPort, server_ip, c->ServerPort);
+ }
+ else if (ike_sa != NULL)
+ {
+ UniFormat(prefix, sizeof(prefix), _UU("LI_PREFIX_IKE"),
+ ike_sa->Id, c->Id, client_ip, c->ClientPort, server_ip, c->ServerPort);
+ }
+ else
+ {
+ UniFormat(prefix, sizeof(prefix), _UU("LI_PREFIX_CLIENT"),
+ c->Id, client_ip, c->ClientPort, server_ip, c->ServerPort);
+ }
+ }
+
+ va_start(args, name);
+ UniFormatArgs(buf2, sizeof(buf2), _UU(name), args);
+ va_end(args);
+
+ UniStrCat(prefix, sizeof(prefix), buf2);
+
+ WriteServerLog(ike->Cedar, prefix);
+}
+
+// Write a PPP log
+void PPPLog(PPP_SESSION *p, char *name, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ wchar_t buf2[MAX_SIZE * 2];
+ char ipstr[128];
+ char *s1 = "", *s2 = "";
+ va_list args;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ if (StrCmpi(p->Postfix, "PPP") != 0)
+ {
+ s1 = p->Postfix;
+ s2 = " ";
+ }
+
+ va_start(args, name);
+ UniFormatArgs(buf2, sizeof(buf2), _UU(name), args);
+ va_end(args);
+
+ IPToStr(ipstr, sizeof(ipstr), &p->ClientIP);
+
+ UniFormat(buf, sizeof(buf), _UU("LP_PREFIX"), s1, s2, ipstr, p->ClientPort);
+
+ UniStrCat(buf, sizeof(buf), buf2);
+
+ WriteServerLog(p->Cedar, buf);
+}
+
+// Write an IPC log
+void IPCLog(IPC *ipc, char *name, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ va_list args;
+ HUB *h;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return;
+ }
+
+ h = GetHub(ipc->Cedar, ipc->HubName);
+
+ if (h == NULL)
+ {
+ return;
+ }
+
+ va_start(args, name);
+ UniFormatArgs(buf, sizeof(buf), _UU(name), args);
+
+ WriteHubLog(h, buf);
+ va_end(args);
+
+ ReleaseHub(h);
+}
+
+// Save the security log of the HUB
+void WriteHubLog(HUB *h, wchar_t *str)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ UINT syslog_status;
+ SERVER *s;
+ // Validate arguments
+ if (h == NULL || str == NULL)
+ {
+ return;
+ }
+
+ s = h->Cedar->Server;
+ syslog_status = SiGetSysLogSaveStatus(s);
+
+ UniFormat(buf, sizeof(buf), L"[HUB \"%S\"] %s", h->Name, str);
+
+ if (syslog_status == SYSLOG_NONE)
+ {
+ WriteServerLog(h->Cedar, buf);
+ }
+
+ if (h->LogSetting.SaveSecurityLog == false)
+ {
+ return;
+ }
+
+ if (syslog_status == SYSLOG_SERVER_AND_HUB_SECURITY_LOG
+ || syslog_status == SYSLOG_SERVER_AND_HUB_ALL_LOG)
+ {
+ SiWriteSysLog(s, "SECURITY_LOG", h->Name, str);
+ }
+ else
+ {
+ InsertUnicodeRecord(h->SecurityLogger, str);
+ }
+}
+
+// Save the client log
+void WriteClientLog(CLIENT *c, wchar_t *str)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ InsertUnicodeRecord(c->Logger, str);
+}
+
+// Save the security log of the server
+void WriteServerLog(CEDAR *c, wchar_t *str)
+{
+ SERVER *s;
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return;
+ }
+
+ s = c->Server;
+ if (s == NULL)
+ {
+ return;
+ }
+
+ if (IsDebug())
+ {
+ UniPrint(L"LOG: %s\n", str);
+ }
+
+ if (SiGetSysLogSaveStatus(s) != SYSLOG_NONE)
+ {
+ SiWriteSysLog(s, "SERVER_LOG", NULL, str);
+ }
+ else
+ {
+ InsertUnicodeRecord(s->Logger, str);
+ }
+}
+
+// Write a multi-line log
+void WriteMultiLineLog(LOG *g, BUF *b)
+{
+ // Validate arguments
+ if (g == NULL || b == NULL)
+ {
+ return;
+ }
+
+ SeekBuf(b, 0, 0);
+
+ while (true)
+ {
+ char *s = CfgReadNextLine(b);
+ if (s == NULL)
+ {
+ break;
+ }
+
+ if (IsEmptyStr(s) == false)
+ {
+ InsertStringRecord(g, s);
+ }
+
+ Free(s);
+ }
+}
+
+// Take the security log (variable-length argument) *abolished
+void SecLog(HUB *h, char *fmt, ...)
+{
+ char buf[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (fmt == NULL)
+ {
+ return;
+ }
+
+ if (h->LogSetting.SaveSecurityLog == false)
+ {
+ return;
+ }
+
+ va_start(args, fmt);
+ FormatArgs(buf, sizeof(buf), fmt, args);
+
+ WriteSecurityLog(h, buf);
+ va_end(args);
+}
+
+// Take a security log
+void WriteSecurityLog(HUB *h, char *str)
+{
+ // Validate arguments
+ if (h == NULL || str == NULL)
+ {
+ return;
+ }
+
+ InsertStringRecord(h->SecurityLogger, str);
+}
+
+// Take a packet log
+bool PacketLog(HUB *hub, SESSION *src_session, SESSION *dest_session, PKT *packet, UINT64 now)
+{
+ return true;
+}
+
+// Calculate the logging level of the specified packet
+UINT CalcPacketLoggingLevelEx(HUB_LOG *g, PKT *packet)
+{
+ UINT ret = 0;
+ // Validate arguments
+ if (g == NULL || packet == NULL)
+ {
+ return PACKET_LOG_NONE;
+ }
+
+ // Ethernet log
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ETHERNET]);
+
+ switch (packet->TypeL3)
+ {
+ case L3_ARPV4:
+ // ARP
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ARP]);
+ break;
+
+ case L3_IPV4:
+ // IPv4
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_IP]);
+
+ switch (packet->TypeL4)
+ {
+ case L4_ICMPV4:
+ // ICMPv4
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ICMP]);
+ break;
+
+ case L4_TCP:
+ // TCPv4
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP]);
+
+ if (packet->L4.TCPHeader->Flag & TCP_SYN ||
+ packet->L4.TCPHeader->Flag & TCP_RST ||
+ packet->L4.TCPHeader->Flag & TCP_FIN)
+ {
+ // TCP SYN LOG
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
+ }
+
+ break;
+
+ case L4_UDP:
+ // UDPv4
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_UDP]);
+
+ switch (packet->TypeL7)
+ {
+ case L7_DHCPV4:
+ // DHCPv4
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_DHCP]);
+ break;
+
+ case L7_IKECONN:
+ // IKE connection request
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
+ break;
+
+ case L7_OPENVPNCONN:
+ // OpenVPN connection request
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
+ break;
+ }
+
+ break;
+ }
+
+ break;
+
+ case L3_IPV6:
+ // IPv6
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_IP]);
+
+ switch (packet->TypeL4)
+ {
+ case L4_ICMPV6:
+ // ICMPv6
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ICMP]);
+ break;
+
+ case L4_TCP:
+ // TCPv6
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP]);
+
+ if (packet->L4.TCPHeader->Flag & TCP_SYN ||
+ packet->L4.TCPHeader->Flag & TCP_RST ||
+ packet->L4.TCPHeader->Flag & TCP_FIN)
+ {
+ // TCP SYN LOG
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
+ }
+
+ break;
+
+ case L4_UDP:
+ // UDPv6
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_UDP]);
+
+ switch (packet->TypeL7)
+ {
+ case L7_IKECONN:
+ // IKE connection request
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
+ break;
+
+ case L7_OPENVPNCONN:
+ // OpenVPN connection request
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
+ break;
+ }
+
+ break;
+ }
+
+ break;
+ }
+
+ if (packet->HttpLog != NULL)
+ {
+ // HTTP Connect Log
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
+ }
+
+ return ret;
+}
+UINT CalcPacketLoggingLevel(HUB *hub, PKT *packet)
+{
+ // Validate arguments
+ if (hub == NULL || packet == NULL)
+ {
+ return PACKET_LOG_NONE;
+ }
+
+ return CalcPacketLoggingLevelEx(&hub->LogSetting, packet);
+}
+
+// Generate a string to be stored as an HTTP log
+char *BuildHttpLogStr(HTTPLOG *h)
+{
+ BUF *b;
+ char url[MAX_SIZE];
+ char nullchar = 0;
+ char *ret;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return CopyStr("");
+ }
+
+ b = NewBuf();
+
+ // URL generation
+ if (h->Port == 80)
+ {
+ Format(url, sizeof(url), "http://%s%s",
+ h->Hostname, h->Path);
+ }
+ else
+ {
+ Format(url, sizeof(url), "http://%s:%u%s",
+ h->Hostname, h->Port, h->Path);
+ }
+
+ AddLogBufToStr(b, "HttpMethod", h->Method);
+ AddLogBufToStr(b, "HttpUrl", url);
+ AddLogBufToStr(b, "HttpProtocol", h->Protocol);
+ AddLogBufToStr(b, "HttpReferer", h->Referer);
+ AddLogBufToStr(b, "HttpUserAgent", h->UserAgent);
+
+ WriteBuf(b, &nullchar, 1);
+
+ ret = CopyStr(b->Buf);
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Append an item to the log buffer
+void AddLogBufToStr(BUF *b, char *name, char *value)
+{
+ char tmp[MAX_SIZE * 2];
+ char *p = NULL;
+ // Validate arguments
+ if (b == NULL || value == NULL)
+ {
+ return;
+ }
+
+ if (IsEmptyStr(value))
+ {
+ return;
+ }
+
+ tmp[0] = 0;
+
+ if (IsEmptyStr(name) == false)
+ {
+ p = &tmp[StrLen(tmp)];
+ StrCat(tmp, sizeof(tmp), name);
+ MakeSafeLogStr(p);
+ StrCat(tmp, sizeof(tmp), "=");
+ }
+
+ p = &tmp[StrLen(tmp)];
+ StrCat(tmp, sizeof(tmp), value);
+ MakeSafeLogStr(p);
+ StrCat(tmp, sizeof(tmp), " ");
+
+ WriteBuf(b, tmp, StrLen(tmp));
+}
+
+// Secure the log string
+void MakeSafeLogStr(char *str)
+{
+ UINT i, len;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return;
+ }
+
+ EnPrintableAsciiStr(str, '?');
+
+ len = StrLen(str);
+ for (i = 0;i < len;i++)
+ {
+ if (str[i] == ',')
+ {
+ str[i] = '.';
+ }
+ else if (str[i] == ' ')
+ {
+ str[i] = '_';
+ }
+ }
+}
+
+// Procedure for converting a packet log entry to a string
+char *PacketLogParseProc(RECORD *rec)
+{
+ return NULL;
+}
+
+// Convert TCP flags to a string
+char *TcpFlagStr(UCHAR flag)
+{
+ char tmp[MAX_SIZE];
+ StrCpy(tmp, sizeof(tmp), "");
+
+ if (flag & TCP_FIN)
+ {
+ StrCat(tmp, sizeof(tmp), "FIN+");
+ }
+
+ if (flag & TCP_SYN)
+ {
+ StrCat(tmp, sizeof(tmp), "SYN+");
+ }
+
+ if (flag & TCP_RST)
+ {
+ StrCat(tmp, sizeof(tmp), "RST+");
+ }
+
+ if (flag & TCP_PSH)
+ {
+ StrCat(tmp, sizeof(tmp), "PSH+");
+ }
+
+ if (flag & TCP_ACK)
+ {
+ StrCat(tmp, sizeof(tmp), "ACK+");
+ }
+
+ if (flag & TCP_URG)
+ {
+ StrCat(tmp, sizeof(tmp), "URG+");
+ }
+
+ if (StrLen(tmp) >= 1)
+ {
+ if (tmp[StrLen(tmp) - 1] == '+')
+ {
+ tmp[StrLen(tmp) - 1] = 0;
+ }
+ }
+
+ return CopyStr(tmp);
+}
+
+// Generate a port string
+char *PortStr(CEDAR *cedar, UINT port, bool udp)
+{
+ char tmp[MAX_SIZE];
+ char *name;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ name = GetSvcName(cedar, udp, port);
+
+ if (name == NULL)
+ {
+ snprintf(tmp, sizeof(tmp), "%u", port);
+ }
+ else
+ {
+ snprintf(tmp, sizeof(tmp), "%s(%u)", name, port);
+ }
+
+ return CopyStr(tmp);
+}
+
+// Generate a comma-separated string
+char *GenCsvLine(TOKEN_LIST *t)
+{
+ UINT i;
+ BUF *b;
+ char *ret;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ if (t->Token[i] != NULL)
+ {
+ ReplaceForCsv(t->Token[i]);
+ if (StrLen(t->Token[i]) == 0)
+ {
+ WriteBuf(b, "-", 1);
+ }
+ else
+ {
+ WriteBuf(b, t->Token[i], StrLen(t->Token[i]));
+ }
+ }
+ else
+ {
+ WriteBuf(b, "-", 1);
+ }
+ if (i != (t->NumTokens - 1))
+ {
+ WriteBuf(b, ",", 1);
+ }
+ }
+ WriteBuf(b, "\0", 1);
+
+ ret = (char *)b->Buf;
+
+ Free(b);
+
+ return ret;
+}
+
+// Replace the strings in the CSV correctly
+void ReplaceForCsv(char *str)
+{
+ UINT i, len;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return;
+ }
+
+ // If there are blanks, trim it
+ Trim(str);
+ len = StrLen(str);
+
+ for (i = 0;i < len;i++)
+ {
+ // Convert the comma to underscore
+ if (str[i] == ',')
+ {
+ str[i] = '_';
+ }
+ }
+}
+
+// Set the directory name of the log
+void SetLogDirName(LOG *g, char *dir)
+{
+ // Validate arguments
+ if (g == NULL || dir == NULL)
+ {
+ return;
+ }
+
+ LockLog(g);
+ {
+ if (g->DirName != NULL)
+ {
+ Free(g->DirName);
+ }
+ g->DirName = CopyStr(dir);
+ }
+ UnlockLog(g);
+}
+
+// Set the name of the log
+void SetLogPrefix(LOG *g, char *prefix)
+{
+ // Validate arguments
+ if (g == NULL || prefix == NULL)
+ {
+ return;
+ }
+
+ LockLog(g);
+ {
+ if (g->DirName != NULL)
+ {
+ Free(g->Prefix);
+ }
+ g->DirName = CopyStr(prefix);
+ }
+ UnlockLog(g);
+}
+
+// Set the switch type of log
+void SetLogSwitchType(LOG *g, UINT switch_type)
+{
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ LockLog(g);
+ {
+ g->SwitchType = switch_type;
+ }
+ UnlockLog(g);
+}
+
+// Parse the string record
+char *StringRecordParseProc(RECORD *rec)
+{
+ // Validate arguments
+ if (rec == NULL)
+ {
+ return NULL;
+ }
+
+ return (char *)rec->Data;
+}
+
+// Add an Unicode string record in the log
+void InsertUnicodeRecord(LOG *g, wchar_t *unistr)
+{
+ char *str;
+ UINT size;
+ // Validate arguments
+ if (g == NULL || unistr == NULL)
+ {
+ return;
+ }
+
+ size = CalcUniToUtf8(unistr) + 32;
+ str = ZeroMalloc(size);
+
+ UniToUtf8((BYTE *)str, size, unistr);
+ InsertStringRecord(g, str);
+ Free(str);
+}
+
+// Add a string record to the log
+void InsertStringRecord(LOG *g, char *str)
+{
+ char *str_copy;
+ // Validate arguments
+ if (g == NULL || str == NULL)
+ {
+ return;
+ }
+
+ str_copy = CopyStr(str);
+
+ InsertRecord(g, str_copy, StringRecordParseProc);
+}
+
+// Add a record to the log
+void InsertRecord(LOG *g, void *data, RECORD_PARSE_PROC *proc)
+{
+ RECORD *rec;
+ // Validate arguments
+ if (g == NULL || data == NULL || proc == NULL)
+ {
+ return;
+ }
+
+ rec = ZeroMalloc(sizeof(RECORD));
+ rec->Tick = Tick64();
+ rec->ParseProc = proc;
+ rec->Data = data;
+
+ LockQueue(g->RecordQueue);
+ {
+ InsertQueue(g->RecordQueue, rec);
+ }
+ UnlockQueue(g->RecordQueue);
+
+ Set(g->Event);
+}
+
+// Lock the log
+void LockLog(LOG *g)
+{
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ Lock(g->lock);
+}
+
+// Unlock the log
+void UnlockLog(LOG *g)
+{
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ Unlock(g->lock);
+}
+
+// Generate the string portion of the log file name from the time and the switching rule
+void MakeLogFileNameStringFromTick(LOG *g, char *str, UINT size, UINT64 tick, UINT switch_type)
+{
+ UINT64 time;
+ SYSTEMTIME st;
+
+ // Validate arguments
+ if (str == NULL || g == NULL)
+ {
+ return;
+ }
+
+ if (g->CacheFlag)
+ {
+ if (g->LastTick == tick &&
+ g->LastSwitchType == switch_type)
+ {
+ StrCpy(str, size, g->LastStr);
+ return;
+ }
+ }
+
+ time = TickToTime(tick);
+ UINT64ToSystem(&st, SystemToLocal64(time));
+
+ switch (switch_type)
+ {
+ case LOG_SWITCH_SECOND: // Secondly basis
+ snprintf(str, size, "_%04u%02u%02u_%02u%02u%02u",
+ st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
+ break;
+
+ case LOG_SWITCH_MINUTE: // Minutely basis
+ snprintf(str, size, "_%04u%02u%02u_%02u%02u",
+ st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute);
+ break;
+
+ case LOG_SWITCH_HOUR: // Hourly basis
+ snprintf(str, size, "_%04u%02u%02u_%02u", st.wYear, st.wMonth, st.wDay, st.wHour);
+ break;
+
+ case LOG_SWITCH_DAY: // Daily basis
+ snprintf(str, size, "_%04u%02u%02u", st.wYear, st.wMonth, st.wDay);
+ break;
+
+ case LOG_SWITCH_MONTH: // Monthly basis
+ snprintf(str, size, "_%04u%02u", st.wYear, st.wMonth);
+ break;
+
+ default: // Without switching
+ snprintf(str, size, "");
+ break;
+ }
+
+ g->CacheFlag = true;
+ g->LastTick = tick;
+ g->LastSwitchType = switch_type;
+ StrCpy(g->LastStr, sizeof(g->LastStr), str);
+}
+
+// Create a log file name
+bool MakeLogFileName(LOG *g, char *name, UINT size, char *dir, char *prefix, UINT64 tick, UINT switch_type, UINT num, char *old_datestr)
+{
+ char tmp[MAX_SIZE];
+ char tmp2[64];
+ bool ret = false;
+ // Validate arguments
+ if (g == NULL || name == NULL || prefix == NULL || old_datestr == NULL)
+ {
+ return false;
+ }
+
+ MakeLogFileNameStringFromTick(g, tmp, sizeof(tmp), tick, switch_type);
+
+ if (num == 0)
+ {
+ tmp2[0] = 0;
+ }
+ else
+ {
+ snprintf(tmp2, sizeof(tmp2), "~%02u", num);
+ }
+
+ if (strcmp(old_datestr, tmp) != 0)
+ {
+ ret = true;
+ strcpy(old_datestr, tmp);
+ }
+
+ snprintf(name, size, "%s%s%s%s%s.log", dir,
+ StrLen(dir) == 0 ? "" : "/",
+ prefix, tmp, tmp2
+ );
+
+ return ret;
+}
+
+// Wait until the log have been flushed
+void WaitLogFlush(LOG *g)
+{
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ UINT num;
+ LockQueue(g->RecordQueue);
+ {
+ num = g->RecordQueue->num_item;
+ }
+ UnlockQueue(g->RecordQueue);
+
+ if (num == 0)
+ {
+ break;
+ }
+
+ Wait(g->FlushEvent, 100);
+ }
+}
+
+// Logging thread
+void LogThread(THREAD *thread, void *param)
+{
+ LOG *g;
+ IO *io;
+ BUF *b;
+ bool flag = false;
+ char current_file_name[MAX_SIZE];
+ char current_logfile_datename[MAX_SIZE];
+ bool last_priority_flag = false;
+ bool log_date_changed = false;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ Zero(current_file_name, sizeof(current_file_name));
+ Zero(current_logfile_datename, sizeof(current_logfile_datename));
+
+ g = (LOG *)param;
+
+ io = NULL;
+ b = NewBuf();
+
+#ifdef OS_WIN32
+
+ // Lower priority to bottom
+ MsSetThreadPriorityIdle();
+
+#endif // OS_WIN32
+
+ NoticeThreadInit(thread);
+
+ while (true)
+ {
+ RECORD *rec;
+ UINT64 s = Tick64();
+
+ while (true)
+ {
+ char file_name[MAX_SIZE];
+ UINT num;
+
+ // Retrieve a record from the head of the queue
+ LockQueue(g->RecordQueue);
+ {
+ rec = GetNext(g->RecordQueue);
+ num = g->RecordQueue->num_item;
+ }
+ UnlockQueue(g->RecordQueue);
+
+#ifdef OS_WIN32
+ if (num >= LOG_ENGINE_SAVE_START_CACHE_COUNT)
+ {
+ // Raise the priority
+ if (last_priority_flag == false)
+ {
+ Debug("LOG_THREAD: MsSetThreadPriorityRealtime\n");
+ MsSetThreadPriorityRealtime();
+ last_priority_flag = true;
+ }
+ }
+
+ if (num < (LOG_ENGINE_SAVE_START_CACHE_COUNT / 2))
+ {
+ // Restore the priority
+ if (last_priority_flag)
+ {
+ Debug("LOG_THREAD: MsSetThreadPriorityIdle\n");
+ MsSetThreadPriorityIdle();
+ last_priority_flag = false;
+ }
+ }
+#endif // OS_WIN32
+
+ if (b->Size > g->MaxLogFileSize)
+ {
+ // Erase if the size of the buffer is larger than the maximum log file size
+ ClearBuf(b);
+ }
+
+ if (b->Size >= LOG_ENGINE_BUFFER_CACHE_SIZE_MAX)
+ {
+ // Write the contents of the buffer to the file
+ if (io != NULL)
+ {
+ if ((g->CurrentFilePointer + (UINT64)b->Size) > g->MaxLogFileSize)
+ {
+ if (g->log_number_incremented == false)
+ {
+ g->CurrentLogNumber++;
+ g->log_number_incremented = true;
+ }
+ }
+ else
+ {
+ if (FileWrite(io, b->Buf, b->Size) == false)
+ {
+ FileCloseEx(io, true);
+ // If it fails to write to the file,
+ // erase the buffer and give up
+ ClearBuf(b);
+ io = NULL;
+ }
+ else
+ {
+ g->CurrentFilePointer += (UINT64)b->Size;
+ ClearBuf(b);
+ }
+ }
+ }
+ }
+
+ if (rec == NULL)
+ {
+ if (b->Size != 0)
+ {
+ // Write the contents of the buffer to the file
+ if (io != NULL)
+ {
+ if ((g->CurrentFilePointer + (UINT64)b->Size) > g->MaxLogFileSize)
+ {
+ if (g->log_number_incremented == false)
+ {
+ g->CurrentLogNumber++;
+ g->log_number_incremented = true;
+ }
+ }
+ else
+ {
+ if (FileWrite(io, b->Buf, b->Size) == false)
+ {
+ FileCloseEx(io, true);
+ // If it fails to write to the file,
+ // erase the buffer and give up
+ ClearBuf(b);
+ io = NULL;
+ }
+ else
+ {
+ g->CurrentFilePointer += (UINT64)b->Size;
+ ClearBuf(b);
+ }
+ }
+ }
+ }
+
+ Set(g->FlushEvent);
+ break;
+ }
+
+ // Generate a log file name
+ LockLog(g);
+ {
+ log_date_changed = MakeLogFileName(g, file_name, sizeof(file_name),
+ g->DirName, g->Prefix, rec->Tick, g->SwitchType, g->CurrentLogNumber, current_logfile_datename);
+
+ if (log_date_changed)
+ {
+ UINT i;
+
+ g->CurrentLogNumber = 0;
+ MakeLogFileName(g, file_name, sizeof(file_name),
+ g->DirName, g->Prefix, rec->Tick, g->SwitchType, 0, current_logfile_datename);
+ for (i = 0;;i++)
+ {
+ char tmp[MAX_SIZE];
+ MakeLogFileName(g, tmp, sizeof(tmp),
+ g->DirName, g->Prefix, rec->Tick, g->SwitchType, i, current_logfile_datename);
+
+ if (IsFileExists(tmp) == false)
+ {
+ break;
+ }
+ StrCpy(file_name, sizeof(file_name), tmp);
+ g->CurrentLogNumber = i;
+ }
+ }
+ }
+ UnlockLog(g);
+
+ if (io != NULL)
+ {
+ if (StrCmp(current_file_name, file_name) != 0)
+ {
+ // If a log file is currently opened and writing to another log
+ // file is needed for this time, write the contents of the
+ //buffer and close the log file. Write the contents of the buffer
+ if (io != NULL)
+ {
+ if (log_date_changed)
+ {
+ if ((g->CurrentFilePointer + (UINT64)b->Size) <= g->MaxLogFileSize)
+ {
+ if (FileWrite(io, b->Buf, b->Size) == false)
+ {
+ FileCloseEx(io, true);
+ ClearBuf(b);
+ io = NULL;
+ }
+ else
+ {
+ g->CurrentFilePointer += (UINT64)b->Size;
+ ClearBuf(b);
+ }
+ }
+ }
+ // Close the file
+ FileCloseEx(io, true);
+ }
+
+ g->log_number_incremented = false;
+
+ // Open or create a new log file
+ StrCpy(current_file_name, sizeof(current_file_name), file_name);
+ io = FileOpen(file_name, true);
+ if (io == NULL)
+ {
+ // Create a log file
+ LockLog(g);
+ {
+ MakeDir(g->DirName);
+
+#ifdef OS_WIN32
+ Win32SetFolderCompress(g->DirName, true);
+#endif // OS_WIN32
+ }
+ UnlockLog(g);
+ io = FileCreate(file_name);
+ g->CurrentFilePointer = 0;
+ }
+ else
+ {
+ // Seek to the end of the log file
+ g->CurrentFilePointer = FileSize64(io);
+ FileSeek(io, SEEK_END, 0);
+ }
+ }
+ }
+ else
+ {
+ // Open or create a new log file
+ StrCpy(current_file_name, sizeof(current_file_name), file_name);
+ io = FileOpen(file_name, true);
+ if (io == NULL)
+ {
+ // Create a log file
+ LockLog(g);
+ {
+ MakeDir(g->DirName);
+#ifdef OS_WIN32
+ Win32SetFolderCompress(g->DirName, true);
+#endif // OS_WIN32
+ }
+ UnlockLog(g);
+ io = FileCreate(file_name);
+ g->CurrentFilePointer = 0;
+ if (io == NULL)
+ {
+ //Debug("Logging.c: SleepThread(30);\n");
+ SleepThread(30);
+ }
+ }
+ else
+ {
+ // Seek to the end of the log file
+ g->CurrentFilePointer = FileSize64(io);
+ FileSeek(io, SEEK_END, 0);
+ }
+
+ g->log_number_incremented = false;
+ }
+
+ // Write the contents of the log to the buffer
+ WriteRecordToBuffer(b, rec);
+
+ // Release the memory of record
+ Free(rec);
+
+ if (io == NULL)
+ {
+ break;
+ }
+ }
+
+ if (g->Halt)
+ {
+ // Break after finishing to save all records
+ // when the stop flag stood
+ UINT num;
+
+ if (flag == false)
+ {
+#ifdef OS_WIN32
+ MsSetThreadPriorityRealtime();
+#endif // OS_WIN32
+ flag = true;
+ }
+
+ LockQueue(g->RecordQueue);
+ {
+ num = g->RecordQueue->num_item;
+ }
+ UnlockQueue(g->RecordQueue);
+
+ if (num == 0 || io == NULL)
+ {
+ break;
+ }
+ }
+ else
+ {
+ Wait(g->Event, 9821);
+ }
+ }
+
+ if (io != NULL)
+ {
+ FileCloseEx(io, true);
+ }
+
+ FreeBuf(b);
+}
+
+// Write the contents of the log to the buffer
+void WriteRecordToBuffer(BUF *b, RECORD *r)
+{
+ UINT64 time;
+ char time_str[MAX_SIZE];
+ char date_str[MAX_SIZE];
+ char *s;
+ // Validate arguments
+ if (b == NULL || r == NULL)
+ {
+ return;
+ }
+
+ // Get the time
+ time = SystemToLocal64(TickToTime(r->Tick));
+
+ // Convert a time to a string
+ GetDateStr64(date_str, sizeof(date_str), time);
+ GetTimeStrMilli64(time_str, sizeof(time_str), time);
+
+ if (r->ParseProc != PacketLogParseProc)
+ {
+ // Other than packet log
+ WriteBuf(b, date_str, StrLen(date_str));
+ WriteBuf(b, " ", 1);
+ WriteBuf(b, time_str, StrLen(time_str));
+ WriteBuf(b, " ", 1);
+ }
+ else
+ {
+ // Packet log
+ WriteBuf(b, date_str, StrLen(date_str));
+ WriteBuf(b, ",", 1);
+ WriteBuf(b, time_str, StrLen(time_str));
+ WriteBuf(b, ",", 1);
+ }
+
+ // Output text
+ s = r->ParseProc(r);
+ WriteBuf(b, s, StrLen(s));
+ Free(s);
+
+ WriteBuf(b, "\r\n", 2);
+}
+
+// End of logging
+void FreeLog(LOG *g)
+{
+ RECORD *rec;
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ // Halting flag
+ g->Halt = true;
+ Set(g->Event);
+
+ WaitThread(g->Thread, INFINITE);
+ ReleaseThread(g->Thread);
+
+ DeleteLock(g->lock);
+ Free(g->DirName);
+ Free(g->Prefix);
+
+ // Release the unprocessed record if it remains
+ // (It should not remain here)
+ while (rec = GetNext(g->RecordQueue))
+ {
+ char *s = rec->ParseProc(rec);
+ Free(s);
+ Free(rec);
+ }
+ ReleaseQueue(g->RecordQueue);
+
+ ReleaseEvent(g->Event);
+ ReleaseEvent(g->FlushEvent);
+
+ Free(g);
+}
+
+// Start a new logging
+LOG *NewLog(char *dir, char *prefix, UINT switch_type)
+{
+ LOG *g;
+
+ g = ZeroMalloc(sizeof(LOG));
+ g->lock = NewLock();
+ g->DirName = CopyStr(dir == NULL ? "" : dir);
+ g->Prefix = CopyStr(prefix == NULL ? "log" : prefix);
+ g->SwitchType = switch_type;
+ g->RecordQueue = NewQueue();
+ g->Event = NewEvent();
+ g->MaxLogFileSize = MAX_LOG_SIZE;
+ g->FlushEvent = NewEvent();
+
+ g->Thread = NewThread(LogThread, g);
+
+ WaitThreadInit(g->Thread);
+
+ return g;
+}
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Logging.h b/src/Cedar/Logging.h
new file mode 100644
index 00000000..cffec6fe
--- /dev/null
+++ b/src/Cedar/Logging.h
@@ -0,0 +1,248 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Logging.h
+// Header of Logging.c
+
+#ifndef LOGGING_H
+#define LOGGING_H
+
+
+// Port number for HTTP monitoring
+#define LOG_HTTP_PORT 80
+
+
+#define MAX_LOG_SIZE 1073741823ULL
+
+typedef char *(RECORD_PARSE_PROC)(RECORD *rec);
+
+// Packet log structure
+struct PACKET_LOG
+{
+ CEDAR *Cedar;
+ struct PKT *Packet;
+ char *SrcSessionName;
+ char *DestSessionName;
+ bool PurePacket; // Packet not cloned
+ bool PurePacketNoPayload; // Packet not cloned (without payload)
+ SESSION *SrcSession;
+ bool NoLog; // Not to write a log
+};
+
+// Log save options of the HUB
+struct HUB_LOG
+{
+ bool SaveSecurityLog; // To save the security log
+ UINT SecurityLogSwitchType; // Switching type of security log
+ bool SavePacketLog; // To save the packet log
+ UINT PacketLogSwitchType; // Switching type of packet log
+ UINT PacketLogConfig[NUM_PACKET_LOG]; // Packet log settings
+};
+
+// Record
+struct RECORD
+{
+ UINT64 Tick; // Time
+ RECORD_PARSE_PROC *ParseProc; // Parsing procedure
+ void *Data; // Data
+};
+
+// LOG object
+struct LOG
+{
+ LOCK *lock; // Lock
+ THREAD *Thread; // Thread
+ char *DirName; // Destination directory name
+ char *Prefix; // File name
+ UINT SwitchType; // Switching type of log file
+ QUEUE *RecordQueue; // Record queue
+ volatile bool Halt; // Halting flag
+ EVENT *Event; // Event for Log
+ EVENT *FlushEvent; // Flash completion event
+ bool CacheFlag;
+ UINT64 LastTick;
+ UINT LastSwitchType;
+ char LastStr[MAX_SIZE];
+ UINT64 CurrentFilePointer; // The current file pointer
+ UINT64 MaxLogFileSize; // Maximum log file size
+ UINT CurrentLogNumber; // Log file number of the current
+ bool log_number_incremented;
+};
+
+
+// ERASER object
+struct ERASER
+{
+ LOG *Log; // Logger
+ UINT64 MinFreeSpace; // Disk space to start deleting files
+ char *DirName; // Directory name
+ volatile bool Halt; // Halting flag
+ THREAD *Thread; // Thread
+ bool LastFailed; // Whether deletion of the file failed at the end
+ EVENT *HaltEvent; // Halting event
+};
+
+// List of files that can be deleted
+typedef struct ERASE_FILE
+{
+ char *FullPath; // Full path
+ UINT64 UpdateTime; // Updating date
+} ERASE_FILE;
+
+// SYSLOG object
+struct SLOG
+{
+ LOCK *lock; // Lock
+ SOCK *Udp; // UDP socket
+ IP DestIp; // Destination IP address
+ UINT DestPort; // Destination port number
+ char HostName[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT64 NextPollIp; // Time of examination of the IP address at the end
+};
+
+// Function prototype
+LOG *NewLog(char *dir, char *prefix, UINT switch_type);
+void FreeLog(LOG *g);
+void LogThread(THREAD *thread, void *param);
+void WaitLogFlush(LOG *g);
+void LockLog(LOG *g);
+void UnlockLog(LOG *g);
+void InsertRecord(LOG *g, void *data, RECORD_PARSE_PROC *proc);
+void InsertStringRecord(LOG *g, char *str);
+void InsertUnicodeRecord(LOG *g, wchar_t *unistr);
+char *StringRecordParseProc(RECORD *rec);
+bool MakeLogFileName(LOG *g, char *name, UINT size, char *dir, char *prefix, UINT64 tick, UINT switch_type, UINT num, char *old_datestr);
+void MakeLogFileNameStringFromTick(LOG *g, char *str, UINT size, UINT64 tick, UINT switch_type);
+void WriteRecordToBuffer(BUF *b, RECORD *r);
+void SetLogDirName(LOG *g, char *dir);
+void SetLogPrefix(LOG *g, char *prefix);
+void SetLogSwitchType(LOG *g, UINT switch_type);
+bool PacketLog(HUB *hub, SESSION *src_session, SESSION *dest_session, PKT *packet, UINT64 now);
+char *PacketLogParseProc(RECORD *rec);
+UINT CalcPacketLoggingLevel(HUB *hub, PKT *packet);
+UINT CalcPacketLoggingLevelEx(HUB_LOG *g, PKT *packet);
+char *GenCsvLine(TOKEN_LIST *t);
+void ReplaceForCsv(char *str);
+char *PortStr(CEDAR *cedar, UINT port, bool udp);
+char *TcpFlagStr(UCHAR flag);
+void WriteSecurityLog(HUB *h, char *str);
+void SecLog(HUB *h, char *fmt, ...);
+void SiSetDefaultLogSetting(HUB_LOG *g);
+void DebugLog(CEDAR *c, char *fmt, ...);
+void HubLog(HUB *h, wchar_t *fmt, ...);
+void ServerLog(CEDAR *c, wchar_t *fmt, ...);
+void SLog(CEDAR *c, char *name, ...);
+void WriteHubLog(HUB *h, wchar_t *str);
+void HLog(HUB *h, char *name, ...);
+void NLog(VH *v, char *name, ...);
+void IPCLog(IPC *ipc, char *name, ...);
+void PPPLog(PPP_SESSION *p, char *name, ...);
+void IPsecLog(IKE_SERVER *ike, IKE_CLIENT *c, IKE_SA *ike_sa, IPSECSA *ipsec_sa, char *name, ...);
+void EtherIPLog(ETHERIP_SERVER *s, char *name, ...);
+void WriteServerLog(CEDAR *c, wchar_t *str);
+void ALog(ADMIN *a, HUB *h, char *name, ...);
+void CLog(CLIENT *c, char *name, ...);
+void WriteClientLog(CLIENT *c, wchar_t *str);
+ERASER *NewEraser(LOG *log, UINT64 min_size);
+void FreeEraser(ERASER *e);
+void ELog(ERASER *e, char *name, ...);
+void EraserThread(THREAD *t, void *p);
+void EraserMain(ERASER *e);
+bool CheckEraserDiskFreeSpace(ERASER *e);
+int CompareEraseFile(void *p1, void *p2);
+LIST *GenerateEraseFileList(ERASER *e);
+void FreeEraseFileList(LIST *o);
+void PrintEraseFileList(LIST *o);
+void EnumEraseFile(LIST *o, char *dirname);
+SLOG *NewSysLog(char *hostname, UINT port);
+void SetSysLog(SLOG *g, char *hostname, UINT port);
+void FreeSysLog(SLOG *g);
+void SendSysLog(SLOG *g, wchar_t *str);
+void WriteMultiLineLog(LOG *g, BUF *b);
+char *BuildHttpLogStr(HTTPLOG *h);
+void MakeSafeLogStr(char *str);
+void AddLogBufToStr(BUF *b, char *name, char *value);
+
+#endif // LOGGING_G
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/NM.c b/src/Cedar/NM.c
new file mode 100644
index 00000000..74bb88fd
--- /dev/null
+++ b/src/Cedar/NM.c
@@ -0,0 +1,1516 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// NM.c
+// VPN User-mode Router Manager for Win32
+
+#include
+
+#ifdef WIN32
+
+#define SM_C
+#define CM_C
+#define NM_C
+
+#define _WIN32_WINNT 0x0502
+#define WINVER 0x0502
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "CMInner.h"
+#include "SMInner.h"
+#include "NMInner.h"
+#include "EMInner.h"
+#include "../PenCore/resource.h"
+
+// Global variable
+static NM *nm = NULL;
+
+
+// Change Password dialog
+UINT NmChangePasswordProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ RPC *r = (RPC *)param;
+ char tmp1[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ RPC_SET_PASSWORD t;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ FormatText(hWnd, 0, r->Sock->RemoteHostname);
+ FormatText(hWnd, S_TITLE, r->Sock->RemoteHostname);
+ break;
+
+ case WM_COMMAND:
+ GetTxtA(hWnd, E_PASSWORD1, tmp1, sizeof(tmp1));
+ GetTxtA(hWnd, E_PASSWORD2, tmp2, sizeof(tmp2));
+ switch (LOWORD(wParam))
+ {
+ case E_PASSWORD1:
+ case E_PASSWORD2:
+ SetEnable(hWnd, IDOK, StrCmp(tmp1, tmp2) == 0);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ Zero(&t, sizeof(t));
+ Hash(t.HashedPassword, tmp1, StrLen(tmp1), true);
+
+ if (CALL(hWnd, NcSetPassword(r, &t)))
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("NM_PASSWORD_MSG"));
+ EndDialog(hWnd, true);
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Change the password
+void NmChangePassword(HWND hWnd, RPC *r)
+{
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_NM_CHANGE_PASSWORD, NmChangePasswordProc, r);
+}
+
+// DHCP enumeration initialization
+void NmDhcpInit(HWND hWnd, SM_HUB *r)
+{
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_INTERNET);
+
+ LvInit(hWnd, L_TABLE);
+ LvInsertColumn(hWnd, L_TABLE, 0, _UU("DHCP_DHCP_ID"), 50);
+ LvInsertColumn(hWnd, L_TABLE, 1, _UU("DHCP_LEASED_TIME"), 200);
+ LvInsertColumn(hWnd, L_TABLE, 2, _UU("DHCP_EXPIRE_TIME"), 200);
+ LvInsertColumn(hWnd, L_TABLE, 3, _UU("DHCP_MAC_ADDRESS"), 130);
+ LvInsertColumn(hWnd, L_TABLE, 4, _UU("DHCP_IP_ADDRESS"), 100);
+ LvInsertColumn(hWnd, L_TABLE, 5, _UU("DHCP_HOSTNAME"), 150);
+
+ NmDhcpRefresh(hWnd, r);
+}
+
+// DHCP enumeration
+void NmDhcpRefresh(HWND hWnd, SM_HUB *r)
+{
+ LVB *b;
+ RPC_ENUM_DHCP t;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), r->HubName);
+
+ if (CALL(hWnd, ScEnumDHCP(r->Rpc, &t)) == false)
+ {
+ return;
+ }
+
+ b = LvInsertStart();
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_DHCP_ITEM *e = &t.Items[i];
+ wchar_t tmp0[MAX_SIZE];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t tmp5[MAX_SIZE];
+ char str[MAX_SIZE];
+
+ // ID
+ UniToStru(tmp0, e->Id);
+
+ // Time
+ GetDateTimeStrEx64(tmp1, sizeof(tmp1), SystemToLocal64(e->LeasedTime), NULL);
+ GetDateTimeStrEx64(tmp2, sizeof(tmp2), SystemToLocal64(e->ExpireTime), NULL);
+
+ MacToStr(str, sizeof(str), e->MacAddress);
+ StrToUni(tmp3, sizeof(tmp3), str);
+
+ IPToStr32(str, sizeof(str), e->IpAddress);
+ StrToUni(tmp4, sizeof(tmp4), str);
+
+ StrToUni(tmp5, sizeof(tmp5), e->Hostname);
+
+ LvInsertAdd(b, ICO_INTERNET, NULL, 6,
+ tmp0, tmp1, tmp2, tmp3, tmp4, tmp5);
+ }
+
+ LvInsertEnd(b, hWnd, L_TABLE);
+
+ FreeRpcEnumDhcp(&t);
+}
+
+// DHCP enumeration procedure
+UINT NmDhcpProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_HUB *r = (SM_HUB *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ NmDhcpInit(hWnd, r);
+ SetTimer(hWnd, 1, NM_DHCP_REFRESH_TIME, NULL);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case B_REFRESH:
+ NmDhcpRefresh(hWnd, r);
+ break;
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+ NmDhcpRefresh(hWnd, r);
+ SetTimer(hWnd, 1, NM_DHCP_REFRESH_TIME, NULL);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_TABLE);
+
+ return 0;
+}
+
+// DHCP enumeration
+void NmDhcp(HWND hWnd, SM_HUB *r)
+{
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_NM_DHCP, NmDhcpProc, r);
+}
+
+
+// NAT enumeration initialization
+void NmNatInit(HWND hWnd, SM_HUB *r)
+{
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_PROTOCOL);
+
+ LvInit(hWnd, L_TABLE);
+ LvInsertColumn(hWnd, L_TABLE, 0, _UU("NM_NAT_ID"), 50);
+ LvInsertColumn(hWnd, L_TABLE, 1, _UU("NM_NAT_PROTOCOL"), 80);
+ LvInsertColumn(hWnd, L_TABLE, 2, _UU("NM_NAT_SRC_HOST"), 100);
+ LvInsertColumn(hWnd, L_TABLE, 3, _UU("NM_NAT_SRC_PORT"), 80);
+ LvInsertColumn(hWnd, L_TABLE, 4, _UU("NM_NAT_DST_HOST"), 150);
+ LvInsertColumn(hWnd, L_TABLE, 5, _UU("NM_NAT_DST_PORT"), 80);
+ LvInsertColumn(hWnd, L_TABLE, 6, _UU("NM_NAT_CREATED"), 200);
+ LvInsertColumn(hWnd, L_TABLE, 7, _UU("NM_NAT_LAST_COMM"), 200);
+ LvInsertColumn(hWnd, L_TABLE, 8, _UU("NM_NAT_SIZE"), 120);
+ LvInsertColumn(hWnd, L_TABLE, 9, _UU("NM_NAT_TCP_STATUS"), 120);
+
+ NmNatRefresh(hWnd, r);
+}
+
+// NAT enumeration
+void NmNatRefresh(HWND hWnd, SM_HUB *r)
+{
+ LVB *b;
+ RPC_ENUM_NAT t;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), r->HubName);
+
+ if (CALL(hWnd, ScEnumNAT(r->Rpc, &t)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ b = LvInsertStart();
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_NAT_ITEM *e = &t.Items[i];
+ wchar_t tmp0[MAX_SIZE];
+ wchar_t *tmp1 = L"";
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t tmp5[MAX_SIZE];
+ wchar_t tmp6[MAX_SIZE];
+ wchar_t tmp7[MAX_SIZE];
+ wchar_t tmp8[MAX_SIZE];
+ wchar_t *tmp9 = L"";
+ char v1[128], v2[128];
+
+ // ID
+ UniToStru(tmp0, e->Id);
+
+ // Protocol
+ switch (e->Protocol)
+ {
+ case NAT_TCP:
+ tmp1 = _UU("NM_NAT_PROTO_TCP");
+ break;
+ case NAT_UDP:
+ tmp1 = _UU("NM_NAT_PROTO_UDP");
+ break;
+ case NAT_DNS:
+ tmp1 = _UU("NM_NAT_PROTO_DNS");
+ break;
+ case NAT_ICMP:
+ tmp1 = _UU("NM_NAT_PROTO_ICMP");
+ break;
+ }
+
+ // Source host
+ StrToUni(tmp2, sizeof(tmp2), e->SrcHost);
+
+ // Source port
+ UniToStru(tmp3, e->SrcPort);
+
+ // Destination host
+ StrToUni(tmp4, sizeof(tmp4), e->DestHost);
+
+ // Destination port
+ UniToStru(tmp5, e->DestPort);
+
+ // Creation date and time of the session
+ GetDateTimeStrEx64(tmp6, sizeof(tmp6), SystemToLocal64(e->CreatedTime), NULL);
+
+ // Last communication date and time
+ GetDateTimeStrEx64(tmp7, sizeof(tmp7), SystemToLocal64(e->LastCommTime), NULL);
+
+ // Communication amount
+ ToStr3(v1, sizeof(v1), e->RecvSize);
+ ToStr3(v2, sizeof(v2), e->SendSize);
+ UniFormat(tmp8, sizeof(tmp8), L"%S / %S", v1, v2);
+
+ // TCP state
+ if (e->Protocol == NAT_TCP)
+ {
+ switch (e->TcpStatus)
+ {
+ case NAT_TCP_CONNECTING:
+ tmp9 = _UU("NAT_TCP_CONNECTING");
+ break;
+ case NAT_TCP_SEND_RESET:
+ tmp9 = _UU("NAT_TCP_SEND_RESET");
+ break;
+ case NAT_TCP_CONNECTED:
+ tmp9 = _UU("NAT_TCP_CONNECTED");
+ break;
+ case NAT_TCP_ESTABLISHED:
+ tmp9 = _UU("NAT_TCP_ESTABLISHED");
+ break;
+ case NAT_TCP_WAIT_DISCONNECT:
+ tmp9 = _UU("NAT_TCP_WAIT_DISCONNECT");
+ break;
+ }
+ }
+
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 10,
+ tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9);
+ }
+
+ LvInsertEnd(b, hWnd, L_TABLE);
+
+ FreeRpcEnumNat(&t);
+}
+
+// NAT enumeration procedure
+UINT NmNatProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_HUB *r = (SM_HUB *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ NmNatInit(hWnd, r);
+ SetTimer(hWnd, 1, NM_NAT_REFRESH_TIME, NULL);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case B_REFRESH:
+ NmNatRefresh(hWnd, r);
+ break;
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+ NmNatRefresh(hWnd, r);
+ SetTimer(hWnd, 1, NM_NAT_REFRESH_TIME, NULL);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_TABLE);
+
+ return 0;
+}
+
+// NAT enumeration
+void NmNat(HWND hWnd, SM_HUB *r)
+{
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_NM_NAT, NmNatProc, r);
+}
+
+// Show the information of the router
+bool NmInfo(HWND hWnd, SM_SERVER *s, void *param)
+{
+ LVB *b;
+ RPC_NAT_INFO t;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+
+ if (CALL(hWnd, NcGetInfo(s->Rpc, &t)) == false)
+ {
+ return false;
+ }
+
+ b = LvInsertStart();
+
+ StrToUni(tmp, sizeof(tmp), t.NatProductName);
+ LvInsertAdd(b, ICO_ROUTER, NULL, 2, _UU("NM_INFO_PRODUCT_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.NatVersionString);
+ LvInsertAdd(b, ICO_INFORMATION, NULL, 2, _UU("NM_INFO_VERSION_STR"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.NatBuildInfoString);
+ LvInsertAdd(b, ICO_INFORMATION, NULL, 2, _UU("NM_INFO_BUILD_INFO"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.NatHostName);
+ LvInsertAdd(b, ICO_TOWER, NULL, 2, _UU("NM_INFO_HOSTNAME"), tmp);
+
+ // OS
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsSystemName);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_SYSTEM_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsProductName);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_PRODUCT_NAME"), tmp);
+
+ if (t.OsInfo.OsServicePack != 0)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SM_OS_SP_TAG"), t.OsInfo.OsServicePack);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_SERVICE_PACK"), tmp);
+ }
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsVendorName);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_VENDER_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsVersion);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_VERSION"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.KernelName);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_KERNEL_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.KernelVersion);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_KERNEL_VERSION"), tmp);
+
+ // Memory information
+ if (t.MemInfo.TotalMemory != 0)
+ {
+ char vv[128];
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.TotalMemory);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_TOTAL_MEMORY"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.UsedMemory);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_USED_MEMORY"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.FreeMemory);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_FREE_MEMORY"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.TotalPhys);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_TOTAL_PHYS"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.UsedPhys);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_USED_PHYS"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.FreePhys);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_FREE_PHYS"), tmp);
+ }
+
+ LvInsertEnd(b, hWnd, L_STATUS);
+
+ FreeRpcNatInfo(&t);
+
+ return true;
+}
+
+// Show the status of the router
+bool NmStatus(HWND hWnd, SM_SERVER *s, void *param)
+{
+ LVB *b;
+ RPC_NAT_STATUS t;
+ wchar_t tmp[MAX_SIZE];
+ SM_HUB *h = (SM_HUB *)param;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), h->HubName);
+
+ if (CALL(hWnd, ScGetSecureNATStatus(s->Rpc, &t)) == false)
+ {
+ return false;
+ }
+
+ b = LvInsertStart();
+
+ StrToUni(tmp, sizeof(tmp), h->HubName);
+ LvInsertAdd(b, ICO_HUB, NULL, 2, _UU("SM_HUB_COLUMN_1"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumTcpSessions);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("NM_STATUS_TCP"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumUdpSessions);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("NM_STATUS_UDP"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumIcmpSessions);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("NM_STATUS_ICMP"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumDnsSessions);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("NM_STATUS_DNS"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_CLIENT"), t.NumDhcpClients);
+ LvInsertAdd(b, ICO_PROTOCOL_DHCP, NULL, 2, _UU("NM_STATUS_DHCP"), tmp);
+
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_SNAT_IS_KERNEL"), t.IsKernelMode ? _UU("SEC_YES") : _UU("SEC_NO"));
+
+ LvInsertEnd(b, hWnd, L_STATUS);
+
+ FreeRpcNatStatus(&t);
+
+ return true;
+}
+
+// Convert the contents of the form to the VH_OPTION
+void NmEditVhOptionFormToVH(HWND hWnd, VH_OPTION *t)
+{
+ char tmp[MAX_SIZE];
+ BUF *b;
+ // Validate arguments
+ if (hWnd == NULL || t == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(VH_OPTION));
+
+ GetTxtA(hWnd, E_MAC, tmp, sizeof(tmp));
+ b = StrToBin(tmp);
+ if (b != NULL)
+ {
+ if (b->Size == 6)
+ {
+ Copy(t->MacAddress, b->Buf, 6);
+ }
+ FreeBuf(b);
+ }
+
+ UINTToIP(&t->Ip, IpGet(hWnd, E_IP));
+ UINTToIP(&t->Mask, IpGet(hWnd, E_MASK));
+
+ t->UseNat = IsChecked(hWnd, R_USE_NAT);
+ t->Mtu = GetInt(hWnd, E_MTU);
+ t->NatTcpTimeout = GetInt(hWnd, E_TCP);
+ t->NatUdpTimeout = GetInt(hWnd, E_UDP);
+
+ t->UseDhcp = IsChecked(hWnd, R_USE_DHCP);
+ UINTToIP(&t->DhcpLeaseIPStart, IpGet(hWnd, E_DHCP_START));
+ UINTToIP(&t->DhcpLeaseIPEnd, IpGet(hWnd, E_DHCP_END));
+ UINTToIP(&t->DhcpSubnetMask, IpGet(hWnd, E_DHCP_MASK));
+ t->DhcpExpireTimeSpan = GetInt(hWnd, E_EXPIRES);
+ UINTToIP(&t->DhcpGatewayAddress, IpGet(hWnd, E_GATEWAY));
+ UINTToIP(&t->DhcpDnsServerAddress, IpGet(hWnd, E_DNS));
+ UINTToIP(&t->DhcpDnsServerAddress2, IpGet(hWnd, E_DNS2));
+ GetTxtA(hWnd, E_DOMAIN, t->DhcpDomainName, sizeof(t->DhcpDomainName));
+ t->SaveLog = IsChecked(hWnd, R_SAVE_LOG);
+}
+
+// Initialize
+void NmEditVhOptionInit(HWND hWnd, SM_HUB *r)
+{
+ char tmp[MAX_SIZE];
+ VH_OPTION t;
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ FormatText(hWnd, S_TITLE, r->HubName);
+
+ Zero(&t, sizeof(VH_OPTION));
+ StrCpy(t.HubName, sizeof(t.HubName), r->HubName);
+ if (CALL(hWnd, ScGetSecureNATOption(r->Rpc, &t)) == false)
+ {
+ EndDialog(hWnd, false);
+ return;
+ }
+
+ if (GetCapsBool(r->p->CapsList, "b_virtual_nat_disabled"))
+ {
+ SetEnable(hWnd, R_USE_NAT, false);
+ Check(hWnd, R_USE_NAT, false);
+ }
+
+ MacToStr(tmp, sizeof(tmp), t.MacAddress);
+ SetTextA(hWnd, E_MAC, tmp);
+ IpSet(hWnd, E_IP, IPToUINT(&t.Ip));
+ IpSet(hWnd, E_MASK, IPToUINT(&t.Mask));
+
+ Check(hWnd, R_USE_NAT, t.UseNat);
+ SetIntEx(hWnd, E_MTU, t.Mtu);
+ SetIntEx(hWnd, E_TCP, t.NatTcpTimeout);
+ SetIntEx(hWnd, E_UDP, t.NatUdpTimeout);
+
+ Check(hWnd, R_USE_DHCP, t.UseDhcp);
+ IpSet(hWnd, E_DHCP_START, IPToUINT(&t.DhcpLeaseIPStart));
+ IpSet(hWnd, E_DHCP_END, IPToUINT(&t.DhcpLeaseIPEnd));
+ IpSet(hWnd, E_DHCP_MASK, IPToUINT(&t.DhcpSubnetMask));
+ SetIntEx(hWnd, E_EXPIRES, t.DhcpExpireTimeSpan);
+
+ if (IPToUINT(&t.DhcpGatewayAddress) != 0)
+ {
+ IpSet(hWnd, E_GATEWAY, IPToUINT(&t.DhcpGatewayAddress));
+ }
+
+ if (IPToUINT(&t.DhcpDnsServerAddress) != 0)
+ {
+ IpSet(hWnd, E_DNS, IPToUINT(&t.DhcpDnsServerAddress));
+ }
+
+ if (IPToUINT(&t.DhcpDnsServerAddress2) != 0)
+ {
+ IpSet(hWnd, E_DNS2, IPToUINT(&t.DhcpDnsServerAddress2));
+ }
+
+ SetTextA(hWnd, E_DOMAIN, t.DhcpDomainName);
+ Check(hWnd, R_SAVE_LOG, t.SaveLog);
+
+ NmEditVhOptionUpdate(hWnd, r);
+
+}
+
+void NmEditVhOptionUpdate(HWND hWnd, SM_HUB *r)
+{
+ VH_OPTION t;
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ NmEditVhOptionFormToVH(hWnd, &t);
+
+ if (IsZero(t.MacAddress, 6))
+ {
+ ok = false;
+ }
+
+ if (IPToUINT(&t.Ip) == 0 || IPToUINT(&t.Mask) == 0)
+ {
+ ok = false;
+ }
+
+ if (IpIsFilled(hWnd, E_IP) == false || IpIsFilled(hWnd, E_MASK) == false)
+ {
+ ok = false;
+ }
+
+ if (IsHostIPAddress4(&t.Ip) == false || IsSubnetMask4(&t.Mask) == false)
+ {
+ ok = false;
+ }
+
+ if (t.UseNat)
+ {
+ if (t.Mtu < 64 || t.Mtu > 1500)
+ {
+ ok = false;
+ }
+
+ if (t.NatTcpTimeout < (NAT_TCP_MIN_TIMEOUT / 1000) || t.NatTcpTimeout > (NAT_TCP_MAX_TIMEOUT / 1000))
+ {
+ ok = false;
+ }
+
+ if (t.NatUdpTimeout < (NAT_UDP_MIN_TIMEOUT / 1000) || t.NatUdpTimeout > (NAT_UDP_MAX_TIMEOUT / 1000))
+ {
+ ok = false;
+ }
+ }
+
+ if (t.UseDhcp)
+ {
+ if (IpIsFilled(hWnd, E_DHCP_START) == false || IpIsFilled(hWnd, E_DHCP_END) == false ||
+ IpIsFilled(hWnd, E_DHCP_MASK) == false)
+ {
+ ok = false;
+ }
+
+ if (IpGetFilledNum(hWnd, E_GATEWAY) != 0 && IpGetFilledNum(hWnd, E_GATEWAY) != 4)
+ {
+ ok = false;
+ }
+
+ if (IpGetFilledNum(hWnd, E_DNS) != 0 && IpGetFilledNum(hWnd, E_DNS) != 4)
+ {
+ ok = false;
+ }
+
+ if (IpGetFilledNum(hWnd, E_DNS2) != 0 && IpGetFilledNum(hWnd, E_DNS2) != 4)
+ {
+ ok = false;
+ }
+
+ if (IPToUINT(&t.DhcpLeaseIPStart) == 0 || IPToUINT(&t.DhcpLeaseIPEnd) == 0 ||
+ IPToUINT(&t.DhcpSubnetMask) == 0)
+ {
+ ok = false;
+ }
+
+ if (t.DhcpExpireTimeSpan < 15)
+ {
+ ok = false;
+ }
+
+ if (Endian32(IPToUINT(&t.DhcpLeaseIPStart)) > Endian32(IPToUINT(&t.DhcpLeaseIPEnd)))
+ {
+ ok = false;
+ }
+
+ if (IsHostIPAddress4(&t.DhcpLeaseIPStart) == false ||
+ IsHostIPAddress4(&t.DhcpLeaseIPEnd) == false)
+ {
+ ok = false;
+ }
+
+ if (IsSubnetMask4(&t.DhcpSubnetMask) == false)
+ {
+ ok = false;
+ }
+ }
+
+ SetEnable(hWnd, E_MTU, t.UseNat);
+ SetEnable(hWnd, E_TCP, t.UseNat);
+ SetEnable(hWnd, E_UDP, t.UseNat);
+
+ SetEnable(hWnd, E_DHCP_START, t.UseDhcp);
+ SetEnable(hWnd, E_DHCP_END, t.UseDhcp);
+ SetEnable(hWnd, E_DHCP_MASK, t.UseDhcp);
+ SetEnable(hWnd, E_EXPIRES, t.UseDhcp);
+ SetEnable(hWnd, E_GATEWAY, t.UseDhcp);
+ SetEnable(hWnd, E_DNS, t.UseDhcp);
+ SetEnable(hWnd, E_DNS2, t.UseDhcp);
+ SetEnable(hWnd, E_DOMAIN, t.UseDhcp);
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// [OK] button
+void NmEditVhOptionOnOk(HWND hWnd, SM_HUB *r)
+{
+ VH_OPTION t;
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ NmEditVhOptionFormToVH(hWnd, &t);
+ StrCpy(t.HubName, sizeof(t.HubName), r->HubName);
+
+ if (CALL(hWnd, ScSetSecureNATOption(r->Rpc, &t)))
+ {
+ EndDialog(hWnd, true);
+ }
+}
+
+// Virtual host options editing dialog
+UINT NmEditVhOptionProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_HUB *r = (SM_HUB *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ NmEditVhOptionInit(hWnd, r);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_MAC:
+ case E_IP:
+ case E_MASK:
+ case R_USE_NAT:
+ case E_MTU:
+ case E_TCP:
+ case E_UDP:
+ case R_SAVE_LOG:
+ case R_USE_DHCP:
+ case E_DHCP_START:
+ case E_DHCP_END:
+ case E_DHCP_MASK:
+ case E_EXPIRES:
+ case E_GATEWAY:
+ case E_DNS:
+ case E_DNS2:
+ case E_DOMAIN:
+ NmEditVhOptionUpdate(hWnd, r);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ NmEditVhOptionOnOk(hWnd, r);
+ break;
+
+ case IDCANCEL:
+ EndDialog(hWnd, false);
+ break;
+
+ case R_USE_NAT:
+ if (IsChecked(hWnd, R_USE_NAT))
+ {
+ FocusEx(hWnd, E_MTU);
+ }
+
+ if (IsChecked(hWnd, R_USE_DHCP))
+ {
+ Focus(hWnd, E_DHCP_START);
+ }
+ break;
+ }
+
+ break;
+ }
+
+ return 0;
+}
+
+// Edit the virtual host option
+void NmEditVhOption(HWND hWnd, SM_HUB *r)
+{
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_NM_OPTION, NmEditVhOptionProc, r);
+}
+
+// Edit the client configuration
+void NmEditClientConfig(HWND hWnd, RPC *r)
+{
+ CM_ACCOUNT a;
+ RPC_CREATE_LINK t;
+ bool ret = false;
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ Zero(&a, sizeof(a));
+ Zero(&t, sizeof(t));
+
+ a.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ a.NatMode = true;
+ a.Rpc = r;
+
+ if (CALLEX(hWnd, NcGetClientConfig(r, &t)) != ERR_NO_ERROR)
+ {
+ // Create New
+ a.ClientOption->Port = 443;
+ a.ClientOption->RetryInterval = 15;
+ a.ClientOption->NumRetry = INFINITE;
+ a.ClientOption->AdditionalConnectionInterval = 1;
+ a.ClientOption->UseEncrypt = true;
+ a.ClientOption->NoRoutingTracking = true;
+ a.ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+ a.ClientAuth->AuthType = CLIENT_AUTHTYPE_PASSWORD;
+ }
+ else
+ {
+ // Edit
+ a.EditMode = true;
+ Copy(a.ClientOption, t.ClientOption, sizeof(CLIENT_OPTION));
+ a.ClientAuth = CopyClientAuth(t.ClientAuth);
+
+ FreeRpcCreateLink(&t);
+ }
+
+ ret = CmEditAccountDlg(hWnd, &a);
+
+ Free(a.ServerCert);
+ Free(a.ClientOption);
+ CiFreeClientAuth(a.ClientAuth);
+}
+
+// Initialize
+void NmMainDlgInit(HWND hWnd, RPC *r)
+{
+ // Validate arguments
+ if (r == NULL || hWnd == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_ROUTER);
+ FormatText(hWnd, 0, r->Sock->RemoteHostname);
+ DlgFont(hWnd, S_STATUS, 11, true);
+
+ NmMainDlgRefresh(hWnd, r);
+}
+
+// Update
+void NmMainDlgRefresh(HWND hWnd, RPC *r)
+{
+#if 0
+ RPC_NAT_STATUS t;
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ // Validate arguments
+ if (r == NULL || hWnd == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(RPC_NAT_STATUS));
+
+ CALL(hWnd, NcGetStatus(r, &t));
+
+ if (t.Online == false)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("NM_OFFLINE"));
+
+ Enable(hWnd, B_CONNECT);
+ Disable(hWnd, B_DISCONNECT);
+ }
+ else
+ {
+ if (t.Connected)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("NM_CONNECTED"), t.Status.ServerName);
+ }
+ else
+ {
+ if (t.LastError == ERR_NO_ERROR)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("NM_CONNECTING"));
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("NM_CONNECT_ERROR"), t.LastError, _E(t.LastError));
+ }
+ }
+ Disable(hWnd, B_CONNECT);
+ Enable(hWnd, B_DISCONNECT);
+ }
+
+ UniFormat(tmp2, sizeof(tmp2), _UU("NM_STATUS_TAG"), tmp);
+
+ SetText(hWnd, S_STATUS, tmp2);
+
+ FreeRpcNatStatus(&t);
+#endif
+}
+
+// Main dialog procedure
+UINT NmMainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+#if 0
+ SM_HUB *r = (SM_HUB *)param;
+ RPC_DUMMY dummy;
+ SM_SERVER sm;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ NmMainDlgInit(hWnd, r);
+
+ SetTimer(hWnd, 1, NM_REFRESH_TIME, NULL);
+
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_SETTING:
+ // Connection setting
+ NmEditClientConfig(hWnd, r);
+ break;
+
+ case B_CONNECT:
+ // Connection
+ Zero(&dummy, sizeof(dummy));
+ CALL(hWnd, NcOnline(r, &dummy));
+ NmMainDlgRefresh(hWnd, r);
+ break;
+
+ case B_DISCONNECT:
+ // Disconnect
+ Zero(&dummy, sizeof(dummy));
+ CALL(hWnd, NcOffline(r, &dummy));
+ NmMainDlgRefresh(hWnd, r);
+ break;
+
+ case B_OPTION:
+ // Operation setting
+ NmEditVhOption(hWnd, r->Rpc);
+ break;
+
+ case B_NAT:
+ // NAT
+ NmNat(hWnd, r);
+ break;
+
+ case B_DHCP:
+ // DHCP
+ NmDhcp(hWnd, r);
+ break;
+
+ case B_STATUS:
+ // Status
+ Zero(&sm, sizeof(sm));
+ sm.Rpc = r;
+ SmStatusDlg(hWnd, &sm, NULL, true, true, _UU("NM_STATUS"), ICO_ROUTER,
+ NULL, NmStatus);
+ break;
+
+ case B_INFO:
+ // Information
+ Zero(&sm, sizeof(sm));
+ sm.Rpc = r;
+ SmStatusDlg(hWnd, &sm, NULL, false, true, _UU("NM_INFO"), ICO_ROUTER,
+ NULL, NmInfo);
+ break;
+
+ case B_REFRESH:
+ // Refresh
+ NmMainDlgRefresh(hWnd, r);
+ break;
+
+ case B_PASSWORD:
+ // Change the password
+ NmChangePassword(hWnd, r);
+ break;
+
+ case B_ABOUT:
+ // Version information
+ About(hWnd, nm->Cedar, CEDAR_ROUTER_STR);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+
+ if (IsEnable(hWnd, 0))
+ {
+ NmMainDlgRefresh(hWnd, r);
+ }
+
+ SetTimer(hWnd, 1, NM_REFRESH_TIME, NULL);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+#endif
+
+ return 0;
+}
+
+// Main dialog
+void NmMainDlg(RPC *r)
+{
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+ Dialog(NULL, D_NM_MAIN, NmMainDlgProc, r);
+}
+
+// Login dialog
+UINT NmLogin(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ NM_LOGIN *login = (NM_LOGIN *)param;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ FormatText(hWnd, S_TITLE, login->Hostname);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ GetTxtA(hWnd, E_PASSWORD, tmp, sizeof(tmp));
+ Hash(login->hashed_password, tmp, StrLen(tmp), true);
+ EndDialog(hWnd, true);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Connecting dialog
+UINT NmConnectDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ NM_CONNECT *t = (NM_CONNECT *)param;
+ RPC *rpc;
+ NM_LOGIN login;
+ UINT err;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ FormatText(hWnd, S_TITLE, t->Hostname);
+ SetTimer(hWnd, 1, 50, NULL);
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+
+ while (true)
+ {
+ bool flag = false;
+RETRY_PASSWORD:
+ // Password input dialog
+ Zero(&login, sizeof(login));
+ login.Hostname = t->Hostname;
+ login.Port = t->Port;
+ Hash(login.hashed_password, "", 0, true);
+
+ if (flag)
+ {
+ if (Dialog(hWnd, D_NM_LOGIN, NmLogin, &login) == false)
+ {
+ EndDialog(hWnd, false);
+ break;
+ }
+ }
+
+RETRY_CONNECT:
+ Refresh(DlgItem(hWnd, S_TITLE));
+ Refresh(hWnd);
+ // Connection
+ rpc = NatAdminConnect(nm->Cedar, t->Hostname, t->Port, login.hashed_password, &err);
+ if (rpc != NULL)
+ {
+ t->Rpc = rpc;
+ EndDialog(hWnd, true);
+ break;
+ }
+
+ // Error
+ if (err == ERR_ACCESS_DENIED || err == ERR_AUTH_FAILED)
+ {
+ if (flag)
+ {
+ if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_RETRYCANCEL,
+ _E(err)) == IDCANCEL)
+ {
+ EndDialog(hWnd, false);
+ break;
+ }
+ }
+ flag = true;
+ goto RETRY_PASSWORD;
+ }
+ else
+ {
+ if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_RETRYCANCEL,
+ _E(err)) == IDCANCEL)
+ {
+ EndDialog(hWnd, false);
+ break;
+ }
+ goto RETRY_CONNECT;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Connect to the User-mode NAT program
+RPC *NmConnect(char *hostname, UINT port)
+{
+ NM_CONNECT t;
+ // Validate arguments
+ if (hostname == NULL || port == 0)
+ {
+ return NULL;
+ }
+
+ Zero(&t, sizeof(t));
+ t.Hostname = hostname;
+ t.Port = port;
+
+ Dialog(NULL, D_NM_CONNECT, NmConnectDlgProc, &t);
+
+ return t.Rpc;
+}
+
+// Main process
+void MainNM()
+{
+ UINT port;
+ char hostname[MAX_HOST_NAME_LEN + 1];
+ char *tmp =
+ RemoteDlg(NULL, NM_SETTING_REG_KEY, ICO_ROUTER,
+ _UU("NM_TITLE"), _UU("NM_CONNECT_TITLE"), NULL);
+ TOKEN_LIST *t;
+
+ Zero(hostname, sizeof(hostname));
+
+ if (tmp == NULL)
+ {
+ return;
+ }
+
+ t = ParseToken(tmp, ":");
+ port = DEFAULT_NAT_ADMIN_PORT;
+
+ if (t->NumTokens >= 2)
+ {
+ UINT i = ToInt(t->Token[1]);
+ if (i != 0)
+ {
+ port = i;
+ }
+ }
+ if (t->NumTokens >= 1)
+ {
+ RPC *rpc;
+ StrCpy(hostname, sizeof(hostname), t->Token[0]);
+
+ // Connection
+ Trim(hostname);
+
+ if (StrLen(hostname) != 0)
+ {
+ rpc = NmConnect(hostname, port);
+ if (rpc != NULL)
+ {
+ // Connected
+ NmMainDlg(rpc);
+ NatAdminDisconnect(rpc);
+ }
+ }
+ }
+
+ FreeToken(t);
+
+ Free(tmp);
+}
+
+// Initialize
+void InitNM()
+{
+ if (nm != NULL)
+ {
+ // Already initialized
+ return;
+ }
+
+ nm = ZeroMalloc(sizeof(NM));
+
+ InitWinUi(_UU("NM_TITLE"), _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+
+ nm->Cedar = NewCedar(NULL, NULL);
+
+ InitCM(false);
+ InitSM();
+}
+
+// Release
+void FreeNM()
+{
+ if (nm == NULL)
+ {
+ // Uninitialized
+ return;
+ }
+
+ FreeSM();
+ FreeCM();
+
+ ReleaseCedar(nm->Cedar);
+
+ FreeWinUi();
+
+ Free(nm);
+ nm = NULL;
+}
+
+// Execution of NM
+void NMExec()
+{
+ InitNM();
+ MainNM();
+ FreeNM();
+}
+
+#endif
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/NM.h b/src/Cedar/NM.h
new file mode 100644
index 00000000..27039ea6
--- /dev/null
+++ b/src/Cedar/NM.h
@@ -0,0 +1,96 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// NM.h
+// Header of NM.c
+
+#ifndef NM_H
+#define NM_H
+
+// External function
+void NMExec();
+
+#endif // NM_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/NMInner.h b/src/Cedar/NMInner.h
new file mode 100644
index 00000000..802172dc
--- /dev/null
+++ b/src/Cedar/NMInner.h
@@ -0,0 +1,148 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// NMInner.h
+// The internal header of NM.c
+
+
+// Constants
+#define NM_REG_KEY "Software\\" GC_REG_COMPANY_NAME "\\PacketiX VPN\\User-mode Router Manager"
+#define NM_SETTING_REG_KEY "Software\\" GC_REG_COMPANY_NAME "\\PacketiX VPN\\User-mode Router Manager\\Settings"
+
+#define NM_REFRESH_TIME 1000
+#define NM_NAT_REFRESH_TIME 1000
+#define NM_DHCP_REFRESH_TIME 1000
+
+// Nat Admin structure
+typedef struct NM
+{
+ CEDAR *Cedar; // Cedar
+} NM;
+
+// Connection structure
+typedef struct NM_CONNECT
+{
+ RPC *Rpc; // RPC
+ char *Hostname;
+ UINT Port;
+} NM_CONNECT;
+
+// Login
+typedef struct NM_LOGIN
+{
+ char *Hostname;
+ UINT Port;
+ UCHAR hashed_password[SHA1_SIZE];
+} NM_LOGIN;
+
+// Internal function
+void InitNM();
+void FreeNM();
+void MainNM();
+RPC *NmConnect(char *hostname, UINT port);
+UINT NmConnectDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+UINT NmLogin(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void NmMainDlg(RPC *r);
+UINT NmMainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void NmMainDlgInit(HWND hWnd, RPC *r);
+void NmMainDlgRefresh(HWND hWnd, RPC *r);
+void NmEditClientConfig(HWND hWnd, RPC *r);
+void NmEditVhOption(HWND hWnd, SM_HUB *r);
+UINT NmEditVhOptionProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void NmEditVhOptionInit(HWND hWnd, SM_HUB *r);
+void NmEditVhOptionUpdate(HWND hWnd, SM_HUB *r);
+void NmEditVhOptionOnOk(HWND hWnd, SM_HUB *r);
+void NmEditVhOptionFormToVH(HWND hWnd, VH_OPTION *t);
+bool NmStatus(HWND hWnd, SM_SERVER *s, void *param);
+bool NmInfo(HWND hWnd, SM_SERVER *s, void *param);
+void NmNat(HWND hWnd, SM_HUB *r);
+UINT NmNatProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void NmNatInit(HWND hWnd, SM_HUB *r);
+void NmNatRefresh(HWND hWnd, SM_HUB *r);
+void NmDhcp(HWND hWnd, SM_HUB *r);
+UINT NmDhcpProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void NmDhcpRefresh(HWND hWnd, SM_HUB *r);
+void NmDhcpInit(HWND hWnd, SM_HUB *r);
+void NmChangePassword(HWND hWnd, RPC *r);
+UINT NmChangePasswordProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Nat.c b/src/Cedar/Nat.c
new file mode 100644
index 00000000..33e6243e
--- /dev/null
+++ b/src/Cedar/Nat.c
@@ -0,0 +1,1876 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Nat.c
+// User-mode Router
+
+#include "CedarPch.h"
+
+static LOCK *nat_lock = NULL;
+static NAT *nat = NULL;
+
+
+// Disconnect the connection for the NAT administrator
+void NatAdminDisconnect(RPC *r)
+{
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+ EndRpc(r);
+}
+
+// Connection for NAT administrator
+RPC *NatAdminConnect(CEDAR *cedar, char *hostname, UINT port, void *hashed_password, UINT *err)
+{
+ UCHAR secure_password[SHA1_SIZE];
+ UCHAR random[SHA1_SIZE];
+ SOCK *sock;
+ RPC *rpc;
+ PACK *p;
+ UINT error;
+ // Validate arguments
+ if (cedar == NULL || hostname == NULL || port == 0 || hashed_password == NULL || err == NULL)
+ {
+ if (err != NULL)
+ {
+ *err = ERR_INTERNAL_ERROR;
+ }
+ return NULL;
+ }
+
+ // Connection
+ sock = Connect(hostname, port);
+ if (sock == NULL)
+ {
+ *err = ERR_CONNECT_FAILED;
+ return NULL;
+ }
+
+ if (StartSSL(sock, NULL, NULL) == false)
+ {
+ *err = ERR_PROTOCOL_ERROR;
+ ReleaseSock(sock);
+ return NULL;
+ }
+
+ SetTimeout(sock, 5000);
+
+ p = HttpClientRecv(sock);
+ if (p == NULL)
+ {
+ *err = ERR_DISCONNECTED;
+ ReleaseSock(sock);
+ return NULL;
+ }
+
+ if (PackGetData2(p, "auth_random", random, SHA1_SIZE) == false)
+ {
+ FreePack(p);
+ *err = ERR_PROTOCOL_ERROR;
+ ReleaseSock(sock);
+ return NULL;
+ }
+
+ FreePack(p);
+
+ SecurePassword(secure_password, hashed_password, random);
+
+ p = NewPack();
+ PackAddData(p, "secure_password", secure_password, SHA1_SIZE);
+
+ if (HttpClientSend(sock, p) == false)
+ {
+ FreePack(p);
+ *err = ERR_DISCONNECTED;
+ ReleaseSock(sock);
+ return NULL;
+ }
+
+ FreePack(p);
+
+ p = HttpClientRecv(sock);
+ if (p == NULL)
+ {
+ *err = ERR_DISCONNECTED;
+ ReleaseSock(sock);
+ return NULL;
+ }
+
+ error = GetErrorFromPack(p);
+
+ FreePack(p);
+
+ if (error != ERR_NO_ERROR)
+ {
+ *err = error;
+ ReleaseSock(sock);
+ return NULL;
+ }
+
+ SetTimeout(sock, TIMEOUT_INFINITE);
+
+ rpc = StartRpcClient(sock, NULL);
+ ReleaseSock(sock);
+
+ return rpc;
+}
+
+// RPC functional related macro
+#define DECLARE_RPC_EX(rpc_name, data_type, function, in_rpc, out_rpc, free_rpc) \
+ else if (StrCmpi(name, rpc_name) == 0) \
+ { \
+ data_type t; \
+ Zero(&t, sizeof(t)); \
+ in_rpc(&t, p); \
+ err = function(n, &t); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ out_rpc(ret, &t); \
+ } \
+ free_rpc(&t); \
+ ok = true; \
+ }
+#define DECLARE_RPC(rpc_name, data_type, function, in_rpc, out_rpc) \
+ else if (StrCmpi(name, rpc_name) == 0) \
+ { \
+ data_type t; \
+ Zero(&t, sizeof(t)); \
+ in_rpc(&t, p); \
+ err = function(n, &t); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ out_rpc(ret, &t); \
+ } \
+ ok = true; \
+ }
+#define DECLARE_SC_EX(rpc_name, data_type, function, in_rpc, out_rpc, free_rpc) \
+ UINT function(RPC *r, data_type *t) \
+ { \
+ PACK *p, *ret; \
+ UINT err; \
+ if (r == NULL || t == NULL) \
+ { \
+ return ERR_INTERNAL_ERROR; \
+ } \
+ p = NewPack(); \
+ out_rpc(p, t); \
+ free_rpc(t); \
+ Zero(t, sizeof(data_type)); \
+ ret = AdminCall(r, rpc_name, p); \
+ err = GetErrorFromPack(ret); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ in_rpc(t, ret); \
+ } \
+ FreePack(ret); \
+ return err; \
+ }
+#define DECLARE_SC(rpc_name, data_type, function, in_rpc, out_rpc) \
+ UINT function(RPC *r, data_type *t) \
+ { \
+ PACK *p, *ret; \
+ UINT err; \
+ if (r == NULL || t == NULL) \
+ { \
+ return ERR_INTERNAL_ERROR; \
+ } \
+ p = NewPack(); \
+ out_rpc(p, t); \
+ ret = AdminCall(r, rpc_name, p); \
+ err = GetErrorFromPack(ret); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ in_rpc(t, ret); \
+ } \
+ FreePack(ret); \
+ return err; \
+ }
+
+// RPC server function
+PACK *NiRpcServer(RPC *r, char *name, PACK *p)
+{
+ NAT *n = (NAT *)r->Param;
+ PACK *ret;
+ UINT err;
+ bool ok;
+ // Validate arguments
+ if (r == NULL || name == NULL || p == NULL)
+ {
+ return NULL;
+ }
+
+ ret = NewPack();
+ err = ERR_NO_ERROR;
+ ok = false;
+
+ if (0) {}
+
+ // RPC function definition: From here
+
+// DECLARE_RPC("Online", RPC_DUMMY, NtOnline, InRpcDummy, OutRpcDummy)
+// DECLARE_RPC("Offline", RPC_DUMMY, NtOffline, InRpcDummy, OutRpcDummy)
+ DECLARE_RPC("SetHostOption", VH_OPTION, NtSetHostOption, InVhOption, OutVhOption)
+ DECLARE_RPC("GetHostOption", VH_OPTION, NtGetHostOption, InVhOption, OutVhOption)
+// DECLARE_RPC_EX("SetClientConfig", RPC_CREATE_LINK, NtSetClientConfig, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+// DECLARE_RPC_EX("GetClientConfig", RPC_CREATE_LINK, NtGetClientConfig, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+ DECLARE_RPC_EX("GetStatus", RPC_NAT_STATUS, NtGetStatus, InRpcNatStatus, OutRpcNatStatus, FreeRpcNatStatus)
+// DECLARE_RPC_EX("GetInfo", RPC_NAT_INFO, NtGetInfo, InRpcNatInfo, OutRpcNatInfo, FreeRpcNatInfo)
+ DECLARE_RPC_EX("EnumNatList", RPC_ENUM_NAT, NtEnumNatList, InRpcEnumNat, OutRpcEnumNat, FreeRpcEnumNat)
+ DECLARE_RPC_EX("EnumDhcpList", RPC_ENUM_DHCP, NtEnumDhcpList, InRpcEnumDhcp, OutRpcEnumDhcp, FreeRpcEnumDhcp)
+// DECLARE_RPC("SetPassword", RPC_SET_PASSWORD, NtSetPassword, InRpcSetPassword, OutRpcSetPassword)
+
+ // RPC function definition: To here
+
+ if (ok == false)
+ {
+ err = ERR_NOT_SUPPORTED;
+ }
+
+ PackAddInt(ret, "error", err);
+
+ return ret;
+}
+
+
+
+
+// RPC call definition: From here
+
+DECLARE_SC("Online", RPC_DUMMY, NcOnline, InRpcDummy, OutRpcDummy)
+DECLARE_SC("Offline", RPC_DUMMY, NcOffline, InRpcDummy, OutRpcDummy)
+DECLARE_SC("SetHostOption", VH_OPTION, NcSetHostOption, InVhOption, OutVhOption)
+DECLARE_SC("GetHostOption", VH_OPTION, NcGetHostOption, InVhOption, OutVhOption)
+DECLARE_SC_EX("SetClientConfig", RPC_CREATE_LINK, NcSetClientConfig, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+DECLARE_SC_EX("GetClientConfig", RPC_CREATE_LINK, NcGetClientConfig, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+DECLARE_SC_EX("GetStatus", RPC_NAT_STATUS, NcGetStatus, InRpcNatStatus, OutRpcNatStatus, FreeRpcNatStatus)
+DECLARE_SC_EX("GetInfo", RPC_NAT_INFO, NcGetInfo, InRpcNatInfo, OutRpcNatInfo, FreeRpcNatInfo)
+DECLARE_SC_EX("EnumNatList", RPC_ENUM_NAT, NcEnumNatList, InRpcEnumNat, OutRpcEnumNat, FreeRpcEnumNat)
+DECLARE_SC_EX("EnumDhcpList", RPC_ENUM_DHCP, NcEnumDhcpList, InRpcEnumDhcp, OutRpcEnumDhcp, FreeRpcEnumDhcp)
+DECLARE_SC("SetPassword", RPC_SET_PASSWORD, NcSetPassword, InRpcSetPassword, OutRpcSetPassword)
+
+// RPC call definition: To here
+
+
+
+// Set a password
+UINT NtSetPassword(NAT *n, RPC_SET_PASSWORD *t)
+{
+ Copy(n->HashedPassword, t->HashedPassword, SHA1_SIZE);
+
+ NiWriteConfig(n);
+
+ return ERR_NO_ERROR;
+}
+
+// Online
+UINT NtOnline(NAT *n, RPC_DUMMY *t)
+{
+ UINT ret = ERR_NO_ERROR;
+
+ Lock(n->lock);
+ {
+ if (n->Online)
+ {
+ // It is already online
+ ret = ERR_ALREADY_ONLINE;
+ }
+ else
+ {
+ if (n->ClientOption == NULL || n->ClientAuth == NULL)
+ {
+ // Setting is not yet done
+ ret = ERR_ACCOUNT_NOT_PRESENT;
+ }
+ else
+ {
+ // OK
+ n->Online = true;
+
+ // Start connection
+ n->Virtual = NewVirtualHostEx(n->Cedar, n->ClientOption, n->ClientAuth,
+ &n->Option, n);
+ }
+ }
+ }
+ Unlock(n->lock);
+
+ NiWriteConfig(n);
+
+ return ret;
+}
+
+// Offline
+UINT NtOffline(NAT *n, RPC_DUMMY *t)
+{
+ UINT ret = ERR_NO_ERROR;
+
+ Lock(n->lock);
+ {
+ if (n->Online == false)
+ {
+ // It is offline
+ ret = ERR_OFFLINE;
+ }
+ else
+ {
+ // Offline
+ StopVirtualHost(n->Virtual);
+ ReleaseVirtual(n->Virtual);
+ n->Virtual = NULL;
+
+ n->Online = false;
+ }
+ }
+ Unlock(n->lock);
+
+ NiWriteConfig(n);
+
+ return ret;
+}
+
+// Set host options
+UINT NtSetHostOption(NAT *n, VH_OPTION *t)
+{
+ UINT ret = ERR_NO_ERROR;
+
+ Lock(n->lock);
+ {
+ Copy(&n->Option, t, sizeof(VH_OPTION));
+ }
+ Unlock(n->lock);
+
+ SetVirtualHostOption(n->Virtual, t);
+
+ NiWriteConfig(n);
+
+ return ret;
+}
+
+// Get host options
+UINT NtGetHostOption(NAT *n, VH_OPTION *t)
+{
+ UINT ret = ERR_NO_ERROR;
+
+ Lock(n->lock);
+ {
+ Copy(t, &n->Option, sizeof(VH_OPTION));
+ }
+ Unlock(n->lock);
+
+ return ret;
+}
+
+// Set the connection settings
+UINT NtSetClientConfig(NAT *n, RPC_CREATE_LINK *t)
+{
+ Lock(n->lock);
+ {
+ if (n->ClientOption != NULL || n->ClientAuth != NULL)
+ {
+ Free(n->ClientOption);
+ CiFreeClientAuth(n->ClientAuth);
+ }
+
+ n->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(n->ClientOption, t->ClientOption, sizeof(CLIENT_OPTION));
+ n->ClientAuth = CopyClientAuth(t->ClientAuth);
+ }
+ Unlock(n->lock);
+
+ NiWriteConfig(n);
+
+ if (n->Online)
+ {
+ NtOffline(n, NULL);
+ NtOnline(n, NULL);
+ }
+
+ return ERR_NO_ERROR;
+}
+
+// Get the connection settings
+UINT NtGetClientConfig(NAT *n, RPC_CREATE_LINK *t)
+{
+ UINT err = ERR_NO_ERROR;
+
+ Lock(n->lock);
+ {
+ if (n->ClientOption == NULL || n->ClientAuth == NULL)
+ {
+ err = ERR_ACCOUNT_NOT_PRESENT;
+ }
+ else
+ {
+ FreeRpcCreateLink(t);
+
+ Zero(t, sizeof(RPC_CREATE_LINK));
+ t->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(t->ClientOption, n->ClientOption, sizeof(CLIENT_OPTION));
+ t->ClientAuth = CopyClientAuth(n->ClientAuth);
+ }
+ }
+ Unlock(n->lock);
+
+ return err;
+}
+
+// Get the state
+UINT NtGetStatus(NAT *n, RPC_NAT_STATUS *t)
+{
+ Lock(n->lock);
+ {
+ VH *v = n->Virtual;
+ FreeRpcNatStatus(t);
+ Zero(t, sizeof(RPC_NAT_STATUS));
+
+ LockVirtual(v);
+ {
+ UINT i;
+
+ LockList(v->NatTable);
+ {
+ for (i = 0;i < LIST_NUM(v->NatTable);i++)
+ {
+ NAT_ENTRY *e = LIST_DATA(v->NatTable, i);
+
+ switch (e->Protocol)
+ {
+ case NAT_TCP:
+ t->NumTcpSessions++;
+ break;
+
+ case NAT_UDP:
+ t->NumUdpSessions++;
+ break;
+
+ case NAT_ICMP:
+ t->NumIcmpSessions++;
+ break;
+
+ case NAT_DNS:
+ t->NumDnsSessions++;
+ break;
+ }
+ }
+
+ if (NnIsActive(v) && v->NativeNat != NULL)
+ {
+ NATIVE_NAT *nn = v->NativeNat;
+
+ for (i = 0;i < LIST_NUM(nn->NatTableForSend->AllList);i++)
+ {
+ NATIVE_NAT_ENTRY *e = LIST_DATA(nn->NatTableForSend->AllList, i);
+
+ switch (e->Protocol)
+ {
+ case NAT_TCP:
+ t->NumTcpSessions++;
+ break;
+
+ case NAT_UDP:
+ t->NumUdpSessions++;
+ break;
+
+ case NAT_ICMP:
+ t->NumIcmpSessions++;
+ break;
+
+ case NAT_DNS:
+ t->NumDnsSessions++;
+ break;
+ }
+ }
+ }
+ }
+ UnlockList(v->NatTable);
+
+ t->NumDhcpClients = LIST_NUM(v->DhcpLeaseList);
+
+ t->IsKernelMode = NnIsActive(v);
+ }
+ UnlockVirtual(v);
+ }
+ Unlock(n->lock);
+
+ return ERR_NO_ERROR;
+}
+
+// Get the information
+UINT NtGetInfo(NAT *n, RPC_NAT_INFO *t)
+{
+ OS_INFO *info;
+ FreeRpcNatInfo(t);
+ Zero(t, sizeof(RPC_NAT_INFO));
+
+ StrCpy(t->NatProductName, sizeof(t->NatProductName), CEDAR_ROUTER_STR);
+ StrCpy(t->NatVersionString, sizeof(t->NatVersionString), n->Cedar->VerString);
+ StrCpy(t->NatBuildInfoString, sizeof(t->NatBuildInfoString), n->Cedar->BuildInfo);
+ t->NatVerInt = n->Cedar->Build;
+ t->NatBuildInt = n->Cedar->Build;
+
+ GetMachineName(t->NatHostName, sizeof(t->NatHostName));
+
+ info = GetOsInfo();
+
+ CopyOsInfo(&t->OsInfo, info);
+
+ GetMemInfo(&t->MemInfo);
+
+ return ERR_NO_ERROR;
+}
+
+// Get the NAT list
+UINT NtEnumNatList(NAT *n, RPC_ENUM_NAT *t)
+{
+ UINT ret = ERR_NO_ERROR;
+ VH *v = NULL;
+
+ Lock(n->lock);
+ {
+ v = n->Virtual;
+
+ if (n->Online == false || v == NULL)
+ {
+ ret = ERR_OFFLINE;
+ }
+ else
+ {
+ LockVirtual(v);
+ {
+ if (v->Active == false)
+ {
+ ret = ERR_OFFLINE;
+ }
+ else
+ {
+ FreeRpcEnumNat(t);
+ Zero(t, sizeof(RPC_ENUM_NAT));
+
+ LockList(v->NatTable);
+ {
+ UINT i;
+ UINT num_usermode_nat = LIST_NUM(v->NatTable);
+ UINT num_kernel_mode_nat = 0;
+ NATIVE_NAT *native = NULL;
+
+ if (NnIsActive(v) && (v->NativeNat != NULL))
+ {
+ native = v->NativeNat;
+
+ num_kernel_mode_nat = LIST_NUM(native->NatTableForSend->AllList);
+ }
+
+ t->NumItem = num_usermode_nat + num_kernel_mode_nat;
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_NAT_ITEM) * t->NumItem);
+
+ // Enumerate entries of the user mode NAT
+ for (i = 0;i < num_usermode_nat;i++)
+ {
+ NAT_ENTRY *nat = LIST_DATA(v->NatTable, i);
+ RPC_ENUM_NAT_ITEM *e = &t->Items[i];
+
+ e->Id = nat->Id;
+ e->Protocol = nat->Protocol;
+ e->SrcIp = nat->SrcIp;
+ e->DestIp = nat->DestIp;
+ e->SrcPort = nat->SrcPort;
+ e->DestPort = nat->DestPort;
+
+ e->CreatedTime = TickToTime(nat->CreatedTime);
+ e->LastCommTime = TickToTime(nat->LastCommTime);
+
+ IPToStr32(e->SrcHost, sizeof(e->SrcHost), e->SrcIp);
+ IPToStr32(e->DestHost, sizeof(e->DestHost), e->DestIp);
+
+ if (nat->Sock != NULL)
+ {
+ e->SendSize = nat->Sock->SendSize;
+ e->RecvSize = nat->Sock->RecvSize;
+
+ if (nat->Sock->Type == SOCK_TCP)
+ {
+ StrCpy(e->DestHost, sizeof(e->DestHost), nat->Sock->RemoteHostname);
+ }
+ }
+
+ e->TcpStatus = nat->TcpStatus;
+ }
+
+ // Enumerate the entries in the kernel-mode NAT
+ if (native != NULL)
+ {
+ for (i = 0;i < num_kernel_mode_nat;i++)
+ {
+ NATIVE_NAT_ENTRY *nat = LIST_DATA(native->NatTableForSend->AllList, i);
+ RPC_ENUM_NAT_ITEM *e = &t->Items[num_usermode_nat + i];
+
+ e->Id = nat->Id;
+ e->Protocol = nat->Protocol;
+ e->SrcIp = nat->SrcIp;
+ e->DestIp = nat->DestIp;
+ e->SrcPort = nat->SrcPort;
+ e->DestPort = nat->DestPort;
+ e->CreatedTime = TickToTime(nat->CreatedTime);
+ e->LastCommTime = TickToTime(nat->LastCommTime);
+
+ IPToStr32(e->SrcHost, sizeof(e->SrcHost), e->SrcIp);
+ IPToStr32(e->DestHost, sizeof(e->DestHost), e->DestIp);
+
+ e->SendSize = nat->TotalSent;
+ e->RecvSize = nat->TotalRecv;
+
+ e->TcpStatus = nat->Status;
+ }
+ }
+ }
+ UnlockList(v->NatTable);
+ }
+ }
+ UnlockVirtual(v);
+ }
+ }
+ Unlock(n->lock);
+
+ return ret;
+}
+
+UINT NtEnumDhcpList(NAT *n, RPC_ENUM_DHCP *t)
+{
+ UINT ret = ERR_NO_ERROR;
+ VH *v = NULL;
+
+ Lock(n->lock);
+ {
+ v = n->Virtual;
+
+ if (n->Online == false || v == NULL)
+ {
+ ret = ERR_OFFLINE;
+ }
+ else
+ {
+ LockVirtual(v);
+ {
+ if (v->Active == false)
+ {
+ ret = ERR_OFFLINE;
+ }
+ else
+ {
+ FreeRpcEnumDhcp(t);
+ Zero(t, sizeof(RPC_ENUM_DHCP));
+
+ LockList(v->DhcpLeaseList);
+ {
+ UINT i;
+ t->NumItem = LIST_NUM(v->DhcpLeaseList);
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_DHCP_ITEM) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ DHCP_LEASE *dhcp = LIST_DATA(v->DhcpLeaseList, i);
+ RPC_ENUM_DHCP_ITEM *e = &t->Items[i];
+
+ e->Id = dhcp->Id;
+ e->LeasedTime = TickToTime(dhcp->LeasedTime);
+ e->ExpireTime = TickToTime(dhcp->ExpireTime);
+ Copy(e->MacAddress, dhcp->MacAddress, 6);
+ e->IpAddress = dhcp->IpAddress;
+ e->Mask = dhcp->Mask;
+ StrCpy(e->Hostname, sizeof(e->Hostname), dhcp->Hostname);
+ }
+ }
+ UnlockList(v->DhcpLeaseList);
+ }
+ }
+ UnlockVirtual(v);
+ }
+ }
+ Unlock(n->lock);
+
+ return ret;
+}
+
+// VH_OPTION
+void InVhOption(VH_OPTION *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(VH_OPTION));
+ PackGetData2(p, "MacAddress", t->MacAddress, 6);
+ PackGetIp(p, "Ip", &t->Ip);
+ PackGetIp(p, "Mask", &t->Mask);
+ t->UseNat = PackGetBool(p, "UseNat");
+ t->Mtu = PackGetInt(p, "Mtu");
+ t->NatTcpTimeout = PackGetInt(p, "NatTcpTimeout");
+ t->NatUdpTimeout = PackGetInt(p, "NatUdpTimeout");
+ t->UseDhcp = PackGetBool(p, "UseDhcp");
+ PackGetIp(p, "DhcpLeaseIPStart", &t->DhcpLeaseIPStart);
+ PackGetIp(p, "DhcpLeaseIPEnd", &t->DhcpLeaseIPEnd);
+ PackGetIp(p, "DhcpSubnetMask", &t->DhcpSubnetMask);
+ t->DhcpExpireTimeSpan = PackGetInt(p, "DhcpExpireTimeSpan");
+ PackGetIp(p, "DhcpGatewayAddress", &t->DhcpGatewayAddress);
+ PackGetIp(p, "DhcpDnsServerAddress", &t->DhcpDnsServerAddress);
+ PackGetIp(p, "DhcpDnsServerAddress2", &t->DhcpDnsServerAddress2);
+ PackGetStr(p, "DhcpDomainName", t->DhcpDomainName, sizeof(t->DhcpDomainName));
+ t->SaveLog = PackGetBool(p, "SaveLog");
+ PackGetStr(p, "RpcHubName", t->HubName, sizeof(t->HubName));
+}
+void OutVhOption(PACK *p, VH_OPTION *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddData(p, "MacAddress", t->MacAddress, 6);
+ PackAddIp(p, "Ip", &t->Ip);
+ PackAddIp(p, "Mask", &t->Mask);
+ PackAddBool(p, "UseNat", t->UseNat);
+ PackAddInt(p, "Mtu", t->Mtu);
+ PackAddInt(p, "NatTcpTimeout", t->NatTcpTimeout);
+ PackAddInt(p, "NatUdpTimeout", t->NatUdpTimeout);
+ PackAddBool(p, "UseDhcp", t->UseDhcp);
+ PackAddIp(p, "DhcpLeaseIPStart", &t->DhcpLeaseIPStart);
+ PackAddIp(p, "DhcpLeaseIPEnd", &t->DhcpLeaseIPEnd);
+ PackAddIp(p, "DhcpSubnetMask", &t->DhcpSubnetMask);
+ PackAddInt(p, "DhcpExpireTimeSpan", t->DhcpExpireTimeSpan);
+ PackAddIp(p, "DhcpGatewayAddress", &t->DhcpGatewayAddress);
+ PackAddIp(p, "DhcpDnsServerAddress", &t->DhcpDnsServerAddress);
+ PackAddIp(p, "DhcpDnsServerAddress2", &t->DhcpDnsServerAddress2);
+ PackAddStr(p, "DhcpDomainName", t->DhcpDomainName);
+ PackAddBool(p, "SaveLog", t->SaveLog);
+ PackAddStr(p, "RpcHubName", t->HubName);
+}
+
+// RPC_ENUM_DHCP
+void InRpcEnumDhcp(RPC_ENUM_DHCP *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_DHCP));
+ t->NumItem = PackGetInt(p, "NumItem");
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_DHCP_ITEM) * t->NumItem);
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_DHCP_ITEM *e = &t->Items[i];
+
+ e->Id = PackGetIntEx(p, "Id", i);
+ e->LeasedTime = PackGetInt64Ex(p, "LeasedTime", i);
+ e->ExpireTime = PackGetInt64Ex(p, "ExpireTime", i);
+ PackGetDataEx2(p, "MacAddress", e->MacAddress, 6, i);
+ e->IpAddress = PackGetIp32Ex(p, "IpAddress", i);
+ e->Mask = PackGetIntEx(p, "Mask", i);
+ PackGetStrEx(p, "Hostname", e->Hostname, sizeof(e->Hostname), i);
+ }
+}
+void OutRpcEnumDhcp(PACK *p, RPC_ENUM_DHCP *t)
+{
+ UINT i;
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+ PackAddStr(p, "HubName", t->HubName);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_DHCP_ITEM *e = &t->Items[i];
+
+ PackAddIntEx(p, "Id", e->Id, i, t->NumItem);
+ PackAddInt64Ex(p, "LeasedTime", e->LeasedTime, i, t->NumItem);
+ PackAddInt64Ex(p, "ExpireTime", e->ExpireTime, i, t->NumItem);
+ PackAddDataEx(p, "MacAddress", e->MacAddress, 6, i, t->NumItem);
+ PackAddIp32Ex(p, "IpAddress", e->IpAddress, i, t->NumItem);
+ PackAddIntEx(p, "Mask", e->Mask, i, t->NumItem);
+ PackAddStrEx(p, "Hostname", e->Hostname, i, t->NumItem);
+ }
+}
+void FreeRpcEnumDhcp(RPC_ENUM_DHCP *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_ENUM_NAT
+void InRpcEnumNat(RPC_ENUM_NAT *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_NAT));
+ t->NumItem = PackGetInt(p, "NumItem");
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_NAT_ITEM) * t->NumItem);
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_NAT_ITEM *e = &t->Items[i];
+
+ e->Id = PackGetIntEx(p, "Id", i);
+ e->Protocol = PackGetIntEx(p, "Protocol", i);
+ e->SrcIp = PackGetIntEx(p, "SrcIp", i);
+ PackGetStrEx(p, "SrcHost", e->SrcHost, sizeof(e->SrcHost), i);
+ e->SrcPort = PackGetIntEx(p, "SrcPort", i);
+ e->DestIp = PackGetIntEx(p, "DestIp", i);
+ PackGetStrEx(p, "DestHost", e->DestHost, sizeof(e->DestHost), i);
+ e->DestPort = PackGetIntEx(p, "DestPort", i);
+ e->CreatedTime = PackGetInt64Ex(p, "CreatedTime", i);
+ e->LastCommTime = PackGetInt64Ex(p, "LastCommTime", i);
+ e->SendSize = PackGetInt64Ex(p, "SendSize", i);
+ e->RecvSize = PackGetInt64Ex(p, "RecvSize", i);
+ e->TcpStatus = PackGetIntEx(p, "TcpStatus", i);
+ }
+}
+void OutRpcEnumNat(PACK *p, RPC_ENUM_NAT *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+ PackAddStr(p, "HubName", t->HubName);
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_NAT_ITEM *e = &t->Items[i];
+
+ PackAddIntEx(p, "Id", e->Id, i, t->NumItem);
+ PackAddIntEx(p, "Protocol", e->Protocol, i, t->NumItem);
+ PackAddIp32Ex(p, "SrcIp", e->SrcIp, i, t->NumItem);
+ PackAddStrEx(p, "SrcHost", e->SrcHost, i, t->NumItem);
+ PackAddIntEx(p, "SrcPort", e->SrcPort, i, t->NumItem);
+ PackAddIp32Ex(p, "DestIp", e->DestIp, i, t->NumItem);
+ PackAddStrEx(p, "DestHost", e->DestHost, i, t->NumItem);
+ PackAddIntEx(p, "DestPort", e->DestPort, i, t->NumItem);
+ PackAddInt64Ex(p, "CreatedTime", e->CreatedTime, i, t->NumItem);
+ PackAddInt64Ex(p, "LastCommTime", e->LastCommTime, i, t->NumItem);
+ PackAddInt64Ex(p, "SendSize", e->SendSize, i, t->NumItem);
+ PackAddInt64Ex(p, "RecvSize", e->RecvSize, i, t->NumItem);
+ PackAddIntEx(p, "TcpStatus", e->TcpStatus, i, t->NumItem);
+ }
+}
+void FreeRpcEnumNat(RPC_ENUM_NAT *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_NAT_INFO
+void InRpcNatInfo(RPC_NAT_INFO *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_NAT_INFO));
+ PackGetStr(p, "NatProductName", t->NatProductName, sizeof(t->NatProductName));
+ PackGetStr(p, "NatVersionString", t->NatVersionString, sizeof(t->NatVersionString));
+ PackGetStr(p, "NatBuildInfoString", t->NatBuildInfoString, sizeof(t->NatBuildInfoString));
+ t->NatVerInt = PackGetInt(p, "NatVerInt");
+ t->NatBuildInt = PackGetInt(p, "NatBuildInt");
+ PackGetStr(p, "NatHostName", t->NatHostName, sizeof(t->NatHostName));
+ InRpcOsInfo(&t->OsInfo, p);
+ InRpcMemInfo(&t->MemInfo, p);
+}
+void OutRpcNatInfo(PACK *p, RPC_NAT_INFO *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "NatProductName", t->NatProductName);
+ PackAddStr(p, "NatVersionString", t->NatVersionString);
+ PackAddStr(p, "NatBuildInfoString", t->NatBuildInfoString);
+ PackAddInt(p, "NatVerInt", t->NatVerInt);
+ PackAddInt(p, "NatBuildInt", t->NatBuildInt);
+ PackAddStr(p, "NatHostName", t->NatHostName);
+ OutRpcOsInfo(p, &t->OsInfo);
+ OutRpcMemInfo(p, &t->MemInfo);
+}
+void FreeRpcNatInfo(RPC_NAT_INFO *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FreeRpcOsInfo(&t->OsInfo);
+}
+
+// RPC_NAT_STATUS
+void InRpcNatStatus(RPC_NAT_STATUS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_NAT_STATUS));
+ t->NumTcpSessions = PackGetInt(p, "NumTcpSessions");
+ t->NumUdpSessions = PackGetInt(p, "NumUdpSessions");
+ t->NumIcmpSessions = PackGetInt(p, "NumIcmpSessions");
+ t->NumDnsSessions = PackGetInt(p, "NumDnsSessions");
+ t->NumDhcpClients = PackGetInt(p, "NumDhcpClients");
+ t->IsKernelMode = PackGetBool(p, "IsKernelMode");
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+}
+void OutRpcNatStatus(PACK *p, RPC_NAT_STATUS *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddInt(p, "NumTcpSessions", t->NumTcpSessions);
+ PackAddInt(p, "NumUdpSessions", t->NumUdpSessions);
+ PackAddInt(p, "NumIcmpSessions", t->NumIcmpSessions);
+ PackAddInt(p, "NumDnsSessions", t->NumDnsSessions);
+ PackAddInt(p, "NumDhcpClients", t->NumDhcpClients);
+ PackAddBool(p, "IsKernelMode", t->IsKernelMode);
+}
+void FreeRpcNatStatus(RPC_NAT_STATUS *t)
+{
+}
+
+// RPC_DUMMY
+void InRpcDummy(RPC_DUMMY *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_DUMMY));
+ t->DummyValue = PackGetInt(p, "DummyValue");
+}
+void OutRpcDummy(PACK *p, RPC_DUMMY *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "DummyValue", t->DummyValue);
+}
+
+// Main procedure for management
+void NiAdminMain(NAT *n, SOCK *s)
+{
+ RPC *r;
+ PACK *p;
+ // Validate arguments
+ if (n == NULL || s == NULL)
+ {
+ return;
+ }
+
+ p = NewPack();
+ HttpServerSend(s, p);
+ FreePack(p);
+
+ r = StartRpcServer(s, NiRpcServer, n);
+
+ RpcServer(r);
+
+ RpcFree(r);
+}
+
+// Management thread
+void NiAdminThread(THREAD *thread, void *param)
+{
+ NAT_ADMIN *a = (NAT_ADMIN *)param;
+ NAT *n;
+ SOCK *s;
+ UCHAR random[SHA1_SIZE];
+ UINT err;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Random number generation
+ Rand(random, sizeof(random));
+
+ a->Thread = thread;
+ AddRef(a->Thread->ref);
+ s = a->Sock;
+ AddRef(s->ref);
+
+ n = a->Nat;
+
+ LockList(n->AdminList);
+ {
+ Add(n->AdminList, a);
+ }
+ UnlockList(n->AdminList);
+
+ NoticeThreadInit(thread);
+
+ err = ERR_AUTH_FAILED;
+
+ if (StartSSL(s, n->AdminX, n->AdminK))
+ {
+ PACK *p;
+
+ // Send the random number
+ p = NewPack();
+ PackAddData(p, "auth_random", random, sizeof(random));
+
+ if (HttpServerSend(s, p))
+ {
+ PACK *p;
+ // Receive a password
+ p = HttpServerRecv(s);
+ if (p != NULL)
+ {
+ UCHAR secure_password[SHA1_SIZE];
+ UCHAR secure_check[SHA1_SIZE];
+
+ if (PackGetData2(p, "secure_password", secure_password, sizeof(secure_password)))
+ {
+ SecurePassword(secure_check, n->HashedPassword, random);
+
+ if (Cmp(secure_check, secure_password, SHA1_SIZE) == 0)
+ {
+ UCHAR test[SHA1_SIZE];
+ // Password match
+ Hash(test, "", 0, true);
+ SecurePassword(test, test, random);
+
+#if 0
+ if (Cmp(test, secure_check, SHA1_SIZE) == 0 && s->RemoteIP.addr[0] != 127)
+ {
+ // A client can not connect from the outside with blank password
+ err = ERR_NULL_PASSWORD_LOCAL_ONLY;
+ }
+ else
+#endif
+
+ {
+ // Successful connection
+ err = ERR_NO_ERROR;
+ NiAdminMain(n, s);
+ }
+ }
+ }
+
+ FreePack(p);
+ }
+ }
+
+ FreePack(p);
+
+ if (err != ERR_NO_ERROR)
+ {
+ p = PackError(err);
+ HttpServerSend(s, p);
+ FreePack(p);
+ }
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+}
+
+// Management port Listen thread
+void NiListenThread(THREAD *thread, void *param)
+{
+ NAT *n = (NAT *)param;
+ SOCK *a;
+ UINT i;
+ bool b = false;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Initialize the management list
+ n->AdminList = NewList(NULL);
+
+ while (true)
+ {
+ a = Listen(DEFAULT_NAT_ADMIN_PORT);
+ if (b == false)
+ {
+ b = true;
+ NoticeThreadInit(thread);
+ }
+ if (a != NULL)
+ {
+ break;
+ }
+
+ Wait(n->HaltEvent, NAT_ADMIN_PORT_LISTEN_INTERVAL);
+ if (n->Halt)
+ {
+ return;
+ }
+ }
+
+ n->AdminListenSock = a;
+ AddRef(a->ref);
+
+ // Waiting
+ while (true)
+ {
+ SOCK *s = Accept(a);
+ THREAD *t;
+ NAT_ADMIN *admin;
+ if (s == NULL)
+ {
+ break;
+ }
+ if (n->Halt)
+ {
+ ReleaseSock(s);
+ break;
+ }
+
+ admin = ZeroMalloc(sizeof(NAT_ADMIN));
+ admin->Nat = n;
+ admin->Sock = s;
+ t = NewThread(NiAdminThread, admin);
+ WaitThreadInit(t);
+ ReleaseThread(t);
+ }
+
+ // Disconnect all management connections
+ LockList(n->AdminList);
+ {
+ for (i = 0;i < LIST_NUM(n->AdminList);i++)
+ {
+ NAT_ADMIN *a = LIST_DATA(n->AdminList, i);
+ Disconnect(a->Sock);
+ WaitThread(a->Thread, INFINITE);
+ ReleaseThread(a->Thread);
+ ReleaseSock(a->Sock);
+ Free(a);
+ }
+ }
+ UnlockList(n->AdminList);
+
+ ReleaseList(n->AdminList);
+
+ ReleaseSock(a);
+}
+
+// Initialize receiving management command
+void NiInitAdminAccept(NAT *n)
+{
+ THREAD *t;
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ t = NewThread(NiListenThread, n);
+ WaitThreadInit(t);
+ n->AdminAcceptThread = t;
+}
+
+// Complete receiving management command
+void NiFreeAdminAccept(NAT *n)
+{
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ n->Halt = true;
+ Disconnect(n->AdminListenSock);
+ Set(n->HaltEvent);
+
+ while (true)
+ {
+ if (WaitThread(n->AdminAcceptThread, 1000) == false)
+ {
+ Disconnect(n->AdminListenSock);
+ }
+ else
+ {
+ break;
+ }
+ }
+ ReleaseThread(n->AdminAcceptThread);
+
+ ReleaseSock(n->AdminListenSock);
+}
+
+// Clear the DHCP options that are not supported by the dynamic Virtual HUB
+void NiClearUnsupportedVhOptionForDynamicHub(VH_OPTION *o, bool initial)
+{
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ o->UseNat = false;
+
+ if (initial)
+ {
+ Zero(&o->DhcpGatewayAddress, sizeof(IP));
+ Zero(&o->DhcpDnsServerAddress, sizeof(IP));
+ Zero(&o->DhcpDnsServerAddress2, sizeof(IP));
+ StrCpy(o->DhcpDomainName, sizeof(o->DhcpDomainName), "");
+ }
+}
+
+// Initialize the options for the virtual host
+void NiSetDefaultVhOption(NAT *n, VH_OPTION *o)
+{
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ Zero(o, sizeof(VH_OPTION));
+ GenMacAddress(o->MacAddress);
+
+ // Set the virtual IP to 192.168.30.1/24
+ SetIP(&o->Ip, 192, 168, 30, 1);
+ SetIP(&o->Mask, 255, 255, 255, 0);
+ o->UseNat = true;
+ o->Mtu = 1500;
+ o->NatTcpTimeout = 1800;
+ o->NatUdpTimeout = 60;
+ o->UseDhcp = true;
+ SetIP(&o->DhcpLeaseIPStart, 192, 168, 30, 10);
+ SetIP(&o->DhcpLeaseIPEnd, 192, 168, 30, 200);
+ SetIP(&o->DhcpSubnetMask, 255, 255, 255, 0);
+ o->DhcpExpireTimeSpan = 7200;
+ o->SaveLog = true;
+
+ SetIP(&o->DhcpGatewayAddress, 192, 168, 30, 1);
+ SetIP(&o->DhcpDnsServerAddress, 192, 168, 30, 1);
+
+ GetDomainName(o->DhcpDomainName, sizeof(o->DhcpDomainName));
+}
+
+// Reset the setting of NAT to the default
+void NiInitDefaultConfig(NAT *n)
+{
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ // Initialize the virtual host option
+ NiSetDefaultVhOption(n, &n->Option);
+
+ // Initialize management port
+ n->AdminPort = DEFAULT_NAT_ADMIN_PORT;
+
+ // Offline
+ n->Online = false;
+
+ // Save the log
+ n->Option.SaveLog = true;
+}
+
+// Initialize the NAT configuration
+void NiInitConfig(NAT *n)
+{
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ // Initial state
+ NiInitDefaultConfig(n);
+}
+
+// Read the virtual host option (extended)
+void NiLoadVhOptionEx(VH_OPTION *o, FOLDER *root)
+{
+ FOLDER *host, *nat, *dhcp;
+ char mac_address[MAX_SIZE];
+ // Validate arguments
+ if (o == NULL || root == NULL)
+ {
+ return;
+ }
+
+ host = CfgGetFolder(root, "VirtualHost");
+ nat = CfgGetFolder(root, "VirtualRouter");
+ dhcp = CfgGetFolder(root, "VirtualDhcpServer");
+
+ Zero(o, sizeof(VH_OPTION));
+
+ GenMacAddress(o->MacAddress);
+ if (CfgGetStr(host, "VirtualHostMacAddress", mac_address, sizeof(mac_address)))
+ {
+ BUF *b = StrToBin(mac_address);
+ if (b != NULL)
+ {
+ if (b->Size == 6)
+ {
+ Copy(o->MacAddress, b->Buf, 6);
+ }
+ }
+ FreeBuf(b);
+ }
+ CfgGetIp(host, "VirtualHostIp", &o->Ip);
+ CfgGetIp(host, "VirtualHostIpSubnetMask", &o->Mask);
+
+ o->UseNat = CfgGetBool(nat, "NatEnabled");
+ o->Mtu = CfgGetInt(nat, "NatMtu");
+ o->NatTcpTimeout = CfgGetInt(nat, "NatTcpTimeout");
+ o->NatUdpTimeout = CfgGetInt(nat, "NatUdpTimeout");
+
+ o->UseDhcp = CfgGetBool(dhcp, "DhcpEnabled");
+ CfgGetIp(dhcp, "DhcpLeaseIPStart", &o->DhcpLeaseIPStart);
+ CfgGetIp(dhcp, "DhcpLeaseIPEnd", &o->DhcpLeaseIPEnd);
+ CfgGetIp(dhcp, "DhcpSubnetMask", &o->DhcpSubnetMask);
+ o->DhcpExpireTimeSpan = CfgGetInt(dhcp, "DhcpExpireTimeSpan");
+ CfgGetIp(dhcp, "DhcpGatewayAddress", &o->DhcpGatewayAddress);
+ CfgGetIp(dhcp, "DhcpDnsServerAddress", &o->DhcpDnsServerAddress);
+ CfgGetIp(dhcp, "DhcpDnsServerAddress2", &o->DhcpDnsServerAddress2);
+ CfgGetStr(dhcp, "DhcpDomainName", o->DhcpDomainName, sizeof(o->DhcpDomainName));
+
+ Trim(o->DhcpDomainName);
+ if (StrLen(o->DhcpDomainName) == 0)
+ {
+ //GetDomainName(o->DhcpDomainName, sizeof(o->DhcpDomainName));
+ }
+
+ o->SaveLog = CfgGetBool(root, "SaveLog");
+}
+
+// Read the virtual host option
+void NiLoadVhOption(NAT *n, FOLDER *root)
+{
+ VH_OPTION *o;
+ FOLDER *host, *nat, *dhcp;
+ char mac_address[MAX_SIZE];
+ // Validate arguments
+ if (n == NULL || root == NULL)
+ {
+ return;
+ }
+
+ host = CfgGetFolder(root, "VirtualHost");
+ nat = CfgGetFolder(root, "VirtualRouter");
+ dhcp = CfgGetFolder(root, "VirtualDhcpServer");
+
+ o = &n->Option;
+ Zero(o, sizeof(VH_OPTION));
+
+ GenMacAddress(o->MacAddress);
+ if (CfgGetStr(host, "VirtualHostMacAddress", mac_address, sizeof(mac_address)))
+ {
+ BUF *b = StrToBin(mac_address);
+ if (b != NULL)
+ {
+ if (b->Size == 6)
+ {
+ Copy(o->MacAddress, b->Buf, 6);
+ }
+ }
+ FreeBuf(b);
+ }
+ CfgGetIp(host, "VirtualHostIp", &o->Ip);
+ CfgGetIp(host, "VirtualHostIpSubnetMask", &o->Mask);
+
+ o->UseNat = CfgGetBool(nat, "NatEnabled");
+ o->Mtu = CfgGetInt(nat, "NatMtu");
+ o->NatTcpTimeout = CfgGetInt(nat, "NatTcpTimeout");
+ o->NatUdpTimeout = CfgGetInt(nat, "NatUdpTimeout");
+
+ o->UseDhcp = CfgGetBool(dhcp, "DhcpEnabled");
+ CfgGetIp(dhcp, "DhcpLeaseIPStart", &o->DhcpLeaseIPStart);
+ CfgGetIp(dhcp, "DhcpLeaseIPEnd", &o->DhcpLeaseIPEnd);
+ CfgGetIp(dhcp, "DhcpSubnetMask", &o->DhcpSubnetMask);
+ o->DhcpExpireTimeSpan = CfgGetInt(dhcp, "DhcpExpireTimeSpan");
+ CfgGetIp(dhcp, "DhcpGatewayAddress", &o->DhcpGatewayAddress);
+ CfgGetIp(dhcp, "DhcpDnsServerAddress", &o->DhcpDnsServerAddress);
+ CfgGetIp(dhcp, "DhcpDnsServerAddress2", &o->DhcpDnsServerAddress2);
+ CfgGetStr(dhcp, "DhcpDomainName", o->DhcpDomainName, sizeof(o->DhcpDomainName));
+
+ o->SaveLog = CfgGetBool(root, "SaveLog");
+}
+
+// Read connection options from the VPN server
+void NiLoadClientData(NAT *n, FOLDER *root)
+{
+ FOLDER *co, *ca;
+ // Validate arguments
+ if (n == NULL || root == NULL)
+ {
+ return;
+ }
+
+ co = CfgGetFolder(root, "VpnClientOption");
+ ca = CfgGetFolder(root, "VpnClientAuth");
+ if (co == NULL || ca == NULL)
+ {
+ return;
+ }
+
+ n->ClientOption = CiLoadClientOption(co);
+ n->ClientAuth = CiLoadClientAuth(ca);
+}
+
+// Write connection options to the VPN server
+void NiWriteClientData(NAT *n, FOLDER *root)
+{
+ // Validate arguments
+ if (n == NULL || root == NULL || n->ClientOption == NULL || n->ClientAuth == NULL)
+ {
+ return;
+ }
+
+ CiWriteClientOption(CfgCreateFolder(root, "VpnClientOption"), n->ClientOption);
+ CiWriteClientAuth(CfgCreateFolder(root, "VpnClientAuth"), n->ClientAuth);
+}
+
+// Write the virtual host option (extended)
+void NiWriteVhOptionEx(VH_OPTION *o, FOLDER *root)
+{
+ FOLDER *host, *nat, *dhcp;
+ char mac_address[MAX_SIZE];
+ // Validate arguments
+ if (o == NULL || root == NULL)
+ {
+ return;
+ }
+
+ host = CfgCreateFolder(root, "VirtualHost");
+ nat = CfgCreateFolder(root, "VirtualRouter");
+ dhcp = CfgCreateFolder(root, "VirtualDhcpServer");
+
+ MacToStr(mac_address, sizeof(mac_address), o->MacAddress);
+ CfgAddStr(host, "VirtualHostMacAddress", mac_address);
+ CfgAddIp(host, "VirtualHostIp", &o->Ip);
+ CfgAddIp(host, "VirtualHostIpSubnetMask", &o->Mask);
+
+ CfgAddBool(nat, "NatEnabled", o->UseNat);
+ CfgAddInt(nat, "NatMtu", o->Mtu);
+ CfgAddInt(nat, "NatTcpTimeout", o->NatTcpTimeout);
+ CfgAddInt(nat, "NatUdpTimeout", o->NatUdpTimeout);
+
+ CfgAddBool(dhcp, "DhcpEnabled", o->UseDhcp);
+ CfgAddIp(dhcp, "DhcpLeaseIPStart", &o->DhcpLeaseIPStart);
+ CfgAddIp(dhcp, "DhcpLeaseIPEnd", &o->DhcpLeaseIPEnd);
+ CfgAddIp(dhcp, "DhcpSubnetMask", &o->DhcpSubnetMask);
+ CfgAddInt(dhcp, "DhcpExpireTimeSpan", o->DhcpExpireTimeSpan);
+ CfgAddIp(dhcp, "DhcpGatewayAddress", &o->DhcpGatewayAddress);
+ CfgAddIp(dhcp, "DhcpDnsServerAddress", &o->DhcpDnsServerAddress);
+ CfgAddIp(dhcp, "DhcpDnsServerAddress2", &o->DhcpDnsServerAddress2);
+ CfgAddStr(dhcp, "DhcpDomainName", o->DhcpDomainName);
+
+ CfgAddBool(root, "SaveLog", o->SaveLog);
+}
+
+// Write the virtual host option
+void NiWriteVhOption(NAT *n, FOLDER *root)
+{
+ VH_OPTION *o;
+ FOLDER *host, *nat, *dhcp;
+ char mac_address[MAX_SIZE];
+ // Validate arguments
+ if (n == NULL || root == NULL)
+ {
+ return;
+ }
+
+ host = CfgCreateFolder(root, "VirtualHost");
+ nat = CfgCreateFolder(root, "VirtualRouter");
+ dhcp = CfgCreateFolder(root, "VirtualDhcpServer");
+
+ o = &n->Option;
+
+ MacToStr(mac_address, sizeof(mac_address), o->MacAddress);
+ CfgAddStr(host, "VirtualHostMacAddress", mac_address);
+ CfgAddIp(host, "VirtualHostIp", &o->Ip);
+ CfgAddIp(host, "VirtualHostIpSubnetMask", &o->Mask);
+
+ CfgAddBool(nat, "NatEnabled", o->UseNat);
+ CfgAddInt(nat, "NatMtu", o->Mtu);
+ CfgAddInt(nat, "NatTcpTimeout", o->NatTcpTimeout);
+ CfgAddInt(nat, "NatUdpTimeout", o->NatUdpTimeout);
+
+ CfgAddBool(dhcp, "DhcpEnabled", o->UseDhcp);
+ CfgAddIp(dhcp, "DhcpLeaseIPStart", &o->DhcpLeaseIPStart);
+ CfgAddIp(dhcp, "DhcpLeaseIPEnd", &o->DhcpLeaseIPEnd);
+ CfgAddIp(dhcp, "DhcpSubnetMask", &o->DhcpSubnetMask);
+ CfgAddInt(dhcp, "DhcpExpireTimeSpan", o->DhcpExpireTimeSpan);
+ CfgAddIp(dhcp, "DhcpGatewayAddress", &o->DhcpGatewayAddress);
+ CfgAddIp(dhcp, "DhcpDnsServerAddress", &o->DhcpDnsServerAddress);
+ CfgAddIp(dhcp, "DhcpDnsServerAddress2", &o->DhcpDnsServerAddress2);
+ CfgAddStr(dhcp, "DhcpDomainName", o->DhcpDomainName);
+
+ CfgAddBool(root, "SaveLog", o->SaveLog);
+}
+
+// Read the configuration file
+bool NiLoadConfig(NAT *n, FOLDER *root)
+{
+ FOLDER *host;
+ BUF *b;
+ // Validate arguments
+ if (n == NULL || root == NULL)
+ {
+ return false;
+ }
+
+ host = CfgGetFolder(root, "VirtualHost");
+ if (host == NULL)
+ {
+ return false;
+ }
+
+ CfgGetByte(root, "HashedPassword", n->HashedPassword, sizeof(n->HashedPassword));
+ n->AdminPort = CfgGetInt(root, "AdminPort");
+ n->Online = CfgGetBool(root, "Online");
+
+ b = CfgGetBuf(root, "AdminCert");
+ if (b != NULL)
+ {
+ n->AdminX = BufToX(b, false);
+ FreeBuf(b);
+ }
+
+ b = CfgGetBuf(root, "AdminKey");
+ if (b != NULL)
+ {
+ n->AdminK = BufToK(b, true, false, NULL);
+ FreeBuf(b);
+ }
+
+ NiLoadVhOption(n, root);
+
+ NiLoadClientData(n, root);
+
+ return true;
+}
+
+// Write the configuration to a file
+void NiWriteConfig(NAT *n)
+{
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ Lock(n->lock);
+ {
+ FOLDER *root = CfgCreateFolder(NULL, TAG_ROOT);
+ BUF *b;
+
+ // Certificate
+ b = XToBuf(n->AdminX, false);
+ CfgAddBuf(root, "AdminCert", b);
+ FreeBuf(b);
+
+ // Secret key
+ b = KToBuf(n->AdminK, false, NULL);
+ CfgAddBuf(root, "AdminKey", b);
+ FreeBuf(b);
+
+ // Password
+ CfgAddByte(root, "HashedPassword", n->HashedPassword, sizeof(n->HashedPassword));
+ CfgAddInt(root, "AdminPort", n->AdminPort);
+ CfgAddBool(root, "Online", n->Online);
+
+ // Virtual host option
+ NiWriteVhOption(n, root);
+
+ // Connection options
+ if (n->ClientOption != NULL && n->ClientAuth != NULL)
+ {
+ NiWriteClientData(n, root);
+ }
+
+ SaveCfgRw(n->CfgRw, root);
+ CfgDeleteFolder(root);
+ }
+ Unlock(n->lock);
+}
+
+// Release the NAT configuration
+void NiFreeConfig(NAT *n)
+{
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ // Write the latest configuration
+ NiWriteConfig(n);
+
+ // Release the configuration R/W
+ FreeCfgRw(n->CfgRw);
+ n->CfgRw = NULL;
+
+ Free(n->ClientOption);
+ CiFreeClientAuth(n->ClientAuth);
+
+ FreeX(n->AdminX);
+ FreeK(n->AdminK);
+}
+
+// Create a NAT
+NAT *NiNewNatEx(SNAT *snat, VH_OPTION *o)
+{
+ NAT *n = ZeroMalloc(sizeof(NAT));
+
+ n->lock = NewLock();
+ Hash(n->HashedPassword, "", 0, true);
+ n->HaltEvent = NewEvent();
+
+ //n->Cedar = NewCedar(NULL, NULL);
+
+ n->SecureNAT = snat;
+
+ // Raise the priority
+ //OSSetHighPriority();
+
+ // Initialize the settings
+ NiInitConfig(n);
+
+#if 0
+ // Start the operation of the virtual host
+ if (n->Online && n->ClientOption != NULL)
+ {
+ n->Virtual = NewVirtualHostEx(n->Cedar, n->ClientOption, n->ClientAuth, &n->Option, n);
+ }
+ else
+ {
+ n->Online = false;
+ n->Virtual = NULL;
+ }
+#else
+ n->Virtual = NewVirtualHostEx(n->Cedar, NULL, NULL, o, n);
+ n->Online = true;
+#endif
+
+ // Start management command
+ //NiInitAdminAccept(n);
+
+ return n;
+}
+NAT *NiNewNat()
+{
+ return NiNewNatEx(NULL, NULL);
+}
+
+// Release the NAT
+void NiFreeNat(NAT *n)
+{
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ // Complete management command
+ //NiFreeAdminAccept(n);
+
+ // Stop if the virtual host is running
+ Lock(n->lock);
+ {
+ if (n->Virtual != NULL)
+ {
+ StopVirtualHost(n->Virtual);
+ ReleaseVirtual(n->Virtual);
+ n->Virtual = NULL;
+ }
+ }
+ Unlock(n->lock);
+
+ // Release the settings
+ NiFreeConfig(n);
+
+ // Delete the object
+ ReleaseCedar(n->Cedar);
+ ReleaseEvent(n->HaltEvent);
+ DeleteLock(n->lock);
+
+ Free(n);
+}
+
+// Stop the NAT
+void NtStopNat()
+{
+ Lock(nat_lock);
+ {
+ if (nat != NULL)
+ {
+ NiFreeNat(nat);
+ nat = NULL;
+ }
+ }
+ Unlock(nat_lock);
+}
+
+// Start the NAT
+void NtStartNat()
+{
+ Lock(nat_lock);
+ {
+ if (nat == NULL)
+ {
+ nat = NiNewNat();
+ }
+ }
+ Unlock(nat_lock);
+}
+
+// Initialize the NtXxx function
+void NtInit()
+{
+ if (nat_lock != NULL)
+ {
+ return;
+ }
+
+ nat_lock = NewLock();
+}
+
+// Release the NtXxx function
+void NtFree()
+{
+ if (nat_lock == NULL)
+ {
+ return;
+ }
+
+ DeleteLock(nat_lock);
+ nat_lock = NULL;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Nat.h b/src/Cedar/Nat.h
new file mode 100644
index 00000000..60a865ea
--- /dev/null
+++ b/src/Cedar/Nat.h
@@ -0,0 +1,291 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Nat.h
+// Header of Nat.c
+
+#ifndef NAT_H
+#define NAT_H
+
+// Constants
+#define NAT_CONFIG_FILE_NAME "@vpn_router.config" // NAT configuration file
+#define DEFAULT_NAT_ADMIN_PORT 2828 // Default port number for management
+#define NAT_ADMIN_PORT_LISTEN_INTERVAL 1000 // Interval for trying to open a port for management
+#define NAT_FILE_SAVE_INTERVAL (30 * 1000) // Interval to save
+
+
+// NAT object
+struct NAT
+{
+ LOCK *lock; // Lock
+ UCHAR HashedPassword[SHA1_SIZE]; // Administrative password
+ VH_OPTION Option; // Option
+ CEDAR *Cedar; // Cedar
+ UINT AdminPort; // Management port number
+ bool Online; // Online flag
+ VH *Virtual; // Virtual host object
+ CLIENT_OPTION *ClientOption; // Client Option
+ CLIENT_AUTH *ClientAuth; // Client authentication data
+ CFG_RW *CfgRw; // Config file R/W
+ THREAD *AdminAcceptThread; // Management connection reception thread
+ SOCK *AdminListenSock; // Management port socket
+ EVENT *HaltEvent; // Halting event
+ volatile bool Halt; // Halting flag
+ LIST *AdminList; // Management thread list
+ X *AdminX; // Server certificate for management
+ K *AdminK; // Server private key for management
+ SNAT *SecureNAT; // SecureNAT object
+};
+
+// NAT management connection
+struct NAT_ADMIN
+{
+ NAT *Nat; // NAT
+ SOCK *Sock; // Socket
+ THREAD *Thread; // Thread
+};
+
+// RPC_DUMMY
+struct RPC_DUMMY
+{
+ UINT DummyValue;
+};
+
+// RPC_NAT_STATUS
+struct RPC_NAT_STATUS
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB name
+ UINT NumTcpSessions; // Number of TCP sessions
+ UINT NumUdpSessions; // Ntmber of UDP sessions
+ UINT NumIcmpSessions; // Nymber of ICMP sessions
+ UINT NumDnsSessions; // Number of DNS sessions
+ UINT NumDhcpClients; // Number of DHCP clients
+ bool IsKernelMode; // Whether kernel mode
+};
+
+// RPC_NAT_INFO *
+struct RPC_NAT_INFO
+{
+ char NatProductName[128]; // Server product name
+ char NatVersionString[128]; // Server version string
+ char NatBuildInfoString[128]; // Server build information string
+ UINT NatVerInt; // Server version integer value
+ UINT NatBuildInt; // Server build number integer value
+ char NatHostName[MAX_HOST_NAME_LEN + 1]; // Server host name
+ OS_INFO OsInfo; // OS information
+ MEMINFO MemInfo; // Memory information
+};
+
+// RPC_ENUM_NAT_ITEM
+struct RPC_ENUM_NAT_ITEM
+{
+ UINT Id; // ID
+ UINT Protocol; // Protocol
+ UINT SrcIp; // Source IP address
+ char SrcHost[MAX_HOST_NAME_LEN + 1]; // Source host name
+ UINT SrcPort; // Source port number
+ UINT DestIp; // Destination IP address
+ char DestHost[MAX_HOST_NAME_LEN + 1]; // Destination host name
+ UINT DestPort; // Destination port number
+ UINT64 CreatedTime; // Connection time
+ UINT64 LastCommTime; // Last communication time
+ UINT64 SendSize; // Transmission size
+ UINT64 RecvSize; // Receive size
+ UINT TcpStatus; // TCP state
+};
+
+// RPC_ENUM_NAT *
+struct RPC_ENUM_NAT
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB name
+ UINT NumItem; // Number of items
+ RPC_ENUM_NAT_ITEM *Items; // Item
+};
+
+// RPC_ENUM_DHCP_ITEM
+struct RPC_ENUM_DHCP_ITEM
+{
+ UINT Id; // ID
+ UINT64 LeasedTime; // Lease time
+ UINT64 ExpireTime; // Expiration date
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2]; // Padding
+ UINT IpAddress; // IP address
+ UINT Mask; // Subnet mask
+ char Hostname[MAX_HOST_NAME_LEN + 1]; // Host name
+};
+
+// RPC_ENUM_DHCP *
+struct RPC_ENUM_DHCP
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB name
+ UINT NumItem; // Number of items
+ RPC_ENUM_DHCP_ITEM *Items; // Item
+};
+
+
+// Function prototype
+NAT *NiNewNat();
+NAT *NiNewNatEx(SNAT *snat, VH_OPTION *o);
+void NiFreeNat(NAT *n);
+void NiInitConfig(NAT *n);
+void NiFreeConfig(NAT *n);
+void NiInitDefaultConfig(NAT *n);
+void NiSetDefaultVhOption(NAT *n, VH_OPTION *o);
+void NiClearUnsupportedVhOptionForDynamicHub(VH_OPTION *o, bool initial);
+void NiWriteConfig(NAT *n);
+void NiWriteVhOption(NAT *n, FOLDER *root);
+void NiWriteVhOptionEx(VH_OPTION *o, FOLDER *root);
+void NiWriteClientData(NAT *n, FOLDER *root);
+void NiLoadVhOption(NAT *n, FOLDER *root);
+void NiLoadVhOptionEx(VH_OPTION *o, FOLDER *root);
+bool NiLoadConfig(NAT *n, FOLDER *root);
+void NiLoadClientData(NAT *n, FOLDER *root);
+void NiInitAdminAccept(NAT *n);
+void NiFreeAdminAccept(NAT *n);
+void NiListenThread(THREAD *thread, void *param);
+void NiAdminThread(THREAD *thread, void *param);
+void NiAdminMain(NAT *n, SOCK *s);
+PACK *NiRpcServer(RPC *r, char *name, PACK *p);
+
+RPC *NatAdminConnect(CEDAR *cedar, char *hostname, UINT port, void *hashed_password, UINT *err);
+void NatAdminDisconnect(RPC *r);
+
+void NtStartNat();
+void NtStopNat();
+void NtInit();
+void NtFree();
+
+
+UINT NtOnline(NAT *n, RPC_DUMMY *t);
+UINT NtOffline(NAT *n, RPC_DUMMY *t);
+UINT NtSetHostOption(NAT *n, VH_OPTION *t);
+UINT NtGetHostOption(NAT *n, VH_OPTION *t);
+UINT NtSetClientConfig(NAT *n, RPC_CREATE_LINK *t);
+UINT NtGetClientConfig(NAT *n, RPC_CREATE_LINK *t);
+UINT NtGetStatus(NAT *n, RPC_NAT_STATUS *t);
+UINT NtGetInfo(NAT *n, RPC_NAT_INFO *t);
+UINT NtEnumNatList(NAT *n, RPC_ENUM_NAT *t);
+UINT NtEnumDhcpList(NAT *n, RPC_ENUM_DHCP *t);
+UINT NtSetPassword(NAT *n, RPC_SET_PASSWORD *t);
+
+
+UINT NcOnline(RPC *r, RPC_DUMMY *t);
+UINT NcOffline(RPC *r, RPC_DUMMY *t);
+UINT NcSetHostOption(RPC *r, VH_OPTION *t);
+UINT NcGetHostOption(RPC *r, VH_OPTION *t);
+UINT NcSetClientConfig(RPC *r, RPC_CREATE_LINK *t);
+UINT NcGetClientConfig(RPC *r, RPC_CREATE_LINK *t);
+UINT NcGetStatus(RPC *r, RPC_NAT_STATUS *t);
+UINT NcGetInfo(RPC *r, RPC_NAT_INFO *t);
+UINT NcEnumNatList(RPC *r, RPC_ENUM_NAT *t);
+UINT NcEnumDhcpList(RPC *r, RPC_ENUM_DHCP *t);
+UINT NcSetPassword(RPC *r, RPC_SET_PASSWORD *t);
+
+
+
+
+void InRpcEnumDhcp(RPC_ENUM_DHCP *t, PACK *p);
+void OutRpcEnumDhcp(PACK *p, RPC_ENUM_DHCP *t);
+void FreeRpcEnumDhcp(RPC_ENUM_DHCP *t);
+void InRpcEnumNat(RPC_ENUM_NAT *t, PACK *p);
+void OutRpcEnumNat(PACK *p, RPC_ENUM_NAT *t);
+void FreeRpcEnumNat(RPC_ENUM_NAT *t);
+void InRpcNatInfo(RPC_NAT_INFO *t, PACK *p);
+void OutRpcNatInfo(PACK *p, RPC_NAT_INFO *t);
+void FreeRpcNatInfo(RPC_NAT_INFO *t);
+void InRpcNatStatus(RPC_NAT_STATUS *t, PACK *p);
+void OutRpcNatStatus(PACK *p, RPC_NAT_STATUS *t);
+void FreeRpcNatStatus(RPC_NAT_STATUS *t);
+void InVhOption(VH_OPTION *t, PACK *p);
+void OutVhOption(PACK *p, VH_OPTION *t);
+void InRpcDummy(RPC_DUMMY *t, PACK *p);
+void OutRpcDummy(PACK *p, RPC_DUMMY *t);
+
+
+
+
+#endif // NAT_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/NativeStack.c b/src/Cedar/NativeStack.c
new file mode 100644
index 00000000..9689964e
--- /dev/null
+++ b/src/Cedar/NativeStack.c
@@ -0,0 +1,417 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// NativeStack.c
+// Native IP stack
+
+#include "CedarPch.h"
+
+// Stack main thread
+void NsMainThread(THREAD *thread, void *param)
+{
+ NATIVE_STACK *a = (NATIVE_STACK *)param;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ SOCKSET set;
+ bool err = false;
+ bool flush_tube;
+ LIST *recv_packets;
+ bool state_changed = false;
+
+ InitSockSet(&set);
+ AddSockSet(&set, a->Sock1);
+
+ if (a->Halt)
+ {
+ break;
+ }
+
+ // Pass to the IPC by receiving from the bridge
+LABEL_RESTART:
+ state_changed = false;
+ flush_tube = false;
+ while (true)
+ {
+ void *data;
+ UINT size;
+
+ size = EthGetPacket(a->Eth, &data);
+
+ if (size == INFINITE)
+ {
+ // Device error
+ err = true;
+ break;
+ }
+ else if (size == 0)
+ {
+ // Can not get any more
+ break;
+ }
+ else
+ {
+ // Pass the IPC socket
+ TubeSendEx(a->Sock1->SendTube, data, size, NULL, true);
+ Free(data);
+ flush_tube = true;
+ state_changed = true;
+ }
+ }
+
+ if (flush_tube)
+ {
+ TubeFlush(a->Sock1->SendTube);
+ }
+
+ // Pass to the bridge by receiving from IPC
+ recv_packets = NULL;
+ while (true)
+ {
+ TUBEDATA *d = TubeRecvAsync(a->Sock1->RecvTube);
+
+ if (d == NULL)
+ {
+ break;
+ }
+
+ if (recv_packets == NULL)
+ {
+ recv_packets = NewListFast(NULL);
+ }
+
+ Add(recv_packets, d);
+
+ state_changed = true;
+ }
+ if (recv_packets != NULL)
+ {
+ UINT i;
+ UINT num = LIST_NUM(recv_packets);
+ void **data_array;
+ UINT *size_array;
+
+ data_array = Malloc(sizeof(void *) * num);
+ size_array = Malloc(sizeof(UINT) * num);
+
+ for (i = 0;i < num;i++)
+ {
+ TUBEDATA *d = LIST_DATA(recv_packets, i);
+
+ data_array[i] = d->Data;
+ size_array[i] = d->DataSize;
+ }
+
+ EthPutPackets(a->Eth, num, data_array, size_array);
+
+ for (i = 0;i < num;i++)
+ {
+ TUBEDATA *d = LIST_DATA(recv_packets, i);
+
+ // Because the data buffer has been already released, not to release twice
+ d->Data = NULL;
+
+ FreeTubeData(d);
+ }
+
+ Free(data_array);
+ Free(size_array);
+
+ ReleaseList(recv_packets);
+ }
+
+ if (IsTubeConnected(a->Sock1->SendTube) == false || IsTubeConnected(a->Sock1->RecvTube) == false)
+ {
+ err = true;
+ }
+
+ if (err)
+ {
+ // An error has occured
+ Debug("Native Stack: Error !\n");
+ a->Halt = true;
+ continue;
+ }
+
+ if (state_changed)
+ {
+ goto LABEL_RESTART;
+ }
+
+ Select(&set, 1234, a->Cancel, NULL);
+ }
+
+ Disconnect(a->Sock1);
+ Disconnect(a->Sock2);
+}
+
+// Release the stack
+void FreeNativeStack(NATIVE_STACK *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ if (a->Ipc != NULL && IsZero(&a->CurrentDhcpOptionList, sizeof(a->CurrentDhcpOptionList)) == false)
+ {
+ IP dhcp_server;
+
+ UINTToIP(&dhcp_server, a->CurrentDhcpOptionList.ServerAddress);
+
+ IPCDhcpFreeIP(a->Ipc, &dhcp_server);
+ SleepThread(200);
+ }
+
+ a->Halt = true;
+ Cancel(a->Cancel);
+ Disconnect(a->Sock1);
+ Disconnect(a->Sock2);
+
+ WaitThread(a->MainThread, INFINITE);
+
+ ReleaseThread(a->MainThread);
+
+ CloseEth(a->Eth);
+ FreeIPC(a->Ipc);
+
+ ReleaseCancel(a->Cancel);
+
+ ReleaseSock(a->Sock1);
+ ReleaseSock(a->Sock2);
+
+ ReleaseCedar(a->Cedar);
+
+ Free(a);
+}
+
+// Create a new stack
+NATIVE_STACK *NewNativeStack(CEDAR *cedar, char *device_name, char *mac_address_seed)
+{
+ ETH *eth;
+ NATIVE_STACK *a;
+ IP localhost;
+ char tmp[64];
+ bool release_cedar = false;
+ // Validate arguments
+ if (device_name == NULL || mac_address_seed == NULL)
+ {
+ return NULL;
+ }
+
+ if (cedar == NULL)
+ {
+ cedar = NewCedar(NULL, NULL);
+ release_cedar = true;
+ }
+
+ GetLocalHostIP4(&localhost);
+
+ // Open the Eth device
+ eth = OpenEth(device_name, false, false, NULL);
+ if (eth == NULL)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(NATIVE_STACK));
+
+ NewSocketPair(&a->Sock1, &a->Sock2, &localhost, 1, &localhost, 1);
+
+ a->Cedar = cedar;
+ AddRef(a->Cedar->ref);
+
+ NsGenMacAddress(a->MacAddress, mac_address_seed, device_name);
+
+ BinToStr(tmp, sizeof(tmp), a->MacAddress, sizeof(a->MacAddress));
+ Debug("NewNativeStack: MAC Address = %s\n", tmp);
+
+ a->Ipc = NewIPCBySock(cedar, a->Sock2, a->MacAddress);
+
+ StrCpy(a->DeviceName, sizeof(a->DeviceName), device_name);
+
+ a->Eth = eth;
+ a->Cancel = EthGetCancel(eth);
+
+ a->MainThread = NewThread(NsMainThread, a);
+
+ if (release_cedar)
+ {
+ ReleaseCedar(cedar);
+ }
+
+ return a;
+}
+
+// Identify whether the specified MAC address is for the Native Stack which operate on the same host
+bool NsIsMacAddressOnLocalhost(UCHAR *mac)
+{
+ UCHAR tmp[2];
+ // Validate arguments
+ if (mac == NULL)
+ {
+ return false;
+ }
+
+ if (mac[0] != NS_MAC_ADDRESS_BYTE_1)
+ {
+ return false;
+ }
+
+ NsGenMacAddressSignatureForMachine(tmp, mac);
+
+ if (Cmp(mac + 4, tmp, 2) == 0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Determine the last two bytes of the MAC address
+void NsGenMacAddressSignatureForMachine(UCHAR *dst_last_2, UCHAR *src_mac_addr_4)
+{
+ char machine_name[MAX_SIZE];
+ BUF *b;
+ UCHAR hash[SHA1_SIZE];
+ // Validate arguments
+ if (dst_last_2 == NULL || src_mac_addr_4 == NULL)
+ {
+ return;
+ }
+
+ GetMachineHostName(machine_name, sizeof(machine_name));
+
+ Trim(machine_name);
+ StrUpper(machine_name);
+
+ b = NewBuf();
+ WriteBuf(b, src_mac_addr_4, 4);
+ WriteBufStr(b, machine_name);
+
+ HashSha1(hash, b->Buf, b->Size);
+
+ FreeBuf(b);
+
+ Copy(dst_last_2, hash, 2);
+}
+
+// Generate the MAC address
+void NsGenMacAddress(void *dest, char *mac_address_seed, char *device_name)
+{
+ char tmp[MAX_SIZE];
+ UCHAR mac[6];
+ UCHAR hash[SHA1_SIZE];
+
+ Zero(tmp, sizeof(tmp));
+
+ StrCat(tmp, sizeof(tmp), mac_address_seed);
+ StrCat(tmp, sizeof(tmp), "@");
+ StrCat(tmp, sizeof(tmp), device_name);
+
+ Trim(tmp);
+
+ StrLower(tmp);
+
+ HashSha1(hash, tmp, StrLen(tmp));
+
+ mac[0] = NS_MAC_ADDRESS_BYTE_1;
+ mac[1] = hash[1];
+ mac[2] = hash[2];
+ mac[3] = hash[3];
+ mac[4] = hash[4];
+ mac[5] = hash[5];
+
+ NsGenMacAddressSignatureForMachine(mac + 4, mac);
+
+ Copy(dest, mac, 6);
+}
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/NativeStack.h b/src/Cedar/NativeStack.h
new file mode 100644
index 00000000..f115e671
--- /dev/null
+++ b/src/Cedar/NativeStack.h
@@ -0,0 +1,123 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// NativeStack.h
+// Header of NativeStack.c
+
+#ifndef NATIVESTACK_H
+#define NATIVESTACK_H
+
+//// Constants
+#define NS_MAC_ADDRESS_BYTE_1 0xDA // First byte of the MAC address
+
+//// Type
+struct NATIVE_STACK
+{
+ CEDAR *Cedar;
+ IPC *Ipc; // IPC object
+ char DeviceName[MAX_SIZE]; // Ethernet device name
+ THREAD *MainThread; // Main thread
+ bool Halt; // Halting flag
+ CANCEL *Cancel; // Cancel
+ UCHAR MacAddress[6]; // MAC address of the virtual host
+ ETH *Eth; // Eth device
+ SOCK *Sock1; // Sock1 (To be used in the bridge side)
+ SOCK *Sock2; // Sock2 (Used in the IPC side)
+ DHCP_OPTION_LIST CurrentDhcpOptionList; // Current DHCP options list
+ IP DnsServerIP; // IP address of the DNS server
+};
+
+
+//// Function prototype
+NATIVE_STACK *NewNativeStack(CEDAR *cedar, char *device_name, char *mac_address_seed);
+void FreeNativeStack(NATIVE_STACK *a);
+
+void NsGenMacAddress(void *dest, char *mac_address_seed, char *device_name);
+void NsMainThread(THREAD *thread, void *param);
+void NsGenMacAddressSignatureForMachine(UCHAR *dst_last_2, UCHAR *src_mac_addr_4);
+bool NsIsMacAddressOnLocalhost(UCHAR *mac);
+
+#endif // NATIVESTACK_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/NullLan.c b/src/Cedar/NullLan.c
new file mode 100644
index 00000000..8f3fad40
--- /dev/null
+++ b/src/Cedar/NullLan.c
@@ -0,0 +1,256 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// NullLan.c
+// Virtual LAN card device driver for testing
+
+#include "CedarPch.h"
+
+static UCHAR null_lan_broadcast_address[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+// Get the packet adapter
+PACKET_ADAPTER *NullGetPacketAdapter()
+{
+ PACKET_ADAPTER *pa = NewPacketAdapter(NullPaInit, NullPaGetCancel, NullPaGetNextPacket,
+ NullPaPutPacket, NullPaFree);
+
+ return pa;
+}
+
+// Packet generation thread
+void NullPacketGenerateThread(THREAD *t, void *param)
+{
+ NULL_LAN *n = (NULL_LAN *)param;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ Wait(n->Event, Rand32() % NULL_PACKET_GENERATE_INTERVAL);
+ if (n->Halt)
+ {
+ break;
+ }
+
+ LockQueue(n->PacketQueue);
+ {
+ UCHAR *data;
+ BLOCK *b;
+ UINT size = Rand32() % 1500 + 14;
+ data = Malloc(size);
+ Copy(data, null_lan_broadcast_address, 6);
+ Copy(data + 6, n->MacAddr, 6);
+ b = NewBlock(data, size, 0);
+ InsertQueue(n->PacketQueue, b);
+ }
+ UnlockQueue(n->PacketQueue);
+ Cancel(n->Cancel);
+ }
+}
+
+// Initialize the packet adapter
+bool NullPaInit(SESSION *s)
+{
+ NULL_LAN *n;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ n = ZeroMalloc(sizeof(NULL_LAN));
+ s->PacketAdapter->Param = (void *)n;
+
+ n->Cancel = NewCancel();
+ n->PacketQueue = NewQueue();
+ n->Event = NewEvent();
+
+ GenMacAddress(n->MacAddr);
+
+ n->PacketGeneratorThread = NewThread(NullPacketGenerateThread, n);
+
+ return true;
+}
+
+// Get the cancel object
+CANCEL *NullPaGetCancel(SESSION *s)
+{
+ // Validate arguments
+ NULL_LAN *n;
+ if (s == NULL || (n = s->PacketAdapter->Param) == NULL)
+ {
+ return NULL;
+ }
+
+ AddRef(n->Cancel->ref);
+
+ return n->Cancel;
+}
+
+// Get the next packet
+UINT NullPaGetNextPacket(SESSION *s, void **data)
+{
+ UINT size = 0;
+ // Validate arguments
+ NULL_LAN *n;
+ if (s == NULL || (n = s->PacketAdapter->Param) == NULL)
+ {
+ return INFINITE;
+ }
+
+ LockQueue(n->PacketQueue);
+ {
+ BLOCK *b = GetNext(n->PacketQueue);
+
+ if (b != NULL)
+ {
+ *data = b->Buf;
+ size = b->Size;
+ Free(b);
+ }
+ }
+ UnlockQueue(n->PacketQueue);
+
+ return size;
+}
+
+// Write the packet
+bool NullPaPutPacket(SESSION *s, void *data, UINT size)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+ if (data == NULL)
+ {
+ return true;
+ }
+
+ // Packet ignored
+ Free(data);
+
+ return true;
+}
+
+// Release
+void NullPaFree(SESSION *s)
+{
+ // Validate arguments
+ NULL_LAN *n;
+ BLOCK *b;
+ if (s == NULL || (n = s->PacketAdapter->Param) == NULL)
+ {
+ return;
+ }
+
+ n->Halt = true;
+ Set(n->Event);
+
+ WaitThread(n->PacketGeneratorThread, INFINITE);
+ ReleaseThread(n->PacketGeneratorThread);
+
+ LockQueue(n->PacketQueue);
+ {
+ while (b = GetNext(n->PacketQueue))
+ {
+ FreeBlock(b);
+ }
+ }
+ UnlockQueue(n->PacketQueue);
+
+ ReleaseQueue(n->PacketQueue);
+
+ ReleaseCancel(n->Cancel);
+
+ ReleaseEvent(n->Event);
+
+ s->PacketAdapter->Param = NULL;
+ Free(n);
+}
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/NullLan.h b/src/Cedar/NullLan.h
new file mode 100644
index 00000000..3ccc068e
--- /dev/null
+++ b/src/Cedar/NullLan.h
@@ -0,0 +1,117 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// NullLan.h
+// Header of NullLan.c
+
+#ifndef NULLLAN_H
+#define NULLLAN_H
+
+
+#define NULL_PACKET_GENERATE_INTERVAL 100000000 // Packet generation interval
+
+// NULL device structure
+struct NULL_LAN
+{
+ THREAD *PacketGeneratorThread;
+ CANCEL *Cancel;
+ QUEUE *PacketQueue;
+ volatile bool Halt;
+ EVENT *Event;
+ UCHAR MacAddr[6];
+ UCHAR Padding[2];
+};
+
+PACKET_ADAPTER *NullGetPacketAdapter();
+bool NullPaInit(SESSION *s);
+CANCEL *NullPaGetCancel(SESSION *s);
+UINT NullPaGetNextPacket(SESSION *s, void **data);
+bool NullPaPutPacket(SESSION *s, void *data, UINT size);
+void NullPaFree(SESSION *s);
+void NullPacketGenerateThread(THREAD *t, void *param);
+
+#endif // NULLAN_H
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Protocol.c b/src/Cedar/Protocol.c
new file mode 100644
index 00000000..beb2f3b4
--- /dev/null
+++ b/src/Cedar/Protocol.c
@@ -0,0 +1,6535 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Protocol.c
+// SoftEther protocol related routines
+
+#include "CedarPch.h"
+
+static UCHAR ssl_packet_start[3] = {0x17, 0x03, 0x00};
+
+
+// Convert the date of YYYYMMDD format to a number
+UINT64 ShortStrToDate64(char *str)
+{
+ UINT v;
+ SYSTEMTIME st;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return 0;
+ }
+
+ v = ToInt(str);
+
+ Zero(&st, sizeof(st));
+
+ st.wYear = (v % 100000000) / 10000;
+ st.wMonth = (v % 10000) / 100;
+ st.wDay = v % 100;
+
+ return SystemToUINT64(&st);
+}
+
+// Handle the response that is returned from the server in the update client
+void UpdateClientThreadProcessResults(UPDATE_CLIENT *c, BUF *b)
+{
+ bool exit = false;
+ // Validate arguments
+ if (c == NULL || b == NULL)
+ {
+ return;
+ }
+
+ SeekBufToBegin(b);
+
+ while (true)
+ {
+ char *line = CfgReadNextLine(b);
+ if (line == NULL)
+ {
+ break;
+ }
+
+ Trim(line);
+
+ if (StartWith(line, "#") == false && IsEmptyStr(line) == false)
+ {
+ TOKEN_LIST *t = ParseTokenWithNullStr(line, " \t");
+
+ if (t != NULL)
+ {
+ if (t->NumTokens >= 5)
+ {
+ if (StrCmpi(t->Token[0], c->FamilyName) == 0)
+ {
+ // Match
+ UINT64 date = ShortStrToDate64(t->Token[1]);
+ if (date != 0)
+ {
+ UINT build = ToInt(t->Token[2]);
+ if (build != 0)
+ {
+ if (build > c->MyBuild && build > c->LatestBuild && build > c->Setting.LatestIgnoreBuild)
+ {
+ c->Callback(c, build, date, t->Token[3], t->Token[4], &c->HaltFlag, c->Param);
+
+ c->LatestBuild = build;
+
+ exit = true;
+ }
+ }
+ }
+ }
+ }
+
+ FreeToken(t);
+ }
+ }
+
+ Free(line);
+
+ if (exit)
+ {
+ break;
+ }
+ }
+}
+
+// Update client main process
+void UpdateClientThreadMain(UPDATE_CLIENT *c)
+{
+ char url[MAX_SIZE];
+ char id[MAX_SIZE];
+ URL_DATA data;
+ BUF *cert_hash;
+ UINT ret = 0;
+ BUF *recv;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Generate the URL
+ Format(url, sizeof(url), IsUseAlternativeHostname() ? UPDATE_SERVER_URL_CHINA : UPDATE_SERVER_URL_GLOBAL, c->FamilyName, c->SoftwareName, c->MyBuild, c->MyLanguage);
+
+ if (IsEmptyStr(c->ClientId) == false)
+ {
+ Format(id, sizeof(id), "&id=%s", c->ClientId);
+ StrCat(url, sizeof(url), id);
+ }
+
+ // Get a text file at this URL
+ if (ParseUrl(&data, url, false, NULL) == false)
+ {
+ return;
+ }
+
+ cert_hash = StrToBin(UPDATE_SERVER_CERT_HASH);
+
+ recv = HttpRequest(&data, NULL, UPDATE_CONNECT_TIMEOUT, UPDATE_COMM_TIMEOUT, &ret, false, NULL, NULL,
+ NULL, ((cert_hash != NULL && cert_hash->Size == SHA1_SIZE) ? cert_hash->Buf : NULL));
+
+ FreeBuf(cert_hash);
+
+ if (recv != NULL)
+ {
+ UpdateClientThreadProcessResults(c, recv);
+
+ FreeBuf(recv);
+ }
+}
+
+// Update client main thread
+void UpdateClientThreadProc(THREAD *thread, void *param)
+{
+ UPDATE_CLIENT *c = (UPDATE_CLIENT *)param;
+ bool first_loop = true;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ // Termination check
+ if (c->HaltFlag)
+ {
+ break;
+ }
+
+ if (first_loop == false)
+ {
+ // Wait for the foreground
+ if (c->IsForegroundCb != NULL)
+ {
+ while (true)
+ {
+ if (c->HaltFlag)
+ {
+ break;
+ }
+
+ if (c->IsForegroundCb(c, c->Param))
+ {
+ break;
+ }
+
+ Wait(c->HaltEvent, 1000);
+ }
+ }
+ }
+
+ first_loop = false;
+
+ if (c->HaltFlag)
+ {
+ break;
+ }
+
+ if (c->Setting.DisableCheck == false)
+ {
+ UpdateClientThreadMain(c);
+ }
+
+ // Wait until the next attempt
+ Wait(c->HaltEvent, GenRandInterval(UPDATE_CHECK_INTERVAL_MIN, UPDATE_CHECK_INTERVAL_MAX));
+ }
+}
+
+// Update the configuration of the update client
+void SetUpdateClientSetting(UPDATE_CLIENT *c, UPDATE_CLIENT_SETTING *s)
+{
+ bool old_disable;
+ // Validate arguments
+ if (c == NULL || s == NULL)
+ {
+ return;
+ }
+
+ old_disable = c->Setting.DisableCheck;
+
+ Copy(&c->Setting, s, sizeof(UPDATE_CLIENT_SETTING));
+
+ Set(c->HaltEvent);
+}
+
+// Start the update client
+UPDATE_CLIENT *NewUpdateClient(UPDATE_NOTIFY_PROC *cb, UPDATE_ISFOREGROUND_PROC *isforeground_cb, void *param, char *family_name, char *software_name, wchar_t *software_title, UINT my_build, UINT64 my_date, char *my_lang, UPDATE_CLIENT_SETTING *current_setting, char *client_id)
+{
+ UPDATE_CLIENT *c;
+ // Validate arguments
+ if (family_name == NULL || software_title == NULL || software_name == NULL || my_build == 0 ||
+ my_lang == NULL || current_setting == NULL || cb == NULL)
+ {
+ return NULL;
+ }
+
+ c = ZeroMalloc(sizeof(UPDATE_CLIENT));
+
+ c->Callback = cb;
+ c->IsForegroundCb = isforeground_cb;
+
+ StrCpy(c->ClientId, sizeof(c->ClientId), client_id);
+ StrCpy(c->FamilyName, sizeof(c->FamilyName), family_name);
+ StrCpy(c->SoftwareName, sizeof(c->SoftwareName), software_name);
+ UniStrCpy(c->SoftwareTitle, sizeof(c->SoftwareTitle), software_title);
+ c->MyBuild = my_build;
+ c->MyDate = my_date;
+ StrCpy(c->MyLanguage, sizeof(c->MyLanguage), my_lang);
+
+ Copy(&c->Setting, current_setting, sizeof(c->Setting));
+
+ c->Param = param;
+
+ c->HaltEvent = NewEvent();
+
+ // Create a thread
+ c->Thread = NewThread(UpdateClientThreadProc, c);
+
+ return c;
+}
+
+// Terminate the update client
+void FreeUpdateClient(UPDATE_CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Thread stop
+ c->HaltFlag = true;
+ Set(c->HaltEvent);
+
+ // Wait for thread termination
+ WaitThread(c->Thread, INFINITE);
+
+ ReleaseThread(c->Thread);
+ ReleaseEvent(c->HaltEvent);
+
+ Free(c);
+}
+
+// Generate unique IDs for each machine
+void GenerateMachineUniqueHash(void *data)
+{
+ BUF *b;
+ char name[64];
+ char ip_str[64];
+ IP ip;
+ OS_INFO *osinfo;
+ // Validate arguments
+ if (data == NULL)
+ {
+ return;
+ }
+
+ b = NewBuf();
+ GetMachineName(name, sizeof(name));
+ GetMachineIp(&ip);
+ IPToStr(ip_str, sizeof(ip_str), &ip);
+
+ osinfo = GetOsInfo();
+
+ WriteBuf(b, name, StrLen(name));
+ WriteBuf(b, ip_str, StrLen(ip_str));
+
+ WriteBuf(b, &osinfo->OsType, sizeof(osinfo->OsType));
+ WriteBuf(b, osinfo->KernelName, StrLen(osinfo->KernelName));
+ WriteBuf(b, osinfo->KernelVersion, StrLen(osinfo->KernelVersion));
+ WriteBuf(b, osinfo->OsProductName, StrLen(osinfo->OsProductName));
+ WriteBuf(b, &osinfo->OsServicePack, sizeof(osinfo->OsServicePack));
+ WriteBuf(b, osinfo->OsSystemName, StrLen(osinfo->OsSystemName));
+ WriteBuf(b, osinfo->OsVendorName, StrLen(osinfo->OsVendorName));
+ WriteBuf(b, osinfo->OsVersion, StrLen(osinfo->OsVersion));
+
+ Hash(data, b->Buf, b->Size, true);
+
+ FreeBuf(b);
+}
+
+// Convert a node information to a string
+void NodeInfoToStr(wchar_t *str, UINT size, NODE_INFO *info)
+{
+ char client_ip[128], server_ip[128], proxy_ip[128], unique_id[128];
+ // Validate arguments
+ if (str == NULL || info == NULL)
+ {
+ return;
+ }
+
+ IPToStr4or6(client_ip, sizeof(client_ip), info->ClientIpAddress, info->ClientIpAddress6);
+ IPToStr4or6(server_ip, sizeof(server_ip), info->ServerIpAddress, info->ServerIpAddress6);
+ IPToStr4or6(proxy_ip, sizeof(proxy_ip), info->ProxyIpAddress, info->ProxyIpAddress6);
+ BinToStr(unique_id, sizeof(unique_id), info->UniqueId, sizeof(info->UniqueId));
+
+ UniFormat(str, size, _UU("LS_NODE_INFO_TAG"), info->ClientProductName,
+ Endian32(info->ClientProductVer), Endian32(info->ClientProductBuild),
+ info->ServerProductName, Endian32(info->ServerProductVer), Endian32(info->ServerProductBuild),
+ info->ClientOsName, info->ClientOsVer, info->ClientOsProductId,
+ info->ClientHostname, client_ip, Endian32(info->ClientPort),
+ info->ServerHostname, server_ip, Endian32(info->ServerPort),
+ info->ProxyHostname, proxy_ip, Endian32(info->ProxyPort),
+ info->HubName, unique_id);
+}
+
+// Comparison of node information
+bool CompareNodeInfo(NODE_INFO *a, NODE_INFO *b)
+{
+ // Validate arguments
+ if (a == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ if (StrCmp(a->ClientProductName, b->ClientProductName) != 0)
+ {
+ return false;
+ }
+ if (a->ClientProductVer != b->ClientProductVer)
+ {
+ return false;
+ }
+ if (a->ClientProductBuild != b->ClientProductBuild)
+ {
+ return false;
+ }
+ if (StrCmp(a->ServerProductName, b->ServerProductName) != 0)
+ {
+ return false;
+ }
+ if (a->ServerProductVer != b->ServerProductVer)
+ {
+ return false;
+ }
+ if (a->ServerProductBuild != b->ServerProductBuild)
+ {
+ return false;
+ }
+ if (StrCmp(a->ClientOsName, b->ClientOsName) != 0)
+ {
+ return false;
+ }
+ if (StrCmp(a->ClientOsVer, b->ClientOsVer) != 0)
+ {
+ return false;
+ }
+ if (StrCmp(a->ClientOsProductId, b->ClientOsProductId) != 0)
+ {
+ return false;
+ }
+ if (StrCmp(a->ClientHostname, b->ClientHostname) != 0)
+ {
+ return false;
+ }
+ if (a->ClientIpAddress != b->ClientIpAddress)
+ {
+ return false;
+ }
+ if (StrCmp(a->ServerHostname, b->ServerHostname) != 0)
+ {
+ return false;
+ }
+ if (a->ServerIpAddress != b->ServerIpAddress)
+ {
+ return false;
+ }
+ if (a->ServerPort != b->ServerPort)
+ {
+ return false;
+ }
+ if (StrCmp(a->ProxyHostname, b->ProxyHostname) != 0)
+ {
+ return false;
+ }
+ if (a->ProxyIpAddress != b->ProxyIpAddress)
+ {
+ return false;
+ }
+ if (a->ProxyPort != b->ProxyPort)
+ {
+ return false;
+ }
+ if (StrCmp(a->HubName, b->HubName) != 0)
+ {
+ return false;
+ }
+ if (Cmp(a->UniqueId, b->UniqueId, 16) != 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Accept the password change
+UINT ChangePasswordAccept(CONNECTION *c, PACK *p)
+{
+ CEDAR *cedar;
+ UCHAR random[SHA1_SIZE];
+ char hubname[MAX_HUBNAME_LEN + 1];
+ char username[MAX_USERNAME_LEN + 1];
+ UCHAR secure_old_password[SHA1_SIZE];
+ UCHAR new_password[SHA1_SIZE];
+ UCHAR new_password_ntlm[SHA1_SIZE];
+ UCHAR check_secure_old_password[SHA1_SIZE];
+ UINT ret = ERR_NO_ERROR;
+ HUB *hub;
+ bool save = false;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ Copy(random, c->Random, SHA1_SIZE);
+ if (PackGetStr(p, "hubname", hubname, sizeof(hubname)) == false ||
+ PackGetStr(p, "username", username, sizeof(username)) == false ||
+ PackGetData2(p, "secure_old_password", secure_old_password, sizeof(secure_old_password)) == false ||
+ PackGetData2(p, "new_password", new_password, sizeof(new_password)) == false)
+ {
+ return ERR_PROTOCOL_ERROR;
+ }
+
+ if (PackGetData2(p, "new_password_ntlm", new_password_ntlm, MD5_SIZE) == false)
+ {
+ Zero(new_password_ntlm, sizeof(new_password_ntlm));
+ }
+
+ cedar = c->Cedar;
+
+ LockHubList(cedar);
+ {
+ hub = GetHub(cedar, hubname);
+ }
+ UnlockHubList(cedar);
+
+ if (hub == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ char tmp[MAX_SIZE];
+
+ if (GetHubAdminOption(hub, "deny_change_user_password") != 0)
+ {
+ ReleaseHub(hub);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ IPToStr(tmp, sizeof(tmp), &c->FirstSock->RemoteIP);
+ HLog(hub, "LH_CHANGE_PASSWORD_1", c->Name, tmp);
+
+ AcLock(hub);
+ {
+ USER *u = AcGetUser(hub, username);
+ if (u == NULL)
+ {
+ HLog(hub, "LH_CHANGE_PASSWORD_2", c->Name, username);
+ ret = ERR_OLD_PASSWORD_WRONG;
+ }
+ else
+ {
+ Lock(u->lock);
+ {
+ if (u->AuthType != AUTHTYPE_PASSWORD)
+ {
+ // Not a password authentication
+ HLog(hub, "LH_CHANGE_PASSWORD_3", c->Name, username);
+ ret = ERR_USER_AUTHTYPE_NOT_PASSWORD;
+ }
+ else
+ {
+ bool fix_password = false;
+ if (u->Policy != NULL)
+ {
+ fix_password = u->Policy->FixPassword;
+ }
+ else
+ {
+ if (u->Group != NULL)
+ {
+ if (u->Group->Policy != NULL)
+ {
+ fix_password = u->Group->Policy->FixPassword;
+ }
+ }
+ }
+ if (fix_password == false)
+ {
+ // Confirmation of the old password
+ AUTHPASSWORD *pw = (AUTHPASSWORD *)u->AuthData;
+
+ SecurePassword(check_secure_old_password, pw->HashedKey, random);
+ if (Cmp(check_secure_old_password, secure_old_password, SHA1_SIZE) != 0)
+ {
+ // Old password is incorrect
+ ret = ERR_OLD_PASSWORD_WRONG;
+ HLog(hub, "LH_CHANGE_PASSWORD_4", c->Name, username);
+ }
+ else
+ {
+ // Write a new password
+ if (Cmp(pw->HashedKey, new_password, SHA1_SIZE) != 0 || IsZero(pw->NtLmSecureHash, MD5_SIZE))
+ {
+ Copy(pw->HashedKey, new_password, SHA1_SIZE);
+ Copy(pw->NtLmSecureHash, new_password_ntlm, MD5_SIZE);
+ }
+ HLog(hub, "LH_CHANGE_PASSWORD_5", c->Name, username);
+ save = true;
+ }
+ }
+ else
+ {
+ // Password change is prohibited
+ ret = ERR_NOT_ENOUGH_RIGHT;
+ }
+ }
+ }
+ Unlock(u->lock);
+
+ ReleaseUser(u);
+ }
+ }
+ AcUnlock(hub);
+ ReleaseHub(hub);
+ }
+
+ return ret;
+}
+
+// Change the password
+UINT ChangePassword(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, char *username, char *old_pass, char *new_pass)
+{
+ UINT ret = ERR_NO_ERROR;
+ UCHAR old_password[SHA1_SIZE];
+ UCHAR secure_old_password[SHA1_SIZE];
+ UCHAR new_password[SHA1_SIZE];
+ UCHAR new_password_ntlm[MD5_SIZE];
+ SOCK *sock;
+ SESSION *s;
+ // Validate arguments
+ if (cedar == NULL || o == NULL || hubname == NULL || username == NULL || old_pass == NULL || new_pass == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+
+ // Create a session
+ s = NewRpcSessionEx(cedar, o, &ret, NULL);
+
+ if (s != NULL)
+ {
+ PACK *p = NewPack();
+
+ sock = s->Connection->FirstSock;
+
+ HashPassword(old_password, username, old_pass);
+ SecurePassword(secure_old_password, old_password, s->Connection->Random);
+ HashPassword(new_password, username, new_pass);
+ GenerateNtPasswordHash(new_password_ntlm, new_pass);
+
+ PackAddClientVersion(p, s->Connection);
+
+ PackAddStr(p, "method", "password");
+ PackAddStr(p, "hubname", hubname);
+ PackAddStr(p, "username", username);
+ PackAddData(p, "secure_old_password", secure_old_password, SHA1_SIZE);
+ PackAddData(p, "new_password", new_password, SHA1_SIZE);
+ PackAddData(p, "new_password_ntlm", new_password_ntlm, MD5_SIZE);
+
+ if (HttpClientSend(sock, p))
+ {
+ PACK *p = HttpClientRecv(sock);
+ if (p == NULL)
+ {
+ ret = ERR_DISCONNECTED;
+ }
+ else
+ {
+ ret = GetErrorFromPack(p);
+ }
+ FreePack(p);
+ }
+ else
+ {
+ ret = ERR_DISCONNECTED;
+ }
+ FreePack(p);
+
+ ReleaseSession(s);
+ }
+
+ return ret;
+}
+
+// Enumerate HUBs
+TOKEN_LIST *EnumHub(SESSION *s)
+{
+ SOCK *sock;
+ TOKEN_LIST *ret;
+ PACK *p;
+ UINT num;
+ UINT i;
+ // Validate arguments
+ if (s == NULL || s->Connection == NULL)
+ {
+ return NULL;
+ }
+
+ sock = s->Connection->FirstSock;
+ if (sock == NULL)
+ {
+ return NULL;
+ }
+
+ // Set the Timeout
+ SetTimeout(sock, 10000);
+
+ p = NewPack();
+ PackAddStr(p, "method", "enum_hub");
+
+ PackAddClientVersion(p, s->Connection);
+
+ if (HttpClientSend(sock, p) == false)
+ {
+ FreePack(p);
+ return NULL;
+ }
+ FreePack(p);
+
+ p = HttpClientRecv(sock);
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ num = PackGetInt(p, "NumHub");
+ ret = ZeroMalloc(sizeof(TOKEN_LIST));
+ ret->NumTokens = num;
+ ret->Token = ZeroMalloc(sizeof(char *) * num);
+ for (i = 0;i < num;i++)
+ {
+ char tmp[MAX_SIZE];
+ if (PackGetStrEx(p, "HubName", tmp, sizeof(tmp), i))
+ {
+ ret->Token[i] = CopyStr(tmp);
+ }
+ }
+ FreePack(p);
+
+ return ret;
+}
+
+// Server accepts a connection from client
+bool ServerAccept(CONNECTION *c)
+{
+ bool ret = false;
+ UINT err;
+ PACK *p;
+ char username_real[MAX_SIZE];
+ char method[MAX_SIZE];
+ char hubname[MAX_SIZE];
+ char username[MAX_SIZE];
+ char groupname[MAX_SIZE];
+ UCHAR session_key[SHA1_SIZE];
+ UCHAR ticket[SHA1_SIZE];
+ RC4_KEY_PAIR key_pair;
+ UINT authtype;
+ POLICY *policy;
+ HUB *hub;
+ SESSION *s = NULL;
+ UINT64 user_expires = 0;
+ bool use_encrypt;
+ bool use_compress;
+ bool half_connection;
+ UINT adjust_mss;
+ bool use_udp_acceleration_client;
+ bool support_hmac_on_udp_acceleration_client = false;
+ bool support_udp_accel_fast_disconnect_detect;
+ bool use_hmac_on_udp_acceleration = false;
+ IP udp_acceleration_client_ip;
+ UCHAR udp_acceleration_client_key[UDP_ACCELERATION_COMMON_KEY_SIZE];
+ UINT udp_acceleration_client_port;
+ bool use_fast_rc4;
+ bool admin_mode = false;
+ UINT direction;
+ UINT max_connection;
+ UINT timeout;
+ bool no_reconnect_to_session = false;
+ bool farm_controller = false;
+ bool farm_member = false;
+ bool farm_mode = false;
+ bool require_bridge_routing_mode;
+ bool require_monitor_mode;
+ bool support_bulk_on_rudp = false;
+ bool support_hmac_on_bulk_of_rudp = false;
+ bool support_udp_recovery = false;
+ bool enable_bulk_on_rudp = false;
+ bool enable_udp_recovery = false;
+ bool enable_hmac_on_bulk_of_rudp = false;
+ bool use_client_license = false, use_bridge_license = false;
+ bool local_host_session = false;
+ char sessionname[MAX_SESSION_NAME_LEN + 1];
+ bool is_server_or_bridge = false;
+ bool qos = false;
+ bool cluster_dynamic_secure_nat = false;
+ bool no_save_password = false;
+ NODE_INFO node;
+ wchar_t *msg = NULL;
+ USER *loggedin_user_object = NULL;
+ FARM_MEMBER *f = NULL;
+ SERVER *server = NULL;
+ POLICY ticketed_policy;
+ UINT64 timestamp;
+ UCHAR unique[SHA1_SIZE], unique2[SHA1_SIZE];
+ CEDAR *cedar;
+ RPC_WINVER winver;
+ UINT client_id;
+ bool no_more_users_in_server = false;
+ UCHAR mschap_v2_server_response_20[20];
+ UINT ms_chap_error = 0;
+ bool is_empty_password = false;
+ char *error_detail = NULL;
+ char *error_detail_2 = NULL;
+ char ctoken_hash_str[64];
+
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ Zero(ctoken_hash_str, sizeof(ctoken_hash_str));
+
+ Zero(mschap_v2_server_response_20, sizeof(mschap_v2_server_response_20));
+
+ Zero(&udp_acceleration_client_ip, sizeof(udp_acceleration_client_ip));
+ udp_acceleration_client_port = 0;
+ Zero(udp_acceleration_client_key, sizeof(udp_acceleration_client_key));
+
+ Zero(&winver, sizeof(winver));
+
+ StrCpy(groupname, sizeof(groupname), "");
+ StrCpy(sessionname, sizeof(sessionname), "");
+
+ if (IsZero(c->CToken_Hash, SHA1_SIZE) == false)
+ {
+ BinToStr(ctoken_hash_str, sizeof(ctoken_hash_str), c->CToken_Hash, SHA1_SIZE);
+ }
+
+ cedar = c->Cedar;
+
+ // Get the license status
+
+ no_more_users_in_server = SiTooManyUserObjectsInServer(cedar->Server, true);
+
+ c->Status = CONNECTION_STATUS_NEGOTIATION;
+
+ if (c->Cedar->Server != NULL)
+ {
+ SERVER *s = c->Cedar->Server;
+ server = s;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ farm_member = true;
+ farm_mode = true;
+ }
+
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ farm_controller = true;
+ farm_mode = true;
+ }
+ }
+
+ // Receive the signature
+ Debug("Downloading Signature...\n");
+ error_detail_2 = NULL;
+ if (ServerDownloadSignature(c, &error_detail_2) == false)
+ {
+ if (error_detail_2 == NULL)
+ {
+ error_detail = "ServerDownloadSignature";
+ }
+ else
+ {
+ error_detail = error_detail_2;
+ }
+ goto CLEANUP;
+ }
+
+ // Send a Hello packet
+ Debug("Uploading Hello...\n");
+ if (ServerUploadHello(c) == false)
+ {
+ error_detail = "ServerUploadHello";
+ goto CLEANUP;
+ }
+
+ // Receive the authentication data
+ Debug("Auth...\n");
+
+ p = HttpServerRecv(c->FirstSock);
+ if (p == NULL)
+ {
+ // The connection disconnected
+ c->Err = ERR_DISCONNECTED;
+ error_detail = "RecvAuth1";
+ goto CLEANUP;
+ }
+
+ if (err = GetErrorFromPack(p))
+ {
+ // An error has occured
+ FreePack(p);
+ c->Err = err;
+ error_detail = "RecvAuth2";
+ goto CLEANUP;
+ }
+
+ // Get the method
+ if (GetMethodFromPack(p, method, sizeof(method)) == false)
+ {
+ // Protocol error
+ FreePack(p);
+ c->Err = ERR_PROTOCOL_ERROR;
+ error_detail = "GetMethodFromPack";
+ goto CLEANUP;
+ }
+
+ // Brand string for the connection limit
+ {
+ char tmp[20];
+ char *branded_ctos = _SS("BRANDED_C_TO_S");
+ PackGetStr(p, "branded_ctos", tmp, sizeof(tmp));
+
+ if(StrCmpi(method, "login") == 0 && StrLen(branded_ctos) > 0 && StrCmpi(branded_ctos, tmp) != 0)
+ {
+ FreePack(p);
+ c->Err = ERR_BRANDED_C_TO_S;
+ goto CLEANUP;
+ }
+ }
+
+ // Time inspection
+ timestamp = PackGetInt64(p, "timestamp");
+ if (timestamp != 0)
+ {
+ UINT64 now = SystemTime64();
+ UINT64 abs;
+ if (now >= timestamp)
+ {
+ abs = now - timestamp;
+ }
+ else
+ {
+ abs = timestamp - now;
+ }
+
+ if (abs > ALLOW_TIMESTAMP_DIFF)
+ {
+ // Time difference is too large
+ FreePack(p);
+ c->Err = ERR_BAD_CLOCK;
+ error_detail = "ERR_BAD_CLOCK";
+ goto CLEANUP;
+ }
+ }
+
+ // Get the client version
+ PackGetStr(p, "client_str", c->ClientStr, sizeof(c->ClientStr));
+ c->ClientVer = PackGetInt(p, "client_ver");
+ c->ClientBuild = PackGetInt(p, "client_build");
+
+ if (SearchStrEx(c->ClientStr, "server", 0, false) != INFINITE ||
+ SearchStrEx(c->ClientStr, "bridge", 0, false) != INFINITE)
+ {
+ is_server_or_bridge = true;
+ }
+
+ // Get the client Windows version
+ InRpcWinVer(&winver, p);
+
+ DecrementNoSsl(c->Cedar, &c->FirstSock->RemoteIP, 2);
+
+ if (StrCmpi(method, "login") == 0)
+ {
+ bool auth_ret = false;
+
+ Debug("Login...\n");
+ c->Status = CONNECTION_STATUS_USERAUTH;
+
+ c->Type = CONNECTION_TYPE_LOGIN;
+
+ if (no_more_users_in_server)
+ {
+ // There are many users than are allowed in the VPN Server
+ FreePack(p);
+ c->Err = ERR_TOO_MANY_USER;
+ error_detail = "ERR_TOO_MANY_USER";
+ goto CLEANUP;
+ }
+
+ // Such as the client name
+ if (PackGetStr(p, "hello", c->ClientStr, sizeof(c->ClientStr)) == false)
+ {
+ StrCpy(c->ClientStr, sizeof(c->ClientStr), "Unknown");
+ }
+ c->ServerVer = CEDAR_VER;
+ c->ServerBuild = CEDAR_BUILD;
+
+ // Get the NODE_INFO
+ Zero(&node, sizeof(node));
+ InRpcNodeInfo(&node, p);
+
+ // Protocol
+ c->Protocol = GetProtocolFromPack(p);
+ if (c->Protocol == CONNECTION_UDP)
+ {
+ // Release the structure of the TCP connection
+ if (c->Tcp)
+ {
+ ReleaseList(c->Tcp->TcpSockList);
+ Free(c->Tcp);
+ }
+ }
+
+ if (GetServerCapsBool(c->Cedar->Server, "b_vpn_client_connect") == false)
+ {
+ // VPN client is unable to connect
+ FreePack(p);
+ c->Err = ERR_NOT_SUPPORTED;
+ goto CLEANUP;
+ }
+
+
+
+ // Login
+ if (GetHubnameAndUsernameFromPack(p, username, sizeof(username), hubname, sizeof(hubname)) == false)
+ {
+ // Protocol error
+ FreePack(p);
+ c->Err = ERR_PROTOCOL_ERROR;
+ error_detail = "GetHubnameAndUsernameFromPack";
+ goto CLEANUP;
+ }
+
+ if (farm_member)
+ {
+ bool ok = false;
+ UINT authtype;
+
+ authtype = GetAuthTypeFromPack(p);
+ if (StrCmpi(username, ADMINISTRATOR_USERNAME) == 0 &&
+ authtype == AUTHTYPE_PASSWORD)
+ {
+ ok = true;
+ }
+
+ if (authtype == AUTHTYPE_TICKET)
+ {
+ ok = true;
+ }
+
+ if (ok == false)
+ {
+ // Logging on directly to server farm members by
+ // non-Administrators are prohibited
+ FreePack(p);
+ SLog(c->Cedar, "LS_FARMMEMBER_NOT_ADMIN", c->Name, hubname, ADMINISTRATOR_USERNAME, username);
+ c->Err = ERR_ACCESS_DENIED;
+ goto CLEANUP;
+ }
+ }
+
+ Debug("Username = %s, HubName = %s\n", username, hubname);
+ LockHubList(c->Cedar);
+ {
+ hub = GetHub(c->Cedar, hubname);
+ }
+ UnlockHubList(c->Cedar);
+ if (hub == NULL)
+ {
+ // The HUB does not exist
+ FreePack(p);
+ c->Err = ERR_HUB_NOT_FOUND;
+ SLog(c->Cedar, "LS_HUB_NOT_FOUND", c->Name, hubname);
+ error_detail = "ERR_HUB_NOT_FOUND";
+ goto CLEANUP;
+ }
+
+
+ Lock(hub->lock);
+ {
+ UINT cert_size = 0;
+ void *cert_buf = NULL;
+ USER *user;
+ USERGROUP *group;
+ char plain_password[MAX_PASSWORD_LEN + 1];
+ if (hub->Halt || hub->Offline)
+ {
+ // HUB is off-line
+ FreePack(p);
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ c->Err = ERR_HUB_STOPPING;
+ goto CLEANUP;
+ }
+
+ // Get the various flags
+ use_encrypt = PackGetInt(p, "use_encrypt") == 0 ? false : true;
+ use_compress = PackGetInt(p, "use_compress") == 0 ? false : true;
+ max_connection = PackGetInt(p, "max_connection");
+ half_connection = PackGetInt(p, "half_connection") == 0 ? false : true;
+ use_fast_rc4 = PackGetInt(p, "use_fast_rc4") == 0 ? false : true;
+ qos = PackGetInt(p, "qos") ? true : false;
+ client_id = PackGetInt(p, "client_id");
+ adjust_mss = PackGetInt(p, "adjust_mss");
+ use_udp_acceleration_client = PackGetBool(p, "use_udp_acceleration");
+ support_hmac_on_udp_acceleration_client = PackGetBool(p, "support_hmac_on_udp_acceleration");
+ support_udp_accel_fast_disconnect_detect = PackGetBool(p, "support_udp_accel_fast_disconnect_detect");
+ support_bulk_on_rudp = PackGetBool(p, "support_bulk_on_rudp");
+ support_hmac_on_bulk_of_rudp = PackGetBool(p, "support_hmac_on_bulk_of_rudp");
+ support_udp_recovery = PackGetBool(p, "support_udp_recovery");
+
+ if (c->IsInProc)
+ {
+ char tmp[MAX_SIZE];
+ PackGetStr(p, "inproc_postfix", c->InProcPrefix, sizeof(c->InProcPrefix));
+ Zero(tmp, sizeof(tmp));
+ PackGetStr(p, "inproc_cryptname", tmp, sizeof(tmp));
+
+ if (c->FirstSock != NULL)
+ {
+ if (IsEmptyStr(c->InProcPrefix) == false)
+ {
+ Format(c->FirstSock->UnderlayProtocol, sizeof(c->FirstSock->UnderlayProtocol),
+ SOCK_UNDERLAY_INPROC_EX, c->InProcPrefix);
+ }
+ }
+
+ if (c->CipherName != NULL)
+ {
+ Free(c->CipherName);
+ }
+
+ c->CipherName = NULL;
+
+ if (IsEmptyStr(tmp) == false)
+ {
+ c->CipherName = CopyStr(tmp);
+ use_encrypt = true;
+ }
+
+ use_udp_acceleration_client = false;
+ }
+ else
+ {
+ if (c->CipherName != NULL)
+ {
+ Free(c->CipherName);
+ }
+ c->CipherName = NULL;
+
+ if (c->FirstSock != NULL && IsEmptyStr(c->FirstSock->CipherName) == false)
+ {
+ c->CipherName = CopyStr(c->FirstSock->CipherName);
+ }
+ }
+
+ if (support_bulk_on_rudp && c->FirstSock != NULL && c->FirstSock->IsRUDPSocket &&
+ c->FirstSock->BulkRecvKey != NULL && c->FirstSock->BulkSendKey != NULL)
+ {
+ // RAllow UDP bulk transfer if the client side supports
+ // in the case of using R-UDP Socket
+ enable_bulk_on_rudp = true;
+
+ enable_hmac_on_bulk_of_rudp = support_hmac_on_bulk_of_rudp;
+ }
+
+ if (support_udp_recovery && c->FirstSock != NULL && c->FirstSock->IsRUDPSocket)
+ {
+ // Allow UDP recovery
+ enable_udp_recovery = true;
+ }
+
+ if (use_udp_acceleration_client)
+ {
+ // Get the parameters for the UDP acceleration function
+ if (PackGetIp(p, "udp_acceleration_client_ip", &udp_acceleration_client_ip) == false ||
+ PackGetData2(p, "udp_acceleration_client_key", udp_acceleration_client_key, UDP_ACCELERATION_COMMON_KEY_SIZE) == false)
+ {
+ use_udp_acceleration_client = false;
+ }
+ else
+ {
+ if (IsZeroIp(&udp_acceleration_client_ip))
+ {
+ Copy(&udp_acceleration_client_ip, &c->FirstSock->RemoteIP, sizeof(IP));
+ }
+ udp_acceleration_client_port = PackGetInt(p, "udp_acceleration_client_port");
+ if (udp_acceleration_client_port == 0)
+ {
+ use_udp_acceleration_client = false;
+ }
+ }
+
+ use_hmac_on_udp_acceleration = support_hmac_on_udp_acceleration_client;
+ }
+
+ Debug("use_udp_acceleration_client = %u\n", use_udp_acceleration_client);
+ Debug("use_hmac_on_udp_acceleration = %u\n", use_hmac_on_udp_acceleration);
+
+ // Request mode
+ require_bridge_routing_mode = PackGetBool(p, "require_bridge_routing_mode");
+ require_monitor_mode = PackGetBool(p, "require_monitor_mode");
+ if (require_monitor_mode)
+ {
+ qos = false;
+ }
+
+ if (is_server_or_bridge)
+ {
+ require_bridge_routing_mode = true;
+ }
+
+ // Client unique ID
+ Zero(unique, sizeof(unique));
+ if (PackGetDataSize(p, "unique_id") == SHA1_SIZE)
+ {
+ PackGetData(p, "unique_id", unique);
+ }
+
+ // Get the authentication method
+ authtype = GetAuthTypeFromPack(p);
+
+ if (1)
+ {
+ // Log
+ char ip1[64], ip2[64], verstr[64];
+ wchar_t *authtype_str = _UU("LH_AUTH_UNKNOWN");
+ switch (authtype)
+ {
+ case CLIENT_AUTHTYPE_ANONYMOUS:
+ authtype_str = _UU("LH_AUTH_ANONYMOUS");
+ break;
+ case CLIENT_AUTHTYPE_PASSWORD:
+ authtype_str = _UU("LH_AUTH_PASSWORD");
+ break;
+ case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+ authtype_str = _UU("LH_AUTH_PLAIN_PASSWORD");
+ break;
+ case CLIENT_AUTHTYPE_CERT:
+ authtype_str = _UU("LH_AUTH_CERT");
+ break;
+ case AUTHTYPE_TICKET:
+ authtype_str = _UU("LH_AUTH_TICKET");
+ break;
+ }
+ IPToStr(ip1, sizeof(ip1), &c->FirstSock->RemoteIP);
+ IPToStr(ip2, sizeof(ip2), &c->FirstSock->LocalIP);
+
+ Format(verstr, sizeof(verstr), "%u.%02u", c->ClientVer / 100, c->ClientVer % 100);
+
+ HLog(hub, "LH_CONNECT_CLIENT", c->Name, ip1, c->FirstSock->RemoteHostname, c->FirstSock->RemotePort,
+ c->ClientStr, verstr, c->ClientBuild, authtype_str, username);
+ }
+
+ // Attempt an anonymous authentication first
+ auth_ret = SamAuthUserByAnonymous(hub, username);
+
+ if (auth_ret)
+ {
+ if (c->IsInProc)
+ {
+ IPC_MSCHAP_V2_AUTHINFO mschap;
+ char password_tmp[MAX_SIZE];
+
+ Zero(&mschap, sizeof(mschap));
+
+ Zero(password_tmp, sizeof(password_tmp));
+ PackGetStr(p, "plain_password", password_tmp, sizeof(password_tmp));
+
+ if (ParseAndExtractMsChapV2InfoFromPassword(&mschap, password_tmp))
+ {
+ // Because the server don't know the NTLM hashed password, the bet to the possibility of
+ // the same character to the user name and empty, search a password of different
+ // versions of the upper and lower case characters in the case of anonymous authentication.
+ // Returns the MS-CHAPv2 response by using the password if there is a match.
+ // Fail the authentication if no match is found.
+ // (Because, if return a false MS-CHAPv2 Response, PPP client cause an error)
+ LIST *o = NewListFast(NULL);
+ char tmp1[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ char tmp3[MAX_SIZE];
+ char tmp4[MAX_SIZE];
+ char *response_pw;
+ char psk[MAX_SIZE];
+
+ ParseNtUsername(mschap.MsChapV2_PPPUsername, tmp1, sizeof(tmp1), tmp2, sizeof(tmp2), false);
+ ParseNtUsername(mschap.MsChapV2_PPPUsername, tmp3, sizeof(tmp3), tmp4, sizeof(tmp4), true);
+
+ Add(o, "");
+ Add(o, "-");
+ Add(o, ".");
+ Add(o, "*");
+ Add(o, "?");
+ Add(o, " ");
+ Add(o, "p");
+ Add(o, "guest");
+ Add(o, "anony");
+ Add(o, "anonymouse");
+ Add(o, "password");
+ Add(o, "passwd");
+ Add(o, "pass");
+ Add(o, "pw");
+ Add(o, mschap.MsChapV2_PPPUsername);
+ Add(o, tmp1);
+ Add(o, tmp2);
+ Add(o, tmp3);
+ Add(o, tmp4);
+
+ Zero(psk, sizeof(psk));
+
+ if (c->Cedar->Server != NULL)
+ {
+ SERVER *s = c->Cedar->Server;
+
+ if (s->IPsecServer != NULL)
+ {
+ StrCpy(psk, sizeof(psk), s->IPsecServer->Services.IPsec_Secret);
+
+ Add(o, psk);
+ }
+ }
+
+ response_pw = MsChapV2DoBruteForce(&mschap, o);
+
+ ReleaseList(o);
+
+ if (response_pw != NULL)
+ {
+ UCHAR challenge8[8];
+ UCHAR nt_hash[16];
+ UCHAR nt_hash_hash[16];
+
+ GenerateNtPasswordHash(nt_hash, response_pw);
+ GenerateNtPasswordHashHash(nt_hash_hash, nt_hash);
+ MsChapV2_GenerateChallenge8(challenge8, mschap.MsChapV2_ClientChallenge, mschap.MsChapV2_ServerChallenge,
+ mschap.MsChapV2_PPPUsername);
+ MsChapV2Server_GenerateResponse(mschap_v2_server_response_20, nt_hash_hash,
+ mschap.MsChapV2_ClientResponse, challenge8);
+
+ Free(response_pw);
+ }
+ else
+ {
+ auth_ret = false;
+ }
+ }
+ }
+
+ if (auth_ret)
+ {
+ // User authentication success by anonymous authentication
+ HLog(hub, "LH_AUTH_OK", c->Name, username);
+ is_empty_password = true;
+ }
+ }
+
+ if (auth_ret == false)
+ {
+ // Attempt other authentication methods if anonymous authentication fails
+ switch (authtype)
+ {
+ case CLIENT_AUTHTYPE_ANONYMOUS:
+ // Anonymous authentication (this have been already attempted)
+ break;
+
+ case AUTHTYPE_TICKET:
+ // Ticket authentication
+ if (PackGetDataSize(p, "ticket") == SHA1_SIZE)
+ {
+ PackGetData(p, "ticket", ticket);
+
+ auth_ret = SiCheckTicket(hub, ticket, username, sizeof(username), username_real, sizeof(username_real),
+ &ticketed_policy, sessionname, sizeof(sessionname), groupname, sizeof(groupname));
+ }
+ break;
+
+ case CLIENT_AUTHTYPE_PASSWORD:
+ // Password authentication
+ if (PackGetDataSize(p, "secure_password") == SHA1_SIZE)
+ {
+ POLICY *pol = NULL;
+ UCHAR secure_password[SHA1_SIZE];
+ Zero(secure_password, sizeof(secure_password));
+ if (PackGetDataSize(p, "secure_password") == SHA1_SIZE)
+ {
+ PackGetData(p, "secure_password", secure_password);
+ }
+ auth_ret = SamAuthUserByPassword(hub, username, c->Random, secure_password, NULL, NULL, NULL);
+
+ pol = SamGetUserPolicy(hub, username);
+ if (pol != NULL)
+ {
+ no_save_password = pol->NoSavePassword;
+ Free(pol);
+ }
+
+ if(auth_ret){
+ // Check whether the password was empty
+ UCHAR hashed_empty_password[SHA1_SIZE];
+ UCHAR secure_empty_password[SHA1_SIZE];
+ HashPassword(hashed_empty_password, username, "");
+ SecurePassword(secure_empty_password, hashed_empty_password, c->Random);
+ if(Cmp(secure_password, secure_empty_password, SHA1_SIZE)==0){
+ is_empty_password = true;
+ }
+ }
+ }
+ break;
+
+ case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+ {
+ POLICY *pol = NULL;
+
+ // Plaintext password authentication
+ Zero(plain_password, sizeof(plain_password));
+ PackGetStr(p, "plain_password", plain_password, sizeof(plain_password));
+ if (c->IsInProc == false && StartWith(plain_password, IPC_PASSWORD_MSCHAPV2_TAG))
+ {
+ // Do not allow the MS-CHAPv2 authentication other than IPC sessions
+ Zero(plain_password, sizeof(plain_password));
+ }
+
+ if (auth_ret == false)
+ {
+ // Attempt a password authentication of normal user
+ UCHAR secure_password[SHA1_SIZE];
+ UCHAR hash_password[SHA1_SIZE];
+ bool is_mschap = StartWith(plain_password, IPC_PASSWORD_MSCHAPV2_TAG);
+
+ HashPassword(hash_password, username, plain_password);
+ SecurePassword(secure_password, hash_password, c->Random);
+
+ if (is_mschap == false)
+ {
+ auth_ret = SamAuthUserByPassword(hub, username, c->Random, secure_password, NULL, NULL, NULL);
+ }
+ else
+ {
+ auth_ret = SamAuthUserByPassword(hub, username, c->Random, secure_password,
+ plain_password, mschap_v2_server_response_20, &ms_chap_error);
+ }
+
+ if (auth_ret && pol == NULL)
+ {
+ pol = SamGetUserPolicy(hub, username);
+ }
+ }
+
+ if (auth_ret == false)
+ {
+ // Attempt external authentication registered users
+ bool fail_ext_user_auth = false;
+ if (true)
+ {
+ fail_ext_user_auth = true;
+ }
+
+ if (fail_ext_user_auth == false)
+ {
+ auth_ret = SamAuthUserByPlainPassword(c, hub, username, plain_password, false, mschap_v2_server_response_20);
+ }
+
+ if (auth_ret && pol == NULL)
+ {
+ pol = SamGetUserPolicy(hub, username);
+ }
+ }
+
+
+ if (pol != NULL)
+ {
+ no_save_password = pol->NoSavePassword;
+ Free(pol);
+ }
+
+ if(auth_ret){
+ // Check whether the password was empty
+ if(IsEmptyStr(plain_password)){
+ is_empty_password = true;
+ }
+ }
+ }
+ break;
+
+ case CLIENT_AUTHTYPE_CERT:
+ // Certificate authentication is not supported in the open source version
+ HLog(hub, "LH_AUTH_CERT_NOT_SUPPORT_ON_OPEN_SOURCE", c->Name, username);
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ FreePack(p);
+ c->Err = ERR_AUTHTYPE_NOT_SUPPORTED;
+ goto CLEANUP;
+ break;
+
+ default:
+ // Unknown authentication method
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ FreePack(p);
+ c->Err = ERR_AUTHTYPE_NOT_SUPPORTED;
+ error_detail = "ERR_AUTHTYPE_NOT_SUPPORTED";
+ goto CLEANUP;
+ }
+
+ if (auth_ret == false)
+ {
+ // Authentication failure
+ HLog(hub, "LH_AUTH_NG", c->Name, username);
+ }
+ else
+ {
+ // Authentication success
+ HLog(hub, "LH_AUTH_OK", c->Name, username);
+ }
+ }
+
+ if (auth_ret == false)
+ {
+ // Authentication failure
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ FreePack(p);
+ c->Err = ERR_AUTH_FAILED;
+ if (ms_chap_error != 0)
+ {
+ c->Err = ms_chap_error;
+ }
+ error_detail = "ERR_AUTH_FAILED";
+ goto CLEANUP;
+ }
+ else
+ {
+ if(is_empty_password)
+ {
+ SOCK *s = c->FirstSock;
+ if (s != NULL && s->RemoteIP.addr[0] != 127)
+ {
+ if(StrCmpi(username, ADMINISTRATOR_USERNAME) == 0 ||
+ GetHubAdminOption(hub, "deny_empty_password") != 0)
+ {
+ // When the password is empty, remote connection is not acceptable
+ HLog(hub, "LH_LOCAL_ONLY", c->Name, username);
+
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ FreePack(p);
+ c->Err = ERR_NULL_PASSWORD_LOCAL_ONLY;
+ error_detail = "ERR_NULL_PASSWORD_LOCAL_ONLY";
+ goto CLEANUP;
+ }
+ }
+ }
+ }
+
+ policy = NULL;
+
+ // Authentication success
+ FreePack(p);
+
+ if (StrCmpi(username, ADMINISTRATOR_USERNAME) != 0)
+ {
+ // Get the policy
+ if (farm_member == false)
+ {
+ // In the case of not a farm member
+ user = AcGetUser(hub, username);
+ if (user == NULL)
+ {
+ user = AcGetUser(hub, "*");
+ if (user == NULL)
+ {
+ // User acquisition failure
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ c->Err = ERR_ACCESS_DENIED;
+ error_detail = "AcGetUser";
+ goto CLEANUP;
+ }
+ }
+
+ policy = NULL;
+
+ Lock(user->lock);
+ {
+ // Get the expiration date
+ user_expires = user->ExpireTime;
+
+ StrCpy(username_real, sizeof(username_real), user->Name);
+ group = user->Group;
+ if (group != NULL)
+ {
+ AddRef(group->ref);
+
+ Lock(group->lock);
+ {
+ // Get the group name
+ StrCpy(groupname, sizeof(groupname), group->Name);
+ }
+ Unlock(group->lock);
+ }
+
+ if (user->Policy != NULL)
+ {
+ policy = ClonePolicy(user->Policy);
+ }
+ else
+ {
+ if (group)
+ {
+ Lock(group->lock);
+ {
+ if (group->Policy != NULL)
+ {
+ policy = ClonePolicy(group->Policy);
+ }
+ }
+ Unlock(group->lock);
+ }
+ }
+
+ if (group != NULL)
+ {
+ ReleaseGroup(group);
+ }
+ }
+ Unlock(user->lock);
+ loggedin_user_object = user;
+ }
+ else
+ {
+ // In the case of farm member
+ policy = ClonePolicy(&ticketed_policy);
+ }
+ }
+ else
+ {
+ // Administrator mode
+ admin_mode = true;
+ StrCpy(username_real, sizeof(username_real), ADMINISTRATOR_USERNAME);
+
+ policy = ClonePolicy(GetDefaultPolicy());
+ policy->NoBroadcastLimiter = true;
+ policy->MonitorPort = true;
+ }
+
+ if (policy == NULL)
+ {
+ // Use the default policy
+ policy = ClonePolicy(GetDefaultPolicy());
+ }
+
+ if (policy->MaxConnection == 0)
+ {
+ policy->MaxConnection = MAX_TCP_CONNECTION;
+ }
+
+ if (policy->TimeOut == 0)
+ {
+ policy->TimeOut = 20;
+ }
+
+ if (qos)
+ {
+ // VoIP / QoS
+ if (policy->NoQoS)
+ {
+ // Policy does not allow QoS
+ qos = false;
+ }
+ if (GetServerCapsBool(c->Cedar->Server, "b_support_qos") == false)
+ {
+ // Server does not support QoS
+ qos = false;
+ policy->NoQoS = true;
+ }
+ if (GetHubAdminOption(hub, "deny_qos") != 0)
+ {
+ // It is prohibited in the management options
+ qos = false;
+ policy->NoQoS = true;
+ }
+ }
+
+ if (GetHubAdminOption(hub, "max_bitrates_download") != 0)
+ {
+ if (policy->MaxDownload == 0)
+ {
+ policy->MaxDownload = GetHubAdminOption(hub, "max_bitrates_download");
+ }
+ else
+ {
+ UINT r = GetHubAdminOption(hub, "max_bitrates_download");
+ policy->MaxDownload = MIN(policy->MaxDownload, r);
+ }
+ }
+
+ if (GetHubAdminOption(hub, "max_bitrates_upload") != 0)
+ {
+ if (policy->MaxUpload == 0)
+ {
+ policy->MaxUpload = GetHubAdminOption(hub, "max_bitrates_upload");
+ }
+ else
+ {
+ UINT r = GetHubAdminOption(hub, "max_bitrates_upload");
+ policy->MaxUpload = MIN(policy->MaxUpload, r);
+ }
+ }
+
+ if (GetHubAdminOption(hub, "deny_bridge") != 0)
+ {
+ policy->NoBridge = true;
+ }
+
+ if (GetHubAdminOption(hub, "deny_routing") != 0)
+ {
+ policy->NoRouting = true;
+ }
+
+ if (c->IsInProc)
+ {
+ policy->NoBridge = false;
+ policy->NoRouting = false;
+ }
+
+ if (hub->Option->ClientMinimumRequiredBuild > c->ClientBuild &&
+ InStrEx(c->ClientStr, "client", false))
+ {
+ // Build number of the client is too small
+ HLog(hub, "LH_CLIENT_VERSION_OLD", c->Name, c->ClientBuild, hub->Option->ClientMinimumRequiredBuild);
+
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ c->Err = ERR_VERSION_INVALID;
+ Free(policy);
+ error_detail = "ERR_VERSION_INVALID";
+ goto CLEANUP;
+ }
+
+ if (hub->Option->RequiredClientId != 0 &&
+ hub->Option->RequiredClientId != client_id &&
+ InStrEx(c->ClientStr, "client", false))
+ {
+ // Build number of the client is too small
+ HLog(hub, "LH_CLIENT_ID_REQUIRED", c->Name, client_id, hub->Option->RequiredClientId);
+
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ c->Err = ERR_CLIENT_ID_REQUIRED;
+ error_detail = "ERR_CLIENT_ID_REQUIRED";
+ Free(policy);
+ goto CLEANUP;
+ }
+
+ if ((policy->NoSavePassword) || (policy->AutoDisconnect != 0))
+ {
+ if (c->ClientBuild < 6560 && InStrEx(c->ClientStr, "client", false))
+ {
+ // If NoSavePassword policy is specified,
+ // only supported client can connect
+ HLog(hub, "LH_CLIENT_VERSION_OLD", c->Name, c->ClientBuild, 6560);
+
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ c->Err = ERR_VERSION_INVALID;
+ error_detail = "ERR_VERSION_INVALID";
+ Free(policy);
+ goto CLEANUP;
+ }
+ }
+
+ if (user_expires != 0 && user_expires <= SystemTime64())
+ {
+ // User expired
+ HLog(hub, "LH_USER_EXPIRES", c->Name, username);
+
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ c->Err = ERR_ACCESS_DENIED;
+ error_detail = "LH_USER_EXPIRES";
+ Free(policy);
+ goto CLEANUP;
+ }
+
+ if (policy->Access == false)
+ {
+ // Access is denied
+ HLog(hub, "LH_POLICY_ACCESS_NG", c->Name, username);
+
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ error_detail = "LH_POLICY_ACCESS_NG";
+ c->Err = ERR_ACCESS_DENIED;
+ Free(policy);
+ goto CLEANUP;
+ }
+
+ // Determine the contents of the policy by comparing to
+ // option presented by client or deny the connection.
+ // Confirm the connectivity in the monitor-mode first
+ if (require_monitor_mode && policy->MonitorPort == false)
+ {
+ // Can not connect in the monitor port mode
+ HLog(hub, "LH_POLICY_MONITOR_MODE", c->Name);
+
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ c->Err = ERR_MONITOR_MODE_DENIED;
+ Free(policy);
+ error_detail = "ERR_MONITOR_MODE_DENIED";
+ goto CLEANUP;
+ }
+
+ if (policy->MonitorPort)
+ {
+ if (require_monitor_mode == false)
+ {
+ policy->MonitorPort = false;
+ }
+ }
+
+ if (policy->MonitorPort)
+ {
+ qos = false;
+ }
+
+ // Determine whether it can be connected by a bridge / routing mode next
+ if (require_bridge_routing_mode &&
+ (policy->NoBridge && policy->NoRouting))
+ {
+ // Can not be connected by a bridge / routing mode
+ HLog(hub, "LH_POLICY_BRIDGE_MODE", c->Name);
+
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ c->Err = ERR_BRIDGE_MODE_DENIED;
+ error_detail = "ERR_BRIDGE_MODE_DENIED";
+ Free(policy);
+ goto CLEANUP;
+ }
+
+ if (require_bridge_routing_mode == false)
+ {
+ policy->NoBridge = true;
+ policy->NoRouting = true;
+ }
+
+ GenerateMachineUniqueHash(unique2);
+
+ if (Cmp(unique, unique2, SHA1_SIZE) == 0)
+ {
+ // It's a localhost session
+ local_host_session = true;
+ }
+
+ if (local_host_session == false)
+ {
+ // Make further judgment whether localhost session
+ SOCK *s = c->FirstSock;
+
+ if (s != NULL)
+ {
+ if (IsIPMyHost(&s->RemoteIP))
+ {
+ // It's a localhost session
+ local_host_session = true;
+ }
+ }
+ }
+
+ if (local_host_session)
+ {
+ // Permit routing or bridging in the case of localhost session
+ policy->NoBridge = false;
+ policy->NoRouting = false;
+ }
+
+ if (local_host_session == false)
+ {
+
+ if (policy->NoBridge == false || policy->NoRouting == false)
+ {
+ use_bridge_license = true;
+ }
+ else
+ {
+ use_client_license = true;
+ }
+ }
+
+
+ if (server != NULL && server->ServerType != SERVER_TYPE_FARM_MEMBER &&
+ policy != NULL)
+ {
+ if (GetServerCapsBool(hub->Cedar->Server, "b_support_limit_multilogin"))
+ {
+ // Check if the number of concurrent multiple logins limit is specified in the policy
+ RPC_ENUM_SESSION t;
+ UINT i, num;
+ UINT max_logins = policy->MultiLogins;
+ UINT ao = GetHubAdminOption(hub, "max_multilogins_per_user");
+
+ if (ao != 0)
+ {
+ if (max_logins != 0)
+ {
+ max_logins = MIN(max_logins, ao);
+ }
+ else
+ {
+ max_logins = ao;
+ }
+ }
+
+ if (max_logins != 0)
+ {
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hub->Name);
+
+ Unlock(hub->lock);
+
+ SiEnumSessionMain(server, &t);
+
+ Lock(hub->lock);
+
+ num = 0;
+
+ for (i = 0;i < t.NumSession;i++)
+ {
+ RPC_ENUM_SESSION_ITEM *e = &t.Sessions[i];
+
+ if (e->BridgeMode == false && e->Layer3Mode == false && e->LinkMode == false && e->CurrentNumTcp != 0)
+ {
+ if (StrCmpi(e->Username, username) == 0 &&
+ (IsZero(e->UniqueId, 16) || Cmp(e->UniqueId, node.UniqueId, 16) != 0))
+ {
+ num++;
+ }
+ }
+ }
+
+ FreeRpcEnumSession(&t);
+
+ if (num >= max_logins)
+ {
+ // Can not connect any more
+ Unlock(hub->lock);
+
+ // Dump a detailed error log
+ HLog(hub, "LH_TOO_MANY_MULTILOGINS",
+ c->Name,
+ username, max_logins, num);
+
+ ReleaseHub(hub);
+ c->Err = ERR_TOO_MANY_USER_SESSION;
+ Free(policy);
+ goto CLEANUP;
+ }
+ }
+ }
+ }
+
+ if (loggedin_user_object != NULL)
+ {
+ // Update the user information
+ Lock(loggedin_user_object->lock);
+ {
+ loggedin_user_object->LastLoginTime = SystemTime64();
+ }
+ Unlock(loggedin_user_object->lock);
+ }
+
+ // Update the number of log-ins
+ hub->LastCommTime = hub->LastLoginTime = SystemTime64();
+
+ if (farm_controller)
+ {
+ wchar_t *msg = GetHubMsg(hub);
+
+ Unlock(hub->lock);
+
+ Lock(cedar->CedarSuperLock);
+
+ // In the case of farm controller, choose a farm members to host this HUB
+ LockList(server->FarmMemberList);
+ {
+ HLog(hub, "LH_FARM_SELECT_1", c->Name);
+ f = SiGetHubHostingMember(server, hub, admin_mode, c);
+
+ if (f == NULL)
+ {
+ // Failed in the selection
+ HLog(hub, "LH_FARM_SELECT_2", c->Name);
+ UnlockList(server->FarmMemberList);
+ Unlock(cedar->CedarSuperLock);
+ ReleaseHub(hub);
+ c->Err = ERR_COULD_NOT_HOST_HUB_ON_FARM;
+ Free(policy);
+ Free(msg);
+ goto CLEANUP;
+ }
+ else
+ {
+ if (f->Me == false)
+ {
+ UCHAR ticket[SHA1_SIZE];
+ PACK *p;
+ BUF *b;
+ UINT i;
+
+ SLog(c->Cedar, "LH_FARM_SELECT_4", c->Name, f->hostname);
+
+ // Create a session on the selected server farm member
+ Rand(ticket, sizeof(ticket));
+ SiCallCreateTicket(server, f, hub->Name,
+ username, username_real, policy, ticket, Inc(hub->SessionCounter), groupname);
+
+ p = NewPack();
+ PackAddInt(p, "Redirect", 1);
+ PackAddIp32(p, "Ip", f->Ip);
+ for (i = 0;i < f->NumPort;i++)
+ {
+ PackAddIntEx(p, "Port", f->Ports[i], i, f->NumPort);
+ }
+ PackAddData(p, "Ticket", ticket, sizeof(ticket));
+
+ if (true)
+ {
+ char *utf = CopyUniToUtf(msg);
+
+ PackAddData(p, "Msg", utf, StrLen(utf));
+
+ Free(utf);
+ }
+
+ b = XToBuf(f->ServerCert, false);
+ PackAddBuf(p, "Cert", b);
+ FreeBuf(b);
+
+ UnlockList(server->FarmMemberList);
+ Unlock(cedar->CedarSuperLock);
+ ReleaseHub(hub);
+
+ HttpServerSend(c->FirstSock, p);
+ FreePack(p);
+
+ c->Err = 0;
+ Free(policy);
+
+ FreePack(HttpServerRecv(c->FirstSock));
+ Free(msg);
+ goto CLEANUP;
+ }
+ else
+ {
+ HLog(hub, "LH_FARM_SELECT_3", c->Name);
+ // Continue the process because myself was selected
+ UnlockList(server->FarmMemberList);
+ Unlock(cedar->CedarSuperLock);
+ f->Point = SiGetPoint(server);
+ Lock(hub->lock);
+ Free(msg);
+ }
+ }
+ }
+ }
+
+ if (admin_mode == false)
+ {
+ // Check the maximum number of connections of the HUB
+ if (hub->Option->MaxSession != 0 &&
+ hub->Option->MaxSession <= Count(hub->NumSessions))
+ {
+ // Can not connect any more
+ Unlock(hub->lock);
+
+ HLog(hub, "LH_MAX_SESSION", c->Name, hub->Option->MaxSession);
+
+ ReleaseHub(hub);
+ c->Err = ERR_HUB_IS_BUSY;
+ Free(policy);
+ error_detail = "ERR_HUB_IS_BUSY";
+ goto CLEANUP;
+ }
+ }
+
+ if (use_client_license || use_bridge_license)
+ {
+ // Examine whether not to conflict with the limit of simultaneous connections
+ // number of sessions defined by the Virtual HUB management options
+ if (
+ (GetHubAdminOption(hub, "max_sessions") != 0 &&
+ (Count(hub->NumSessionsClient) + Count(hub->NumSessionsBridge)) >= GetHubAdminOption(hub, "max_sessions"))
+ ||
+ (hub->Option->MaxSession != 0 &&
+ (Count(hub->NumSessionsClient) + Count(hub->NumSessionsBridge)) >= hub->Option->MaxSession))
+ {
+ // Can not connect any more
+ Unlock(hub->lock);
+
+ HLog(hub, "LH_MAX_SESSION", c->Name, GetHubAdminOption(hub, "max_sessions"));
+
+ ReleaseHub(hub);
+ c->Err = ERR_HUB_IS_BUSY;
+ Free(policy);
+ goto CLEANUP;
+ }
+ }
+
+ if (use_client_license)
+ {
+ // Examine whether not to conflict with the limit of simultaneous connections
+ // number of sessions(client) defined by the Virtual HUB management options
+ if (((GetHubAdminOption(hub, "max_sessions_client_bridge_apply") != 0
+ ) &&
+ Count(hub->NumSessionsClient) >= GetHubAdminOption(hub, "max_sessions_client") && hub->Cedar->Server != NULL && hub->Cedar->Server->ServerType != SERVER_TYPE_FARM_MEMBER)
+ ||
+ (hub->FarmMember_MaxSessionClientBridgeApply &&
+ Count(hub->NumSessionsClient) >= hub->FarmMember_MaxSessionClient))
+ {
+ // Can not connect any more
+ Unlock(hub->lock);
+
+ HLog(hub, "LH_MAX_SESSION_CLIENT", c->Name, GetHubAdminOption(hub, "max_sessions_client"));
+
+ ReleaseHub(hub);
+ c->Err = ERR_HUB_IS_BUSY;
+ Free(policy);
+ goto CLEANUP;
+ }
+ }
+
+ if (use_bridge_license)
+ {
+ // Examine whether not to conflict with the limit of simultaneous connections
+ // number of sessions(bridge) defined by the Virtual HUB management options
+ if (((GetHubAdminOption(hub, "max_sessions_client_bridge_apply") != 0
+ ) &&
+ Count(hub->NumSessionsBridge) >= GetHubAdminOption(hub, "max_sessions_bridge") && hub->Cedar->Server != NULL && hub->Cedar->Server->ServerType != SERVER_TYPE_FARM_MEMBER)
+ ||
+ (hub->FarmMember_MaxSessionClientBridgeApply &&
+ Count(hub->NumSessionsBridge) >= hub->FarmMember_MaxSessionBridge))
+ {
+ // Can not connect any more
+ Unlock(hub->lock);
+
+ HLog(hub, "LH_MAX_SESSION_BRIDGE", c->Name, GetHubAdminOption(hub, "max_sessions_bridge"));
+
+ ReleaseHub(hub);
+ c->Err = ERR_HUB_IS_BUSY;
+ Free(policy);
+ goto CLEANUP;
+ }
+ }
+
+ if (Count(hub->Cedar->CurrentSessions) >= GetServerCapsInt(hub->Cedar->Server, "i_max_sessions"))
+ {
+ // Can not connect any more
+ Unlock(hub->lock);
+
+ HLog(hub, "LH_MAX_SESSION_2", c->Name, GetServerCapsInt(hub->Cedar->Server, "i_max_sessions"));
+
+ ReleaseHub(hub);
+ c->Err = ERR_HUB_IS_BUSY;
+ Free(policy);
+ goto CLEANUP;
+ }
+
+ // Increment the current number of connections
+ Inc(hub->NumSessions);
+ if (use_bridge_license)
+ {
+ Inc(hub->NumSessionsBridge);
+ }
+
+ if (use_client_license)
+ {
+ Inc(hub->NumSessionsClient);
+ }
+ Inc(hub->Cedar->CurrentSessions);
+
+ // Calculate the time-out period
+ timeout = policy->TimeOut * 1000; // Convert milliseconds to seconds
+ if (timeout == 0)
+ {
+ timeout = TIMEOUT_DEFAULT;
+ }
+ timeout = MIN(timeout, TIMEOUT_MAX);
+ timeout = MAX(timeout, TIMEOUT_MIN);
+
+ // Update the max_connection according to the policy
+ max_connection = MIN(max_connection, policy->MaxConnection);
+ max_connection = MIN(max_connection, MAX_TCP_CONNECTION);
+ max_connection = MAX(max_connection, 1);
+
+ if (c->FirstSock->IsRUDPSocket)
+ {
+ // In the case of TCP-over-UDP
+ half_connection = false;
+
+ // Disable the QoS
+ qos = false;
+
+ if (enable_udp_recovery == false)
+ {
+ // Disable the session reconnection feature
+ no_reconnect_to_session = true;
+ max_connection = 1;
+ }
+ else
+ {
+ // If the UDP recovery is enabled, permit the session re-connection feature (for 2)
+ no_reconnect_to_session = false;
+ max_connection = NUM_TCP_CONNECTION_FOR_UDP_RECOVERY;
+ }
+ }
+
+ if (half_connection)
+ {
+ // Number of connections should be more than 2 in the case of Half Connection
+ max_connection = MAX(max_connection, 2);
+ }
+
+ if (qos)
+ {
+ // Number of connections is set to 2 or more when using the VoIP / QoS
+ max_connection = MAX(max_connection, 2);
+ if (half_connection)
+ {
+ max_connection = MAX(max_connection, 4);
+ }
+ }
+
+ c->Status = CONNECTION_STATUS_ESTABLISHED;
+
+ // Remove the connection from Cedar
+ DelConnection(c->Cedar, c);
+
+ // Create a Session
+ StrLower(username);
+ s = NewServerSessionEx(c->Cedar, c, hub, username, policy, c->IsInProc);
+
+ s->EnableUdpRecovery = enable_udp_recovery;
+ s->LocalHostSession = local_host_session;
+ s->NormalClient = true;
+
+ if (c->FirstSock->IsRUDPSocket)
+ {
+ // R-UDP session
+ s->IsRUDPSession = true;
+ s->RUdpMss = c->FirstSock->RUDP_OptimizedMss;
+ Debug("Optimized MSS Value for R-UDP: %u\n", s->RUdpMss);
+ }
+
+ if (enable_bulk_on_rudp)
+ {
+ // Allow bulk transfer on R-UDP
+ s->EnableBulkOnRUDP = true;
+ s->EnableHMacOnBulkOfRUDP = enable_hmac_on_bulk_of_rudp;
+ }
+
+ s->IsAzureSession = c->FirstSock->IsReverseAcceptedSocket;
+
+ StrCpy(s->UnderlayProtocol, sizeof(s->UnderlayProtocol), c->FirstSock->UnderlayProtocol);
+
+ if (server != NULL)
+ {
+ s->NoSendSignature = server->NoSendSignature;
+ }
+
+ if (c->IsInProc)
+ {
+ s->NoSendSignature = true;
+ }
+
+ if (c->IsInProc && StrCmpi(c->InProcPrefix, OPENVPN_IPC_POSTFIX_L3) == 0)
+ {
+ // OpenVPN L3 session
+ s->IsOpenVPNL3Session = true;
+ }
+
+ if (c->IsInProc && StrCmpi(c->InProcPrefix, OPENVPN_IPC_POSTFIX_L2) == 0)
+ {
+ // OpenVPN L2 session
+ s->IsOpenVPNL2Session = true;
+ }
+
+ // Determine whether the use of UDP acceleration mode
+ if (use_udp_acceleration_client)
+ {
+ s->UseUdpAcceleration = true;
+
+ s->UdpAccelFastDisconnectDetect = support_udp_accel_fast_disconnect_detect;
+ }
+
+ if (hub->Option != NULL && hub->Option->DisableUdpAcceleration)
+ {
+ s->UseUdpAcceleration = false;
+ }
+
+ if (IsZeroIP(&c->FirstSock->Reverse_MyServerGlobalIp) == false &&
+ CmpIpAddr(&c->FirstSock->Reverse_MyServerGlobalIp, &c->FirstSock->RemoteIP) == 0)
+ {
+ // Disable forcibly the UDP acceleration mode if VPN Server and VPN Client
+ // are in same LAN in the case of using VPN Azure.
+ // (Or this may cause infinite loop of packet)
+ s->UseUdpAcceleration = false;
+ }
+
+ if (s->UseUdpAcceleration)
+ {
+ s->UseHMacOnUdpAcceleration = use_hmac_on_udp_acceleration;
+ }
+
+ Debug("UseUdpAcceleration = %u\n", s->UseUdpAcceleration);
+ Debug("UseHMacOnUdpAcceleration = %u\n", s->UseHMacOnUdpAcceleration);
+
+ if (s->UseUdpAcceleration)
+ {
+ // Initialize the UDP acceleration function
+ s->UdpAccel = NewUdpAccel(c->Cedar, (c->FirstSock->IsRUDPSocket ? NULL : &c->FirstSock->LocalIP), false, c->FirstSock->IsRUDPSocket, false);
+ if (s->UdpAccel == NULL)
+ {
+ s->UseUdpAcceleration = false;
+ Debug("NewUdpAccel Failed.\n");
+ }
+ else
+ {
+ if (UdpAccelInitServer(s->UdpAccel, udp_acceleration_client_key, &udp_acceleration_client_ip, udp_acceleration_client_port,
+ &c->FirstSock->RemoteIP) == false)
+ {
+ Debug("UdpAccelInitServer Failed.\n");
+ s->UseUdpAcceleration = false;
+ }
+
+ s->UdpAccel->FastDetect = s->UdpAccelFastDisconnectDetect;
+
+ if (use_encrypt == false)
+ {
+ s->UdpAccel->PlainTextMode = true;
+ }
+
+ s->UdpAccel->UseHMac = s->UseHMacOnUdpAcceleration;
+ }
+ }
+
+ s->UseClientLicense = use_client_license;
+ s->UseBridgeLicense = use_bridge_license;
+
+ s->AdjustMss = adjust_mss;
+ if (s->AdjustMss != 0)
+ {
+ Debug("AdjustMSS: %u\n", s->AdjustMss);
+ }
+
+ s->IsBridgeMode = (policy->NoBridge == false) || (policy->NoRouting == false);
+ s->IsMonitorMode = policy->MonitorPort;
+
+ // Decide whether IPv6 session
+ s->IPv6Session = false;
+
+ if (node.ClientIpAddress == 0)
+ {
+ s->IPv6Session = true;
+ }
+
+ if (use_bridge_license)
+ {
+ Inc(s->Cedar->AssignedBridgeLicense);
+ }
+
+ if (use_client_license)
+ {
+ Inc(s->Cedar->AssignedClientLicense);
+ }
+
+ if (server != NULL)
+ {
+ // Update the total allocation of the number of licenses for Server structure
+ if (server->ServerType == SERVER_TYPE_STANDALONE)
+ {
+ // Update only stand-alone mode
+ // (Periodically poll in the cluster controller mode)
+ server->CurrentAssignedClientLicense = Count(s->Cedar->AssignedClientLicense);
+ server->CurrentAssignedBridgeLicense = Count(s->Cedar->AssignedBridgeLicense);
+ }
+ }
+
+ if (StrLen(sessionname) != 0)
+ {
+ // Specify the session name
+ Free(s->Name);
+ s->Name = CopyStr(sessionname);
+ }
+
+ {
+ char ip[128];
+ IPToStr(ip, sizeof(ip), &c->FirstSock->RemoteIP);
+ HLog(hub, "LH_NEW_SESSION", c->Name, s->Name, ip, c->FirstSock->RemotePort,
+ c->FirstSock->UnderlayProtocol);
+ }
+
+ c->Session = s;
+ s->AdministratorMode = admin_mode;
+ StrCpy(s->UserNameReal, sizeof(s->UserNameReal), username_real);
+ StrCpy(s->GroupName, sizeof(s->GroupName), groupname);
+
+ // Get the session key
+ Copy(session_key, s->SessionKey, SHA1_SIZE);
+
+ // Set the parameters
+ s->MaxConnection = max_connection;
+ s->UseEncrypt = use_encrypt;
+ if (s->UseEncrypt && use_fast_rc4)
+ {
+ s->UseFastRC4 = use_fast_rc4;
+ }
+ s->UseCompress = use_compress;
+ s->HalfConnection = half_connection;
+ s->Timeout = timeout;
+ s->QoS = qos;
+ s->NoReconnectToSession = no_reconnect_to_session;
+
+ if (policy != NULL)
+ {
+ s->VLanId = policy->VLanId;
+ }
+
+ // User name
+ s->Username = CopyStr(username);
+
+ HLog(hub, "LH_SET_SESSION", s->Name, s->MaxConnection,
+ s->UseEncrypt ? _UU("L_YES") : _UU("L_NO"),
+ s->UseCompress ? _UU("L_YES") : _UU("L_NO"),
+ s->HalfConnection ? _UU("L_YES") : _UU("L_NO"),
+ s->Timeout / 1000);
+
+ msg = GetHubMsg(hub);
+ }
+ Unlock(hub->lock);
+
+ // Send a Welcome packet to the client
+ p = PackWelcome(s);
+
+ if (s->InProcMode)
+ {
+ if (IsZero(mschap_v2_server_response_20, sizeof(mschap_v2_server_response_20)) == false)
+ {
+ // MS-CHAPv2 Response
+ PackAddData(p, "IpcMsChapV2ServerResponse", mschap_v2_server_response_20, sizeof(mschap_v2_server_response_20));
+ }
+ }
+
+ if (true)
+ {
+ // A message to be displayed in the VPN Client (Will not be displayed if the VPN Gate Virtual HUB)
+ char *utf;
+ wchar_t winver_msg_client[3800];
+ wchar_t winver_msg_server[3800];
+ UINT tmpsize;
+ wchar_t *tmp;
+ RPC_WINVER server_winver;
+
+ GetWinVer(&server_winver);
+
+ Zero(winver_msg_client, sizeof(winver_msg_client));
+ Zero(winver_msg_server, sizeof(winver_msg_server));
+
+ if (IsSupportedWinVer(&winver) == false)
+ {
+ SYSTEMTIME st;
+
+ LocalTime(&st);
+
+ UniFormat(winver_msg_client, sizeof(winver_msg_client), _UU("WINVER_ERROR_FORMAT"),
+ _UU("WINVER_ERROR_PC_LOCAL"),
+ winver.Title,
+ _UU("WINVER_ERROR_VPNSERVER"),
+ SUPPORTED_WINDOWS_LIST,
+ _UU("WINVER_ERROR_PC_LOCAL"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ st.wYear, st.wMonth);
+ }
+
+ if (IsSupportedWinVer(&server_winver) == false)
+ {
+ SYSTEMTIME st;
+
+ LocalTime(&st);
+
+ UniFormat(winver_msg_server, sizeof(winver_msg_server), _UU("WINVER_ERROR_FORMAT"),
+ _UU("WINVER_ERROR_PC_REMOTE"),
+ server_winver.Title,
+ _UU("WINVER_ERROR_VPNSERVER"),
+ SUPPORTED_WINDOWS_LIST,
+ _UU("WINVER_ERROR_PC_REMOTE"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ st.wYear, st.wMonth);
+ }
+
+ tmpsize = UniStrSize(winver_msg_client) + UniStrSize(winver_msg_server) + UniStrSize(msg) + 16000;
+
+ tmp = ZeroMalloc(tmpsize);
+
+ if (IsURLMsg(msg, NULL, 0) == false)
+ {
+
+ {
+ if (GetCurrentLangId() != SE_LANG_ENGLISH)
+ {
+ UniStrCat(tmp, tmpsize, _UU("OSS_MSG"));
+ }
+ }
+
+ {
+ UniStrCat(tmp, tmpsize, winver_msg_client);
+ UniStrCat(tmp, tmpsize, winver_msg_server);
+ }
+ }
+ UniStrCat(tmp, tmpsize, msg);
+
+ utf = CopyUniToUtf(tmp);
+
+ PackAddData(p, "Msg", utf, StrLen(utf));
+
+ Free(tmp);
+ Free(utf);
+ }
+
+ Free(msg);
+
+
+ if (s->UseFastRC4)
+ {
+ // Generate a RC4 key pair
+ GenerateRC4KeyPair(&key_pair);
+
+ // Add to Welcome packet
+ PackAddData(p, "rc4_key_client_to_server", key_pair.ClientToServerKey, sizeof(key_pair.ClientToServerKey));
+ PackAddData(p, "rc4_key_server_to_client", key_pair.ServerToClientKey, sizeof(key_pair.ServerToClientKey));
+ {
+ char key1[64], key2[64];
+ BinToStr(key1, sizeof(key1), key_pair.ClientToServerKey, 16);
+ BinToStr(key2, sizeof(key2), key_pair.ServerToClientKey, 16);
+ Debug(
+ "Client to Server Key: %s\n"
+ "Server to Client Key: %s\n",
+ key1, key2);
+ }
+ }
+
+ // Brand string for the connection limit
+ {
+ char *branded_cfroms = _SS("BRANDED_C_FROM_S");
+ if(StrLen(branded_cfroms) > 0)
+ {
+ PackAddStr(p, "branded_cfroms", branded_cfroms);
+ }
+ }
+
+ HttpServerSend(c->FirstSock, p);
+ FreePack(p);
+
+ // Receive a signature
+ Copy(&c->Session->NodeInfo, &node, sizeof(NODE_INFO));
+
+
+ {
+ wchar_t tmp[MAX_SIZE * 2];
+ NodeInfoToStr(tmp, sizeof(tmp), &s->NodeInfo);
+
+ HLog(hub, "LH_NODE_INFO", s->Name, tmp);
+ }
+
+ // Shift the connection to the tunneling mode
+ StartTunnelingMode(c);
+
+ // Processing of half-connection mode
+ if (s->HalfConnection)
+ {
+ // The direction of the first socket is client to server
+ TCPSOCK *ts = (TCPSOCK *)LIST_DATA(c->Tcp->TcpSockList, 0);
+ ts->Direction = TCP_CLIENT_TO_SERVER;
+ }
+
+ if (s->UseFastRC4)
+ {
+ // Set the RC4 key information to the first TCP connection
+ TCPSOCK *ts = (TCPSOCK *)LIST_DATA(c->Tcp->TcpSockList, 0);
+ Copy(&ts->Rc4KeyPair, &key_pair, sizeof(RC4_KEY_PAIR));
+
+ InitTcpSockRc4Key(ts, true);
+ }
+
+ if (s->UseEncrypt && s->UseFastRC4 == false)
+ {
+ s->UseSSLDataEncryption = true;
+ }
+ else
+ {
+ s->UseSSLDataEncryption = false;
+ }
+
+ if (s->Hub->Type == HUB_TYPE_FARM_DYNAMIC && s->Cedar->Server != NULL && s->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ if (s->Hub->BeingOffline == false)
+ {
+ // Start the SecureNAT on the dynamic Virtual HUB
+ EnableSecureNATEx(s->Hub, false, true);
+
+ cluster_dynamic_secure_nat = true;
+ }
+ }
+
+ if (s->LocalHostSession)
+ {
+ // Update the local MAC address list
+ RefreshLocalMacAddressList();
+ }
+
+ // Discard the user list cache
+ DeleteAllUserListCache(hub->UserList);
+
+
+ // Main routine of the session
+ Debug("SessionMain()\n");
+ s->NumLoginIncrementUserObject = loggedin_user_object;
+ s->NumLoginIncrementHubObject = s->Hub;
+ s->NumLoginIncrementTick = Tick64() + (UINT64)NUM_LOGIN_INCREMENT_INTERVAL;
+ SessionMain(s);
+
+
+ // Discard the user list cache
+ DeleteAllUserListCache(hub->UserList);
+
+ // Decrement the current number of connections
+ Lock(s->Hub->lock);
+ {
+ if (use_bridge_license)
+ {
+ Dec(hub->NumSessionsBridge);
+ }
+
+ if (use_client_license)
+ {
+ Dec(hub->NumSessionsClient);
+ }
+
+ Dec(s->Hub->NumSessions);
+ Dec(s->Hub->Cedar->CurrentSessions);
+
+ // Decrement the number of licenses
+ if (use_bridge_license)
+ {
+ Dec(s->Cedar->AssignedBridgeLicense);
+ }
+
+ if (use_client_license)
+ {
+ Dec(s->Cedar->AssignedClientLicense);
+ }
+
+ if (server != NULL)
+ {
+ // Update the total allocation of the number of licenses for Server structure
+ if (server->ServerType == SERVER_TYPE_STANDALONE)
+ {
+ // Update only stand-alone mode
+ // (Periodically polled in the cluster controller mode)
+ server->CurrentAssignedClientLicense = Count(s->Cedar->AssignedClientLicense);
+ server->CurrentAssignedBridgeLicense = Count(s->Cedar->AssignedBridgeLicense);
+ }
+ }
+ }
+ Unlock(s->Hub->lock);
+
+ PrintSessionTotalDataSize(s);
+
+ HLog(s->Hub, "LH_END_SESSION", s->Name, s->TotalSendSizeReal, s->TotalRecvSizeReal);
+
+ if (cluster_dynamic_secure_nat && s->Hub->BeingOffline == false)
+ {
+ // Stop the SecureNAT on the dynamic Virtual HUB
+ EnableSecureNATEx(s->Hub, false, true);
+ }
+
+ if (s->UdpAccel != NULL)
+ {
+ // Release the UDP acceleration
+ FreeUdpAccel(s->UdpAccel);
+ s->UdpAccel = NULL;
+ }
+
+ ReleaseSession(s);
+
+ ret = true;
+ c->Err = ERR_SESSION_REMOVED;
+
+ ReleaseHub(hub);
+
+ goto CLEANUP;
+ }
+ else if (StrCmpi(method, "additional_connect") == 0)
+ {
+ SOCK *sock;
+ TCPSOCK *ts;
+ UINT dummy;
+
+ c->Type = CONNECTION_TYPE_ADDITIONAL;
+
+ // Additional connection
+ // Read the session key
+ if (GetSessionKeyFromPack(p, session_key, &dummy) == false)
+ {
+ FreePack(p);
+ c->Err = ERR_PROTOCOL_ERROR;
+ goto CLEANUP;
+ }
+
+ FreePack(p);
+
+ // Get the session from the session key
+ s = GetSessionFromKey(c->Cedar, session_key);
+ if (s == NULL || s->Halt || s->NoReconnectToSession)
+ {
+ // Session can not be found, or re-connection is prohibited
+ Debug("Session Not Found.\n");
+ c->Err = ERR_SESSION_TIMEOUT;
+ goto CLEANUP;
+ }
+
+ // Session is found
+ Debug("Session Found: %s\n", s->Name);
+ // Check the protocol of session
+ c->Err = 0;
+ Lock(s->lock);
+ {
+ if (s->Connection->Protocol != CONNECTION_TCP)
+ {
+ c->Err = ERR_INVALID_PROTOCOL;
+ }
+ }
+ Unlock(s->lock);
+ // Check the current number of connections of the session
+ Lock(s->Connection->lock);
+ if (c->Err == 0)
+ {
+ if (Count(s->Connection->CurrentNumConnection) > s->MaxConnection)
+ {
+ c->Err = ERR_TOO_MANY_CONNECTION;
+ }
+ }
+ if (c->Err != 0)
+ {
+ Unlock(s->Connection->lock);
+ if (c->Err == ERR_TOO_MANY_CONNECTION)
+ {
+ Debug("Session TOO MANY CONNECTIONS !!: %u\n",
+ Count(s->Connection->CurrentNumConnection));
+ }
+ else
+ {
+ Debug("Session Invalid Protocol.\n");
+ }
+ ReleaseSession(s);
+ goto CLEANUP;
+ }
+
+ // Generate a high-speed RC4 encryption key
+ if (s->UseFastRC4)
+ {
+ GenerateRC4KeyPair(&key_pair);
+ }
+
+ // Add the socket of this connection to the connection list of the session (TCP)
+ sock = c->FirstSock;
+ ts = NewTcpSock(sock);
+ SetTimeout(sock, CONNECTING_TIMEOUT);
+ direction = TCP_BOTH;
+ LockList(s->Connection->Tcp->TcpSockList);
+ {
+ if (s->HalfConnection)
+ {
+ // In half-connection, directions of the TCP connections are automatically
+ // adjusted by examining all current direction of the TCP connections
+ UINT i, c2s, s2c;
+ c2s = s2c = 0;
+ for (i = 0;i < LIST_NUM(s->Connection->Tcp->TcpSockList);i++)
+ {
+ TCPSOCK *ts = (TCPSOCK *)LIST_DATA(s->Connection->Tcp->TcpSockList, i);
+ if (ts->Direction == TCP_SERVER_TO_CLIENT)
+ {
+ s2c++;
+ }
+ else
+ {
+ c2s++;
+ }
+ }
+ if (s2c > c2s)
+ {
+ direction = TCP_CLIENT_TO_SERVER;
+ }
+ else
+ {
+ direction = TCP_SERVER_TO_CLIENT;
+ }
+ Debug("%u/%u\n", s2c, c2s);
+ ts->Direction = direction;
+ }
+ }
+ UnlockList(s->Connection->Tcp->TcpSockList);
+
+ if (s->UseFastRC4)
+ {
+ // Set the RC4 key information
+ Copy(&ts->Rc4KeyPair, &key_pair, sizeof(RC4_KEY_PAIR));
+
+ InitTcpSockRc4Key(ts, true);
+ }
+
+ // Return a success result
+ p = PackError(ERR_NO_ERROR);
+ PackAddInt(p, "direction", direction);
+
+ if (s->UseFastRC4)
+ {
+ // Add a RC4 key information
+ PackAddData(p, "rc4_key_client_to_server", key_pair.ClientToServerKey, sizeof(key_pair.ClientToServerKey));
+ PackAddData(p, "rc4_key_server_to_client", key_pair.ServerToClientKey, sizeof(key_pair.ServerToClientKey));
+ {
+ char key1[64], key2[64];
+ BinToStr(key1, sizeof(key1), key_pair.ClientToServerKey, 16);
+ BinToStr(key2, sizeof(key2), key_pair.ServerToClientKey, 16);
+ Debug(
+ "Client to Server Key: %s\n"
+ "Server to Client Key: %s\n",
+ key1, key2);
+ }
+ }
+
+ HttpServerSend(c->FirstSock, p);
+ FreePack(p);
+
+ SetTimeout(sock, INFINITE);
+
+ LockList(s->Connection->Tcp->TcpSockList);
+ {
+ Add(s->Connection->Tcp->TcpSockList, ts);
+ }
+ UnlockList(s->Connection->Tcp->TcpSockList);
+
+ // Increment the number of connections
+ Inc(s->Connection->CurrentNumConnection);
+ Debug("TCP Connection Incremented: %u\n", Count(s->Connection->CurrentNumConnection));
+
+ // Issue the Cancel of session
+ Cancel(s->Cancel1);
+
+ Unlock(s->Connection->lock);
+
+ c->flag1 = true;
+
+ ReleaseSession(s);
+
+ return true;
+ }
+ else if (StrCmpi(method, "enum_hub") == 0)
+ {
+ // Enumerate the Virtual HUB
+ UINT i, num;
+ LIST *o;
+ o = NewListFast(NULL);
+
+ c->Type = CONNECTION_TYPE_ENUM_HUB;
+
+ FreePack(p);
+ p = NewPack();
+ LockList(c->Cedar->HubList);
+ {
+ num = LIST_NUM(c->Cedar->HubList);
+ for (i = 0;i < num;i++)
+ {
+ HUB *h = LIST_DATA(c->Cedar->HubList, i);
+ if (h->Option != NULL && h->Option->NoEnum == false)
+ {
+ Insert(o, CopyStr(h->Name));
+ }
+ }
+ }
+ UnlockList(c->Cedar->HubList);
+
+ num = LIST_NUM(o);
+ for (i = 0;i < num;i++)
+ {
+ char *name = LIST_DATA(o, i);
+ PackAddStrEx(p, "HubName", name, i, num);
+ Free(name);
+ }
+ ReleaseList(o);
+ PackAddInt(p, "NumHub", num);
+
+ HttpServerSend(c->FirstSock, p);
+ FreePack(p);
+ FreePack(HttpServerRecv(c->FirstSock));
+ c->Err = 0;
+
+ SLog(c->Cedar, "LS_ENUM_HUB", c->Name, num);
+
+ error_detail = "enum_hub";
+
+ goto CLEANUP;
+ }
+ else if (StrCmpi(method, "farm_connect") == 0)
+ {
+ // Server farm connection request
+ CEDAR *cedar = c->Cedar;
+ c->Type = CONNECTION_TYPE_FARM_RPC;
+ c->Err = 0;
+ if (c->Cedar->Server == NULL)
+ {
+ // Unsupported
+ c->Err = ERR_NOT_FARM_CONTROLLER;
+ }
+ else
+ {
+ SERVER *s = c->Cedar->Server;
+ if (s->ServerType != SERVER_TYPE_FARM_CONTROLLER || s->FarmControllerInited == false)
+ {
+ // Not a farm controller
+ SLog(c->Cedar, "LS_FARM_ACCEPT_1", c->Name);
+ c->Err = ERR_NOT_FARM_CONTROLLER;
+ }
+ else
+ {
+ UCHAR check_secure_password[SHA1_SIZE];
+ UCHAR secure_password[SHA1_SIZE];
+ // User authentication
+ SecurePassword(check_secure_password, s->HashedPassword, c->Random);
+ if (PackGetDataSize(p, "SecurePassword") == sizeof(secure_password))
+ {
+ PackGetData(p, "SecurePassword", secure_password);
+ }
+ else
+ {
+ Zero(secure_password, sizeof(secure_password));
+ }
+
+ if (Cmp(secure_password, check_secure_password, SHA1_SIZE) != 0)
+ {
+ // Password is different
+ SLog(c->Cedar, "LS_FARM_ACCEPT_2", c->Name);
+ c->Err = ERR_ACCESS_DENIED;
+ }
+ else
+ {
+ // Get the certificate
+ BUF *b;
+ X *server_x;
+
+ SLog(c->Cedar, "LS_FARM_ACCEPT_3", c->Name);
+ b = PackGetBuf(p, "ServerCert");
+ if (b == NULL)
+ {
+ c->Err = ERR_PROTOCOL_ERROR;
+ }
+ else
+ {
+ server_x = BufToX(b, false);
+ FreeBuf(b);
+ if (server_x == NULL)
+ {
+ c->Err = ERR_PROTOCOL_ERROR;
+ }
+ else
+ {
+ UINT ip;
+ UINT point;
+ char hostname[MAX_SIZE];
+
+#ifdef OS_WIN32
+ MsSetThreadPriorityRealtime();
+#endif // OS_WIN32
+
+ SetTimeout(c->FirstSock, SERVER_CONTROL_TCP_TIMEOUT);
+
+ ip = PackGetIp32(p, "PublicIp");
+ point = PackGetInt(p, "Point");
+ if (PackGetStr(p, "HostName", hostname, sizeof(hostname)))
+ {
+ UINT num_port = PackGetIndexCount(p, "PublicPort");
+ if (num_port >= 1 && num_port <= MAX_PUBLIC_PORT_NUM)
+ {
+ UINT *ports = ZeroMalloc(sizeof(UINT) * num_port);
+ UINT i;
+
+ for (i = 0;i < num_port;i++)
+ {
+ ports[i] = PackGetIntEx(p, "PublicPort", i);
+ }
+
+ SiFarmServ(s, c->FirstSock, server_x, ip, num_port, ports, hostname, point,
+ PackGetInt(p, "Weight"), PackGetInt(p, "MaxSessions"));
+
+ Free(ports);
+ }
+ }
+
+ FreeX(server_x);
+ }
+ }
+ }
+ }
+ }
+ FreePack(p);
+ goto CLEANUP;
+ }
+ else if (StrCmpi(method, "admin") == 0 && c->Cedar->Server != NULL)
+ {
+ UINT err;
+ // Administrative RPC connection request
+ c->Type = CONNECTION_TYPE_ADMIN_RPC;
+ err = AdminAccept(c, p);
+ FreePack(p);
+ if (err != ERR_NO_ERROR)
+ {
+ PACK *p = PackError(err);
+ HttpServerSend(c->FirstSock, p);
+ FreePack(p);
+ }
+
+ error_detail = "admin_rpc";
+
+ goto CLEANUP;
+ }
+ else if (StrCmpi(method, "password") == 0)
+ {
+ UINT err;
+ // Password change request
+ c->Type = CONNECTION_TYPE_PASSWORD;
+ err = ChangePasswordAccept(c, p);
+ FreePack(p);
+
+ p = PackError(err);
+ HttpServerSend(c->FirstSock, p);
+ FreePack(p);
+
+ error_detail = "change_password";
+
+ goto CLEANUP;
+ }
+ else
+ {
+ // Unknown method
+ FreePack(p);
+ c->Err = ERR_PROTOCOL_ERROR;
+
+ error_detail = "unknown_method";
+
+ goto CLEANUP;
+ }
+
+CLEANUP:
+ // Release the user object
+ if (loggedin_user_object != NULL)
+ {
+ ReleaseUser(loggedin_user_object);
+ }
+
+
+ // Error packet transmission
+ p = PackError(c->Err);
+ PackAddBool(p, "no_save_password", no_save_password);
+ HttpServerSend(c->FirstSock, p);
+ FreePack(p);
+ FreePack(HttpServerRecv(c->FirstSock));
+ SleepThread(25);
+
+ SLog(c->Cedar, "LS_CONNECTION_ERROR", c->Name, GetUniErrorStr(c->Err), c->Err);
+
+ return ret;
+}
+
+
+// Create a Node information
+void CreateNodeInfo(NODE_INFO *info, CONNECTION *c)
+{
+ SESSION *s;
+ OS_INFO *os;
+ char *product_id;
+ IP ip;
+ bool is_vgc = false;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ s = c->Session;
+ os = GetOsInfo();
+
+
+
+ Zero(info, sizeof(NODE_INFO));
+
+ // Client product name
+ StrCpy(info->ClientProductName, sizeof(info->ClientProductName), c->ClientStr);
+ // Client version
+ info->ClientProductVer = Endian32(c->ClientVer);
+ // Client build number
+ info->ClientProductBuild = Endian32(c->ClientBuild);
+
+ // Server product name
+ StrCpy(info->ServerProductName, sizeof(info->ServerProductName), c->ServerStr);
+ // Server version
+ info->ServerProductVer = Endian32(c->ServerVer);
+ // Server build number
+ info->ServerProductBuild = Endian32(c->ServerBuild);
+
+ // Client OS name
+ StrCpy(info->ClientOsName, sizeof(info->ClientOsName), os->OsProductName);
+ // Client OS version
+ StrCpy(info->ClientOsVer, sizeof(info->ClientOsVer), os->OsVersion);
+ // Client OS Product ID
+ product_id = OSGetProductId();
+ StrCpy(info->ClientOsProductId, sizeof(info->ClientOsProductId), product_id);
+ Free(product_id);
+
+ // Client host name
+#ifndef OS_WIN32
+ GetMachineName(info->ClientHostname, sizeof(info->ClientHostname));
+#else // OS_WIN32
+ if (true)
+ {
+ wchar_t namew[256];
+ char namea[256];
+
+ Zero(namew, sizeof(namew));
+ MsGetComputerNameFullEx(namew, sizeof(namew), true);
+
+ Zero(namea, sizeof(namea));
+ UniToStr(namea, sizeof(namea), namew);
+
+ if (IsEmptyStr(namea))
+ {
+ GetMachineName(namea, sizeof(namea));
+ }
+
+ StrCpy(info->ClientHostname, sizeof(info->ClientHostname), namea);
+
+ }
+#endif // OS_WIN32
+ // Client IP address
+ if (IsIP6(&c->FirstSock->LocalIP) == false)
+ {
+ info->ClientIpAddress = IPToUINT(&c->FirstSock->LocalIP);
+ }
+ else
+ {
+ Copy(info->ClientIpAddress6, c->FirstSock->LocalIP.ipv6_addr, sizeof(info->ClientIpAddress6));
+ }
+ // Client port number
+ info->ClientPort = Endian32(c->FirstSock->LocalPort);
+
+ // Server host name
+ StrCpy(info->ServerHostname, sizeof(info->ServerHostname), c->ServerName);
+ // Server IP address
+ if (GetIP(&ip, info->ServerHostname))
+ {
+ if (IsIP6(&ip) == false)
+ {
+ info->ServerIpAddress = IPToUINT(&ip);
+ }
+ else
+ {
+ Copy(info->ServerIpAddress6, ip.ipv6_addr, sizeof(info->ServerIpAddress6));
+ }
+ }
+ // Server port number
+ info->ServerPort = Endian32(c->ServerPort);
+
+ if (s->ClientOption->ProxyType == PROXY_SOCKS || s->ClientOption->ProxyType == PROXY_HTTP)
+ {
+ // Proxy host name
+ StrCpy(info->ProxyHostname, sizeof(info->ProxyHostname), s->ClientOption->ProxyName);
+
+ // Proxy Server IP Address
+ if (IsIP6(&c->FirstSock->RemoteIP) == false)
+ {
+ info->ProxyIpAddress = IPToUINT(&c->FirstSock->RemoteIP);
+ }
+ else
+ {
+ Copy(&info->ProxyIpAddress6, c->FirstSock->RemoteIP.ipv6_addr, sizeof(info->ProxyIpAddress6));
+ }
+
+ info->ProxyPort = Endian32(c->FirstSock->RemotePort);
+ }
+
+ // HUB name
+ StrCpy(info->HubName, sizeof(info->HubName), s->ClientOption->HubName);
+
+ // Unique ID
+ Copy(info->UniqueId, c->Cedar->UniqueId, sizeof(info->UniqueId));
+}
+
+// Connect a socket additionally
+SOCK *ClientAdditionalConnectToServer(CONNECTION *c)
+{
+ SOCK *s;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ // Socket connection
+ s = ClientConnectGetSocket(c, true, (c->DontUseTls1 ? false : true));
+ if (s == NULL)
+ {
+ // Connection failure
+ return NULL;
+ }
+
+ // Add the socket to the list
+ LockList(c->ConnectingSocks);
+ {
+ Add(c->ConnectingSocks, s);
+ AddRef(s->ref);
+ }
+ UnlockList(c->ConnectingSocks);
+
+ if (c->Session->Halt)
+ {
+ // Stop
+ Disconnect(s);
+ LockList(c->ConnectingSocks);
+ {
+ if (Delete(c->ConnectingSocks, s))
+ {
+ ReleaseSock(s);
+ }
+ }
+ UnlockList(c->ConnectingSocks);
+ ReleaseSock(s);
+ return NULL;
+ }
+
+ // Time-out
+ SetTimeout(s, CONNECTING_TIMEOUT);
+
+ // Start the SSL communication
+ if (StartSSLEx(s, NULL, NULL, (c->DontUseTls1 ? false : true), 0, c->ServerName) == false)
+ {
+ // SSL communication failure
+ Disconnect(s);
+ LockList(c->ConnectingSocks);
+ {
+ if (Delete(c->ConnectingSocks, s))
+ {
+ ReleaseSock(s);
+ }
+ }
+ UnlockList(c->ConnectingSocks);
+ ReleaseSock(s);
+ return NULL;
+ }
+
+ // Check the certificate
+ if (CompareX(s->RemoteX, c->ServerX) == false)
+ {
+ // The certificate is invalid
+ Disconnect(s);
+ c->Session->SessionTimeOuted = true;
+ }
+
+ return s;
+}
+
+// Remove the key and certificate in the secure device
+UINT SecureDelete(UINT device_id, char *pin, char *cert_name, char *key_name)
+{
+ SECURE *sec;
+ // Validate arguments
+ if (pin == NULL || device_id == 0)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ // Open the device
+ sec = OpenSec(device_id);
+ if (sec == NULL)
+ {
+ return ERR_SECURE_DEVICE_OPEN_FAILED;
+ }
+
+ // Open the session
+ if (OpenSecSession(sec, 0) == false)
+ {
+ CloseSec(sec);
+ return ERR_SECURE_DEVICE_OPEN_FAILED;
+ }
+
+ // Login
+ if (LoginSec(sec, pin) == false)
+ {
+ CloseSecSession(sec);
+ CloseSec(sec);
+ return ERR_SECURE_PIN_LOGIN_FAILED;
+ }
+
+ // Delete the certificate
+ if (cert_name != NULL)
+ {
+ DeleteSecCert(sec, cert_name);
+ }
+
+ // Delete the Private key
+ if (key_name != NULL)
+ {
+ DeleteSecKey(sec, key_name);
+ }
+
+ // Log out
+ LogoutSec(sec);
+
+ // Close the session
+ CloseSecSession(sec);
+
+ // Close the device
+ CloseSec(sec);
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate certificates and keys in the secure device
+UINT SecureEnum(UINT device_id, char *pin, TOKEN_LIST **cert_list, TOKEN_LIST **key_list)
+{
+ SECURE *sec;
+ LIST *o;
+ LIST *cert_name_list, *key_name_list;
+ // Validate arguments
+ if (pin == NULL || device_id == 0 || cert_list == NULL || key_list == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ // Open the device
+ sec = OpenSec(device_id);
+ if (sec == NULL)
+ {
+ return ERR_SECURE_DEVICE_OPEN_FAILED;
+ }
+
+ // Open the session
+ if (OpenSecSession(sec, 0) == false)
+ {
+ CloseSec(sec);
+ return ERR_SECURE_DEVICE_OPEN_FAILED;
+ }
+
+ // Login
+ if (LoginSec(sec, pin) == false)
+ {
+ CloseSecSession(sec);
+ CloseSec(sec);
+ return ERR_SECURE_PIN_LOGIN_FAILED;
+ }
+
+ // Enumerate objects
+ if ((o = EnumSecObject(sec)) != NULL)
+ {
+ UINT i;
+
+ cert_name_list = NewList(CompareStr);
+ key_name_list = NewList(CompareStr);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ SEC_OBJ *obj = LIST_DATA(o, i);
+
+ if (obj->Type == SEC_X)
+ {
+ Add(cert_name_list, CopyStr(obj->Name));
+ }
+ else if (obj->Type == SEC_K)
+ {
+ Add(key_name_list, CopyStr(obj->Name));
+ }
+ }
+
+ Sort(cert_name_list);
+ Sort(key_name_list);
+
+ *cert_list = ListToTokenList(cert_name_list);
+ *key_list = ListToTokenList(key_name_list);
+
+ // Release the memory
+ FreeStrList(cert_name_list);
+ FreeStrList(key_name_list);
+ FreeEnumSecObject(o);
+ }
+ else
+ {
+ *cert_list = NullToken();
+ *key_list = NullToken();
+ }
+
+ // Log out
+ LogoutSec(sec);
+
+ // Close the session
+ CloseSecSession(sec);
+
+ // Close the device
+ CloseSec(sec);
+
+ return ERR_NO_ERROR;
+}
+
+// Record the certificate and key to secure device
+UINT SecureWrite(UINT device_id, char *cert_name, X *x, char *key_name, K *k, char *pin)
+{
+ SECURE *sec;
+ bool failed;
+ // Validate arguments
+ if (pin == NULL || device_id == 0 || cert_name == NULL || x == NULL || key_name == NULL || k == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ // Open the device
+ sec = OpenSec(device_id);
+ if (sec == NULL)
+ {
+ return ERR_SECURE_DEVICE_OPEN_FAILED;
+ }
+
+ // Open the session
+ if (OpenSecSession(sec, 0) == false)
+ {
+ CloseSec(sec);
+ return ERR_SECURE_DEVICE_OPEN_FAILED;
+ }
+
+ // Login
+ if (LoginSec(sec, pin) == false)
+ {
+ CloseSecSession(sec);
+ CloseSec(sec);
+ return ERR_SECURE_PIN_LOGIN_FAILED;
+ }
+
+ // Registration
+ failed = false;
+
+ // Register the certificate
+ if (WriteSecCert(sec, true, cert_name, x) == false)
+ {
+ failed = true;
+ }
+
+ // Register the private key
+ if (WriteSecKey(sec, true, key_name, k) == false)
+ {
+ failed = true;
+ }
+
+ // Log out
+ LogoutSec(sec);
+
+ // Close the session
+ CloseSecSession(sec);
+
+ // Close the device
+ CloseSec(sec);
+
+ if (failed == false)
+ {
+ // Success
+ return ERR_NO_ERROR;
+ }
+ else
+ {
+ // Failure
+ return ERR_SECURE_CANT_WRITE;
+ }
+}
+
+// Attempt to sign by the secure device
+UINT SecureSign(SECURE_SIGN *sign, UINT device_id, char *pin)
+{
+ SECURE *sec;
+ X *x;
+ // Validate arguments
+ if (sign == false || pin == NULL || device_id == 0)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ // Open the device
+ sec = OpenSec(device_id);
+ if (sec == NULL)
+ {
+ return ERR_SECURE_DEVICE_OPEN_FAILED;
+ }
+
+ // Open the session
+ if (OpenSecSession(sec, 0) == false)
+ {
+ CloseSec(sec);
+ return ERR_SECURE_DEVICE_OPEN_FAILED;
+ }
+
+ // Login
+ if (LoginSec(sec, pin) == false)
+ {
+ CloseSecSession(sec);
+ CloseSec(sec);
+ return ERR_SECURE_PIN_LOGIN_FAILED;
+ }
+
+ // Read the certificate
+ x = ReadSecCert(sec, sign->SecurePublicCertName);
+ if (x == NULL)
+ {
+ LogoutSec(sec);
+ CloseSecSession(sec);
+ CloseSec(sec);
+ return ERR_SECURE_NO_CERT;
+ }
+
+ // Sign by the private key
+ if (SignSec(sec, sign->SecurePrivateKeyName, sign->Signature, sign->Random, SHA1_SIZE) == false)
+ {
+ // Signing failure
+ FreeX(x);
+ LogoutSec(sec);
+ CloseSecSession(sec);
+ CloseSec(sec);
+ return ERR_SECURE_NO_PRIVATE_KEY;
+ }
+
+ // Convert the certificate to buffer
+ sign->ClientCert = x;
+
+ // Log out
+ LogoutSec(sec);
+
+ // Close the session
+ CloseSecSession(sec);
+
+ // Close the device
+ CloseSec(sec);
+
+ // Success
+ return ERR_NO_ERROR;
+}
+
+// Client connects to the server additionally
+bool ClientAdditionalConnect(CONNECTION *c, THREAD *t)
+{
+ SOCK *s;
+ PACK *p;
+ TCPSOCK *ts;
+ UINT err;
+ UINT direction;
+ RC4_KEY_PAIR key_pair;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ // Socket connection to the server
+ s = ClientAdditionalConnectToServer(c);
+ if (s == NULL)
+ {
+ // Failed to connect socket
+ return false;
+ }
+
+ if (c->Halt)
+ {
+ goto CLEANUP;
+ }
+
+ // Send a signature
+ Debug("Uploading Signature...\n");
+ if (ClientUploadSignature(s) == false)
+ {
+ goto CLEANUP;
+ }
+
+ if (c->Halt)
+ {
+ // Stop
+ goto CLEANUP;
+ }
+
+ // Receive a Hello packet
+ Debug("Downloading Hello...\n");
+ if (ClientDownloadHello(c, s) == false)
+ {
+ goto CLEANUP;
+ }
+
+ if (c->Halt)
+ {
+ // Stop
+ goto CLEANUP;
+ }
+
+ // Send a authentication data for the additional connection
+ if (ClientUploadAuth2(c, s) == false)
+ {
+ // Disconnected
+ goto CLEANUP;
+ }
+
+ // Receive a response
+ p = HttpClientRecv(s);
+ if (p == NULL)
+ {
+ // Disconnected
+ goto CLEANUP;
+ }
+
+ err = GetErrorFromPack(p);
+ direction = PackGetInt(p, "direction");
+
+ if (c->Session->UseFastRC4)
+ {
+ // Get the RC4 key information
+ if (PackGetDataSize(p, "rc4_key_client_to_server") == 16)
+ {
+ PackGetData(p, "rc4_key_client_to_server", key_pair.ClientToServerKey);
+ }
+ if (PackGetDataSize(p, "rc4_key_server_to_client") == 16)
+ {
+ PackGetData(p, "rc4_key_server_to_client", key_pair.ServerToClientKey);
+ }
+ {
+ char key1[64], key2[64];
+ BinToStr(key1, sizeof(key1), key_pair.ClientToServerKey, 16);
+ BinToStr(key2, sizeof(key2), key_pair.ServerToClientKey, 16);
+ Debug(
+ "Client to Server Key: %s\n"
+ "Server to Client Key: %s\n",
+ key1, key2);
+ }
+ }
+
+ FreePack(p);
+ p = NULL;
+
+ if (err != 0)
+ {
+ // Error has occurred
+ Debug("Additional Connect Error: %u\n", err);
+ if (err == ERR_SESSION_TIMEOUT || err == ERR_INVALID_PROTOCOL)
+ {
+ // We shall re-connection because it is a fatal error
+ c->Session->SessionTimeOuted = true;
+ }
+ goto CLEANUP;
+ }
+
+ Debug("Additional Connect Succeed!\n");
+
+ // Success the additional connection
+ // Add to the TcpSockList of the connection
+ ts = NewTcpSock(s);
+
+ if (c->ServerMode == false)
+ {
+ if (c->Session->ClientOption->ConnectionDisconnectSpan != 0)
+ {
+ ts->DisconnectTick = Tick64() + c->Session->ClientOption->ConnectionDisconnectSpan * (UINT64)1000;
+ }
+ }
+
+ LockList(c->Tcp->TcpSockList);
+ {
+ ts->Direction = direction;
+ Add(c->Tcp->TcpSockList, ts);
+ }
+ UnlockList(c->Tcp->TcpSockList);
+ Debug("TCP Connection Incremented: %u\n", Count(c->CurrentNumConnection));
+
+ if (c->Session->HalfConnection)
+ {
+ Debug("New Half Connection: %s\n",
+ direction == TCP_SERVER_TO_CLIENT ? "TCP_SERVER_TO_CLIENT" : "TCP_CLIENT_TO_SERVER"
+ );
+ }
+
+ if (c->Session->UseFastRC4)
+ {
+ // Set the RC4 encryption key
+ Copy(&ts->Rc4KeyPair, &key_pair, sizeof(RC4_KEY_PAIR));
+
+ InitTcpSockRc4Key(ts, false);
+ }
+
+ // Issue the Cancel to the session
+ Cancel(c->Session->Cancel1);
+
+ // Remove the socket from the socket list of connected
+ LockList(c->ConnectingSocks);
+ {
+ if (Delete(c->ConnectingSocks, s))
+ {
+ ReleaseSock(s);
+ }
+ }
+ UnlockList(c->ConnectingSocks);
+ ReleaseSock(s);
+ return true;
+
+CLEANUP:
+ // Disconnection process
+ Disconnect(s);
+ LockList(c->ConnectingSocks);
+ {
+ if (Delete(c->ConnectingSocks, s))
+ {
+ ReleaseSock(s);
+
+ }
+ }
+ UnlockList(c->ConnectingSocks);
+ ReleaseSock(s);
+ return false;
+}
+
+// Secure device signing thread
+void ClientSecureSignThread(THREAD *thread, void *param)
+{
+ SECURE_SIGN_THREAD_PROC *p = (SECURE_SIGN_THREAD_PROC *)param;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ NoticeThreadInit(thread);
+
+ p->Ok = p->SecureSignProc(p->Connection->Session, p->Connection, p->SecureSign);
+ p->UserFinished = true;
+}
+
+// Signing with the secure device
+bool ClientSecureSign(CONNECTION *c, UCHAR *sign, UCHAR *random, X **x)
+{
+ SECURE_SIGN_THREAD_PROC *p;
+ SECURE_SIGN *ss;
+ SESSION *s;
+ CLIENT_OPTION *o;
+ CLIENT_AUTH *a;
+ THREAD *thread;
+ UINT64 start;
+ bool ret;
+ // Validate arguments
+ if (c == NULL || sign == NULL || random == NULL || x == NULL)
+ {
+ return false;
+ }
+
+ s = c->Session;
+ o = s->ClientOption;
+ a = s->ClientAuth;
+
+ p = ZeroMalloc(sizeof(SECURE_SIGN_THREAD_PROC));
+ p->Connection = c;
+ ss = p->SecureSign = ZeroMallocEx(sizeof(SECURE_SIGN), true);
+ StrCpy(ss->SecurePrivateKeyName, sizeof(ss->SecurePrivateKeyName),
+ a->SecurePrivateKeyName);
+ StrCpy(ss->SecurePublicCertName, sizeof(ss->SecurePublicCertName),
+ a->SecurePublicCertName);
+ ss->UseSecureDeviceId = c->Cedar->Client->UseSecureDeviceId;
+ Copy(ss->Random, random, SHA1_SIZE);
+
+#ifdef OS_WIN32
+ ss->BitmapId = CmGetSecureBitmapId(c->ServerName);
+#endif // OS_WIN32
+
+ p->SecureSignProc = a->SecureSignProc;
+
+ // Create a thread
+ thread = NewThread(ClientSecureSignThread, p);
+ WaitThreadInit(thread);
+
+ // Poll every 0.5 seconds until signing is completed or canceled
+ start = Tick64();
+ while (true)
+ {
+ if ((Tick64() - start) > CONNECTING_POOLING_SPAN)
+ {
+ // Send a NOOP periodically for disconnection prevention
+ start = Tick64();
+ ClientUploadNoop(c);
+ }
+ if (p->UserFinished)
+ {
+ // User selected
+ break;
+ }
+ WaitThread(thread, 500);
+ }
+ ReleaseThread(thread);
+
+ ret = p->Ok;
+
+ if (ret)
+ {
+ Copy(sign, ss->Signature, 128);
+ *x = ss->ClientCert;
+ }
+
+ Free(p->SecureSign);
+ Free(p);
+
+ return ret;
+}
+
+// Server certificate confirmation thread
+void ClientCheckServerCertThread(THREAD *thread, void *param)
+{
+ CHECK_CERT_THREAD_PROC *p = (CHECK_CERT_THREAD_PROC *)param;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Notify the completion of initialization
+ NoticeThreadInit(thread);
+
+ // Query for the selection to the user
+ p->Ok = p->CheckCertProc(p->Connection->Session, p->Connection, p->ServerX, &p->Exipred);
+ p->UserSelected = true;
+}
+
+// Client verify the certificate of the server
+bool ClientCheckServerCert(CONNECTION *c, bool *expired)
+{
+ CLIENT_AUTH *auth;
+ X *x;
+ CHECK_CERT_THREAD_PROC *p;
+ THREAD *thread;
+ CEDAR *cedar;
+ bool ret;
+ UINT64 start;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ if (expired != NULL)
+ {
+ *expired = false;
+ }
+
+ auth = c->Session->ClientAuth;
+ cedar = c->Cedar;
+
+ if (auth->CheckCertProc == NULL && c->Session->LinkModeClient == false)
+ {
+ // No checking function
+ return true;
+ }
+
+ if (c->Session->LinkModeClient && c->Session->Link->CheckServerCert == false)
+ {
+ // It's in cascade connection mode, but do not check the server certificate
+ return true;
+ }
+
+ if (c->UseTicket)
+ {
+ // Check the certificate of the redirected VPN server
+ if (CompareX(c->FirstSock->RemoteX, c->ServerX) == false)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ x = CloneX(c->FirstSock->RemoteX);
+ if (x == NULL)
+ {
+ // Strange error occurs
+ return false;
+ }
+
+ if (CheckXDateNow(x))
+ {
+ // Check whether it is signed by the root certificate to trust
+ if (c->Session->LinkModeClient == false)
+ {
+ // Normal VPN Client mode
+ if (CheckSignatureByCa(cedar, x))
+ {
+ // This certificate can be trusted because it is signed
+ FreeX(x);
+ return true;
+ }
+ }
+ else
+ {
+ // Cascade connection mode
+ if (CheckSignatureByCaLinkMode(c->Session, x))
+ {
+ // This certificate can be trusted because it is signed
+ FreeX(x);
+ return true;
+ }
+ }
+ }
+
+ if (c->Session->LinkModeClient)
+ {
+ if (CheckXDateNow(x))
+ {
+ Lock(c->Session->Link->lock);
+ {
+ if (c->Session->Link->ServerCert != NULL)
+ {
+ if (CompareX(c->Session->Link->ServerCert, x))
+ {
+ Unlock(c->Session->Link->lock);
+ // Exactly match the certificate that is registered in the cascade configuration
+ FreeX(x);
+ return true;
+ }
+ }
+ }
+ Unlock(c->Session->Link->lock);
+ }
+ else
+ {
+ if (expired != NULL)
+ {
+ *expired = true;
+ }
+ }
+
+ // Verification failure at this point in the case of cascade connection mode
+ FreeX(x);
+ return false;
+ }
+
+ p = ZeroMalloc(sizeof(CHECK_CERT_THREAD_PROC));
+ p->ServerX = x;
+ p->CheckCertProc = auth->CheckCertProc;
+ p->Connection = c;
+
+ // Create a thread
+ thread = NewThread(ClientCheckServerCertThread, p);
+ WaitThreadInit(thread);
+
+ // Poll at 0.5-second intervals until the user selects whether the connection
+ start = Tick64();
+ while (true)
+ {
+ if ((Tick64() - start) > CONNECTING_POOLING_SPAN)
+ {
+ // Send a NOOP periodically for disconnection prevention
+ start = Tick64();
+ ClientUploadNoop(c);
+ }
+ if (p->UserSelected)
+ {
+ // User-selected
+ break;
+ }
+ WaitThread(thread, 500);
+ }
+
+ if (expired != NULL)
+ {
+ *expired = p->Exipred;
+ }
+
+ ret = p->Ok;
+ FreeX(p->ServerX);
+ Free(p);
+ ReleaseThread(thread);
+
+ return ret;
+}
+
+// Client connects to the server
+bool ClientConnect(CONNECTION *c)
+{
+ bool ret = false;
+ bool ok = false;
+ UINT err;
+ SOCK *s;
+ PACK *p = NULL;
+ UINT session_key_32;
+ SESSION *sess;
+ char session_name[MAX_SESSION_NAME_LEN + 1];
+ char connection_name[MAX_CONNECTION_NAME_LEN + 1];
+ UCHAR session_key[SHA1_SIZE];
+ RC4_KEY_PAIR key_pair;
+ POLICY *policy;
+ bool expired = false;
+ IP server_ip;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ sess = c->Session;
+
+ PrintStatus(sess, L"init");
+ PrintStatus(sess, _UU("STATUS_1"));
+
+REDIRECTED:
+
+ // [Connecting]
+ c->Status = CONNECTION_STATUS_CONNECTING;
+ c->Session->ClientStatus = CLIENT_STATUS_CONNECTING;
+
+ s = ClientConnectToServer(c);
+ if (s == NULL)
+ {
+ PrintStatus(sess, L"free");
+ return false;
+ }
+
+ Copy(&server_ip, &s->RemoteIP, sizeof(IP));
+
+ if (c->Halt)
+ {
+ // Stop
+ c->Err = ERR_USER_CANCEL;
+ goto CLEANUP;
+ }
+
+ // [Negotiating]
+ c->Session->ClientStatus = CLIENT_STATUS_NEGOTIATION;
+
+ // Initialize the UDP acceleration function
+ if (sess->ClientOption != NULL && sess->ClientOption->NoUdpAcceleration == false)
+ {
+ if (sess->ClientOption->ProxyType == PROXY_DIRECT)
+ {
+ if (s->Type == SOCK_TCP)
+ {
+ if (sess->UdpAccel == NULL)
+ {
+ bool no_nat_t = false;
+
+ if (sess->ClientOption->PortUDP != 0)
+ {
+ // There is no need for NAT-T treatment on my part if the UDP port on the other end is known beforehand
+ no_nat_t = true;
+ }
+
+
+ sess->UdpAccel = NewUdpAccel(c->Cedar, &s->LocalIP, true, true, no_nat_t);
+ }
+ }
+ }
+ }
+
+ // Send a signature
+ Debug("Uploading Signature...\n");
+ if (ClientUploadSignature(s) == false)
+ {
+ c->Err = ERR_DISCONNECTED;
+ goto CLEANUP;
+ }
+
+ if (c->Halt)
+ {
+ // Stop
+ c->Err = ERR_USER_CANCEL;
+ goto CLEANUP;
+ }
+
+ PrintStatus(sess, _UU("STATUS_5"));
+
+ // Receive a Hello packet
+ Debug("Downloading Hello...\n");
+ if (ClientDownloadHello(c, s) == false)
+ {
+ goto CLEANUP;
+ }
+
+ if (c->Session->ClientOption != NULL && c->Session->ClientOption->FromAdminPack)
+ {
+ if (IsAdminPackSupportedServerProduct(c->ServerStr) == false)
+ {
+ c->Err = ERR_NOT_ADMINPACK_SERVER;
+ goto CLEANUP;
+ }
+ }
+
+ if (c->Halt)
+ {
+ // Stop
+ c->Err = ERR_USER_CANCEL;
+ goto CLEANUP;
+ }
+
+ Debug("Server Version : %u\n"
+ "Server String : %s\n"
+ "Server Build : %u\n"
+ "Client Version : %u\n"
+ "Client String : %s\n"
+ "Client Build : %u\n",
+ c->ServerVer, c->ServerStr, c->ServerBuild,
+ c->ClientVer, c->ClientStr, c->ClientBuild);
+
+ // During user authentication
+ c->Session->ClientStatus = CLIENT_STATUS_AUTH;
+
+ // Verify the server certificate by the client
+ if (ClientCheckServerCert(c, &expired) == false)
+ {
+ if (expired == false)
+ {
+ c->Err = ERR_CERT_NOT_TRUSTED;
+ }
+ else
+ {
+ c->Err = ERR_SERVER_CERT_EXPIRES;
+ }
+
+ if (c->Session->LinkModeClient == false && c->Err == ERR_CERT_NOT_TRUSTED)
+ {
+ c->Session->ForceStopFlag = true;
+ }
+
+ goto CLEANUP;
+ }
+
+ PrintStatus(sess, _UU("STATUS_6"));
+
+ // Send the authentication data
+ if (ClientUploadAuth(c) == false)
+ {
+ goto CLEANUP;
+ }
+
+ if (c->Halt)
+ {
+ // Stop
+ c->Err = ERR_USER_CANCEL;
+ goto CLEANUP;
+ }
+
+ // Receive a Welcome packet
+ p = HttpClientRecv(s);
+ if (p == NULL)
+ {
+ c->Err = ERR_DISCONNECTED;
+ goto CLEANUP;
+ }
+
+ // Error checking
+ err = GetErrorFromPack(p);
+ if (err != 0)
+ {
+ // An error has occured
+ c->Err = err;
+ c->ClientConnectError_NoSavePassword = PackGetBool(p, "no_save_password");
+ goto CLEANUP;
+ }
+
+ // Branding string check for the connection limit
+ {
+ char tmp[20];
+ char *branded_cfroms = _SS("BRANDED_C_FROM_S");
+ PackGetStr(p, "branded_cfroms", tmp, sizeof(tmp));
+
+ if(StrLen(branded_cfroms) > 0 && StrCmpi(branded_cfroms, tmp) != 0)
+ {
+ c->Err = ERR_BRANDED_C_FROM_S;
+ goto CLEANUP;
+ }
+ }
+
+ if (true)
+ {
+ // Message retrieval
+ UINT utf_size;
+ char *utf;
+ wchar_t *msg;
+
+ utf_size = PackGetDataSize(p, "Msg");
+ utf = ZeroMalloc(utf_size + 8);
+ PackGetData(p, "Msg", utf);
+
+ msg = CopyUtfToUni(utf);
+
+ if (IsEmptyUniStr(msg) == false)
+ {
+ if (c->Session->Client_Message != NULL)
+ {
+ Free(c->Session->Client_Message);
+ }
+
+ c->Session->Client_Message = msg;
+ }
+ else
+ {
+ Free(msg);
+ }
+
+ Free(utf);
+ }
+
+ if (PackGetInt(p, "Redirect") != 0)
+ {
+ UINT i;
+ UINT ip;
+ UINT num_port;
+ UINT *ports;
+ UINT use_port = 0;
+ UINT current_port = c->ServerPort;
+ UCHAR ticket[SHA1_SIZE];
+ X *server_cert;
+ BUF *b;
+
+ // Redirect mode
+ PrintStatus(sess, _UU("STATUS_8"));
+
+ ip = PackGetIp32(p, "Ip");
+ num_port = MAX(MIN(PackGetIndexCount(p, "Port"), MAX_PUBLIC_PORT_NUM), 1);
+ ports = ZeroMalloc(sizeof(UINT) * num_port);
+ for (i = 0;i < num_port;i++)
+ {
+ ports[i] = PackGetIntEx(p, "Port", i);
+ }
+
+ // Select a port number
+ for (i = 0;i < num_port;i++)
+ {
+ if (ports[i] == current_port)
+ {
+ use_port = current_port;
+ }
+ }
+ if (use_port == 0)
+ {
+ use_port = ports[0];
+ }
+
+ Free(ports);
+
+ if (PackGetDataSize(p, "Ticket") == SHA1_SIZE)
+ {
+ PackGetData(p, "Ticket", ticket);
+ }
+
+ b = PackGetBuf(p, "Cert");
+ if (b != NULL)
+ {
+ server_cert = BufToX(b, false);
+ FreeBuf(b);
+ }
+
+ if (c->ServerX != NULL)
+ {
+ FreeX(c->ServerX);
+ }
+ c->ServerX = server_cert;
+
+ IPToStr32(c->ServerName, sizeof(c->ServerName), ip);
+ c->ServerPort = use_port;
+
+ c->UseTicket = true;
+ Copy(c->Ticket, ticket, SHA1_SIZE);
+
+ FreePack(p);
+
+ p = NewPack();
+ HttpClientSend(s, p);
+ FreePack(p);
+
+ p = NULL;
+
+ c->FirstSock = NULL;
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+
+ goto REDIRECTED;
+ }
+
+ PrintStatus(sess, _UU("STATUS_7"));
+
+ // Parse the Welcome packet
+ if (ParseWelcomeFromPack(p, session_name, sizeof(session_name),
+ connection_name, sizeof(connection_name), &policy) == false)
+ {
+ // Parsing failure
+ c->Err = ERR_PROTOCOL_ERROR;
+ goto CLEANUP;
+ }
+
+ // Get the session key
+ if (GetSessionKeyFromPack(p, session_key, &session_key_32) == false)
+ {
+ // Acquisition failure
+ Free(policy);
+ policy = NULL;
+ c->Err = ERR_PROTOCOL_ERROR;
+ goto CLEANUP;
+ }
+
+ Copy(c->Session->SessionKey, session_key, SHA1_SIZE);
+ c->Session->SessionKey32 = session_key_32;
+
+ // Save the contents of the Welcome packet
+ Debug("session_name: %s, connection_name: %s\n",
+ session_name, connection_name);
+
+ Lock(c->Session->lock);
+ {
+ // Deploy and update connection parameters
+ sess->EnableUdpRecovery = PackGetBool(p, "enable_udp_recovery");
+ c->Session->MaxConnection = PackGetInt(p, "max_connection");
+
+ if (sess->EnableUdpRecovery == false)
+ {
+ c->Session->MaxConnection = MIN(c->Session->MaxConnection, c->Session->ClientOption->MaxConnection);
+ }
+
+ c->Session->MaxConnection = MIN(c->Session->MaxConnection, MAX_TCP_CONNECTION);
+ c->Session->MaxConnection = MAX(c->Session->MaxConnection, 1);
+ c->Session->UseCompress = PackGetInt(p, "use_compress") == 0 ? false : true;
+ c->Session->UseEncrypt = PackGetInt(p, "use_encrypt") == 0 ? false : true;
+ c->Session->NoSendSignature = PackGetBool(p, "no_send_signature");
+ if (c->Session->UseEncrypt)
+ {
+ c->Session->UseFastRC4 = PackGetInt(p, "use_fast_rc4") == 0 ? false : true;
+ }
+ c->Session->HalfConnection = PackGetInt(p, "half_connection") == 0 ? false : true;
+ c->Session->IsAzureSession = PackGetInt(p, "is_azure_session") == 0 ? false : true;
+ c->Session->Timeout = PackGetInt(p, "timeout");
+ c->Session->QoS = PackGetInt(p, "qos") == 0 ? false : true;
+ if (c->Session->QoS)
+ {
+ c->Session->MaxConnection = MAX(c->Session->MaxConnection, (UINT)(c->Session->HalfConnection ? 4 : 2));
+ }
+ c->Session->VLanId = PackGetInt(p, "vlan_id");
+
+ // R-UDP Session ?
+ c->Session->IsRUDPSession = s->IsRUDPSocket;
+
+ ZeroIP4(&c->Session->AzureRealServerGlobalIp);
+
+ if (c->Session->IsAzureSession)
+ {
+ // Disable the life parameter of the connection in the case of VPN Azure relayed session
+ c->Session->ClientOption->ConnectionDisconnectSpan = 0;
+
+ // Get the AzureRealServerGlobalIp the case of VPN Azure relayed
+ PackGetIp(p, "azure_real_server_global_ip", &c->Session->AzureRealServerGlobalIp);
+ }
+
+ if (c->Session->IsRUDPSession)
+ {
+ // Disable the life parameter of the connection in the case of R-UDP session
+ c->Session->ClientOption->ConnectionDisconnectSpan = 0;
+
+ // Disable QoS, etc. in the case of R-UDP session
+ c->Session->QoS = false;
+ c->Session->HalfConnection = false;
+
+ if (c->Session->EnableUdpRecovery == false)
+ {
+ // Set the number of connection to 1 if UDP recovery is not supported
+ c->Session->MaxConnection = 1;
+ }
+ }
+
+ // Physical communication protocol
+ StrCpy(c->Session->UnderlayProtocol, sizeof(c->Session->UnderlayProtocol), s->UnderlayProtocol);
+
+ if (c->Session->IsAzureSession)
+ {
+ StrCpy(c->Session->UnderlayProtocol, sizeof(c->Session->UnderlayProtocol), SOCK_UNDERLAY_AZURE);
+ }
+
+ if (c->Protocol == CONNECTION_UDP)
+ {
+ // In the case of UDP protocol, receive the key from the server
+ if (PackGetDataSize(p, "udp_send_key") == sizeof(c->Session->UdpSendKey))
+ {
+ PackGetData(p, "udp_send_key", c->Session->UdpSendKey);
+ }
+
+ if (PackGetDataSize(p, "udp_recv_key") == sizeof(c->Session->UdpRecvKey))
+ {
+ PackGetData(p, "udp_recv_key", c->Session->UdpRecvKey);
+ }
+ }
+
+ if (c->Session->UseFastRC4)
+ {
+ // Get the RC4 key information
+ if (PackGetDataSize(p, "rc4_key_client_to_server") == 16)
+ {
+ PackGetData(p, "rc4_key_client_to_server", key_pair.ClientToServerKey);
+ }
+ if (PackGetDataSize(p, "rc4_key_server_to_client") == 16)
+ {
+ PackGetData(p, "rc4_key_server_to_client", key_pair.ServerToClientKey);
+ }
+ {
+ char key1[64], key2[64];
+ BinToStr(key1, sizeof(key1), key_pair.ClientToServerKey, 16);
+ BinToStr(key2, sizeof(key2), key_pair.ServerToClientKey, 16);
+ Debug(
+ "Client to Server Key: %s\n"
+ "Server to Client Key: %s\n",
+ key1, key2);
+ }
+ }
+
+ sess->EnableBulkOnRUDP = false;
+ sess->EnableHMacOnBulkOfRUDP = false;
+ if (s != NULL && s->IsRUDPSocket && s->BulkRecvKey != NULL && s->BulkSendKey != NULL)
+ {
+ // Bulk transfer on R-UDP
+ if (PackGetBool(p, "enable_bulk_on_rudp"))
+ {
+ // Receive the key
+ UCHAR key_send[SHA1_SIZE];
+ UCHAR key_recv[SHA1_SIZE];
+
+ if (PackGetData2(p, "bulk_on_rudp_send_key", key_send, SHA1_SIZE) &&
+ PackGetData2(p, "bulk_on_rudp_recv_key", key_recv, SHA1_SIZE))
+ {
+ sess->EnableBulkOnRUDP = true;
+
+ Copy(s->BulkSendKey->Data, key_send, SHA1_SIZE);
+ Copy(s->BulkRecvKey->Data, key_recv, SHA1_SIZE);
+ }
+ }
+
+ sess->EnableHMacOnBulkOfRUDP = PackGetBool(p, "enable_hmac_on_bulk_of_rudp");
+ }
+
+ Debug("EnableBulkOnRUDP = %u\n", sess->EnableBulkOnRUDP);
+ Debug("EnableHMacOnBulkOfRUDP = %u\n", sess->EnableHMacOnBulkOfRUDP);
+ Debug("EnableUdpRecovery = %u\n", sess->EnableUdpRecovery);
+
+ sess->UseUdpAcceleration = false;
+ sess->IsUsingUdpAcceleration = false;
+ sess->UseHMacOnUdpAcceleration = false;
+
+ if (sess->UdpAccel != NULL)
+ {
+ sess->UdpAccel->UseHMac = false;
+
+ sess->UdpAccelFastDisconnectDetect = false;
+
+ if (PackGetBool(p, "use_udp_acceleration"))
+ {
+ IP udp_acceleration_server_ip;
+
+ sess->UdpAccelFastDisconnectDetect = PackGetBool(p, "udp_accel_fast_disconnect_detect");
+
+ if (PackGetIp(p, "udp_acceleration_server_ip", &udp_acceleration_server_ip))
+ {
+ UINT udp_acceleration_server_port = PackGetInt(p, "udp_acceleration_server_port");
+
+ if (IsZeroIp(&udp_acceleration_server_ip))
+ {
+ Copy(&udp_acceleration_server_ip, &s->RemoteIP, sizeof(IP));
+ }
+
+ if (udp_acceleration_server_port != 0)
+ {
+ UCHAR udp_acceleration_server_key[UDP_ACCELERATION_COMMON_KEY_SIZE];
+
+ if (PackGetData2(p, "udp_acceleration_server_key", udp_acceleration_server_key, UDP_ACCELERATION_COMMON_KEY_SIZE))
+ {
+ UINT server_cookie = PackGetInt(p, "udp_acceleration_server_cookie");
+ UINT client_cookie = PackGetInt(p, "udp_acceleration_client_cookie");
+ bool encryption = PackGetBool(p, "udp_acceleration_use_encryption");
+
+ if (server_cookie != 0 && client_cookie != 0)
+ {
+ IP remote_ip;
+
+ Copy(&remote_ip, &s->RemoteIP, sizeof(IP));
+
+ if (IsZeroIp(&c->Session->AzureRealServerGlobalIp) == false)
+ {
+ Copy(&remote_ip, &c->Session->AzureRealServerGlobalIp, sizeof(IP));
+ }
+
+ if (UdpAccelInitClient(sess->UdpAccel, udp_acceleration_server_key,
+ &udp_acceleration_server_ip, udp_acceleration_server_port,
+ server_cookie, client_cookie, &remote_ip) == false)
+ {
+ Debug("UdpAccelInitClient failed.\n");
+ }
+ else
+ {
+ sess->UseUdpAcceleration = true;
+
+ sess->UdpAccel->FastDetect = sess->UdpAccelFastDisconnectDetect;
+
+ sess->UdpAccel->PlainTextMode = !encryption;
+
+ sess->UseHMacOnUdpAcceleration = PackGetBool(p, "use_hmac_on_udp_acceleration");
+
+ if (sess->UseHMacOnUdpAcceleration)
+ {
+ sess->UdpAccel->UseHMac = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ Unlock(c->Session->lock);
+
+ Debug("UseUdpAcceleration = %u\n", sess->UseUdpAcceleration);
+
+ if (sess->UseUdpAcceleration == false)
+ {
+ if (sess->UdpAccel != NULL)
+ {
+ FreeUdpAccel(sess->UdpAccel);
+ sess->UdpAccel = NULL;
+ }
+ }
+
+ Lock(c->lock);
+ {
+ if (c->Name != NULL)
+ {
+ Free(c->Name);
+ }
+ c->Name = CopyStr(connection_name);
+
+ // Save the name of a cryptographic algorithm
+ if (c->CipherName != NULL)
+ {
+ Free(c->CipherName);
+ }
+
+ c->CipherName = CopyStr(c->FirstSock->CipherName);
+ }
+ Unlock(c->lock);
+
+ Lock(c->Session->lock);
+ {
+ if (c->Session->Name != NULL)
+ {
+ Free(c->Session->Name);
+ }
+ c->Session->Name = CopyStr(session_name);
+
+ c->Session->Policy = policy;
+ }
+ Unlock(c->Session->lock);
+
+ // Discard the Welcome packet
+ FreePack(p);
+ p = NULL;
+
+
+ // Connection establishment
+ c->Session->ClientStatus = CLIENT_STATUS_ESTABLISHED;
+
+ // Save the server certificate
+ if (c->ServerX == NULL)
+ {
+ c->ServerX = CloneX(c->FirstSock->RemoteX);
+ }
+
+ PrintStatus(sess, _UU("STATUS_9"));
+
+ // Shift the connection to the tunneling mode
+ StartTunnelingMode(c);
+ s = NULL;
+
+ if (c->Session->HalfConnection)
+ {
+ // Processing in the case of half-connection
+ TCPSOCK *ts = (TCPSOCK *)LIST_DATA(c->Tcp->TcpSockList, 0);
+ ts->Direction = TCP_CLIENT_TO_SERVER;
+ }
+
+ if (c->Session->UseFastRC4)
+ {
+ // Set the high-speed RC4 encryption key
+ TCPSOCK *ts = (TCPSOCK *)LIST_DATA(c->Tcp->TcpSockList, 0);
+ Copy(&ts->Rc4KeyPair, &key_pair, sizeof(key_pair));
+
+ InitTcpSockRc4Key(ts, false);
+ }
+
+ // SSL encryption flag
+ if (c->Session->UseEncrypt && c->Session->UseFastRC4 == false)
+ {
+ c->Session->UseSSLDataEncryption = true;
+ }
+ else
+ {
+ c->Session->UseSSLDataEncryption = false;
+ }
+
+ PrintStatus(sess, L"free");
+
+ CLog(c->Cedar->Client, "LC_CONNECT_2", c->Session->ClientOption->AccountName,
+ session_name);
+
+ if (c->Session->LinkModeClient && c->Session->Link != NULL)
+ {
+ HLog(c->Session->Link->Hub, "LH_CONNECT_2", c->Session->ClientOption->AccountName, session_name);
+ }
+
+ // Main routine of the session
+ SessionMain(c->Session);
+
+ ok = true;
+
+ if (c->Err == ERR_USER_CANCEL)
+ {
+ ret = true;
+ }
+
+CLEANUP:
+ c->FirstSock = NULL;
+
+ if (sess->UdpAccel != NULL)
+ {
+ FreeUdpAccel(sess->UdpAccel);
+ sess->UdpAccel = NULL;
+ }
+
+ if (p != NULL)
+ {
+ FreePack(p);
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+
+ Debug("Error: %u\n", c->Err);
+
+ if (ok == false)
+ {
+ PrintStatus(sess, L"free");
+ }
+
+ return ret;
+}
+
+// Parse the Welcome packet
+bool ParseWelcomeFromPack(PACK *p, char *session_name, UINT session_name_size,
+ char *connection_name, UINT connection_name_size,
+ POLICY **policy)
+{
+ // Validate arguments
+ if (p == NULL || session_name == NULL || connection_name == NULL || policy == NULL)
+ {
+ return false;
+ }
+
+ // Session name
+ if (PackGetStr(p, "session_name", session_name, session_name_size) == false)
+ {
+ return false;
+ }
+
+ // Connection name
+ if (PackGetStr(p, "connection_name", connection_name, connection_name_size) == false)
+ {
+ return false;
+ }
+
+ // Policy
+ *policy = PackGetPolicy(p);
+ if (*policy == NULL)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Generate the Welcome packet
+PACK *PackWelcome(SESSION *s)
+{
+ PACK *p;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+
+ // Session name
+ PackAddStr(p, "session_name", s->Name);
+
+ // Connection name
+ PackAddStr(p, "connection_name", s->Connection->Name);
+
+ // Parameters
+ PackAddInt(p, "max_connection", s->MaxConnection);
+ PackAddInt(p, "use_encrypt", s->UseEncrypt == false ? 0 : 1);
+ PackAddInt(p, "use_fast_rc4", s->UseFastRC4 == false ? 0 : 1);
+ PackAddInt(p, "use_compress", s->UseCompress == false ? 0 : 1);
+ PackAddInt(p, "half_connection", s->HalfConnection == false ? 0 : 1);
+ PackAddInt(p, "timeout", s->Timeout);
+ PackAddInt(p, "qos", s->QoS ? 1 : 0);
+ PackAddInt(p, "is_azure_session", s->IsAzureSession);
+
+ // Session key
+ PackAddData(p, "session_key", s->SessionKey, SHA1_SIZE);
+ PackAddInt(p, "session_key_32", s->SessionKey32);
+
+ // Policy
+ PackAddPolicy(p, s->Policy);
+
+ // VLAN ID
+ PackAddInt(p, "vlan_id", s->VLanId);
+
+ if (s->Connection->Protocol == CONNECTION_UDP)
+ {
+ // In the case of UDP protocol, generate 2 pairs of key
+ Rand(s->UdpSendKey, sizeof(s->UdpSendKey));
+ Rand(s->UdpRecvKey, sizeof(s->UdpRecvKey));
+
+ // Send to client by exchanging 2 keys
+ PackAddData(p, "udp_send_key", s->UdpRecvKey, sizeof(s->UdpRecvKey));
+ PackAddData(p, "udp_recv_key", s->UdpSendKey, sizeof(s->UdpSendKey));
+ }
+
+ // no_send_signature
+ if (s->NoSendSignature)
+ {
+ PackAddBool(p, "no_send_signature", true);
+ }
+
+ if (s->InProcMode)
+ {
+ // MAC address for IPC
+ PackAddData(p, "IpcMacAddress", s->IpcMacAddress, 6);
+
+ // Virtual HUB name
+ PackAddStr(p, "IpcHubName", s->Hub->Name);
+ }
+
+ if (s->UdpAccel != NULL)
+ {
+ // UDP acceleration function
+ PackAddBool(p, "use_udp_acceleration", true);
+ PackAddIp(p, "udp_acceleration_server_ip", &s->UdpAccel->MyIp);
+ PackAddInt(p, "udp_acceleration_server_port", s->UdpAccel->MyPort);
+ PackAddData(p, "udp_acceleration_server_key", s->UdpAccel->MyKey, UDP_ACCELERATION_COMMON_KEY_SIZE);
+ PackAddInt(p, "udp_acceleration_server_cookie", s->UdpAccel->MyCookie);
+ PackAddInt(p, "udp_acceleration_client_cookie", s->UdpAccel->YourCookie);
+ PackAddBool(p, "udp_acceleration_use_encryption", !s->UdpAccel->PlainTextMode);
+ PackAddBool(p, "use_hmac_on_udp_acceleration", s->UdpAccel->UseHMac);
+ PackAddBool(p, "udp_accel_fast_disconnect_detect", s->UdpAccelFastDisconnectDetect);
+ }
+
+ if (s->EnableBulkOnRUDP)
+ {
+ // Allow bulk transfer on R-UDP
+ PackAddBool(p, "enable_bulk_on_rudp", true);
+ PackAddBool(p, "enable_hmac_on_bulk_of_rudp", s->EnableHMacOnBulkOfRUDP);
+
+ PackAddData(p, "bulk_on_rudp_send_key", s->Connection->FirstSock->BulkRecvKey->Data, SHA1_SIZE);
+ PackAddData(p, "bulk_on_rudp_recv_key", s->Connection->FirstSock->BulkSendKey->Data, SHA1_SIZE);
+ }
+
+ if (s->IsAzureSession)
+ {
+ if (s->Connection != NULL && s->Connection->FirstSock != NULL)
+ {
+ SOCK *sock = s->Connection->FirstSock;
+
+ PackAddIp(p, "azure_real_server_global_ip", &sock->Reverse_MyServerGlobalIp);
+ }
+ }
+
+ PackAddBool(p, "enable_udp_recovery", s->EnableUdpRecovery);
+
+ return p;
+}
+
+#define PACK_ADD_POLICY_BOOL(name, value) \
+ PackAddInt(p, "policy:" name, y->value == false ? 0 : 1)
+#define PACK_ADD_POLICY_UINT(name, value) \
+ PackAddInt(p, "policy:" name, y->value)
+#define PACK_GET_POLICY_BOOL(name, value) \
+ y->value = (PackGetInt(p, "policy:" name) == 0 ? false : true)
+#define PACK_GET_POLICY_UINT(name, value) \
+ y->value = PackGetInt(p, "policy:" name)
+
+// Get a PACK from the session key
+bool GetSessionKeyFromPack(PACK *p, UCHAR *session_key, UINT *session_key_32)
+{
+ // Validate arguments
+ if (p == NULL || session_key == NULL || session_key_32 == NULL)
+ {
+ return false;
+ }
+
+ if (PackGetDataSize(p, "session_key") != SHA1_SIZE)
+ {
+ return false;
+ }
+ if (PackGetData(p, "session_key", session_key) == false)
+ {
+ return false;
+ }
+ *session_key_32 = PackGetInt(p, "session_key_32");
+
+ return true;
+}
+
+// Get the policy from the PACK
+POLICY *PackGetPolicy(PACK *p)
+{
+ POLICY *y;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ y = ZeroMalloc(sizeof(POLICY));
+
+ // Bool value
+ // Ver 2
+ PACK_GET_POLICY_BOOL("Access", Access);
+ PACK_GET_POLICY_BOOL("DHCPFilter", DHCPFilter);
+ PACK_GET_POLICY_BOOL("DHCPNoServer", DHCPNoServer);
+ PACK_GET_POLICY_BOOL("DHCPForce", DHCPForce);
+ PACK_GET_POLICY_BOOL("NoBridge", NoBridge);
+ PACK_GET_POLICY_BOOL("NoRouting", NoRouting);
+ PACK_GET_POLICY_BOOL("PrivacyFilter", PrivacyFilter);
+ PACK_GET_POLICY_BOOL("NoServer", NoServer);
+ PACK_GET_POLICY_BOOL("CheckMac", CheckMac);
+ PACK_GET_POLICY_BOOL("CheckIP", CheckIP);
+ PACK_GET_POLICY_BOOL("ArpDhcpOnly", ArpDhcpOnly);
+ PACK_GET_POLICY_BOOL("MonitorPort", MonitorPort);
+ PACK_GET_POLICY_BOOL("NoBroadcastLimiter", NoBroadcastLimiter);
+ PACK_GET_POLICY_BOOL("FixPassword", FixPassword);
+ PACK_GET_POLICY_BOOL("NoQoS", NoQoS);
+ // Ver 3
+ PACK_GET_POLICY_BOOL("RSandRAFilter", RSandRAFilter);
+ PACK_GET_POLICY_BOOL("RAFilter", RAFilter);
+ PACK_GET_POLICY_BOOL("DHCPv6Filter", DHCPv6Filter);
+ PACK_GET_POLICY_BOOL("DHCPv6NoServer", DHCPv6NoServer);
+ PACK_GET_POLICY_BOOL("NoRoutingV6", NoRoutingV6);
+ PACK_GET_POLICY_BOOL("CheckIPv6", CheckIPv6);
+ PACK_GET_POLICY_BOOL("NoServerV6", NoServerV6);
+ PACK_GET_POLICY_BOOL("NoSavePassword", NoSavePassword);
+ PACK_GET_POLICY_BOOL("FilterIPv4", FilterIPv4);
+ PACK_GET_POLICY_BOOL("FilterIPv6", FilterIPv6);
+ PACK_GET_POLICY_BOOL("FilterNonIP", FilterNonIP);
+ PACK_GET_POLICY_BOOL("NoIPv6DefaultRouterInRA", NoIPv6DefaultRouterInRA);
+ PACK_GET_POLICY_BOOL("NoIPv6DefaultRouterInRAWhenIPv6", NoIPv6DefaultRouterInRAWhenIPv6);
+
+ // UINT value
+ // Ver 2
+ PACK_GET_POLICY_UINT("MaxConnection", MaxConnection);
+ PACK_GET_POLICY_UINT("TimeOut", TimeOut);
+ PACK_GET_POLICY_UINT("MaxMac", MaxMac);
+ PACK_GET_POLICY_UINT("MaxIP", MaxIP);
+ PACK_GET_POLICY_UINT("MaxUpload", MaxUpload);
+ PACK_GET_POLICY_UINT("MaxDownload", MaxDownload);
+ PACK_GET_POLICY_UINT("MultiLogins", MultiLogins);
+ // Ver 3
+ PACK_GET_POLICY_UINT("MaxIPv6", MaxIPv6);
+ PACK_GET_POLICY_UINT("AutoDisconnect", AutoDisconnect);
+ PACK_GET_POLICY_UINT("VLanId", VLanId);
+
+ // Ver 3 flag
+ PACK_GET_POLICY_BOOL("Ver3", Ver3);
+
+ return y;
+}
+
+// Insert the policy into the PACK
+void PackAddPolicy(PACK *p, POLICY *y)
+{
+ // Validate arguments
+ if (p == NULL || y == NULL)
+ {
+ return;
+ }
+
+ // Bool value
+ // Ver 2
+ PACK_ADD_POLICY_BOOL("Access", Access);
+ PACK_ADD_POLICY_BOOL("DHCPFilter", DHCPFilter);
+ PACK_ADD_POLICY_BOOL("DHCPNoServer", DHCPNoServer);
+ PACK_ADD_POLICY_BOOL("DHCPForce", DHCPForce);
+ PACK_ADD_POLICY_BOOL("NoBridge", NoBridge);
+ PACK_ADD_POLICY_BOOL("NoRouting", NoRouting);
+ PACK_ADD_POLICY_BOOL("PrivacyFilter", PrivacyFilter);
+ PACK_ADD_POLICY_BOOL("NoServer", NoServer);
+ PACK_ADD_POLICY_BOOL("CheckMac", CheckMac);
+ PACK_ADD_POLICY_BOOL("CheckIP", CheckIP);
+ PACK_ADD_POLICY_BOOL("ArpDhcpOnly", ArpDhcpOnly);
+ PACK_ADD_POLICY_BOOL("MonitorPort", MonitorPort);
+ PACK_ADD_POLICY_BOOL("NoBroadcastLimiter", NoBroadcastLimiter);
+ PACK_ADD_POLICY_BOOL("FixPassword", FixPassword);
+ PACK_ADD_POLICY_BOOL("NoQoS", NoQoS);
+ // Ver 3
+ PACK_ADD_POLICY_BOOL("RSandRAFilter", RSandRAFilter);
+ PACK_ADD_POLICY_BOOL("RAFilter", RAFilter);
+ PACK_ADD_POLICY_BOOL("DHCPv6Filter", DHCPv6Filter);
+ PACK_ADD_POLICY_BOOL("DHCPv6NoServer", DHCPv6NoServer);
+ PACK_ADD_POLICY_BOOL("NoRoutingV6", NoRoutingV6);
+ PACK_ADD_POLICY_BOOL("CheckIPv6", CheckIPv6);
+ PACK_ADD_POLICY_BOOL("NoServerV6", NoServerV6);
+ PACK_ADD_POLICY_BOOL("NoSavePassword", NoSavePassword);
+ PACK_ADD_POLICY_BOOL("FilterIPv4", FilterIPv4);
+ PACK_ADD_POLICY_BOOL("FilterIPv6", FilterIPv6);
+ PACK_ADD_POLICY_BOOL("FilterNonIP", FilterNonIP);
+ PACK_ADD_POLICY_BOOL("NoIPv6DefaultRouterInRA", NoIPv6DefaultRouterInRA);
+ PACK_ADD_POLICY_BOOL("NoIPv6DefaultRouterInRAWhenIPv6", NoIPv6DefaultRouterInRAWhenIPv6);
+
+ // UINT value
+ // Ver 2
+ PACK_ADD_POLICY_UINT("MaxConnection", MaxConnection);
+ PACK_ADD_POLICY_UINT("TimeOut", TimeOut);
+ PACK_ADD_POLICY_UINT("MaxMac", MaxMac);
+ PACK_ADD_POLICY_UINT("MaxIP", MaxIP);
+ PACK_ADD_POLICY_UINT("MaxUpload", MaxUpload);
+ PACK_ADD_POLICY_UINT("MaxDownload", MaxDownload);
+ PACK_ADD_POLICY_UINT("MultiLogins", MultiLogins);
+ // Ver 3
+ PACK_ADD_POLICY_UINT("MaxIPv6", MaxIPv6);
+ PACK_ADD_POLICY_UINT("AutoDisconnect", AutoDisconnect);
+ PACK_ADD_POLICY_UINT("VLanId", VLanId);
+
+ // Ver 3 flag
+ PackAddBool(p, "policy:Ver3", true);
+}
+
+// Upload the authentication data for the additional connection
+bool ClientUploadAuth2(CONNECTION *c, SOCK *s)
+{
+ PACK *p = NULL;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ p = PackAdditionalConnect(c->Session->SessionKey);
+
+ PackAddClientVersion(p, c);
+
+ if (HttpClientSend(s, p) == false)
+ {
+ FreePack(p);
+ return false;
+ }
+ FreePack(p);
+
+ return true;
+}
+
+// Send a NOOP
+void ClientUploadNoop(CONNECTION *c)
+{
+ PACK *p;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ p = PackError(0);
+ PackAddInt(p, "noop", 1);
+ HttpClientSend(c->FirstSock, p);
+ FreePack(p);
+
+ p = HttpClientRecv(c->FirstSock);
+ if (p != NULL)
+ {
+ FreePack(p);
+ }
+}
+
+// Add client version information to the PACK
+void PackAddClientVersion(PACK *p, CONNECTION *c)
+{
+ // Validate arguments
+ if (p == NULL || c == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "client_str", c->ClientStr);
+ PackAddInt(p, "client_ver", c->ClientVer);
+ PackAddInt(p, "client_build", c->ClientBuild);
+}
+
+// Upload the certificate data for the new connection
+bool ClientUploadAuth(CONNECTION *c)
+{
+ PACK *p = NULL;
+ CLIENT_AUTH *a;
+ CLIENT_OPTION *o;
+ X *x;
+ bool ret;
+ NODE_INFO info;
+ UCHAR secure_password[SHA1_SIZE];
+ UCHAR sign[4096 / 8];
+ UCHAR unique[SHA1_SIZE];
+ RPC_WINVER v;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ Zero(sign, sizeof(sign));
+
+ a = c->Session->ClientAuth;
+ o = c->Session->ClientOption;
+
+ if (c->UseTicket == false)
+ {
+ switch (a->AuthType)
+ {
+ case CLIENT_AUTHTYPE_ANONYMOUS:
+ // Anonymous authentication
+ p = PackLoginWithAnonymous(o->HubName, a->Username);
+ break;
+
+ case CLIENT_AUTHTYPE_PASSWORD:
+ // Password authentication
+ SecurePassword(secure_password, a->HashedPassword, c->Random);
+ p = PackLoginWithPassword(o->HubName, a->Username, secure_password);
+ break;
+
+ case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+ // Plaintext password authentication
+ p = PackLoginWithPlainPassword(o->HubName, a->Username, a->PlainPassword);
+ break;
+
+ case CLIENT_AUTHTYPE_CERT:
+ // Certificate authentication
+ if (a->ClientX != NULL && a->ClientX->is_compatible_bit &&
+ a->ClientX->bits != 0 && (a->ClientX->bits / 8) <= sizeof(sign))
+ {
+ if (RsaSignEx(sign, c->Random, SHA1_SIZE, a->ClientK, a->ClientX->bits))
+ {
+ p = PackLoginWithCert(o->HubName, a->Username, a->ClientX, sign, a->ClientX->bits / 8);
+ c->ClientX = CloneX(a->ClientX);
+ }
+ }
+ break;
+
+ case CLIENT_AUTHTYPE_SECURE:
+ // Authentication by secure device
+ if (ClientSecureSign(c, sign, c->Random, &x))
+ {
+ p = PackLoginWithCert(o->HubName, a->Username, x, sign, 128);
+ c->ClientX = CloneX(x);
+ FreeX(x);
+ }
+ else
+ {
+ c->Err = ERR_SECURE_DEVICE_OPEN_FAILED;
+ c->Session->ForceStopFlag = true;
+ }
+ break;
+ }
+ }
+ else
+ {
+ // Ticket
+ p = NewPack();
+ PackAddStr(p, "method", "login");
+ PackAddStr(p, "hubname", o->HubName);
+ PackAddStr(p, "username", a->Username);
+ PackAddInt(p, "authtype", AUTHTYPE_TICKET);
+ PackAddData(p, "ticket", c->Ticket, SHA1_SIZE);
+ }
+
+ // Current time
+ PackAddInt64(p, "timestamp", SystemTime64());
+
+ if (p == NULL)
+ {
+ // Error
+ if (c->Err != ERR_SECURE_DEVICE_OPEN_FAILED)
+ {
+ c->Err = ERR_PROTOCOL_ERROR;
+ }
+ return false;
+ }
+
+ PackAddClientVersion(p, c);
+
+ // Protocol
+ PackAddInt(p, "protocol", c->Protocol);
+
+ // Version, etc.
+ PackAddStr(p, "hello", c->ClientStr);
+ PackAddInt(p, "version", c->ClientVer);
+ PackAddInt(p, "build", c->ClientBuild);
+ PackAddInt(p, "client_id", c->Cedar->ClientId);
+
+ // The maximum number of connections
+ PackAddInt(p, "max_connection", o->MaxConnection);
+ // Flag to use of cryptography
+ PackAddInt(p, "use_encrypt", o->UseEncrypt == false ? 0 : 1);
+ // Fast encryption using flag
+ // PackAddInt(p, "use_fast_rc4", o->UseFastRC4 == false ? 0 : 1);
+ // Data compression flag
+ PackAddInt(p, "use_compress", o->UseCompress == false ? 0 : 1);
+ // Half connection flag
+ PackAddInt(p, "half_connection", o->HalfConnection == false ? 0 : 1);
+
+ // Bridge / routing mode flag
+ PackAddBool(p, "require_bridge_routing_mode", o->RequireBridgeRoutingMode);
+
+ // Monitor mode flag
+ PackAddBool(p, "require_monitor_mode", o->RequireMonitorMode);
+
+ // VoIP / QoS flag
+ PackAddBool(p, "qos", o->DisableQoS ? false : true);
+
+ // Bulk transfer support
+ PackAddBool(p, "support_bulk_on_rudp", true);
+ PackAddBool(p, "support_hmac_on_bulk_of_rudp", true);
+
+ // UDP recovery support
+ PackAddBool(p, "support_udp_recovery", true);
+
+ // Unique ID
+ GenerateMachineUniqueHash(unique);
+ PackAddData(p, "unique_id", unique, SHA1_SIZE);
+
+ // UDP acceleration function using flag
+ if (o->NoUdpAcceleration == false && c->Session->UdpAccel != NULL)
+ {
+ PackAddBool(p, "use_udp_acceleration", true);
+ PackAddIp(p, "udp_acceleration_client_ip", &c->Session->UdpAccel->MyIp);
+ PackAddInt(p, "udp_acceleration_client_port", c->Session->UdpAccel->MyPort);
+ PackAddData(p, "udp_acceleration_client_key", c->Session->UdpAccel->MyKey, UDP_ACCELERATION_COMMON_KEY_SIZE);
+ PackAddBool(p, "support_hmac_on_udp_acceleration", true);
+ PackAddBool(p, "support_udp_accel_fast_disconnect_detect", true);
+ }
+
+ // Brand string for the connection limit
+ {
+ char *branded_ctos = _SS("BRANDED_C_TO_S");
+ if(StrLen(branded_ctos) > 0)
+ {
+ PackAddStr(p, "branded_ctos", branded_ctos);
+ }
+ }
+
+ // Node information
+ CreateNodeInfo(&info, c);
+ OutRpcNodeInfo(p, &info);
+
+ // OS information
+ GetWinVer(&v);
+ OutRpcWinVer(p, &v);
+
+ ret = HttpClientSend(c->FirstSock, p);
+ if (ret == false)
+ {
+ c->Err = ERR_DISCONNECTED;
+ }
+
+ FreePack(p);
+
+ return ret;
+}
+
+// Upload the Hello packet
+bool ServerUploadHello(CONNECTION *c)
+{
+ PACK *p;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ // Random number generation
+ Rand(c->Random, SHA1_SIZE);
+
+ p = PackHello(c->Random, c->ServerVer, c->ServerBuild, c->ServerStr);
+ if (HttpServerSend(c->FirstSock, p) == false)
+ {
+ FreePack(p);
+ c->Err = ERR_DISCONNECTED;
+ return false;
+ }
+
+ FreePack(p);
+
+ return true;
+}
+
+// Download the Hello packet
+bool ClientDownloadHello(CONNECTION *c, SOCK *s)
+{
+ PACK *p;
+ UINT err;
+ UCHAR random[SHA1_SIZE];
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ // Data reception
+ p = HttpClientRecv(s);
+ if (p == NULL)
+ {
+ c->Err = ERR_SERVER_IS_NOT_VPN;
+ return false;
+ }
+
+ if (err = GetErrorFromPack(p))
+ {
+ // An error has occured
+ c->Err = err;
+ FreePack(p);
+ return false;
+ }
+
+ // Packet interpretation
+ if (GetHello(p, random, &c->ServerVer, &c->ServerBuild, c->ServerStr, sizeof(c->ServerStr)) == false)
+ {
+ c->Err = ERR_SERVER_IS_NOT_VPN;
+ FreePack(p);
+ return false;
+ }
+
+ if (c->FirstSock == s)
+ {
+ Copy(c->Random, random, SHA1_SIZE);
+ }
+
+ FreePack(p);
+
+ return true;
+}
+
+// Download the signature
+bool ServerDownloadSignature(CONNECTION *c, char **error_detail_str)
+{
+ HTTP_HEADER *h;
+ UCHAR *data;
+ UINT data_size;
+ SOCK *s;
+ UINT num = 0, max = 19;
+ SERVER *server;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ server = c->Cedar->Server;
+
+ s = c->FirstSock;
+
+ while (true)
+ {
+ num++;
+ if (num > max)
+ {
+ // Disconnect
+ Disconnect(s);
+ c->Err = ERR_CLIENT_IS_NOT_VPN;
+
+ *error_detail_str = "HTTP_TOO_MANY_REQUEST";
+ return false;
+ }
+ // Receive a header
+ h = RecvHttpHeader(s);
+ if (h == NULL)
+ {
+ c->Err = ERR_CLIENT_IS_NOT_VPN;
+ return false;
+ }
+
+ // Interpret
+ if (StrCmpi(h->Method, "POST") == 0)
+ {
+ // Receive the data since it's POST
+ data_size = GetContentLength(h);
+ if ((data_size > MAX_WATERMARK_SIZE || data_size < SizeOfWaterMark()) && (data_size != StrLen(HTTP_VPN_TARGET_POSTDATA)))
+ {
+ // Data is too large
+ HttpSendForbidden(s, h->Target, NULL);
+ FreeHttpHeader(h);
+ c->Err = ERR_CLIENT_IS_NOT_VPN;
+ *error_detail_str = "POST_Recv_TooLong";
+ return false;
+ }
+ data = Malloc(data_size);
+ if (RecvAll(s, data, data_size, s->SecureMode) == false)
+ {
+ // Data reception failure
+ Free(data);
+ FreeHttpHeader(h);
+ c->Err = ERR_DISCONNECTED;
+ *error_detail_str = "POST_Recv_Failed";
+ return false;
+ }
+ // Check the Target
+ if (StrCmpi(h->Target, HTTP_VPN_TARGET2) != 0)
+ {
+ // Target is invalid
+ HttpSendNotFound(s, h->Target);
+ Free(data);
+ FreeHttpHeader(h);
+ *error_detail_str = "POST_Target_Wrong";
+ }
+ else
+ {
+ // Compare posted data with the WaterMark
+ if ((data_size == StrLen(HTTP_VPN_TARGET_POSTDATA) && (Cmp(data, HTTP_VPN_TARGET_POSTDATA, data_size) == 0))
+ || (Cmp(data, WaterMark, SizeOfWaterMark()) == 0))
+ {
+ // Check the WaterMark
+ Free(data);
+ FreeHttpHeader(h);
+ return true;
+ }
+ else
+ {
+ // WaterMark is incorrect
+ HttpSendForbidden(s, h->Target, NULL);
+ FreeHttpHeader(h);
+ *error_detail_str = "POST_WaterMark_Error";
+ }
+ }
+ }
+ else if (StrCmpi(h->Method, "SSTP_DUPLEX_POST") == 0 && (server->DisableSSTPServer == false || s->IsReverseAcceptedSocket
+ ) &&
+ GetServerCapsBool(server, "b_support_sstp") && GetNoSstp() == false)
+ {
+ // SSTP client is connected
+ c->WasSstp = true;
+
+ if (StrCmpi(h->Target, SSTP_URI) == 0)
+ {
+ bool sstp_ret;
+ // Accept the SSTP connection
+ c->Type = CONNECTION_TYPE_SSTP;
+
+ sstp_ret = AcceptSstp(c);
+
+ c->Err = ERR_DISCONNECTED;
+ FreeHttpHeader(h);
+
+ if (sstp_ret)
+ {
+ *error_detail_str = "";
+ }
+ else
+ {
+ *error_detail_str = "SSTP_ABORT";
+ }
+
+ return false;
+ }
+ else
+ {
+ // URI is invalid
+ HttpSendNotFound(s, h->Target);
+ *error_detail_str = "SSTP_URL_WRONG";
+ }
+
+ FreeHttpHeader(h);
+ }
+ else
+ {
+ // This should not be a VPN client, but interpret a bit more
+ if (StrCmpi(h->Method, "GET") != 0)
+ {
+ // Unsupported method calls
+ HttpSendNotImplemented(s, h->Method, h->Target, h->Version);
+ *error_detail_str = "HTTP_BAD_METHOD";
+ }
+ else
+ {
+
+ if (StrCmpi(h->Target, "/") == 0)
+ {
+ // Root directory
+ SERVER *s = c->Cedar->Server;
+ bool is_free = false;
+
+ *error_detail_str = "HTTP_ROOT";
+
+ if (s != NULL && s->UseWebTimePage)
+ {
+ // Generate a page that shows the current time as the top page automatically
+ BUF *b = ReadDump("|time.htm");
+
+ if (b != NULL)
+ {
+ char *src = ZeroMalloc(b->Size + 1);
+ UINT dst_size = b->Size * 2 + 64;
+ char *dst = ZeroMalloc(dst_size);
+ char host[MAX_PATH];
+ char portstr[64];
+ char now_str[MAX_PATH];
+
+ GetDateTimeStr64(now_str, sizeof(now_str), LocalTime64());
+
+ GetMachineName(host, sizeof(host));
+ ToStr(portstr, c->FirstSock->LocalPort);
+
+ Copy(src, b->Buf, b->Size);
+ ReplaceStrEx(dst, dst_size, src,
+ "$HOST$", host, false);
+ ReplaceStrEx(dst, dst_size, dst,
+ "$PORT$", portstr, false);
+ ReplaceStrEx(dst, dst_size, dst,
+ "$NOW$", now_str, false);
+
+ FreeHttpHeader(h);
+ h = NewHttpHeader("HTTP/1.1", "202", "OK");
+ AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE4));
+ AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));
+ AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));
+ PostHttp(c->FirstSock, h, dst, StrLen(dst));
+
+ Free(src);
+ Free(dst);
+
+ FreeBuf(b);
+ }
+ }
+ else
+ {
+ if (is_free == false)
+ {
+ // Other than free version
+ HttpSendForbidden(c->FirstSock, h->Target, "");
+ }
+ else
+ {
+ // Free version
+ BUF *b = ReadDump("|free.htm");
+
+ if (b != NULL)
+ {
+ char *src = ZeroMalloc(b->Size + 1);
+ UINT dst_size = b->Size * 2 + 64;
+ char *dst = ZeroMalloc(dst_size);
+ char host[MAX_PATH];
+ char portstr[64];
+
+ GetMachineName(host, sizeof(host));
+ ToStr(portstr, c->FirstSock->LocalPort);
+
+ Copy(src, b->Buf, b->Size);
+ ReplaceStrEx(dst, dst_size, src,
+ "$HOST$", host, false);
+ ReplaceStrEx(dst, dst_size, dst,
+ "$PORT$", portstr, false);
+
+ FreeHttpHeader(h);
+ h = NewHttpHeader("HTTP/1.1", "202", "OK");
+ AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE4));
+ AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));
+ AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));
+ PostHttp(c->FirstSock, h, dst, StrLen(dst));
+
+ Free(src);
+ Free(dst);
+
+ FreeBuf(b);
+ }
+ }
+ }
+ }
+ else
+ {
+ bool b = false;
+
+ // Show the WebUI if the configuration allow to use the WebUI
+ if (c->Cedar->Server != NULL && c->Cedar->Server->UseWebUI)
+ {
+ WU_WEBPAGE *page;
+
+ // Show the WebUI
+ page = WuGetPage(h->Target, c->Cedar->WebUI);
+
+ if (page != NULL)
+ {
+ PostHttp(s, page->header, page->data, page->size);
+ b = true;
+ WuFreeWebPage(page);
+ }
+
+ }
+
+ if (c->FirstSock->RemoteIP.addr[0] == 127)
+ {
+ if (StrCmpi(h->Target, HTTP_SAITAMA) == 0)
+ {
+ // Saitama (joke)
+ FreeHttpHeader(h);
+ h = NewHttpHeader("HTTP/1.1", "202", "OK");
+ AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE3));
+ AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));
+ AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));
+ PostHttp(s, h, Saitama, SizeOfSaitama());
+ b = true;
+ }
+ else if (StartWith(h->Target, HTTP_PICTURES))
+ {
+ BUF *buf;
+
+ // Lots of photos
+ buf = ReadDump("|Pictures.mht");
+
+ if (buf != NULL)
+ {
+ FreeHttpHeader(h);
+ h = NewHttpHeader("HTTP/1.1", "202", "OK");
+ AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE5));
+ AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));
+ AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));
+ PostHttp(s, h, buf->Buf, buf->Size);
+ b = true;
+
+ FreeBuf(buf);
+ }
+ }
+ }
+
+ if (b == false)
+ {
+ // Not Found
+ HttpSendNotFound(s, h->Target);
+
+ *error_detail_str = "HTTP_NOT_FOUND";
+ }
+ }
+ }
+ FreeHttpHeader(h);
+ }
+ }
+}
+
+// Upload a signature
+bool ClientUploadSignature(SOCK *s)
+{
+ HTTP_HEADER *h;
+ UINT water_size, rand_size;
+ UCHAR *water;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ h = NewHttpHeader("POST", HTTP_VPN_TARGET2, "HTTP/1.1");
+ AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE3));
+ AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));
+
+ // Generate a watermark
+ rand_size = Rand32() % (HTTP_PACK_RAND_SIZE_MAX * 2);
+ water_size = SizeOfWaterMark() + rand_size;
+ water = Malloc(water_size);
+ Copy(water, WaterMark, SizeOfWaterMark());
+ Rand(&water[SizeOfWaterMark()], rand_size);
+
+ // Upload the watermark data
+ if (PostHttp(s, h, water, water_size) == false)
+ {
+ Free(water);
+ FreeHttpHeader(h);
+ return false;
+ }
+
+ Free(water);
+ FreeHttpHeader(h);
+
+ return true;
+}
+
+// Establish a connection to the server
+SOCK *ClientConnectToServer(CONNECTION *c)
+{
+ SOCK *s = NULL;
+ X *x = NULL;
+ K *k = NULL;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ if (c->Halt)
+ {
+ c->Err = ERR_USER_CANCEL;
+ return NULL;
+ }
+
+ // Get the socket by connecting
+ s = ClientConnectGetSocket(c, false, (c->DontUseTls1 ? false : true));
+ if (s == NULL)
+ {
+ // Connection failure
+ return NULL;
+ }
+
+ c->FirstSock = s;
+
+ if (c->Halt)
+ {
+ c->Err = ERR_USER_CANCEL;
+ ReleaseSock(s);
+ c->FirstSock = NULL;
+ return NULL;
+ }
+
+ // Time-out
+ SetTimeout(s, CONNECTING_TIMEOUT);
+
+ // Start the SSL communication
+ if (StartSSLEx(s, x, k, (c->DontUseTls1 ? false : true), 0, c->ServerName) == false)
+ {
+ // SSL communication start failure
+ Disconnect(s);
+ ReleaseSock(s);
+ c->FirstSock = NULL;
+ c->Err = ERR_SERVER_IS_NOT_VPN;
+ return NULL;
+ }
+
+ if (s->RemoteX == NULL)
+ {
+ // SSL communication start failure
+ Disconnect(s);
+ ReleaseSock(s);
+ c->FirstSock = NULL;
+ c->Err = ERR_SERVER_IS_NOT_VPN;
+ return NULL;
+ }
+
+ return s;
+}
+
+// Return a socket by connecting to the server
+SOCK *ClientConnectGetSocket(CONNECTION *c, bool additional_connect, bool no_tls)
+{
+ SOCK *s = NULL;
+ CLIENT_OPTION *o;
+ char *host_for_direct_connection;
+ UINT port_for_direct_connection;
+ wchar_t tmp[MAX_SIZE];
+ SESSION *sess;
+ volatile bool *cancel_flag = NULL;
+ void *hWnd;
+ UINT nat_t_err = 0;
+ bool is_additonal_rudp_session = false;
+ UCHAR uc = 0;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ sess = c->Session;
+
+ if (sess != NULL)
+ {
+ cancel_flag = &sess->CancelConnect;
+ is_additonal_rudp_session = sess->IsRUDPSession;
+ }
+
+ hWnd = c->hWndForUI;
+
+ o = c->Session->ClientOption;
+
+ if (c->RestoreServerNameAndPort && additional_connect)
+ {
+ // Restore to the original server name and port number
+ c->RestoreServerNameAndPort = false;
+
+ StrCpy(c->ServerName, sizeof(c->ServerName), o->Hostname);
+ c->ServerPort = o->Port;
+ }
+
+ host_for_direct_connection = c->ServerName;
+ port_for_direct_connection = c->ServerPort;
+
+ switch (o->ProxyType)
+ {
+ case PROXY_DIRECT: // TCP/IP
+ UniFormat(tmp, sizeof(tmp), _UU("STATUS_4"), c->ServerName);
+ PrintStatus(sess, tmp);
+ // Production job
+ if (o->PortUDP == 0)
+ {
+ {
+ // If additional_connect == false, enable trying to NAT-T connection
+ // If additional_connect == true, follow the IsRUDPSession setting in this session
+ s = TcpIpConnectEx(host_for_direct_connection, port_for_direct_connection,
+ (bool *)cancel_flag, hWnd, &nat_t_err, (additional_connect ? (!is_additonal_rudp_session) : false),
+ true, no_tls);
+ }
+ }
+ else
+ {
+ // Mode to connect with R-UDP directly without using NAT-T server when using UDP
+ IP ip;
+
+ Zero(&ip, sizeof(ip));
+
+ StrToIP(&ip, o->Hostname);
+
+
+ s = NewRUDPClientDirect(VPN_RUDP_SVC_NAME, &ip, o->PortUDP, &nat_t_err,
+ TIMEOUT_TCP_PORT_CHECK, (bool *)cancel_flag, NULL, NULL, 0, false);
+
+ if (s != NULL)
+ {
+ StrCpy(s->UnderlayProtocol, sizeof(s->UnderlayProtocol), SOCK_UNDERLAY_NAT_T);
+ }
+ }
+ if (s == NULL)
+ {
+ // Connection failure
+ if (nat_t_err != RUDP_ERROR_NAT_T_TWO_OR_MORE)
+ {
+ c->Err = ERR_CONNECT_FAILED;
+ }
+ else
+ {
+ c->Err = ERR_NAT_T_TWO_OR_MORE;
+ }
+ return NULL;
+ }
+ break;
+
+ case PROXY_HTTP: // HTTP Proxy
+ host_for_direct_connection = o->ProxyName;
+ port_for_direct_connection = o->ProxyPort;
+
+ UniFormat(tmp, sizeof(tmp), _UU("STATUS_2"), c->ServerName, o->ProxyName);
+ PrintStatus(sess, tmp);
+
+
+ // Proxy connection
+ s = ProxyConnectEx(c, host_for_direct_connection, port_for_direct_connection,
+ c->ServerName, c->ServerPort, o->ProxyUsername, o->ProxyPassword,
+ additional_connect, (bool *)cancel_flag, hWnd);
+ if (s == NULL)
+ {
+ // Connection failure
+ return NULL;
+ }
+ break;
+
+ case PROXY_SOCKS: // SOCKS Proxy
+ host_for_direct_connection = o->ProxyName;
+
+ port_for_direct_connection = o->ProxyPort;
+
+ UniFormat(tmp, sizeof(tmp), _UU("STATUS_2"), c->ServerName, o->ProxyName);
+ PrintStatus(sess, tmp);
+
+
+ // SOCKS connection
+ s = SocksConnectEx(c, host_for_direct_connection, port_for_direct_connection,
+ c->ServerName, c->ServerPort, o->ProxyUsername,
+ additional_connect, (bool *)cancel_flag, hWnd);
+ if (s == NULL)
+ {
+ // Connection failure
+ return NULL;
+ }
+ break;
+ }
+
+ if (s == NULL)
+ {
+ // Connection failure
+ c->Err = ERR_CONNECT_FAILED;
+ }
+ else
+ {
+ // Success to connect
+ // Keep a note of the IP address
+ if (additional_connect == false || IsZeroIP(&s->RemoteIP))
+ {
+ if (((s->IsRUDPSocket || s->IPv6) && IsZeroIP(&s->RemoteIP) == false && o->ProxyType == PROXY_DIRECT) || GetIP(&c->Session->ServerIP, host_for_direct_connection) == false)
+ {
+ Copy(&c->Session->ServerIP, &s->RemoteIP, sizeof(IP));
+ }
+ }
+ }
+
+ return s;
+}
+
+// Connect via SOCKS
+SOCK *SocksConnect(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, bool additional_connect)
+{
+ return SocksConnectEx(c, proxy_host_name, proxy_port,
+ server_host_name, server_port, username, additional_connect, NULL, NULL);
+}
+SOCK *SocksConnectEx(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, bool additional_connect,
+ bool *cancel_flag, void *hWnd)
+{
+ return SocksConnectEx2(c, proxy_host_name, proxy_port,
+ server_host_name, server_port, username, additional_connect, cancel_flag,
+ hWnd, 0);
+}
+SOCK *SocksConnectEx2(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, bool additional_connect,
+ bool *cancel_flag, void *hWnd, UINT timeout)
+{
+ SOCK *s = NULL;
+ IP ip;
+ // Validate arguments
+ if (c == NULL || proxy_host_name == NULL || proxy_port == 0 || server_host_name == NULL
+ || server_port == 0)
+ {
+ c->Err = ERR_PROXY_CONNECT_FAILED;
+ return NULL;
+ }
+
+ // Get the IP address of the destination server
+ if (GetIP(&ip, server_host_name) == false)
+ {
+ // Failure
+ c->Err = ERR_CONNECT_FAILED;
+ return NULL;
+ }
+
+ if (c->Halt)
+ {
+ // Stop
+ c->Err = ERR_USER_CANCEL;
+ return NULL;
+ }
+
+ // Connection
+ s = TcpConnectEx3(proxy_host_name, proxy_port, timeout, cancel_flag, hWnd, true, NULL, false, false);
+ if (s == NULL)
+ {
+ // Failure
+ c->Err = ERR_PROXY_CONNECT_FAILED;
+ return NULL;
+ }
+
+ // Timeout setting
+ SetTimeout(s, MIN(CONNECTING_TIMEOUT_PROXY, (timeout == 0 ? INFINITE : timeout)));
+
+ if (additional_connect == false)
+ {
+ c->FirstSock = s;
+ }
+
+ // Request packet transmission
+ if (SocksSendRequestPacket(c, s, server_port, &ip, username) == false)
+ {
+ // Failure
+ if (additional_connect == false)
+ {
+ c->FirstSock = NULL;
+ }
+ Disconnect(s);
+ ReleaseSock(s);
+ return NULL;
+ }
+
+ // Receive a response packet
+ if (SocksRecvResponsePacket(c, s) == false)
+ {
+ // Failure
+ if (additional_connect == false)
+ {
+ c->FirstSock = NULL;
+ }
+ Disconnect(s);
+ ReleaseSock(s);
+ return NULL;
+ }
+
+ SetTimeout(s, INFINITE);
+
+ return s;
+}
+
+// Receive a SOCKS response packet
+bool SocksRecvResponsePacket(CONNECTION *c, SOCK *s)
+{
+ BUF *b;
+ UINT size = 8;
+ UCHAR tmp[8];
+ UCHAR vn, cd;
+ // Validate arguments
+ if (c == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ if (RecvAll(s, tmp, sizeof(tmp), false) == false)
+ {
+ c->Err = ERR_DISCONNECTED;
+ return false;
+ }
+
+ b = NewBuf();
+ WriteBuf(b, tmp, sizeof(tmp));
+ SeekBuf(b, 0, 0);
+
+ ReadBuf(b, &vn, 1);
+ ReadBuf(b, &cd, 1);
+
+ FreeBuf(b);
+
+ if (vn != 0)
+ {
+ c->Err = ERR_PROXY_ERROR;
+ return false;
+ }
+
+ switch (cd)
+ {
+ case 90:
+ // Success
+ return true;
+
+ case 93:
+ // Authentication failure
+ c->Err = ERR_PROXY_AUTH_FAILED;
+ return false;
+
+ default:
+ // Connection to the server failure
+ c->Err = ERR_CONNECT_FAILED;
+ return false;
+ }
+}
+
+// Send a SOCKS request packet
+bool SocksSendRequestPacket(CONNECTION *c, SOCK *s, UINT dest_port, IP *dest_ip, char *userid)
+{
+ BUF *b;
+ UCHAR vn, cd;
+ USHORT port;
+ UINT ip;
+ bool ret;
+ // Validate arguments
+ if (s == NULL || dest_port == 0 || dest_ip == NULL || c == NULL)
+ {
+ return false;
+ }
+ if (userid == NULL)
+ {
+ userid = "";
+ }
+
+ b = NewBuf();
+ vn = 4;
+ cd = 1;
+ WriteBuf(b, &vn, 1);
+ WriteBuf(b, &cd, 1);
+ port = Endian16((USHORT)dest_port);
+ ip = IPToUINT(dest_ip);
+ WriteBuf(b, &port, 2);
+ WriteBuf(b, &ip, 4);
+ WriteBuf(b, userid, StrLen(userid) + 1);
+
+ ret = SendAll(s, b->Buf, b->Size, false);
+ if (ret == false)
+ {
+ c->Err = ERR_DISCONNECTED;
+ }
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Connect through a proxy
+SOCK *ProxyConnect(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, char *password, bool additional_connect)
+{
+ return ProxyConnectEx(c, proxy_host_name, proxy_port,
+ server_host_name, server_port, username, password, additional_connect, NULL, NULL);
+}
+SOCK *ProxyConnectEx(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, char *password, bool additional_connect,
+ bool *cancel_flag, void *hWnd)
+{
+ return ProxyConnectEx2(c, proxy_host_name, proxy_port,
+ server_host_name, server_port, username, password, additional_connect,
+ cancel_flag, hWnd, 0);
+}
+SOCK *ProxyConnectEx2(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, char *password, bool additional_connect,
+ bool *cancel_flag, void *hWnd, UINT timeout)
+{
+ SOCK *s = NULL;
+ bool use_auth = false;
+ char tmp[MAX_SIZE];
+ char auth_tmp_str[MAX_SIZE], auth_b64_str[MAX_SIZE * 2];
+ char basic_str[MAX_SIZE * 2];
+ UINT http_error_code;
+ HTTP_HEADER *h;
+ // Validate arguments
+ if (c == NULL || proxy_host_name == NULL || proxy_port == 0 || server_host_name == NULL ||
+ server_port == 0)
+ {
+ c->Err = ERR_PROXY_CONNECT_FAILED;
+ return NULL;
+ }
+ if (username != NULL && password != NULL &&
+ (StrLen(username) != 0 || StrLen(password) != 0))
+ {
+ use_auth = true;
+ }
+
+ if (c->Halt)
+ {
+ // Stop
+ c->Err = ERR_USER_CANCEL;
+ return NULL;
+ }
+
+ // Connection
+ s = TcpConnectEx3(proxy_host_name, proxy_port, timeout, cancel_flag, hWnd, true, NULL, false, false);
+ if (s == NULL)
+ {
+ // Failure
+ c->Err = ERR_PROXY_CONNECT_FAILED;
+ return NULL;
+ }
+
+ // Timeout setting
+ SetTimeout(s, MIN(CONNECTING_TIMEOUT_PROXY, (timeout == 0 ? INFINITE : timeout)));
+
+ if (additional_connect == false)
+ {
+ c->FirstSock = s;
+ }
+
+ // HTTP header generation
+ if (IsStrIPv6Address(server_host_name))
+ {
+ IP ip;
+ char iptmp[MAX_PATH];
+
+ StrToIP(&ip, server_host_name);
+ IPToStr(iptmp, sizeof(iptmp), &ip);
+
+ Format(tmp, sizeof(tmp), "[%s]:%u", iptmp, server_port);
+ }
+ else
+ {
+ Format(tmp, sizeof(tmp), "%s:%u", server_host_name, server_port);
+ }
+
+ h = NewHttpHeader("CONNECT", tmp, "HTTP/1.0");
+ AddHttpValue(h, NewHttpValue("User-Agent", (c->Cedar == NULL ? DEFAULT_USER_AGENT : c->Cedar->HttpUserAgent)));
+ AddHttpValue(h, NewHttpValue("Host", server_host_name));
+ AddHttpValue(h, NewHttpValue("Content-Length", "0"));
+ AddHttpValue(h, NewHttpValue("Proxy-Connection", "Keep-Alive"));
+ AddHttpValue(h, NewHttpValue("Pragma", "no-cache"));
+
+ if (use_auth)
+ {
+ wchar_t tmp[MAX_SIZE];
+ UniFormat(tmp, sizeof(tmp), _UU("STATUS_3"), server_host_name);
+ // Generate the authentication string
+ Format(auth_tmp_str, sizeof(auth_tmp_str), "%s:%s",
+ username, password);
+
+ // Base64 encode
+ Zero(auth_b64_str, sizeof(auth_b64_str));
+ Encode64(auth_b64_str, auth_tmp_str);
+ Format(basic_str, sizeof(basic_str), "Basic %s", auth_b64_str);
+
+ AddHttpValue(h, NewHttpValue("Proxy-Authorization", basic_str));
+ }
+
+ // Transmission
+ if (SendHttpHeader(s, h) == false)
+ {
+ // Failure
+ if (additional_connect == false)
+ {
+ c->FirstSock = NULL;
+ }
+ FreeHttpHeader(h);
+ Disconnect(s);
+ ReleaseSock(s);
+ c->Err = ERR_PROXY_ERROR;
+ return NULL;
+ }
+
+ FreeHttpHeader(h);
+
+ if (c->Halt)
+ {
+ // Stop
+ if (additional_connect == false)
+ {
+ c->FirstSock = NULL;
+ }
+ Disconnect(s);
+ ReleaseSock(s);
+ c->Err = ERR_USER_CANCEL;
+ return NULL;
+ }
+
+ // Receive the results
+ h = RecvHttpHeader(s);
+ if (h == NULL)
+ {
+ // Failure
+ if (additional_connect == false)
+ {
+ c->FirstSock = NULL;
+ }
+ FreeHttpHeader(h);
+ Disconnect(s);
+ ReleaseSock(s);
+ c->Err = ERR_PROXY_ERROR;
+ return NULL;
+ }
+
+ http_error_code = 0;
+ if (StrLen(h->Method) == 8)
+ {
+ if (Cmp(h->Method, "HTTP/1.", 7) == 0)
+ {
+ http_error_code = ToInt(h->Target);
+ }
+ }
+ FreeHttpHeader(h);
+
+ // Check the code
+ switch (http_error_code)
+ {
+ case 401:
+ case 403:
+ case 407:
+ // Authentication failure
+ if (additional_connect == false)
+ {
+ c->FirstSock = NULL;
+ }
+ Disconnect(s);
+ ReleaseSock(s);
+ c->Err = ERR_PROXY_AUTH_FAILED;
+ return NULL;
+
+ default:
+ if ((http_error_code / 100) == 2)
+ {
+ // Success
+ SetTimeout(s, INFINITE);
+ return s;
+ }
+ else
+ {
+ // Receive an unknown result
+ if (additional_connect == false)
+ {
+ c->FirstSock = NULL;
+ }
+ Disconnect(s);
+ ReleaseSock(s);
+ c->Err = ERR_PROXY_ERROR;
+ return NULL;
+ }
+ }
+}
+
+// TCP connection function
+SOCK *TcpConnectEx2(char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd, bool try_start_ssl, bool ssl_no_tls)
+{
+ return TcpConnectEx3(hostname, port, timeout, cancel_flag, hWnd, false, NULL, try_start_ssl, ssl_no_tls);
+}
+SOCK *TcpConnectEx3(char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd, bool no_nat_t, UINT *nat_t_error_code, bool try_start_ssl, bool ssl_no_tls)
+{
+#ifdef OS_WIN32
+ if (hWnd == NULL)
+ {
+#endif // OS_WIN32
+ return ConnectEx3(hostname, port, timeout, cancel_flag, (no_nat_t ? NULL : VPN_RUDP_SVC_NAME), nat_t_error_code, try_start_ssl, ssl_no_tls, false);
+#ifdef OS_WIN32
+ }
+ else
+ {
+ return WinConnectEx3((HWND)hWnd, hostname, port, timeout, 0, NULL, NULL, nat_t_error_code, (no_nat_t ? NULL : VPN_RUDP_SVC_NAME), try_start_ssl, ssl_no_tls);
+ }
+#endif // OS_WIN32
+}
+
+// Connect with TCP/IP
+SOCK *TcpIpConnect(char *hostname, UINT port, bool try_start_ssl, bool ssl_no_tls)
+{
+ return TcpIpConnectEx(hostname, port, NULL, NULL, NULL, false, try_start_ssl, ssl_no_tls);
+}
+SOCK *TcpIpConnectEx(char *hostname, UINT port, bool *cancel_flag, void *hWnd, UINT *nat_t_error_code, bool no_nat_t, bool try_start_ssl, bool ssl_no_tls)
+{
+ SOCK *s = NULL;
+ UINT dummy_int = 0;
+ // Validate arguments
+ if (nat_t_error_code == NULL)
+ {
+ nat_t_error_code = &dummy_int;
+ }
+ *nat_t_error_code = 0;
+ if (hostname == NULL || port == 0)
+ {
+ return NULL;
+ }
+
+ s = TcpConnectEx3(hostname, port, 0, cancel_flag, hWnd, no_nat_t, nat_t_error_code, try_start_ssl, ssl_no_tls);
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ return s;
+}
+
+// Protocol routine initialization
+void InitProtocol()
+{
+}
+
+// Release the protocol routine
+void FreeProtocol()
+{
+}
+
+// Create a Hello packet
+PACK *PackHello(void *random, UINT ver, UINT build, char *server_str)
+{
+ PACK *p;
+ // Validate arguments
+ if (random == NULL || server_str == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "hello", server_str);
+ PackAddInt(p, "version", ver);
+ PackAddInt(p, "build", build);
+ PackAddData(p, "random", random, SHA1_SIZE);
+
+ return p;
+}
+
+// Interpret the Hello packet
+bool GetHello(PACK *p, void *random, UINT *ver, UINT *build, char *server_str, UINT server_str_size)
+{
+ // Validate arguments
+ if (p == NULL || random == NULL || ver == NULL || server_str == NULL)
+ {
+ return false;
+ }
+
+ if (PackGetStr(p, "hello", server_str, server_str_size) == false)
+ {
+ return false;
+ }
+ *ver = PackGetInt(p, "version");
+ *build = PackGetInt(p, "build");
+ if (PackGetDataSize(p, "random") != SHA1_SIZE)
+ {
+ return false;
+ }
+ if (PackGetData(p, "random", random) == false)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Get the authentication method from PACK
+UINT GetAuthTypeFromPack(PACK *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return 0;
+ }
+
+ return PackGetInt(p, "authtype");
+}
+
+// Get the HUB name and the user name from the PACK
+bool GetHubnameAndUsernameFromPack(PACK *p, char *username, UINT username_size,
+ char *hubname, UINT hubname_size)
+{
+ // Validate arguments
+ if (p == NULL || username == NULL || hubname == NULL)
+ {
+ return false;
+ }
+
+ if (PackGetStr(p, "username", username, username_size) == false)
+ {
+ return false;
+ }
+ if (PackGetStr(p, "hubname", hubname, hubname_size) == false)
+ {
+ return false;
+ }
+ return true;
+}
+
+// Get the protocol from PACK
+UINT GetProtocolFromPack(PACK *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return 0;
+ }
+
+#if 0
+ return PackGetInt(p, "protocol");
+#else
+ // Limit to the TCP protocol in the current version
+ return CONNECTION_TCP;
+#endif
+}
+
+// Get the method from the PACK
+bool GetMethodFromPack(PACK *p, char *method, UINT size)
+{
+ // Validate arguments
+ if (p == NULL || method == NULL || size == 0)
+ {
+ return false;
+ }
+
+ return PackGetStr(p, "method", method, size);
+}
+
+// Generate a packet of certificate authentication login
+PACK *PackLoginWithCert(char *hubname, char *username, X *x, void *sign, UINT sign_size)
+{
+ PACK *p;
+ BUF *b;
+ // Validate arguments
+ if (hubname == NULL || username == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "method", "login");
+ PackAddStr(p, "hubname", hubname);
+ PackAddStr(p, "username", username);
+ PackAddInt(p, "authtype", CLIENT_AUTHTYPE_CERT);
+
+ // Certificate
+ b = XToBuf(x, false);
+ PackAddData(p, "cert", b->Buf, b->Size);
+ FreeBuf(b);
+
+ // Signature data
+ PackAddData(p, "sign", sign, sign_size);
+
+ return p;
+}
+
+// Generate a packet of plain text password authentication login
+PACK *PackLoginWithPlainPassword(char *hubname, char *username, void *plain_password)
+{
+ PACK *p;
+ // Validate arguments
+ if (hubname == NULL || username == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "method", "login");
+ PackAddStr(p, "hubname", hubname);
+ PackAddStr(p, "username", username);
+ PackAddInt(p, "authtype", CLIENT_AUTHTYPE_PLAIN_PASSWORD);
+ PackAddStr(p, "plain_password", plain_password);
+
+ return p;
+}
+
+// Create a packet of password authentication login
+PACK *PackLoginWithPassword(char *hubname, char *username, void *secure_password)
+{
+ PACK *p;
+ // Validate arguments
+ if (hubname == NULL || username == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "method", "login");
+ PackAddStr(p, "hubname", hubname);
+ PackAddStr(p, "username", username);
+ PackAddInt(p, "authtype", CLIENT_AUTHTYPE_PASSWORD);
+ PackAddData(p, "secure_password", secure_password, SHA1_SIZE);
+
+ return p;
+}
+
+// Create a packet for anonymous login
+PACK *PackLoginWithAnonymous(char *hubname, char *username)
+{
+ PACK *p;
+ // Validate arguments
+ if (hubname == NULL || username == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "method", "login");
+ PackAddStr(p, "hubname", hubname);
+ PackAddStr(p, "username", username);
+ PackAddInt(p, "authtype", CLIENT_AUTHTYPE_ANONYMOUS);
+
+ return p;
+}
+
+// Create a packet for the additional connection
+PACK *PackAdditionalConnect(UCHAR *session_key)
+{
+ PACK *p;
+ // Validate arguments
+ if (session_key == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "method", "additional_connect");
+ PackAddData(p, "session_key", session_key, SHA1_SIZE);
+
+ return p;
+}
+
+
+// Generate a RC4 key pair
+void GenerateRC4KeyPair(RC4_KEY_PAIR *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ Rand(k->ClientToServerKey, sizeof(k->ClientToServerKey));
+ Rand(k->ServerToClientKey, sizeof(k->ServerToClientKey));
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Protocol.h b/src/Cedar/Protocol.h
new file mode 100644
index 00000000..45827d82
--- /dev/null
+++ b/src/Cedar/Protocol.h
@@ -0,0 +1,270 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Protocol.h
+// Header of Protocol.c
+
+#ifndef PROTOCOL_H
+#define PROTOCOL_H
+
+// The parameters that will be passed to the certificate confirmation thread
+struct CHECK_CERT_THREAD_PROC
+{
+ CONNECTION *Connection;
+ X *ServerX;
+ CHECK_CERT_PROC *CheckCertProc;
+ bool UserSelected;
+ bool Exipred;
+ bool Ok;
+};
+
+// The parameters that will be passed to the secure device signature thread
+struct SECURE_SIGN_THREAD_PROC
+{
+ SECURE_SIGN_PROC *SecureSignProc;
+ CONNECTION *Connection;
+ SECURE_SIGN *SecureSign;
+ bool UserFinished;
+ bool Ok;
+};
+
+// Signature sending thread parameters
+struct SEND_SIGNATURE_PARAM
+{
+ char Hostname[MAX_PATH]; // Host name
+ UINT Port; // Port number
+ BUF *Buffer; // Packet contents
+};
+
+// Software update client callback
+typedef void (UPDATE_NOTIFY_PROC)(UPDATE_CLIENT *c, UINT latest_build, UINT64 latest_date, char *latest_ver, char *url, volatile bool *halt_flag, void *param);
+typedef bool (UPDATE_ISFOREGROUND_PROC)(UPDATE_CLIENT *c, void *param);
+
+// Configure the software update client
+struct UPDATE_CLIENT_SETTING
+{
+ bool DisableCheck; // Disable the update check
+ UINT LatestIgnoreBuild; // Ignore for earlier or identical to this build number
+};
+
+// Software update client
+struct UPDATE_CLIENT
+{
+ char FamilyName[MAX_SIZE]; // Product family name
+ char SoftwareName[MAX_SIZE]; // Software Name
+ wchar_t SoftwareTitle[MAX_SIZE]; // Software display name
+ char ClientId[128]; // Client ID
+ UINT MyBuild; // Build number of myself
+ UINT64 MyDate; // Build date of myself
+ char MyLanguage[MAX_SIZE]; // My language
+ UPDATE_CLIENT_SETTING Setting; // Setting
+ UINT LatestBuild; // Latest build number that was successfully acquired
+ volatile bool HaltFlag; // Halting flag
+ EVENT *HaltEvent; // Halting event
+ void *Param; // Any parameters
+ THREAD *Thread; // Thread
+ UPDATE_NOTIFY_PROC *Callback; // Callback function
+ UPDATE_ISFOREGROUND_PROC *IsForegroundCb; // Callback function for retrieving whether foreground
+};
+
+//// Constant related to updating of the software
+
+// Family
+#define UPDATE_FAMILY_NAME _SS("PRODUCT_FAMILY_NAME")
+
+// Software update server certificate hash
+#define UPDATE_SERVER_CERT_HASH "EFAC5FA0CDD14E0F864EED58A73C35D7E33B62F3"
+
+// URL
+#define UPDATE_SERVER_URL_GLOBAL "https://update-check.softether-network.net/update/update.aspx?family=%s&software=%s&mybuild=%u&lang=%s"
+#define UPDATE_SERVER_URL_CHINA "https://update-check.uxcom.jp/update/update.aspx?family=%s&software=%s&mybuild=%u&lang=%s"
+
+// Update check interval
+#define UPDATE_CHECK_INTERVAL_MIN (12 * 3600 * 1000)
+#define UPDATE_CHECK_INTERVAL_MAX (24 * 7200 * 1000)
+
+// Connection parameters
+#define UPDATE_CONNECT_TIMEOUT 5000
+#define UPDATE_COMM_TIMEOUT 5000
+
+
+
+// Function prototype
+UPDATE_CLIENT *NewUpdateClient(UPDATE_NOTIFY_PROC *cb, UPDATE_ISFOREGROUND_PROC *isforeground_cb, void *param, char *family_name, char *software_name, wchar_t *software_title, UINT my_build, UINT64 my_date, char *my_lang, UPDATE_CLIENT_SETTING *current_setting, char *client_id);
+void FreeUpdateClient(UPDATE_CLIENT *c);
+void UpdateClientThreadProc(THREAD *thread, void *param);
+void UpdateClientThreadMain(UPDATE_CLIENT *c);
+void UpdateClientThreadProcessResults(UPDATE_CLIENT *c, BUF *b);
+void SetUpdateClientSetting(UPDATE_CLIENT *c, UPDATE_CLIENT_SETTING *s);
+UINT64 ShortStrToDate64(char *str);
+
+
+bool ServerAccept(CONNECTION *c);
+bool ClientConnect(CONNECTION *c);
+SOCK *ClientConnectToServer(CONNECTION *c);
+SOCK *TcpIpConnect(char *hostname, UINT port, bool try_start_ssl, bool ssl_no_tls);
+SOCK *TcpIpConnectEx(char *hostname, UINT port, bool *cancel_flag, void *hWnd, UINT *nat_t_error_code, bool no_nat_t, bool try_start_ssl, bool ssl_no_tls);
+bool ClientUploadSignature(SOCK *s);
+bool ClientDownloadHello(CONNECTION *c, SOCK *s);
+bool ServerDownloadSignature(CONNECTION *c, char **error_detail_str);
+bool ServerUploadHello(CONNECTION *c);
+bool ClientUploadAuth(CONNECTION *c);
+SOCK *ClientConnectGetSocket(CONNECTION *c, bool additional_connect, bool no_tls);
+SOCK *TcpConnectEx2(char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd, bool try_start_ssl, bool ssl_no_tls);
+SOCK *TcpConnectEx3(char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd, bool no_nat_t, UINT *nat_t_error_code, bool try_start_ssl, bool ssl_no_tls);
+
+void InitProtocol();
+void FreeProtocol();
+
+
+
+POLICY *PackGetPolicy(PACK *p);
+void PackAddPolicy(PACK *p, POLICY *y);
+PACK *PackWelcome(SESSION *s);
+PACK *PackHello(void *random, UINT ver, UINT build, char *server_str);
+bool GetHello(PACK *p, void *random, UINT *ver, UINT *build, char *server_str, UINT server_str_size);
+PACK *PackLoginWithAnonymous(char *hubname, char *username);
+PACK *PackLoginWithPassword(char *hubname, char *username, void *secure_password);
+PACK *PackLoginWithPlainPassword(char *hubname, char *username, void *plain_password);
+PACK *PackLoginWithCert(char *hubname, char *username, X *x, void *sign, UINT sign_size);
+bool GetMethodFromPack(PACK *p, char *method, UINT size);
+bool GetHubnameAndUsernameFromPack(PACK *p, char *username, UINT username_size,
+ char *hubname, UINT hubname_size);
+PACK *PackAdditionalConnect(UCHAR *session_key);
+UINT GetAuthTypeFromPack(PACK *p);
+UINT GetProtocolFromPack(PACK *p);
+bool ParseWelcomeFromPack(PACK *p, char *session_name, UINT session_name_size,
+ char *connection_name, UINT connection_name_size,
+ POLICY **policy);
+
+
+bool ClientAdditionalConnect(CONNECTION *c, THREAD *t);
+SOCK *ClientAdditionalConnectToServer(CONNECTION *c);
+bool ClientUploadAuth2(CONNECTION *c, SOCK *s);
+bool GetSessionKeyFromPack(PACK *p, UCHAR *session_key, UINT *session_key_32);
+void GenerateRC4KeyPair(RC4_KEY_PAIR *k);
+
+SOCK *ProxyConnect(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, char *password, bool additional_connect);
+SOCK *ProxyConnectEx(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, char *password, bool additional_connect,
+ bool *cancel_flag, void *hWnd);
+SOCK *ProxyConnectEx2(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, char *password, bool additional_connect,
+ bool *cancel_flag, void *hWnd, UINT timeout);
+SOCK *SocksConnect(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, bool additional_connect);
+SOCK *SocksConnectEx(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, bool additional_connect,
+ bool *cancel_flag, void *hWnd);
+SOCK *SocksConnectEx2(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, bool additional_connect,
+ bool *cancel_flag, void *hWnd, UINT timeout);
+bool SocksSendRequestPacket(CONNECTION *c, SOCK *s, UINT dest_port, IP *dest_ip, char *userid);
+bool SocksRecvResponsePacket(CONNECTION *c, SOCK *s);
+void CreateNodeInfo(NODE_INFO *info, CONNECTION *c);
+UINT SecureSign(SECURE_SIGN *sign, UINT device_id, char *pin);
+void ClientUploadNoop(CONNECTION *c);
+bool ClientCheckServerCert(CONNECTION *c, bool *expired);
+void ClientCheckServerCertThread(THREAD *thread, void *param);
+bool ClientSecureSign(CONNECTION *c, UCHAR *sign, UCHAR *random, X **x);
+void ClientSecureSignThread(THREAD *thread, void *param);
+UINT SecureWrite(UINT device_id, char *cert_name, X *x, char *key_name, K *k, char *pin);
+UINT SecureEnum(UINT device_id, char *pin, TOKEN_LIST **cert_list, TOKEN_LIST **key_list);
+UINT SecureDelete(UINT device_id, char *pin, char *cert_name, char *key_name);
+TOKEN_LIST *EnumHub(SESSION *s);
+UINT ChangePasswordAccept(CONNECTION *c, PACK *p);
+UINT ChangePassword(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, char *username, char *old_pass, char *new_pass);
+void PackAddClientVersion(PACK *p, CONNECTION *c);
+void NodeInfoToStr(wchar_t *str, UINT size, NODE_INFO *info);
+void GenerateMachineUniqueHash(void *data);
+
+
+#endif // PROTOCOL_H
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Radius.c b/src/Cedar/Radius.c
new file mode 100644
index 00000000..24ac5751
--- /dev/null
+++ b/src/Cedar/Radius.c
@@ -0,0 +1,90 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Radius.c
+// Radius authentication module
+
+#include "CedarPch.h"
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Radius.h b/src/Cedar/Radius.h
new file mode 100644
index 00000000..681e2a56
--- /dev/null
+++ b/src/Cedar/Radius.h
@@ -0,0 +1,99 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Radius.h
+// Header of Radius.c
+
+#ifndef RADIUS_H
+#define RADIUS_H
+
+#define RADIUS_DEFAULT_PORT 1812 // The default port number
+#define RADIUS_RETRY_INTERVAL 500 // Retransmission interval
+#define RADIUS_RETRY_TIMEOUT (10 * 1000) // Time-out period
+
+
+#endif // RADIUS_H
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Remote.c b/src/Cedar/Remote.c
new file mode 100644
index 00000000..b8ab70b8
--- /dev/null
+++ b/src/Cedar/Remote.c
@@ -0,0 +1,448 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Remote.c
+// Remote Procedure Call
+
+#include "CedarPch.h"
+
+// End of RPC
+void EndRpc(RPC *rpc)
+{
+ RpcFree(rpc);
+}
+
+// Release the RPC
+void RpcFree(RPC *rpc)
+{
+ // Validate arguments
+ if (rpc == NULL)
+ {
+ return;
+ }
+
+ Disconnect(rpc->Sock);
+ ReleaseSock(rpc->Sock);
+
+ DeleteLock(rpc->Lock);
+
+ Free(rpc);
+}
+
+// Get error
+UINT RpcGetError(PACK *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return ERR_DISCONNECTED;
+ }
+
+ return PackGetInt(p, "error_code");
+}
+
+// Error checking
+bool RpcIsOk(PACK *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return false;
+ }
+
+ if (PackGetInt(p, "error") == 0)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// Error code setting
+void RpcError(PACK *p, UINT err)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "error", 1);
+ PackAddInt(p, "error_code", err);
+}
+
+// Start the RPC dispatcher
+PACK *CallRpcDispatcher(RPC *r, PACK *p)
+{
+ char func_name[MAX_SIZE];
+ // Validate arguments
+ if (r == NULL || p == NULL)
+ {
+ return NULL;
+ }
+
+ if (PackGetStr(p, "function_name", func_name, sizeof(func_name)) == false)
+ {
+ return NULL;
+ }
+
+ return r->Dispatch(r, func_name, p);
+}
+
+// Wait for the next RPC call
+bool RpcRecvNextCall(RPC *r)
+{
+ UINT size;
+ void *tmp;
+ SOCK *s;
+ BUF *b;
+ PACK *p;
+ PACK *ret;
+ // Validate arguments
+ if (r == NULL)
+ {
+ return false;
+ }
+
+ s = r->Sock;
+
+ if (RecvAll(s, &size, sizeof(UINT), s->SecureMode) == false)
+ {
+ return false;
+ }
+
+ size = Endian32(size);
+
+ if (size > MAX_PACK_SIZE)
+ {
+ return false;
+ }
+
+ tmp = MallocEx(size, true);
+
+ if (RecvAll(s, tmp, size, s->SecureMode) == false)
+ {
+ Free(tmp);
+ return false;
+ }
+
+ b = NewBuf();
+ WriteBuf(b, tmp, size);
+ SeekBuf(b, 0, 0);
+ Free(tmp);
+
+ p = BufToPack(b);
+ FreeBuf(b);
+
+ if (p == NULL)
+ {
+ return false;
+ }
+
+ ret = CallRpcDispatcher(r, p);
+ FreePack(p);
+
+ if (ret == NULL)
+ {
+ ret = PackError(ERR_NOT_SUPPORTED);
+ }
+
+ b = PackToBuf(ret);
+ FreePack(ret);
+
+ size = Endian32(b->Size);
+ SendAdd(s, &size, sizeof(UINT));
+ SendAdd(s, b->Buf, b->Size);
+
+ if (SendNow(s, s->SecureMode) == false)
+ {
+ FreeBuf(b);
+ return false;
+ }
+
+ FreeBuf(b);
+
+ return true;
+}
+
+// RPC server operation
+void RpcServer(RPC *r)
+{
+ SOCK *s;
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+ s = r->Sock;
+
+ while (true)
+ {
+ // Wait for the next RPC call
+ if (RpcRecvNextCall(r) == false)
+ {
+ // Communication error
+ break;
+ }
+ }
+}
+
+// RPC call
+PACK *RpcCall(RPC *r, char *function_name, PACK *p)
+{
+ PACK *ret;
+ UINT num_retry = 0;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || function_name == NULL)
+ {
+ return NULL;
+ }
+
+// Debug("RpcCall: %s\n", function_name);
+
+ Lock(r->Lock);
+ {
+ if (p == NULL)
+ {
+ p = NewPack();
+ }
+
+ PackAddStr(p, "function_name", function_name);
+
+RETRY:
+ err = 0;
+ ret = RpcCallInternal(r, p);
+
+ if (ret == NULL)
+ {
+ if (r->IsVpnServer && r->Sock != NULL)
+ {
+ if (num_retry < 1)
+ {
+ num_retry++;
+
+ // Attempt to reconnect the RPC to the VPN Server
+ err = AdminReconnect(r);
+
+ if (err == ERR_NO_ERROR)
+ {
+ goto RETRY;
+ }
+ }
+ }
+ }
+
+ FreePack(p);
+
+ if (ret == NULL)
+ {
+ if (err == 0)
+ {
+ err = ERR_DISCONNECTED;
+ }
+
+ ret = PackError(err);
+ PackAddInt(ret, "error_code", err);
+ }
+ }
+ Unlock(r->Lock);
+
+ return ret;
+}
+
+// RPC internal call
+PACK *RpcCallInternal(RPC *r, PACK *p)
+{
+ BUF *b;
+ UINT size;
+ PACK *ret;
+ void *tmp;
+ // Validate arguments
+ if (r == NULL || p == NULL)
+ {
+ return NULL;
+ }
+
+ if (r->Sock == NULL)
+ {
+ return NULL;
+ }
+
+ b = PackToBuf(p);
+
+ size = Endian32(b->Size);
+ SendAdd(r->Sock, &size, sizeof(UINT));
+ SendAdd(r->Sock, b->Buf, b->Size);
+ FreeBuf(b);
+
+ if (SendNow(r->Sock, r->Sock->SecureMode) == false)
+ {
+ return NULL;
+ }
+
+ if (RecvAll(r->Sock, &size, sizeof(UINT), r->Sock->SecureMode) == false)
+ {
+ return NULL;
+ }
+
+ size = Endian32(size);
+ if (size > MAX_PACK_SIZE)
+ {
+ return NULL;
+ }
+
+ tmp = MallocEx(size, true);
+ if (RecvAll(r->Sock, tmp, size, r->Sock->SecureMode) == false)
+ {
+ Free(tmp);
+ return NULL;
+ }
+
+ b = NewBuf();
+ WriteBuf(b, tmp, size);
+ SeekBuf(b, 0, 0);
+ Free(tmp);
+
+ ret = BufToPack(b);
+ if (ret == NULL)
+ {
+ FreeBuf(b);
+ return NULL;
+ }
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Start the RPC server
+RPC *StartRpcServer(SOCK *s, RPC_DISPATCHER *dispatch, void *param)
+{
+ RPC *r;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ r = ZeroMallocEx(sizeof(RPC), true);
+ r->Sock = s;
+ r->Param = param;
+ r->Lock = NewLock();
+ AddRef(s->ref);
+
+ r->ServerMode = true;
+ r->Dispatch = dispatch;
+
+ // Name generation
+ Format(r->Name, sizeof(r->Name), "RPC-%u", s->socket);
+
+ return r;
+}
+
+// Start the RPC client
+RPC *StartRpcClient(SOCK *s, void *param)
+{
+ RPC *r;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ r = ZeroMalloc(sizeof(RPC));
+ r->Sock = s;
+ r->Param = param;
+ r->Lock = NewLock();
+ AddRef(s->ref);
+
+ r->ServerMode = false;
+
+ return r;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Remote.h b/src/Cedar/Remote.h
new file mode 100644
index 00000000..2081e70b
--- /dev/null
+++ b/src/Cedar/Remote.h
@@ -0,0 +1,127 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Remote.h
+// Header of Remote.c
+
+#ifndef REMOTE_H
+#define REMOTE_H
+
+// RPC execution function
+typedef PACK *(RPC_DISPATCHER)(RPC *r, char *function_name, PACK *p);
+
+// RPC object
+struct RPC
+{
+ SOCK *Sock; // Socket
+ bool ServerMode; // Server mode
+ RPC_DISPATCHER *Dispatch; // Execution routine
+ void *Param; // Parameters
+ bool ServerAdminMode; // Server management mode
+ char HubName[MAX_HUBNAME_LEN + 1]; // Managing HUB name
+ char Name[MAX_SIZE]; // RPC session name
+ LOCK *Lock; // Lock
+ bool IsVpnServer; // Whether VPN Server management RPC
+ CLIENT_OPTION VpnServerClientOption;
+ char VpnServerHubName[MAX_HUBNAME_LEN + 1];
+ UCHAR VpnServerHashedPassword[SHA1_SIZE];
+ char VpnServerClientName[MAX_PATH];
+};
+
+// Function prototype
+RPC *StartRpcClient(SOCK *s, void *param);
+RPC *StartRpcServer(SOCK *s, RPC_DISPATCHER *dispatch, void *param);
+PACK *RpcCallInternal(RPC *r, PACK *p);
+PACK *RpcCall(RPC *r, char *function_name, PACK *p);
+void RpcServer(RPC *r);
+bool RpcRecvNextCall(RPC *r);
+PACK *CallRpcDispatcher(RPC *r, PACK *p);
+void RpcError(PACK *p, UINT err);
+bool RpcIsOk(PACK *p);
+UINT RpcGetError(PACK *p);
+void EndRpc(RPC *rpc);
+void RpcFree(RPC *rpc);
+
+#endif // REMOTE_H
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/SM.c b/src/Cedar/SM.c
new file mode 100644
index 00000000..1aba59e2
--- /dev/null
+++ b/src/Cedar/SM.c
@@ -0,0 +1,20505 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// SM.c
+// VPN Server Manager for Win32
+
+#include
+
+#ifdef WIN32
+
+#define SM_C
+#define CM_C
+#define NM_C
+
+#define _WIN32_WINNT 0x0502
+#define WINVER 0x0502
+#include
+#include
+#include
+#include
+#include
+#include
+#include