0
0
mirror of https://github.com/OpenVPN/openvpn.git synced 2024-09-19 11:32:28 +02:00

This is the start of the BETA21 branch.

It includes the --topology feature, and
TAP-Win32 driver changes to allow
non-admin access.



git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@580 e7ae566f-a301-0410-adde-c780ea21d3b5
This commit is contained in:
james 2005-09-26 05:28:27 +00:00
commit 6fbf66fad3
255 changed files with 77931 additions and 0 deletions

1
AUTHORS Normal file
View File

@ -0,0 +1 @@
James Yonan <jim@yonan.net>

215
COPYING Normal file
View File

@ -0,0 +1,215 @@
OpenVPN (TM) -- An Open Source VPN daemon
Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
This distribution contains multiple components, some
of which fall under different licenses. By using OpenVPN
or any of the bundled components enumerated below, you
agree to be bound by the conditions of the license for
each respective component.
OpenVPN trademark
-----------------
"OpenVPN" is a trademark of OpenVPN Solutions LLC.
OpenVPN license:
----------------
OpenVPN is distributed under the GPL license version 2 (see Below).
Special exception for linking OpenVPN with OpenSSL:
In addition, as a special exception, OpenVPN Solutions LLC gives
permission to link the code of this program with the OpenSSL
library (or with modified versions of OpenSSL that use the same
license as OpenSSL), and distribute linked combinations including
the two. You must obey the GNU General Public License in all
respects for all of the code used other than OpenSSL. If you modify
this file, you may extend this exception to your version of the
file, but you are not obligated to do so. If you do not wish to
do so, delete this exception statement from your version.
LZO license:
------------
LZO is Copyright (C) Markus F.X.J. Oberhumer,
and is licensed under the GPL.
Special exception for linking OpenVPN with both OpenSSL and LZO:
Hereby I grant a special exception to the OpenVPN project
(http://openvpn.net/) to link the LZO library with
the OpenSSL library (http://www.openssl.org).
Markus F.X.J. Oberhumer
TAP-Win32 Driver license:
-------------------------
The TAP-Win32 driver is derived from the CIPE-Win32
kernel driver, Copyright (C) Damion K. Wilson,
and is licensed under the GPL.
Windows DDK Samples:
--------------------
The Windows binary distribution includes devcon.exe, a
Microsoft DDK sample which is redistributed under the terms
of the DDK EULA.
NSIS License:
-------------
Copyright (C) 2002-2003 Joost Verburg
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 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 distribution.
OpenSSL License:
----------------
The OpenSSL toolkit stays under a dual license, i.e. both the conditions of
the OpenSSL License and the original SSLeay license apply to the toolkit.
See below for the actual license texts. Actually both licenses are BSD-style
Open Source licenses. In case of any license issues related to OpenSSL
please contact openssl-core@openssl.org.
/* ====================================================================
* Copyright (c) 1998-2003 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.]
*/
GNU Public License (GPL)
------------------------
OpenVPN, LZO, and the TAP-Win32 distributions are
licensed under the GPL version 2 (see COPYRIGHT.GPL).
In the Windows binary distribution of OpenVPN, the
GPL is reproduced below.

339
COPYRIGHT.GPL Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library General
Public License instead of this License.

2102
ChangeLog Normal file

File diff suppressed because it is too large Load Diff

284
INSTALL Normal file
View File

@ -0,0 +1,284 @@
Installation instructions for OpenVPN, a Secure Tunneling Daemon
Copyright (C) 2002-2005 OpenVPN Solutions LLC. 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.
*************************************************************************
To download OpenVPN, go to:
http://openvpn.net/download.html
For step-by-step installation instructions with real-world
examples see:
http://openvpn.net/howto.html
For examples see:
http://openvpn.net/examples.html
*************************************************************************
SUPPORTED PLATFORMS:
(1) Linux 2.2+
(2) Solaris
(3) OpenBSD 3.0+ (Comes with OpenSSL and TUN devices by default)
(4) Mac OS X Darwin
(5) FreeBSD
(6) NetBSD
(7) Windows (Win 2K and higher)
SUPPORTED PROCESSOR ARCHITECTURES:
In general, OpenVPN is word size and endian independent, so
most processors should be supported. Architectures known to
work include Intel x86, Alpha, Sparc, Amd64, and ARM.
REQUIRES:
(1) TUN and/or TAP driver to allow user-space programs to control
a virtual point-to-point IP or Ethernet device. See
TUN/TAP Driver Configuration section below for more info.
OPTIONAL (but recommended):
(1) OpenSSL library, necessary for encryption, version 0.9.5 or higher
required, available from http://www.openssl.org/
(2) LZO real-time compression library, required for link compression,
available from http://www.oberhumer.com/opensource/lzo/
OpenBSD users can use ports or packages to install lzo, but remember
to add "--with-lzo-headers" and "--with-lzo-lib" directives to
"configure", pointing to /usr/local/include and /usr/local/lib
respectively since gcc will not find them otherwise.
(3) Pthread library.
OPTIONAL (for developers only):
(1) Autoconf 2.50 or higher + Automake 1.5 or higher
-- available from http://www.gnu.org/software/software.html
(2) Dmalloc library
-- available from http://dmalloc.com/
*************************************************************************
BUILD COMMANDS FROM TARBALL:
./configure
make
make install
*************************************************************************
BUILD COMMANDS FROM CVS:
autoreconf -i -v
./configure
make
make install
*************************************************************************
BUILD A TARBALL FROM CVS:
autoreconf -i -v
./configure
make dist
*************************************************************************
LOOPBACK TESTS (after BUILD):
make check (Run all tests below)
Test Crypto:
./openvpn --genkey --secret key
./openvpn --test-crypto --secret key
Test SSL/TLS negotiations (runs for 2 minutes):
./openvpn --config sample-config-files/loopback-client (In one window)
./openvpn --config sample-config-files/loopback-server (Simultaneously in another window)
*************************************************************************
OPTIONS for ./configure:
--enable-pthread Compile pthread support for
improved latency during SSL/TLS key
negotiations (Linux or Solaris only)
--disable-lzo Do not compile LZO compression support
--disable-crypto Do not compile OpenSSL crypto support
--disable-ssl Do not compile OpenSSL SSL support for
TLS-based key exchange
--with-ssl-headers=DIR Crypto/SSL Include files location
--with-ssl-lib=DIR Crypto/SSL Library location
--with-lzo-headers=DIR LZO Include files location
--with-lzo-lib=DIR LZO Library location
--with-ifconfig-path=PATH Path to ifconfig tool (only need to
specify if in a non-standard location)
--with-leak-check=TYPE Build with memory leak checking
TYPE = dmalloc or ssl
--enable-strict Enable strict compiler warnings
--enable-strict-options Enable strict options check between peers
*************************************************************************
BUILDING ON LINUX 2.4+ FROM RPM
You can build a binary RPM directly from the OpenVPN tarball file:
rpmbuild -tb [tarball]
This command will build a binary RPM file and place it in the system
RPM directory. You can then install the RPM with the standard RPM
install command:
rpm -ivh [binary-rpm]
When you install the binary RPM, it will install
sample-scripts/openvpn.init, which can be used to
automatically start or stop one or more OpenVPN tunnels on system
startup or shutdown, based on OpenVPN .conf files in /etc/openvpn.
See the comments in openvpn.init for more information.
Installing the RPM will also configure the TUN/TAP device node
for linux 2.4.
Note that the current openvpn.spec file, which instructs the rpm tool
how to build a package, will build OpenVPN with all options enabled,
including OpenSSL, LZO, and pthread linkage. Therefore all of
these packages will need to be present prior to the RPM build, unless
you edit the openvpn.spec file.
*************************************************************************
TUN/TAP Driver Configuration:
* Linux 2.4 or higher (with integrated TUN/TAP driver):
(1) make device node: mknod /dev/net/tun c 10 200
(2a) add to /etc/modules.conf: alias char-major-10-200 tun
(2b) load driver: modprobe tun
(3) enable routing: echo 1 > /proc/sys/net/ipv4/ip_forward
Note that either of steps (2a) or (2b) is sufficient. While (2a)
only needs to be done once per install, (2b) needs to be done once
per reboot. If you install from RPM (see above) and use the
openvpn.init script, these steps are taken care of for you.
* Linux 2.2 or Solaris:
You should obtain
version 1.1 of the TUN/TAP driver from
http://vtun.sourceforge.net/tun/
and follow the installation instructions.
* Solaris
For 64 bit, I used the tun-1.1.tar.gz source and compiled it.
Of course there is a but :)
In the tun-1-1\solaris\Makefile I changed a line so it compiles with 64 bit
CFLAGS = $(DEFS) -m64 -O2 -Wall -D_KERNEL -I.
I just added -m64 and it worked.
The tun driver works fine as said previously, however we noticed there is a
minor problem when creating multiple tunnels on Solaris.
Mr Tycho Fruru changed the code in tun.c file where he locked the tun device
number to -1. This way it is impossible to specify the name of the tun device
but it is still possible to have multiple devices.
The modification will increment automatically meaning starting from tun0 --->
tunX I know you are not responsible for the tun coding but if you think the
modification can be useful for you feel free to use it.
http://openvpn.net/solaris/tun.c
* FreeBSD 4.1.1+:
FreeBSD ships with the TUN/TAP driver, and the device nodes for tap0,
tap1, tap2, tap3, tun0, tun1, tun2 and tun3 are made by default.
However, only the TUN driver is linked into the GENERIC kernel.
To load the TAP driver, enter:
kldload if_tap
See man rc(8) to find out how you can do this at boot time.
The easiest way is to install OpenVPN from the FreeBSD ports system,
the port includes a sample script to automatically load the TAP driver
at boot-up time.
* OpenBSD:
OpenBSD ships with tun0 and tun1 installed by default on pre-3.5 systems,
while 3.5 and later have dynamically created tun* devices so you only need
to create an empty /etc/hostname.tun0 (tun1, tun2 and so on) for each tun
you plan to use to create the device(s) at boot.
* Mac OS X:
2005.02.13: Angelo Laub has developed a GUI for OS X:
http://rechenknecht.net/OpenVPN-GUI/
2004.10.26: Mattias Nissler has developed a new TUN/TAP driver for
MAC OS X:
http://www-user.rhrk.uni-kl.de/~nissler/tuntap/
Christoph Pfisterer's old TUN driver can be obtained at
http://chrisp.de/en/projects/tunnel.html -- note that it
is no longer being maintained.
* Solaris9 Sparc/64
The kernel module for solaris
can be generated by adding the -m64 switch to a modern
gcc compiler (I'm using 3.2) The resulting kernel driver
needs to be manually copied to /kernel/drv/sparcv9/ and then a
reconfiguration reboot. (boot -r).
* Windows 2000 and XP
See INSTALL-win32.txt for more info
See the man page for more information, usage examples, and
information on firewall configuration.
*************************************************************************
CAVEATS & BUGS:
* I have noticed cases where TCP sessions tunneled over the Linux
TAP driver (kernel 2.4.21 and 2.4.22) stall when lower --mssfix
values are used. The TCP sessions appear to unstall and resume
normally when the remote VPN endpoint is pinged.
* If run through a firewall using OpenBSDs packet filter PF and the
filter rules include a "scrub" directive, you may get problems talking
to Linux hosts over the tunnel, since the scrubbing will kill packets
sent from Linux hosts if they are fragmented. This is usually seen as
tunnels where small packets and pings get through but large packets
and "regular traffic" don't. To circumvent this, add "no-df" to
the scrub directive so that the packet filter will let fragments with
the "dont fragment"-flag set through anyway.
* Mixing OFB or CFB cipher modes with static key mode is not recommended,
and is flagged as an error on OpenVPN versions 1.2.1 and greater.
If you use the --cipher option to explicitly select an OFB or CFB
cipher AND you are using static key mode, it is possible that there
could be an IV collision if the OpenVPN daemons on both sides
of the connection are started at exactly the same time, since
OpenVPN uses a timestamp combined with a sequence number as the cipher
IV for OFB and CFB modes. This is not an issue if you are
using CBC cipher mode (the default), or if you are using OFB or CFB
cipher mode with SSL/TLS authentication.

3
INSTALL-win32.txt Normal file
View File

@ -0,0 +1,3 @@
OpenVPN on Windows Notes can be found here:
http://openvpn.net/INSTALL-win32.html

128
Makefile.am Normal file
View File

@ -0,0 +1,128 @@
#
# OpenVPN -- An application to securely tunnel IP networks
# over a single UDP port, with support for SSL/TLS-based
# session authentication and key exchange,
# packet encryption, packet authentication, and
# packet compression.
#
# Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
#
# 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
# along with this program (see the file COPYING included with this
# distribution); if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# This option prevents autoreconf from overriding our COPYING and
# INSTALL targets:
AUTOMAKE_OPTIONS = foreign
sbin_PROGRAMS = openvpn
nodist_openvpn_SOURCES = config.h
TESTS = t_lpback.sh t_cltsrv.sh
dist_noinst_SCRIPTS = $(TESTS)
openvpn_SOURCES = \
base64.c base64.h \
basic.h \
buffer.c buffer.h \
circ_list.h \
common.h \
crypto.c crypto.h \
errlevel.h \
error.c error.h \
event.c event.h \
fdmisc.c fdmisc.h \
forward.c forward.h forward-inline.h \
fragment.c fragment.h \
gremlin.c gremlin.h \
helper.c helper.h \
init.c init.h \
integer.h \
interval.c interval.h \
list.c list.h \
lzo.c lzo.h \
manage.c manage.h \
mbuf.c mbuf.h \
memdbg.h \
misc.c misc.h \
mroute.c mroute.h \
mss.c mss.h \
mtcp.c mtcp.h \
mtu.c mtu.h \
mudp.c mudp.h \
multi.c multi.h \
ntlm.c ntlm.h \
occ.c occ.h occ-inline.h \
openvpn.c openvpn.h \
openvpn-plugin.h \
options.c options.h \
otime.c otime.h \
packet_id.c packet_id.h \
perf.c perf.h \
ping.c ping.h ping-inline.h \
plugin.c plugin.h \
pool.c pool.h \
proto.c proto.h \
proxy.c proxy.h \
push.c push.h \
reliable.c reliable.h \
route.c route.h \
schedule.c schedule.h \
session_id.c session_id.h \
shaper.c shaper.h \
sig.c sig.h \
socket.c socket.h \
socks.c socks.h \
ssl.c ssl.h \
status.c status.h \
syshead.h \
thread.c thread.h \
tun.c tun.h
LDADD = @LIBOBJS@
man_MANS = openvpn.8
EXTRA_DIST = \
doclean \
$(man_MANS) \
COPYRIGHT.GPL \
PORTS \
openvpn.spec \
easy-rsa \
sample-config-files \
sample-keys \
sample-scripts \
gentoo \
suse \
openvpn.spec.in \
config-win32.h \
win32.h \
win32.c \
cryptoapi.h \
cryptoapi.c \
makefile.w32 \
makefile.w32-vc \
INSTALL-win32.txt \
tap-win32 \
install-win32 \
service-win32 \
contrib \
debug \
plugin \
management
dist-hook:
cd $(distdir) && for i in $(EXTRA_DIST) ; do find $$i -name CVS -type d -prune -exec rm -r '{}' ';' ; rm -f `find $$i -type f | grep -E '(^|\/)\.?\#|\~$$|\.s?o$$'` ; done

0
NEWS Normal file
View File

94
PORTS Normal file
View File

@ -0,0 +1,94 @@
OpenVPN
Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
OpenVPN has been written to try to avoid features
that are not standardized well across different
OSes, so porting OpenVPN itself will probably be
straightforward if a tun or tap driver already exists.
Where special OS features are used, they are usually
bracketed with #ifdef HAVE_SOME_FUNCTION.
PLATFORM STATUS:
* Linux 2.2+ (supported)
* Solaris (supported)
* OpenBSD 3.0 (supported but pthreads are broken)
* Max OS X Darwin
* FreeBSD
* NetBSD
* Windows
* 64 bit platforms -- I have heard reports that
OpenVPN runs on Alpha Linux and FreeBSD.
* ARM -- I have heard of at least one case
where OpenVPN was successfully built and
run on the ARM architecture.
PORTING NOTES:
* Make sure that OpenSSL will build on your
platform.
* Make sure that a tun or tap virtual device
driver exists for your platform. See
http://vtun.sourceforge.net/tun/ for examples
of tun and tap drivers that have been written
for Linux, Solaris, and FreeBSD.
* Make sure you have autoconf 2.50+ and
automake 1.6+.
* Edit configure.ac, adding platform specific
config code, and a TARGET_YOUROS define.
* Add platform-specific includes to syshead.h.
* Add an #ifdef TARGET_YOUROS to the do_ifconfig()
function in tun.c to generate a correct "ifconfig"
command for your platform. Note that OpenVPN
determines the ifconfig path at ./configure time.
* Add an ifconfig_order() variant for your OS so
openvpn knows whether to call ifconfig before
or after tun/tap dev open.
* Add an #ifdef TARGET_YOUROS block in tun.c and define
the open_tun, close_tun, read_tun, and write_tun
functions. If your tun/tap virtual device is
sufficiently generic, you may be able to use the
default case.
* Add appropriate code to route.c to handle
the route command on your platform. This
is necessary for the --route option to
work correctly.
* After you successfully build OpenVPN, run
the loopback tests as described in INSTALL.
* For the next test, confirm that the UDP socket
functionality is working independently of the
tun device, by doing something like:
./openvpn --remote localhost --verb 9 --ping 1 --dev null
* Now try with --remote [a real host]
* Now try with a real tun/tap device, you will
need to figure out the appropriate ifconfig
command to use once openvpn has opened the tun/tap
device.
* Once you have simple tests working on the tun device,
try more complex tests such as using TLS mode.
* Stress test the link by doing ping -f across it.
* Make sure that packet fragmenting is happening
correctly by doing a ping -s 2000 or higher.
* Ensure that OpenVPN on your platform will talk
to OpenVPN on other platforms such as Linux.
Some tun/tap driver implementations will prepend
unnecessary stuff onto the datagram that must be
disabled with an explicit ioctl call if cross-platform
compatibility is to be preserved. You can see some
examples of this in tun.c.
* If your system supports pthreads, try building
with ./configure --enable-pthread and do a stress
test in TLS mode.
* Try the ultimate stress test which is --gremlin
--reneg-sec 10 in TLS mode (preferably with pthreads
enabled), then do a flood ping across the tunnel
(ping -f remote-endpoint) in both directions and let
it run overnight. --gremlin will induce massive
corruption and packet loss, but you win if you
wake up the next morning and both peers are still
running and occasionally even succeeding in their
attempted once-per-10-seconds TLS handshake.
* When it's working, submit your patch to
<openvpn-devel@lists.sourceforge.net>
and rejoice :)

75
README Normal file
View File

@ -0,0 +1,75 @@
OpenVPN -- A Secure tunneling daemon
Copyright (C) 2002-2005 OpenVPN Solutions LLC. 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.
*************************************************************************
For the latest version of OpenVPN, go to:
http://openvpn.net/
To Build and Install,
./configure
make
make install
or see the file INSTALL for more info.
*************************************************************************
For detailed information on OpenVPN, including examples, see the man page
http://openvpn.net/man.html
For a sample VPN configuration, see
http://openvpn.net/howto.html
For a description of OpenVPN's underlying protocol,
see the file ssl.h included in the source distribution.
*************************************************************************
Other Files & Directories:
* INSTALL-win32.txt -- installation instructions
for Windows
* configure.ac -- script to rebuild our configure
script and makefile.
* openvpn.spec -- RPM Spec file
To build an OpenVPN binary RPM, use the command:
rpmbuild -tb [tarball]
When you install the binary RPM, it will automatically
install sample-scripts/openvpn.init (see below)
* sample-scripts/openvpn.init
A sample init script for OpenVPN. See the file for
comments and additional information.
* sample-scripts/verify-cn
A sample perl script which can be used with OpenVPN's
--tls-verify option to provide a customized authentication
test on embedded X509 certificate fields.
* sample-keys/
Sample RSA keys and certificates. DON'T USE THESE FILES
FOR ANYTHING OTHER THAN TESTING BECAUSE THEY ARE TOTALLY INSECURE.
* sample-config-files/
A collection of OpenVPN config files and scripts from
the HOWTO at http://openvpn.net/howto.html
* easy-rsa/
A simple guide to RSA key management, scripts included.
Also see http://openvpn.net/easyrsa.html

346
acinclude.m4 Normal file
View File

@ -0,0 +1,346 @@
dnl Special Autoconf Macros for OpenVPN
dnl OPENVPN_ADD_LIBS(LIB)
AC_DEFUN([OPENVPN_ADD_LIBS], [
LIBS="$1 $LIBS"
])
dnl @synopsis AX_EMPTY_ARRAY
dnl
dnl Define EMPTY_ARRAY_SIZE to be either "0"
dnl or "" depending on which syntax the compiler
dnl prefers for empty arrays in structs.
dnl
dnl @version
dnl @author James Yonan <jim@yonan.net>
AC_DEFUN([AX_EMPTY_ARRAY], [
AC_MSG_RESULT([checking for C compiler empty array support])
AC_COMPILE_IFELSE(
[
struct { int foo; int bar[0]; } mystruct;
], [
AC_DEFINE_UNQUOTED(EMPTY_ARRAY_SIZE, 0, [Dimension to use for empty array declaration])
], [
AC_COMPILE_IFELSE(
[
struct { int foo; int bar[]; } mystruct;
], [
AC_DEFINE_UNQUOTED(EMPTY_ARRAY_SIZE,, [Dimension to use for empty array declaration])
], [
AC_MSG_ERROR([C compiler is unable to creaty empty arrays])
])
])
]
)
dnl @synopsis AX_CPP_VARARG_MACRO_GCC
dnl
dnl Test if the preprocessor understands GNU GCC-style vararg macros.
dnl If it does, defines HAVE_CPP_VARARG_MACRO_GCC to 1.
dnl
dnl @version
dnl @author James Yonan <jim@yonan.net>, Matthias Andree <matthias.andree@web.de>
AC_DEFUN([AX_CPP_VARARG_MACRO_GCC], [dnl
AS_VAR_PUSHDEF([VAR],[ax_cv_cpp_vararg_macro_gcc])dnl
AC_CACHE_CHECK([for GNU GCC vararg macro support], VAR, [dnl
AC_COMPILE_IFELSE([
#define macro(a, b...) func(a, b)
int func(int a, int b, int c);
int test() { return macro(1, 2, 3); }
], [ VAR=yes ], [VAR=no])])
if test $VAR = yes ; then
AC_DEFINE([HAVE_CPP_VARARG_MACRO_GCC], 1,
[Define to 1 if your compiler supports GNU GCC-style variadic macros])
fi
AS_VAR_POPDEF([VAR])dnl
])
dnl @synopsis AX_CPP_VARARG_MACRO_ISO
dnl
dnl Test if the preprocessor understands ISO C 1999 vararg macros.
dnl If it does, defines HAVE_CPP_VARARG_MACRO_ISO to 1.
dnl
dnl @version
dnl @author James Yonan <jim@yonan.net>, Matthias Andree <matthias.andree@web.de>
AC_DEFUN([AX_CPP_VARARG_MACRO_ISO], [dnl
AS_VAR_PUSHDEF([VAR],[ax_cv_cpp_vararg_macro_iso])dnl
AC_CACHE_CHECK([for ISO C 1999 vararg macro support], VAR, [dnl
AC_COMPILE_IFELSE([
#define macro(a, ...) func(a, __VA_ARGS__)
int func(int a, int b, int c);
int test() { return macro(1, 2, 3); }
], [ VAR=yes ], [VAR=no])])
if test $VAR = yes ; then
AC_DEFINE([HAVE_CPP_VARARG_MACRO_ISO], 1,
[Define to 1 if your compiler supports ISO C99 variadic macros])
fi
AS_VAR_POPDEF([VAR])dnl
])
dnl -- The following is taken from curl's acinclude.m4 --
dnl Check for socklen_t: historically on BSD it is an int, and in
dnl POSIX 1g it is a type of its own, but some platforms use different
dnl types for the argument to getsockopt, getpeername, etc. So we
dnl have to test to find something that will work.
AC_DEFUN([TYPE_SOCKLEN_T],
[
AC_CHECK_TYPE([socklen_t], ,[
AC_MSG_CHECKING([for socklen_t equivalent])
AC_CACHE_VAL([curl_cv_socklen_t_equiv],
[
# Systems have either "struct sockaddr *" or
# "void *" as the second argument to getpeername
curl_cv_socklen_t_equiv=
for arg2 in "struct sockaddr" void; do
for t in int size_t unsigned long "unsigned long"; do
AC_TRY_COMPILE([
#include <sys/types.h>
#include <sys/socket.h>
int getpeername (int, $arg2 *, $t *);
],[
$t len;
getpeername(0,0,&len);
],[
curl_cv_socklen_t_equiv="$t"
break
])
done
done
if test "x$curl_cv_socklen_t_equiv" = x; then
AC_MSG_ERROR([Cannot find a type to use in place of socklen_t])
fi
])
AC_MSG_RESULT($curl_cv_socklen_t_equiv)
AC_DEFINE_UNQUOTED(socklen_t, $curl_cv_socklen_t_equiv,
[type to use in place of socklen_t if not defined])],
[#include <sys/types.h>
#include <sys/socket.h>])
])
dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
dnl
dnl This macro figures out how to build C programs using POSIX
dnl threads. It sets the PTHREAD_LIBS output variable to the threads
dnl library and linker flags, and the PTHREAD_CFLAGS output variable
dnl to any special C compiler flags that are needed. (The user can also
dnl force certain compiler flags/libs to be tested by setting these
dnl environment variables.)
dnl
dnl Also sets PTHREAD_CC to any special C compiler that is needed for
dnl multi-threaded programs (defaults to the value of CC otherwise).
dnl (This is necessary on AIX to use the special cc_r compiler alias.)
dnl
dnl If you are only building threads programs, you may wish to
dnl use these variables in your default LIBS, CFLAGS, and CC:
dnl
dnl LIBS="$PTHREAD_LIBS $LIBS"
dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
dnl CC="$PTHREAD_CC"
dnl
dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE
dnl to that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
dnl
dnl ACTION-IF-FOUND is a list of shell commands to run if a threads
dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands
dnl to run it if it is not found. If ACTION-IF-FOUND is not specified,
dnl the default action will define HAVE_PTHREAD.
dnl
dnl Please let the authors know if this macro fails on any platform,
dnl or if you have any other suggestions or comments. This macro was
dnl based on work by SGJ on autoconf scripts for FFTW (www.fftw.org)
dnl (with help from M. Frigo), as well as ac_pthread and hb_pthread
dnl macros posted by AFC to the autoconf macro repository. We are also
dnl grateful for the helpful feedback of numerous users.
dnl
dnl @author Steven G. Johnson <stevenj@alum.mit.edu> and Alejandro Forero Cuervo <bachue@bachue.com>
AC_DEFUN([ACX_PTHREAD], [
AC_REQUIRE([AC_CANONICAL_HOST])
acx_pthread_ok=no
# We used to check for pthread.h first, but this fails if pthread.h
# requires special compiler flags (e.g. on True64 or Sequent).
# It gets checked for in the link test anyway.
# First of all, check if the user has set any of the PTHREAD_LIBS,
# etcetera environment variables, and if threads linking works using
# them:
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
AC_MSG_RESULT($acx_pthread_ok)
if test x"$acx_pthread_ok" = xno; then
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
fi
# We must check for the threads library under a number of different
# names; the ordering is very important because some systems
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
# libraries is broken (non-POSIX).
# Create a list of thread flags to try. Items starting with a "-" are
# C compiler flags, and other items are library names, except for "none"
# which indicates that we try without any flags at all.
acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt"
# The ordering *is* (sometimes) important. Some notes on the
# individual items follow:
# pthreads: AIX (must check this before -lpthread)
# none: in case threads are in libc; should be tried before -Kthread and
# other compiler flags to prevent continual compiler warnings
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
# -pthreads: Solaris/gcc
# -mthreads: Mingw32/gcc, Lynx/gcc
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
# doesn't hurt to check since this sometimes defines pthreads too;
# also defines -D_REENTRANT)
# pthread: Linux, etcetera
# --thread-safe: KAI C++
case "$target" in
*solaris*)
# On Solaris (at least, for some versions), libc contains stubbed
# (non-functional) versions of the pthreads routines, so link-based
# tests will erroneously succeed. (We need to link with -pthread or
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
# a function called by this macro, so we could check for that, but
# who knows whether they'll stub that too in a future libc.) So,
# we'll just look for -pthreads and -lpthread first:
acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags"
;;
esac
if test x"$acx_pthread_ok" = xno; then
for flag in $acx_pthread_flags; do
case $flag in
none)
AC_MSG_CHECKING([whether pthreads work without any flags])
;;
-*)
AC_MSG_CHECKING([whether pthreads work with $flag])
PTHREAD_CFLAGS="$flag"
;;
*)
AC_MSG_CHECKING([for the pthreads library -l$flag])
PTHREAD_LIBS="-l$flag"
;;
esac
save_LIBS="$LIBS"
save_CFLAGS="$CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Check for various functions. We must include pthread.h,
# since some functions may be macros. (On the Sequent, we
# need a special flag -Kthread to make this header compile.)
# We check for pthread_join because it is in -lpthread on IRIX
# while pthread_create is in libc. We check for pthread_attr_init
# due to DEC craziness with -lpthreads. We check for
# pthread_cleanup_push because it is one of the few pthread
# functions on Solaris that doesn't have a non-functional libc stub.
# We try pthread_create on general principles.
AC_TRY_LINK([#include <pthread.h>],
[pthread_t th; pthread_join(th, 0);
pthread_attr_init(0); pthread_cleanup_push(0, 0);
pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
[acx_pthread_ok=yes])
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
AC_MSG_RESULT($acx_pthread_ok)
if test "x$acx_pthread_ok" = xyes; then
break;
fi
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
done
fi
# Various other checks:
if test "x$acx_pthread_ok" = xyes; then
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Detect AIX lossage: threads are created detached by default
# and the JOINABLE attribute has a nonstandard name (UNDETACHED).
AC_MSG_CHECKING([for joinable pthread attribute])
AC_TRY_LINK([#include <pthread.h>],
[int attr=PTHREAD_CREATE_JOINABLE;],
ok=PTHREAD_CREATE_JOINABLE, ok=unknown)
if test x"$ok" = xunknown; then
AC_TRY_LINK([#include <pthread.h>],
[int attr=PTHREAD_CREATE_UNDETACHED;],
ok=PTHREAD_CREATE_UNDETACHED, ok=unknown)
fi
if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then
AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok,
[Define to the necessary symbol if this constant
uses a non-standard name on your system.])
fi
AC_MSG_RESULT(${ok})
if test x"$ok" = xunknown; then
AC_MSG_WARN([we do not know how to create joinable pthreads])
fi
AC_MSG_CHECKING([if more special flags are required for pthreads])
flag=no
case "$target" in
*-aix* | *-freebsd*) flag="-D_THREAD_SAFE";;
*solaris* | alpha*-osf* | *linux*) flag="-D_REENTRANT";;
esac
AC_MSG_RESULT(${flag})
if test "x$flag" != xno; then
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
# More AIX lossage: must compile with cc_r
AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC})
else
PTHREAD_CC="$CC"
fi
AC_SUBST(PTHREAD_LIBS)
AC_SUBST(PTHREAD_CFLAGS)
AC_SUBST(PTHREAD_CC)
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test x"$acx_pthread_ok" = xyes; then
ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
:
else
acx_pthread_ok=no
$2
fi
])dnl ACX_PTHREAD

146
base64.c Normal file
View File

@ -0,0 +1,146 @@
/*
* Copyright (c) 1995-2001 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
*/
#ifdef WIN32
#include "config-win32.h"
#else
#include "config.h"
#endif
#include "syshead.h"
#if NTLM
#include "base64.h"
#include "memdbg.h"
static char base64_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static int
pos(char c)
{
char *p;
for (p = base64_chars; *p; p++)
if (*p == c)
return p - base64_chars;
return -1;
}
int
base64_encode(const void *data, int size, char **str)
{
char *s, *p;
int i;
int c;
const unsigned char *q;
p = s = (char *) malloc(size * 4 / 3 + 4);
if (p == NULL)
return -1;
q = (const unsigned char *) data;
i = 0;
for (i = 0; i < size;) {
c = q[i++];
c *= 256;
if (i < size)
c += q[i];
i++;
c *= 256;
if (i < size)
c += q[i];
i++;
p[0] = base64_chars[(c & 0x00fc0000) >> 18];
p[1] = base64_chars[(c & 0x0003f000) >> 12];
p[2] = base64_chars[(c & 0x00000fc0) >> 6];
p[3] = base64_chars[(c & 0x0000003f) >> 0];
if (i > size)
p[3] = '=';
if (i > size + 1)
p[2] = '=';
p += 4;
}
*p = 0;
*str = s;
return strlen(s);
}
#define DECODE_ERROR 0xffffffff
static unsigned int
token_decode(const char *token)
{
int i;
unsigned int val = 0;
int marker = 0;
if (strlen(token) < 4)
return DECODE_ERROR;
for (i = 0; i < 4; i++) {
val *= 64;
if (token[i] == '=')
marker++;
else if (marker > 0)
return DECODE_ERROR;
else
val += pos(token[i]);
}
if (marker > 2)
return DECODE_ERROR;
return (marker << 24) | val;
}
int
base64_decode(const char *str, void *data)
{
const char *p;
unsigned char *q;
q = data;
for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) {
unsigned int val = token_decode(p);
unsigned int marker = (val >> 24) & 0xff;
if (val == DECODE_ERROR)
return -1;
*q++ = (val >> 16) & 0xff;
if (marker < 2)
*q++ = (val >> 8) & 0xff;
if (marker < 1)
*q++ = val & 0xff;
}
return q - (unsigned char *) data;
}
#else
static void dummy(void) {}
#endif

46
base64.h Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
*/
/* $KTH: base64.h,v 1.2 1999/12/02 16:58:45 joda Exp $ */
#ifndef _BASE64_H_
#define _BASE64_H_
#if NTLM
int base64_encode(const void *data, int size, char **str);
int base64_decode(const char *str, void *data);
#endif
#endif

41
basic.h Normal file
View File

@ -0,0 +1,41 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef BASIC_H
#define BASIC_H
/* bool definitions */
#define bool int
#define true 1
#define false 0
#define BOOL_CAST(x) ((x) ? (true) : (false))
/* size of an array */
#define SIZE(x) (sizeof(x)/sizeof(x[0]))
/* clear an object */
#define CLEAR(x) memset(&(x), 0, sizeof(x))
#endif

743
buffer.c Normal file
View File

@ -0,0 +1,743 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef WIN32
#include "config-win32.h"
#else
#include "config.h"
#endif
#include "syshead.h"
#include "common.h"
#include "buffer.h"
#include "error.h"
#include "mtu.h"
#include "thread.h"
#include "memdbg.h"
struct buffer
#ifdef DMALLOC
alloc_buf_debug (size_t size, const char *file, int line)
#else
alloc_buf (size_t size)
#endif
{
#ifdef DMALLOC
return alloc_buf_gc_debug (size, NULL, file, line);
#else
return alloc_buf_gc (size, NULL);
#endif
}
struct buffer
#ifdef DMALLOC
alloc_buf_gc_debug (size_t size, struct gc_arena *gc, const char *file, int line)
#else
alloc_buf_gc (size_t size, struct gc_arena *gc)
#endif
{
struct buffer buf;
buf.capacity = (int)size;
buf.offset = 0;
buf.len = 0;
#ifdef DMALLOC
buf.data = (uint8_t *) gc_malloc_debug (size, false, gc, file, line);
#else
buf.data = (uint8_t *) gc_malloc (size, false, gc);
#endif
if (size)
*buf.data = 0;
return buf;
}
struct buffer
#ifdef DMALLOC
clone_buf_debug (const struct buffer* buf, const char *file, int line)
#else
clone_buf (const struct buffer* buf)
#endif
{
struct buffer ret;
ret.capacity = buf->capacity;
ret.offset = buf->offset;
ret.len = buf->len;
#ifdef DMALLOC
ret.data = (uint8_t *) openvpn_dmalloc (file, line, buf->capacity);
#else
ret.data = (uint8_t *) malloc (buf->capacity);
#endif
check_malloc_return (ret.data);
memcpy (BPTR (&ret), BPTR (buf), BLEN (buf));
return ret;
}
#ifdef BUF_INIT_TRACKING
bool
buf_init_debug (struct buffer *buf, int offset, const char *file, int line)
{
buf->debug_file = file;
buf->debug_line = line;
return buf_init_dowork (buf, offset);
}
static inline int
buf_debug_line (const struct buffer *buf)
{
return buf->debug_line;
}
static const char *
buf_debug_file (const struct buffer *buf)
{
return buf->debug_file;
}
#else
#define buf_debug_line(buf) 0
#define buf_debug_file(buf) "[UNDEF]"
#endif
void
buf_clear (struct buffer *buf)
{
if (buf->capacity > 0)
memset (buf->data, 0, buf->capacity);
buf->len = 0;
buf->offset = 0;
}
bool
buf_assign (struct buffer *dest, const struct buffer *src)
{
if (!buf_init (dest, src->offset))
return false;
return buf_write (dest, BPTR (src), BLEN (src));
}
struct buffer
clear_buf ()
{
struct buffer buf;
CLEAR (buf);
return buf;
}
void
free_buf (struct buffer *buf)
{
if (buf->data)
free (buf->data);
CLEAR (*buf);
}
/*
* Return a buffer for write that is a subset of another buffer
*/
struct buffer
buf_sub (struct buffer *buf, int size, bool prepend)
{
struct buffer ret;
uint8_t *data;
CLEAR (ret);
data = prepend ? buf_prepend (buf, size) : buf_write_alloc (buf, size);
if (data)
{
ret.capacity = size;
ret.data = data;
}
return ret;
}
/*
* printf append to a buffer with overflow check
*/
void
buf_printf (struct buffer *buf, const char *format, ...)
{
if (buf_defined (buf))
{
va_list arglist;
uint8_t *ptr = BEND (buf);
int cap = buf_forward_capacity (buf);
if (cap > 0)
{
va_start (arglist, format);
vsnprintf ((char *)ptr, cap, format, arglist);
va_end (arglist);
*(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */
buf->len += (int) strlen ((char *)ptr);
}
}
}
/*
* This is necessary due to certain buggy implementations of snprintf,
* that don't guarantee null termination for size > 0.
*/
int openvpn_snprintf(char *str, size_t size, const char *format, ...)
{
va_list arglist;
int ret = 0;
if (size > 0)
{
va_start (arglist, format);
ret = vsnprintf (str, size, format, arglist);
va_end (arglist);
str[size - 1] = 0;
}
return ret;
}
/*
* write a string to the end of a buffer that was
* truncated by buf_printf
*/
void
buf_catrunc (struct buffer *buf, const char *str)
{
if (buf_forward_capacity (buf) <= 1)
{
int len = (int) strlen (str) + 1;
if (len < buf_forward_capacity_total (buf))
{
strncpynt ((char *)(buf->data + buf->capacity - len), str, len);
}
}
}
/*
* convert a multi-line output to one line
*/
void
convert_to_one_line (struct buffer *buf)
{
uint8_t *cp = BPTR(buf);
int len = BLEN(buf);
while (len--)
{
if (*cp == '\n')
*cp = '|';
++cp;
}
}
/* NOTE: requires that string be null terminated */
void
buf_write_string_file (const struct buffer *buf, const char *filename, int fd)
{
const int len = strlen ((char *) BPTR (buf));
const int size = write (fd, BPTR (buf), len);
if (size != len)
msg (M_ERR, "Write error on file '%s'", filename);
}
/*
* Garbage collection
*/
void *
#ifdef DMALLOC
gc_malloc_debug (size_t size, bool clear, struct gc_arena *a, const char *file, int line)
#else
gc_malloc (size_t size, bool clear, struct gc_arena *a)
#endif
{
void *ret;
if (a)
{
struct gc_entry *e;
#ifdef DMALLOC
e = (struct gc_entry *) openvpn_dmalloc (file, line, size + sizeof (struct gc_entry));
#else
e = (struct gc_entry *) malloc (size + sizeof (struct gc_entry));
#endif
check_malloc_return (e);
ret = (char *) e + sizeof (struct gc_entry);
/*mutex_lock_static (L_GC_MALLOC);*/
e->next = a->list;
a->list = e;
/*mutex_unlock_static (L_GC_MALLOC);*/
}
else
{
#ifdef DMALLOC
ret = openvpn_dmalloc (file, line, size);
#else
ret = malloc (size);
#endif
check_malloc_return (ret);
}
#ifndef ZERO_BUFFER_ON_ALLOC
if (clear)
#endif
memset (ret, 0, size);
return ret;
}
void
x_gc_free (struct gc_arena *a)
{
struct gc_entry *e;
/*mutex_lock_static (L_GC_MALLOC);*/
e = a->list;
a->list = NULL;
/*mutex_unlock_static (L_GC_MALLOC);*/
while (e != NULL)
{
struct gc_entry *next = e->next;
free (e);
e = next;
}
}
/*
* Hex dump -- Output a binary buffer to a hex string and return it.
*/
char *
format_hex_ex (const uint8_t *data, int size, int maxoutput,
int space_break, const char* separator,
struct gc_arena *gc)
{
struct buffer out = alloc_buf_gc (maxoutput ? maxoutput :
((size * 2) + (size / space_break) * (int) strlen (separator) + 2),
gc);
int i;
for (i = 0; i < size; ++i)
{
if (separator && i && !(i % space_break))
buf_printf (&out, "%s", separator);
buf_printf (&out, "%02x", data[i]);
}
buf_catrunc (&out, "[more...]");
return (char *)out.data;
}
/*
* remove specific trailing character
*/
void
buf_rmtail (struct buffer *buf, uint8_t remove)
{
uint8_t *cp = BLAST(buf);
if (cp && *cp == remove)
{
*cp = '\0';
--buf->len;
}
}
/*
* force a null termination even it requires
* truncation of the last char.
*/
void
buf_null_terminate (struct buffer *buf)
{
char *last = (char *) BLAST (buf);
if (last && *last == '\0') /* already terminated? */
return;
if (!buf_safe (buf, 1)) /* make space for trailing null */
buf_inc_len (buf, -1);
buf_write_u8 (buf, 0);
}
/*
* Remove trailing \r and \n chars and ensure
* null termination.
*/
void
buf_chomp (struct buffer *buf)
{
while (true)
{
char *last = (char *) BLAST (buf);
if (!last)
break;
if (char_class (*last, CC_CRLF|CC_NULL))
{
if (!buf_inc_len (buf, -1))
break;
}
else
break;
}
buf_null_terminate (buf);
}
/*
* like buf_null_terminate, but operate on strings
*/
void
string_null_terminate (char *str, int len, int capacity)
{
ASSERT (len >= 0 && len <= capacity && capacity > 0);
if (len < capacity)
*(str + len) = '\0';
else if (len == capacity)
*(str + len - 1) = '\0';
}
/*
* Remove trailing \r and \n chars.
*/
void
chomp (char *str)
{
bool modified;
do {
const int len = strlen (str);
modified = false;
if (len > 0)
{
char *cp = str + (len - 1);
if (*cp == '\n' || *cp == '\r')
{
*cp = '\0';
modified = true;
}
}
} while (modified);
}
/*
* Allocate a string
*/
char *
#ifdef DMALLOC
string_alloc_debug (const char *str, struct gc_arena *gc, const char *file, int line)
#else
string_alloc (const char *str, struct gc_arena *gc)
#endif
{
if (str)
{
const int n = strlen (str) + 1;
char *ret;
#ifdef DMALLOC
ret = (char *) gc_malloc_debug (n, false, gc, file, line);
#else
ret = (char *) gc_malloc (n, false, gc);
#endif
memcpy (ret, str, n);
return ret;
}
else
return NULL;
}
/*
* Allocate a string inside a buffer
*/
struct buffer
#ifdef DMALLOC
string_alloc_buf_debug (const char *str, struct gc_arena *gc, const char *file, int line)
#else
string_alloc_buf (const char *str, struct gc_arena *gc)
#endif
{
struct buffer buf;
ASSERT (str);
#ifdef DMALLOC
buf_set_read (&buf, (uint8_t*) string_alloc_debug (str, gc, file, line), strlen (str) + 1);
#else
buf_set_read (&buf, (uint8_t*) string_alloc (str, gc), strlen (str) + 1);
#endif
if (buf.len > 0) /* Don't count trailing '\0' as part of length */
--buf.len;
return buf;
}
/*
* String comparison
*/
bool
buf_string_match_head_str (const struct buffer *src, const char *match)
{
const int size = strlen (match);
if (size < 0 || size > src->len)
return false;
return memcmp (BPTR (src), match, size) == 0;
}
bool
buf_string_compare_advance (struct buffer *src, const char *match)
{
if (buf_string_match_head_str (src, match))
{
buf_advance (src, strlen (match));
return true;
}
else
return false;
}
int
buf_substring_len (const struct buffer *buf, int delim)
{
int i = 0;
struct buffer tmp = *buf;
int c;
while ((c = buf_read_u8 (&tmp)) >= 0)
{
++i;
if (c == delim)
return i;
}
return -1;
}
/*
* String parsing
*/
bool
buf_parse (struct buffer *buf, const int delim, char *line, const int size)
{
bool eol = false;
int n = 0;
int c;
ASSERT (size > 0);
do
{
c = buf_read_u8 (buf);
if (c < 0)
eol = true;
if (c <= 0 || c == delim)
c = 0;
if (n >= size)
break;
line[n++] = c;
}
while (c);
line[size-1] = '\0';
return !(eol && !strlen (line));
}
/*
* Classify and mutate strings based on character types.
*/
bool
char_class (const char c, const unsigned int flags)
{
if (!flags)
return false;
if (flags & CC_ANY)
return true;
if ((flags & CC_NULL) && c == '\0')
return true;
if ((flags & CC_ALNUM) && isalnum (c))
return true;
if ((flags & CC_ALPHA) && isalpha (c))
return true;
if ((flags & CC_ASCII) && isascii (c))
return true;
if ((flags & CC_CNTRL) && iscntrl (c))
return true;
if ((flags & CC_DIGIT) && isdigit (c))
return true;
if ((flags & CC_PRINT) && isprint (c))
return true;
if ((flags & CC_PUNCT) && ispunct (c))
return true;
if ((flags & CC_SPACE) && isspace (c))
return true;
if ((flags & CC_XDIGIT) && isxdigit (c))
return true;
if ((flags & CC_BLANK) && (c == ' ' || c == '\t'))
return true;
if ((flags & CC_NEWLINE) && c == '\n')
return true;
if ((flags & CC_CR) && c == '\r')
return true;
if ((flags & CC_BACKSLASH) && c == '\\')
return true;
if ((flags & CC_UNDERBAR) && c == '_')
return true;
if ((flags & CC_DASH) && c == '-')
return true;
if ((flags & CC_DOT) && c == '.')
return true;
if ((flags & CC_COMMA) && c == ',')
return true;
if ((flags & CC_COLON) && c == ':')
return true;
if ((flags & CC_SLASH) && c == '/')
return true;
if ((flags & CC_SINGLE_QUOTE) && c == '\'')
return true;
if ((flags & CC_DOUBLE_QUOTE) && c == '\"')
return true;
if ((flags & CC_REVERSE_QUOTE) && c == '`')
return true;
if ((flags & CC_AT) && c == '@')
return true;
if ((flags & CC_EQUAL) && c == '=')
return true;
return false;
}
static inline bool
char_inc_exc (const char c, const unsigned int inclusive, const unsigned int exclusive)
{
return char_class (c, inclusive) && !char_class (c, exclusive);
}
bool
string_class (const char *str, const unsigned int inclusive, const unsigned int exclusive)
{
char c;
ASSERT (str);
while ((c = *str++))
{
if (!char_inc_exc (c, inclusive, exclusive))
return false;
}
return true;
}
/*
* Modify string in place.
* Guaranteed to not increase string length.
*/
bool
string_mod (char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace)
{
const char *in = str;
bool ret = true;
ASSERT (str);
while (true)
{
char c = *in++;
if (c)
{
if (!char_inc_exc (c, inclusive, exclusive))
{
c = replace;
ret = false;
}
if (c)
*str++ = c;
}
else
{
*str = '\0';
break;
}
}
return ret;
}
const char *
string_mod_const (const char *str,
const unsigned int inclusive,
const unsigned int exclusive,
const char replace,
struct gc_arena *gc)
{
if (str)
{
char *buf = string_alloc (str, gc);
string_mod (buf, inclusive, exclusive, replace);
return buf;
}
else
return NULL;
}
#ifdef CHARACTER_CLASS_DEBUG
#define CC_INCLUDE (CC_PRINT)
#define CC_EXCLUDE (0)
#define CC_REPLACE ('.')
void
character_class_debug (void)
{
char buf[256];
while (fgets (buf, sizeof (buf), stdin) != NULL)
{
string_mod (buf, CC_INCLUDE, CC_EXCLUDE, CC_REPLACE);
printf ("%s", buf);
}
}
#endif
#ifdef VERIFY_ALIGNMENT
void
valign4 (const struct buffer *buf, const char *file, const int line)
{
if (buf && buf->len)
{
int msglevel = D_ALIGN_DEBUG;
const unsigned int u = (unsigned int) BPTR (buf);
if (u & (PAYLOAD_ALIGN-1))
msglevel = D_ALIGN_ERRORS;
msg (msglevel, "%sAlignment at %s/%d ptr=" ptr_format " OLC=%d/%d/%d I=%s/%d",
(msglevel == D_ALIGN_ERRORS) ? "ERROR: " : "",
file,
line,
(ptr_type)buf->data,
buf->offset,
buf->len,
buf->capacity,
buf_debug_file (buf),
buf_debug_line (buf));
}
}
#endif

712
buffer.h Normal file
View File

@ -0,0 +1,712 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef BUFFER_H
#define BUFFER_H
#include "basic.h"
#include "thread.h"
/*
* Define verify_align function, otherwise
* it will be a noop.
*/
/* #define VERIFY_ALIGNMENT */
/*
* Keep track of source file/line of buf_init calls
*/
#ifdef VERIFY_ALIGNMENT
#define BUF_INIT_TRACKING
#endif
/* basic buffer class for OpenVPN */
struct buffer
{
int capacity; /* size of buffer allocated by malloc */
int offset; /* data starts at data + offset, offset > 0 to allow for efficient prepending */
int len; /* length of data that starts at data + offset */
uint8_t *data;
#ifdef BUF_INIT_TRACKING
const char *debug_file;
int debug_line;
#endif
};
/* for garbage collection */
struct gc_entry
{
struct gc_entry *next;
};
struct gc_arena
{
struct gc_entry *list;
};
#define BPTR(buf) ((buf)->data + (buf)->offset)
#define BEND(buf) (BPTR(buf) + (buf)->len)
#define BLAST(buf) (((buf)->data && (buf)->len) ? (BPTR(buf) + (buf)->len - 1) : NULL)
#define BLEN(buf) ((buf)->len)
#define BDEF(buf) ((buf)->data != NULL)
#define BSTR(buf) ((char *)BPTR(buf))
#define BCAP(buf) (buf_forward_capacity (buf))
void buf_clear (struct buffer *buf);
struct buffer clear_buf (void);
void free_buf (struct buffer *buf);
bool buf_assign (struct buffer *dest, const struct buffer *src);
/* for dmalloc debugging */
#ifdef DMALLOC
#define alloc_buf(size) alloc_buf_debug (size, __FILE__, __LINE__)
#define alloc_buf_gc(size, gc) alloc_buf_gc_debug (size, gc, __FILE__, __LINE__);
#define clone_buf(buf) clone_buf_debug (buf, __FILE__, __LINE__);
#define gc_malloc(size, clear, arena) gc_malloc_debug (size, clear, arena, __FILE__, __LINE__)
#define string_alloc(str, gc) string_alloc_debug (str, gc, __FILE__, __LINE__)
#define string_alloc_buf(str, gc) string_alloc_buf_debug (str, gc, __FILE__, __LINE__)
struct buffer alloc_buf_debug (size_t size, const char *file, int line);
struct buffer alloc_buf_gc_debug (size_t size, struct gc_arena *gc, const char *file, int line);
struct buffer clone_buf_debug (const struct buffer* buf, const char *file, int line);
void *gc_malloc_debug (size_t size, bool clear, struct gc_arena *a, const char *file, int line);
char *string_alloc_debug (const char *str, struct gc_arena *gc, const char *file, int line);
struct buffer string_alloc_buf_debug (const char *str, struct gc_arena *gc, const char *file, int line);
#else
struct buffer alloc_buf (size_t size);
struct buffer alloc_buf_gc (size_t size, struct gc_arena *gc); /* allocate buffer with garbage collection */
struct buffer clone_buf (const struct buffer* buf);
void *gc_malloc (size_t size, bool clear, struct gc_arena *a);
char *string_alloc (const char *str, struct gc_arena *gc);
struct buffer string_alloc_buf (const char *str, struct gc_arena *gc);
#endif
#ifdef BUF_INIT_TRACKING
#define buf_init(buf, offset) buf_init_debug (buf, offset, __FILE__, __LINE__)
bool buf_init_debug (struct buffer *buf, int offset, const char *file, int line);
#else
#define buf_init(buf, offset) buf_init_dowork (buf, offset)
#endif
/* inline functions */
static inline void
buf_reset (struct buffer *buf)
{
buf->capacity = 0;
buf->offset = 0;
buf->len = 0;
buf->data = NULL;
}
static inline bool
buf_init_dowork (struct buffer *buf, int offset)
{
if (offset < 0 || offset > buf->capacity || buf->data == NULL)
return false;
buf->len = 0;
buf->offset = offset;
return true;
}
static inline bool
buf_defined (struct buffer *buf)
{
return buf->data != NULL;
}
static inline void
buf_set_write (struct buffer *buf, uint8_t *data, int size)
{
buf->len = 0;
buf->offset = 0;
buf->capacity = size;
buf->data = data;
if (size > 0 && data)
*data = 0;
}
static inline void
buf_set_read (struct buffer *buf, const uint8_t *data, int size)
{
buf->len = buf->capacity = size;
buf->offset = 0;
buf->data = (uint8_t *)data;
}
/* Like strncpy but makes sure dest is always null terminated */
static inline void
strncpynt (char *dest, const char *src, size_t maxlen)
{
strncpy (dest, src, maxlen);
if (maxlen > 0)
dest[maxlen - 1] = 0;
}
/* return true if string contains at least one numerical digit */
static inline bool
has_digit (const char* src)
{
char c;
while ((c = *src++))
{
if (isdigit(c))
return true;
}
return false;
}
/*
* printf append to a buffer with overflow check
*/
void buf_printf (struct buffer *buf, const char *format, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 2, 3)))
#endif
;
/*
* Like snprintf but guarantees null termination for size > 0
*/
int openvpn_snprintf(char *str, size_t size, const char *format, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 3, 4)))
#endif
;
/*
* remove/add trailing characters
*/
void buf_null_terminate (struct buffer *buf);
void buf_chomp (struct buffer *buf);
void buf_rmtail (struct buffer *buf, uint8_t remove);
/*
* non-buffer string functions
*/
void chomp (char *str);
void string_null_terminate (char *str, int len, int capacity);
/*
* Write string in buf to file descriptor fd.
* NOTE: requires that string be null terminated.
*/
void buf_write_string_file (const struct buffer *buf, const char *filename, int fd);
/*
* write a string to the end of a buffer that was
* truncated by buf_printf
*/
void buf_catrunc (struct buffer *buf, const char *str);
/*
* convert a multi-line output to one line
*/
void convert_to_one_line (struct buffer *buf);
/*
* Parse a string based on a given delimiter char
*/
bool buf_parse (struct buffer *buf, const int delim, char *line, const int size);
/*
* Hex dump -- Output a binary buffer to a hex string and return it.
*/
char *
format_hex_ex (const uint8_t *data, int size, int maxoutput,
int space_break, const char* separator,
struct gc_arena *gc);
static inline char *
format_hex (const uint8_t *data, int size, int maxoutput, struct gc_arena *gc)
{
return format_hex_ex (data, size, maxoutput, 4, " ", gc);
}
/*
* Return a buffer that is a subset of another buffer.
*/
struct buffer buf_sub (struct buffer *buf, int size, bool prepend);
/*
* Check if sufficient space to append to buffer.
*/
static inline bool
buf_safe (const struct buffer *buf, int len)
{
return len >= 0 && buf->offset + buf->len + len <= buf->capacity;
}
static inline bool
buf_safe_bidir (const struct buffer *buf, int len)
{
const int newlen = buf->len + len;
return newlen >= 0 && buf->offset + newlen <= buf->capacity;
}
static inline int
buf_forward_capacity (const struct buffer *buf)
{
int ret = buf->capacity - (buf->offset + buf->len);
if (ret < 0)
ret = 0;
return ret;
}
static inline int
buf_forward_capacity_total (const struct buffer *buf)
{
int ret = buf->capacity - buf->offset;
if (ret < 0)
ret = 0;
return ret;
}
static inline int
buf_reverse_capacity (const struct buffer *buf)
{
return buf->offset;
}
static inline bool
buf_inc_len (struct buffer *buf, int inc)
{
if (!buf_safe_bidir (buf, inc))
return false;
buf->len += inc;
return true;
}
/*
* Make space to prepend to a buffer.
* Return NULL if no space.
*/
static inline uint8_t *
buf_prepend (struct buffer *buf, int size)
{
if (size < 0 || size > buf->offset)
return NULL;
buf->offset -= size;
buf->len += size;
return BPTR (buf);
}
static inline bool
buf_advance (struct buffer *buf, int size)
{
if (size < 0 || buf->len < size)
return false;
buf->offset += size;
buf->len -= size;
return true;
}
/*
* Return a pointer to allocated space inside a buffer.
* Return NULL if no space.
*/
static inline uint8_t *
buf_write_alloc (struct buffer *buf, int size)
{
uint8_t *ret;
if (!buf_safe (buf, size))
return NULL;
ret = BPTR (buf) + buf->len;
buf->len += size;
return ret;
}
static inline uint8_t *
buf_write_alloc_prepend (struct buffer *buf, int size, bool prepend)
{
return prepend ? buf_prepend (buf, size) : buf_write_alloc (buf, size);
}
static inline uint8_t *
buf_read_alloc (struct buffer *buf, int size)
{
uint8_t *ret;
if (size < 0 || buf->len < size)
return NULL;
ret = BPTR (buf);
buf->offset += size;
buf->len -= size;
return ret;
}
static inline bool
buf_write (struct buffer *dest, const void *src, int size)
{
uint8_t *cp = buf_write_alloc (dest, size);
if (!cp)
return false;
memcpy (cp, src, size);
return true;
}
static inline bool
buf_write_prepend (struct buffer *dest, const void *src, int size)
{
uint8_t *cp = buf_prepend (dest, size);
if (!cp)
return false;
memcpy (cp, src, size);
return true;
}
static inline bool
buf_write_u8 (struct buffer *dest, int data)
{
uint8_t u8 = (uint8_t) data;
return buf_write (dest, &u8, sizeof (uint8_t));
}
static inline bool
buf_write_u16 (struct buffer *dest, int data)
{
uint16_t u16 = htons ((uint16_t) data);
return buf_write (dest, &u16, sizeof (uint16_t));
}
static inline bool
buf_write_u32 (struct buffer *dest, int data)
{
uint32_t u32 = htonl ((uint32_t) data);
return buf_write (dest, &u32, sizeof (uint32_t));
}
static inline bool
buf_copy (struct buffer *dest, const struct buffer *src)
{
return buf_write (dest, BPTR (src), BLEN (src));
}
static inline bool
buf_copy_n (struct buffer *dest, struct buffer *src, int n)
{
uint8_t *cp = buf_read_alloc (src, n);
if (!cp)
return false;
return buf_write (dest, cp, n);
}
static inline bool
buf_copy_range (struct buffer *dest,
int dest_index,
const struct buffer *src,
int src_index,
int src_len)
{
if (src_index < 0
|| src_len < 0
|| src_index + src_len > src->len
|| dest_index < 0
|| dest->offset + dest_index + src_len > dest->capacity)
return false;
memcpy (dest->data + dest->offset + dest_index, src->data + src->offset + src_index, src_len);
if (dest_index + src_len > dest->len)
dest->len = dest_index + src_len;
return true;
}
/* truncate src to len, copy excess data beyond len to dest */
static inline bool
buf_copy_excess (struct buffer *dest,
struct buffer *src,
int len)
{
if (len < 0)
return false;
if (src->len > len)
{
struct buffer b = *src;
src->len = len;
if (!buf_advance (&b, len))
return false;
return buf_copy (dest, &b);
}
else
{
return true;
}
}
static inline bool
buf_read (struct buffer *src, void *dest, int size)
{
uint8_t *cp = buf_read_alloc (src, size);
if (!cp)
return false;
memcpy (dest, cp, size);
return true;
}
static inline int
buf_read_u8 (struct buffer *buf)
{
int ret;
if (BLEN (buf) < 1)
return -1;
ret = *BPTR(buf);
buf_advance (buf, 1);
return ret;
}
static inline int
buf_read_u16 (struct buffer *buf)
{
uint16_t ret;
if (!buf_read (buf, &ret, sizeof (uint16_t)))
return -1;
return ntohs (ret);
}
static inline uint32_t
buf_read_u32 (struct buffer *buf, bool *good)
{
uint32_t ret;
if (!buf_read (buf, &ret, sizeof (uint32_t)))
{
if (good)
*good = false;
return 0;
}
else
{
if (good)
*good = true;
return ntohl (ret);
}
}
static inline bool
buf_string_match (const struct buffer *src, const void *match, int size)
{
if (size != src->len)
return false;
return memcmp (BPTR (src), match, size) == 0;
}
static inline bool
buf_string_match_head (const struct buffer *src, const void *match, int size)
{
if (size < 0 || size > src->len)
return false;
return memcmp (BPTR (src), match, size) == 0;
}
bool buf_string_match_head_str (const struct buffer *src, const char *match);
bool buf_string_compare_advance (struct buffer *src, const char *match);
int buf_substring_len (const struct buffer *buf, int delim);
/*
* Bitwise operations
*/
static inline void
xor (uint8_t *dest, const uint8_t *src, int len)
{
while (len-- > 0)
*dest++ ^= *src++;
}
/*
* Classify and mutate strings based on character types.
*/
/*#define CHARACTER_CLASS_DEBUG*/
/* character classes */
#define CC_ANY (1<<0)
#define CC_NULL (1<<1)
#define CC_ALNUM (1<<2)
#define CC_ALPHA (1<<3)
#define CC_ASCII (1<<4)
#define CC_CNTRL (1<<5)
#define CC_DIGIT (1<<6)
#define CC_PRINT (1<<7)
#define CC_PUNCT (1<<8)
#define CC_SPACE (1<<9)
#define CC_XDIGIT (1<<10)
#define CC_BLANK (1<<11)
#define CC_NEWLINE (1<<12)
#define CC_CR (1<<13)
#define CC_BACKSLASH (1<<14)
#define CC_UNDERBAR (1<<15)
#define CC_DASH (1<<16)
#define CC_DOT (1<<17)
#define CC_COMMA (1<<18)
#define CC_COLON (1<<19)
#define CC_SLASH (1<<20)
#define CC_SINGLE_QUOTE (1<<21)
#define CC_DOUBLE_QUOTE (1<<22)
#define CC_REVERSE_QUOTE (1<<23)
#define CC_AT (1<<24)
#define CC_EQUAL (1<<25)
/* macro classes */
#define CC_NAME (CC_ALNUM|CC_UNDERBAR)
#define CC_CRLF (CC_CR|CC_NEWLINE)
bool char_class (const char c, const unsigned int flags);
bool string_class (const char *str, const unsigned int inclusive, const unsigned int exclusive);
bool string_mod (char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace);
const char *string_mod_const (const char *str,
const unsigned int inclusive,
const unsigned int exclusive,
const char replace,
struct gc_arena *gc);
#ifdef CHARACTER_CLASS_DEBUG
void character_class_debug (void);
#endif
/*
* Verify that a pointer is correctly aligned
*/
#ifdef VERIFY_ALIGNMENT
void valign4 (const struct buffer *buf, const char *file, const int line);
# define verify_align_4(ptr) valign4(buf, __FILE__, __LINE__)
#else
# define verify_align_4(ptr)
#endif
/*
* Very basic garbage collection, mostly for routines that return
* char ptrs to malloced strings.
*/
void x_gc_free (struct gc_arena *a);
static inline void
gc_init (struct gc_arena *a)
{
a->list = NULL;
}
static inline void
gc_detach (struct gc_arena *a)
{
gc_init (a);
}
static inline struct gc_arena
gc_new (void)
{
struct gc_arena ret;
ret.list = NULL;
return ret;
}
static inline void
gc_free (struct gc_arena *a)
{
if (a->list)
x_gc_free (a);
}
static inline void
gc_reset (struct gc_arena *a)
{
gc_free (a);
}
/*
* Allocate memory to hold a structure
*/
void out_of_memory (void);
#define ALLOC_OBJ(dptr, type) \
{ \
check_malloc_return ((dptr) = (type *) malloc (sizeof (type))); \
}
#define ALLOC_OBJ_CLEAR(dptr, type) \
{ \
ALLOC_OBJ (dptr, type); \
memset ((dptr), 0, sizeof(type)); \
}
#define ALLOC_ARRAY(dptr, type, n) \
{ \
check_malloc_return ((dptr) = (type *) malloc (sizeof (type) * (n))); \
}
#define ALLOC_ARRAY_GC(dptr, type, n, gc) \
{ \
(dptr) = (type *) gc_malloc (sizeof (type) * (n), false, (gc)); \
}
#define ALLOC_ARRAY_CLEAR(dptr, type, n) \
{ \
ALLOC_ARRAY (dptr, type, n); \
memset ((dptr), 0, (sizeof(type) * (n))); \
}
#define ALLOC_ARRAY_CLEAR_GC(dptr, type, n, gc) \
{ \
(dptr) = (type *) gc_malloc (sizeof (type) * (n), true, (gc)); \
}
#define ALLOC_OBJ_GC(dptr, type, gc) \
{ \
(dptr) = (type *) gc_malloc (sizeof (type), false, (gc)); \
}
#define ALLOC_OBJ_CLEAR_GC(dptr, type, gc) \
{ \
(dptr) = (type *) gc_malloc (sizeof (type), true, (gc)); \
}
static inline void
check_malloc_return (void *p)
{
void out_of_memory (void);
if (!p)
out_of_memory ();
}
#endif /* BUFFER_H */

78
circ_list.h Normal file
View File

@ -0,0 +1,78 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CIRC_LIST_H
#define CIRC_LIST_H
#include "basic.h"
#include "integer.h"
#include "error.h"
#define CIRC_LIST(name, type) \
struct name { \
int x_head; \
int x_size; \
int x_cap; \
int x_sizeof; \
type x_list[EMPTY_ARRAY_SIZE]; \
}
#define CIRC_LIST_PUSH(obj, item) \
{ \
(obj)->x_head = modulo_add ((obj)->x_head, -1, (obj)->x_cap); \
(obj)->x_list[(obj)->x_head] = (item); \
(obj)->x_size = min_int ((obj)->x_size + 1, (obj)->x_cap); \
}
#define CIRC_LIST_SIZE(obj) \
((obj)->x_size)
#define CIRC_LIST_INDEX(obj, index) \
modulo_add ((obj)->x_head, \
index_verify ((index), (obj)->x_size, __FILE__, __LINE__), \
(obj)->x_cap)
#define CIRC_LIST_ITEM(obj, index) \
((obj)->x_list[CIRC_LIST_INDEX((obj), (index))])
#define CIRC_LIST_RESET(obj) \
{ \
(obj)->x_head = 0; \
(obj)->x_size = 0; \
}
#define CIRC_LIST_ALLOC(dest, list_type, size) \
{ \
const int so = sizeof (list_type) + sizeof ((dest)->x_list[0]) * (size); \
(dest) = (list_type *) malloc (so); \
check_malloc_return (dest); \
memset ((dest), 0, so); \
(dest)->x_cap = size; \
(dest)->x_sizeof = so; \
}
#define CIRC_LIST_FREE(dest) \
free (dest)
#endif

67
common.h Normal file
View File

@ -0,0 +1,67 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef COMMON_H
#define COMMON_H
/*
* Statistics counters.
*/
typedef unsigned long counter_type;
/*
* Time intervals
*/
typedef int interval_t;
/*
* Used as an upper bound for timeouts.
*/
#define BIG_TIMEOUT (60*60*24*7) /* one week (in seconds) */
/*
* Printf formats for special types
*/
#define counter_format "%lu"
#define ptr_format "0x%08lx"
#define time_format "%lu"
#define fragment_header_format "0x%08x"
/* these are used to cast the arguments
* and MUST match the formats above */
typedef unsigned long time_type;
typedef unsigned long ptr_type;
/* the --client-config-dir default file */
#define CCD_DEFAULT "DEFAULT"
/*
* This parameter controls the TLS channel buffer size. Among
* other things, this buffer must be large enough to contain
* the full --push/--pull list. If you increase it, do so
* on both server and client.
*/
#define TLS_CHANNEL_BUF_SIZE 1024
#endif

309
config-win32.h.in Normal file
View File

@ -0,0 +1,309 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Configuration header for Win32 using the mingw environment.
* Manually edited based on linux version as generated by autoconf.
*
* config-win32.h is normally generated by copying
* config-win32.h.in -> config-win32.h and replacing
* [ampersand] VERSION [ampersand]
* with the appropriate version #. This is normally
* done automatically by configure.ac
*/
#include <windows.h>
#include <winsock2.h>
#define sleep(x) Sleep((x)*1000)
#define random rand
#define srandom srand
typedef unsigned long in_addr_t;
#ifndef _SSIZE_T_
#define _SSIZE_T_
typedef unsigned int ssize_t;
#endif
/* Append a label to program startup title */
/*#define DEBUG_LABEL "DEBUG1"*/
/* Should we print debug info from driver? */
/*#define TAP_WIN32_DEBUG*/
/*
* Minimum TAP-Win32 version number expected by userspace
*
* The TAP-Win32 version number is defined in tap-win32/SOURCES
*/
#define TAP_WIN32_MIN_MAJOR 8
#define TAP_WIN32_MIN_MINOR 1
/* Allow --askpass and --auth-user-pass passwords to be read from a file */
/* #undef ENABLE_PASSWORD_SAVE */
/* Enable client/server capability */
#define ENABLE_CLIENT_SERVER 1
/* Enable client capability only */
/* #undef ENABLE_CLIENT_ONLY */
/* Enable management server capability */
#define ENABLE_MANAGEMENT 1
/* Enable HTTP proxy support */
#define ENABLE_HTTP_PROXY 1
/* Enable Socks proxy support */
#define ENABLE_SOCKS 1
/* Enable internal fragmentation support */
#define ENABLE_FRAGMENT 1
/* Enable smaller executable size */
/* #undef ENABLE_SMALL */
/* Enable debugging support */
#define ENABLE_DEBUG 1
/* if defined, will allow usage of the --plugin directive */
#define USE_LOAD_LIBRARY
/* Dimension size to use for empty array declaration */
#define EMPTY_ARRAY_SIZE 0
/* Define to 1 if you have the <openssl/engine.h> header file. */
#define HAVE_OPENSSL_ENGINE_H 1
/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
#define HAVE_ENGINE_LOAD_BUILTIN_ENGINES 1
/* Define to 1 if you have the `ENGINE_register_all_complete' function. */
#define HAVE_ENGINE_REGISTER_ALL_COMPLETE 1
/* Define to 1 if you have the `ENGINE_cleanup' function. */
#define HAVE_ENGINE_CLEANUP 1
/* gettimeofday() is implemented in otime.c for Windows */
#define HAVE_GETTIMEOFDAY 1
/* Define to 1 if you have the 'chsize' function. */
#define HAVE_CHSIZE 1
/* Define to 1 if you have the `chdir' function. */
#define HAVE_CHDIR 1
/* Define to 1 if your compiler supports GNU GCC-style variadic macros */
#ifndef _MSC_VER /* Defines MSFT compiler version. Defined as 1200 for MSVC++ 6.0. */
#define HAVE_CPP_VARARG_MACRO_GCC 1
#endif
/* Define to 1 if you have the <ctype.h> header file. */
#define HAVE_CTYPE_H 1
/* Define to 1 if you have the <errno.h> header file. */
#define HAVE_ERRNO_H 1
/* Define to 1 if you have the `EVP_CIPHER_CTX_set_key_length' function. */
#define HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH 1
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define to 1 if you have the `getsockopt' function. */
#define HAVE_GETSOCKOPT 1
/* Define to 1 if you have the `inet_ntoa' function. */
#define HAVE_INET_NTOA 1
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
to 0 otherwise. */
#define HAVE_MALLOC 1
/* Define to 1 if you have the `memset' function. */
#define HAVE_MEMSET 1
/* Define to 1 if you have the `setsockopt' function. */
#define HAVE_SETSOCKOPT 1
/* Define to 1 if you have the `socket' function. */
#define HAVE_SOCKET 1
/* Define to 1 if you have the <stdarg.h> header file. */
#define HAVE_STDARG_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#ifndef _MSC_VER
#define HAVE_STDINT_H 1
#endif
/* Define to 1 if you have the <stdio.h> header file. */
#define HAVE_STDIO_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strerror' function. */
#define HAVE_STRERROR 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the `system' function. */
#define HAVE_SYSTEM 1
/* Define to 1 if you have the <sys/file.h> header file. */
#ifndef _MSC_VER
#define HAVE_SYS_FILE_H 1
#endif
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#ifndef _MSC_VER
#define HAVE_SYS_TIME_H 1
#endif
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the `time' function. */
#define HAVE_TIME 1
/* Define to 1 if you have the <unistd.h> header file. */
#ifndef _MSC_VER
#define HAVE_UNISTD_H 1
#endif
/* Define to 1 if you have the `vsnprintf' function. */
#define HAVE_VSNPRINTF 1
/* Special Windows version of getpass() defined in io.c */
#define HAVE_GETPASS 1
/* Name of package */
#define PACKAGE "openvpn"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "openvpn-users@lists.sourceforge.net"
/* Define to the full name of this package. */
#define PACKAGE_NAME "OpenVPN"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "openvpn"
/* Define to the version of this package. */
#define PACKAGE_VERSION "@VERSION@" /* AUTO_VERSION */
/* Define to the full name and version of this package. */
#ifdef DEBUG_LABEL
#define PACKAGE_STRING "OpenVPN " PACKAGE_VERSION " " DEBUG_LABEL
#else
#define PACKAGE_STRING "OpenVPN " PACKAGE_VERSION
#endif
/* Define as the return type of signal handlers (`int' or `void'). */
#define RETSIGTYPE void
/* The size of a `unsigned int', as computed by sizeof. */
#define SIZEOF_UNSIGNED_INT 4
/* The size of a `unsigned long', as computed by sizeof. */
#define SIZEOF_UNSIGNED_LONG 4
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* A string representing our target */
#ifdef _MSC_VER
#define TARGET_ALIAS "Win32-MSVC++"
#else
#define TARGET_ALIAS "Win32-MinGW"
#endif
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#ifndef _MSC_VER
#define TIME_WITH_SYS_TIME 1
#endif
/* Use OpenSSL crypto library */
#define USE_CRYPTO 1
/* Use LZO compression library */
#define USE_LZO 1
/* Use OpenSSL SSL library */
#define USE_SSL 1
/* Version number of package */
#define VERSION PACKAGE_VERSION
/* Define as `__inline' if that's what the C compiler calls it, or to nothing
if it is not supported. */
#define inline __inline
/* type to use in place of socklen_t if not defined */
#define socklen_t unsigned int
/* 32-bit unsigned type */
#define uint32_t unsigned int
/* 16-bit unsigned type */
#define uint16_t unsigned short
/* 8-bit unsigned type */
#define uint8_t unsigned char
/* Route command */
#define ROUTE_PATH "route"
/* Windows doesn't support PTHREAD yet */
#ifdef USE_PTHREAD
#error The Windows version of OpenVPN does not support PTHREAD yet
#endif
#ifdef _MSC_VER
/* MSVC++ hacks */
#include <io.h>
#include <direct.h>
#define vsnprintf _vsnprintf
#define vsnwprintf _vsnwprintf
#define snwprintf _snwprintf
#define write _write
#define open _open
#define read _read
#define close _close
#define chdir _chdir
#define S_IRUSR 0
#define S_IWUSR 0
typedef int intptr_t;
#undef S_NORMAL
#endif

636
configure.ac Normal file
View File

@ -0,0 +1,636 @@
dnl OpenVPN -- An application to securely tunnel IP networks
dnl over a single UDP port, with support for SSL/TLS-based
dnl session authentication and key exchange,
dnl packet encryption, packet authentication, and
dnl packet compression.
dnl
dnl Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
dnl
dnl This program is free software; you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation; either version 2 of the License, or
dnl (at your option) any later version.
dnl
dnl This program is distributed in the hope that it will be useful,
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
dnl GNU General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with this program (see the file COPYING included with this
dnl distribution); if not, write to the Free Software Foundation, Inc.,
dnl 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.50)
AC_INIT([OpenVPN], [2.0.3_rc1], [openvpn-users@lists.sourceforge.net], [openvpn])
AM_CONFIG_HEADER(config.h)
AC_CONFIG_SRCDIR(syshead.h)
AC_ARG_ENABLE(lzo,
[ --disable-lzo Disable LZO compression support],
[LZO="$enableval"],
[LZO="yes"]
)
AC_ARG_ENABLE(crypto,
[ --disable-crypto Disable OpenSSL crypto support],
[CRYPTO="$enableval"],
[CRYPTO="yes"]
)
AC_ARG_ENABLE(ssl,
[ --disable-ssl Disable OpenSSL SSL support for TLS-based key exchange],
[SSL="$enableval"],
[SSL="yes"]
)
AC_ARG_ENABLE(multi,
[ --disable-multi Disable client/server support (--mode server + client mode)],
[MULTI="$enableval"],
[MULTI="yes"]
)
AC_ARG_ENABLE(server,
[ --disable-server Disable server support only (but retain client support)],
[MULTI_SERVER="$enableval"],
[MULTI_SERVER="yes"]
)
AC_ARG_ENABLE(plugins,
[ --disable-plugins Disable plug-in support],
[PLUGINS="$enableval"],
[PLUGINS="yes"]
)
AC_ARG_ENABLE(management,
[ --disable-management Disable management server support],
[MANAGEMENT="$enableval"],
[MANAGEMENT="yes"]
)
AC_ARG_ENABLE(socks,
[ --disable-socks Disable Socks support],
[SOCKS="$enableval"],
[SOCKS="yes"]
)
AC_ARG_ENABLE(http,
[ --disable-http Disable HTTP proxy support],
[HTTP_PROXY="$enableval"],
[HTTP_PROXY="yes"]
)
AC_ARG_ENABLE(fragment,
[ --disable-fragment Disable internal fragmentation support (--fragment)],
[FRAGMENT="$enableval"],
[FRAGMENT="yes"]
)
AC_ARG_ENABLE(debug,
[ --disable-debug Disable debugging support (disable gremlin and verb 7+ messages)],
[DEBUG="$enableval"],
[DEBUG="yes"]
)
AC_ARG_ENABLE(small,
[ --enable-small Enable smaller executable size (disable OCC, usage message, and verb 4 parm list)],
[SMALL="$enableval"],
[SMALL="no"]
)
AC_ARG_ENABLE(pthread,
[ --enable-pthread Enable pthread support (Experimental for OpenVPN 2.0)],
[PTHREAD="$enableval"],
[PTHREAD="no"]
)
AC_ARG_ENABLE(password-save,
[ --enable-password-save Allow --askpass and --auth-user-pass passwords to be read from a file],
[PASSWORD_SAVE="$enableval"],
[PASSWORD_SAVE="no"]
)
AC_ARG_ENABLE(iproute2,
[ --enable-iproute2 Enable support for iproute2],
AC_DEFINE(CONFIG_FEATURE_IPROUTE, 1, [enable iproute2 support])
)
AC_ARG_ENABLE(strict,
[ --enable-strict Enable strict compiler warnings (debugging option)],
[STRICT="$enableval"],
[STRICT="no"]
)
AC_ARG_ENABLE(pedantic,
[ --enable-pedantic Enable pedantic compiler warnings, will not generate a working executable (debugging option)],
[PEDANTIC="$enableval"],
[PEDANTIC="no"]
)
AC_ARG_ENABLE(profiling,
[ --enable-profiling Enable profiling (debugging option)],
[PROFILE="$enableval"],
[PROFILE="no"]
)
AC_ARG_ENABLE(strict-options,
[ --enable-strict-options Enable strict options check between peers (debugging option)],
[STRICT_OPTIONS="$enableval"],
[STRICT_OPTIONS="no"]
)
AC_ARG_WITH(ssl-headers,
[ --with-ssl-headers=DIR Crypto/SSL Include files location],
[CS_HDR_DIR="$withval"]
[CPPFLAGS="$CPPFLAGS -I$withval"]
)
AC_ARG_WITH(ssl-lib,
[ --with-ssl-lib=DIR Crypto/SSL Library location],
[LDFLAGS="$LDFLAGS -L$withval"]
)
AC_ARG_WITH(lzo-headers,
[ --with-lzo-headers=DIR LZO Include files location],
[LZO_HDR_DIR="$withval"]
[CPPFLAGS="$CPPFLAGS -I$withval"]
)
AC_ARG_WITH(lzo-lib,
[ --with-lzo-lib=DIR LZO Library location],
[LDFLAGS="$LDFLAGS -L$withval"]
)
AC_ARG_WITH(ifconfig-path,
[ --with-ifconfig-path=PATH Path to ifconfig tool],
[IFCONFIG="$withval"],
[AC_PATH_PROG([IFCONFIG], [ifconfig], [ifconfig], [$PATH:/usr/local/sbin:/usr/sbin:/sbin])]
)
AC_DEFINE_UNQUOTED(IFCONFIG_PATH, "$IFCONFIG", [Path to ifconfig tool])
AC_ARG_WITH(iproute-path,
[ --with-iproute-path=PATH Path to iproute tool],
[IPROUTE="$withval"],
[AC_PATH_PROG([IPROUTE], [ip], [ip], [$PATH:/usr/local/sbin:/usr/sbin:/sbin])]
)
AC_DEFINE_UNQUOTED(IPROUTE_PATH, "$IPROUTE", [Path to iproute tool])
AC_ARG_WITH(route-path,
[ --with-route-path=PATH Path to route tool],
[ROUTE="$withval"],
[AC_PATH_PROG([ROUTE], [route], [route], [$PATH:/usr/local/sbin:/usr/sbin:/sbin])]
)
AC_DEFINE_UNQUOTED(ROUTE_PATH, "$ROUTE", [Path to route tool])
AC_ARG_WITH(mem-check,
[ --with-mem-check=TYPE Build with debug memory checking, TYPE = dmalloc or valgrind],
[MEMCHECK="$withval"]
)
dnl Guess host type.
AC_CANONICAL_HOST
AC_CANONICAL_SYSTEM
AM_INIT_AUTOMAKE(openvpn, [$PACKAGE_VERSION])
dnl fix search path, to allow compilers to find syshead.h
CPPFLAGS="$CPPFLAGS -I${srcdir}"
dnl check target OS
openvpn_target=$target
if test $target_alias; then
openvpn_target=$target_alias
fi
AC_DEFINE_UNQUOTED(TARGET_ALIAS, "$openvpn_target", [A string representing our target])
case "$target" in
*linux*)
AC_DEFINE(TARGET_LINUX, 1, [Are we running on Linux?])
dnl RH9 SSL headers workaround
if test -z $CS_HDR_DIR && test "$CRYPTO" = "yes"; then
CPPFLAGS="$CPPFLAGS $(pkg-config --cflags openssl 2>/dev/null)"
fi
;;
*solaris*)
AC_DEFINE(TARGET_SOLARIS, 1, [Are we running on Solaris?])
;;
*openbsd*)
AC_DEFINE(TARGET_OPENBSD, 1, [Are we running on OpenBSD?])
;;
*freebsd*)
AC_DEFINE(TARGET_FREEBSD, 1, [Are we running on FreeBSD?])
;;
*netbsd*)
AC_DEFINE(TARGET_NETBSD, 1, [Are we running NetBSD?])
;;
*darwin*)
dnl some Mac OS X tendering (we use vararg macros...)
AC_DEFINE(TARGET_DARWIN, 1, [Are we running on Mac OS X?])
CPPFLAGS="$CPPFLAGS -no-cpp-precomp"
;;
*mingw*)
AC_MSG_RESULT([WARNING: configure support for mingw is incomplete])
AC_MSG_RESULT([WARNING: use makefile.w32 instead])
OPENVPN_ADD_LIBS(-lgdi32)
OPENVPN_ADD_LIBS(-lwsock32)
;;
esac
dnl Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_GCC_TRADITIONAL
dnl Checks for header files.
AC_HEADER_STDC
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_C_INLINE
AC_C_VOLATILE
AC_TYPE_OFF_T
AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_TYPE_UID_T
AC_HEADER_TIME
AX_CPP_VARARG_MACRO_ISO
AX_CPP_VARARG_MACRO_GCC
AX_EMPTY_ARRAY
dnl Check for more header files.
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS(sys/time.h sys/socket.h sys/ioctl.h sys/stat.h dnl
sys/mman.h fcntl.h sys/file.h stdlib.h stdint.h dnl
stdarg.h unistd.h signal.h stdio.h string.h dnl
strings.h ctype.h errno.h syslog.h pwd.h grp.h dnl
net/if_tun.h net/if.h stropts.h sys/sockio.h dnl
netinet/in.h netinet/in_systm.h netinet/ip.h dnl
netinet/if_ether.h netinet/tcp.h resolv.h arpa/inet.h dnl
netdb.h sys/uio.h linux/if_tun.h linux/sockios.h dnl
linux/types.h sys/poll.h sys/epoll.h dnl
)
AC_CHECK_HEADERS(linux/errqueue.h,,,
[#ifdef HAVE_LINUX_TYPES_H
# include <linux/types.h>
#endif
])
AC_CACHE_SAVE
dnl check that in_addr_t is defined
AC_CHECK_TYPE(
[in_addr_t],
[],
[AC_DEFINE(in_addr_t, uint32_t, [Some systems don't define in_addr_t])],
[#include "syshead.h"])
dnl check for basic types
AC_CHECK_TYPE(
[uint8_t],
[],
[AC_DEFINE(uint8_t, unsigned char, [8-bit unsigned type])],
[#include "syshead.h"])
AC_CHECK_TYPE(
[uint16_t],
[],
[AC_DEFINE(uint16_t, unsigned char, [16-bit unsigned type])],
[#include "syshead.h"])
AC_CHECK_TYPE(
[uint32_t],
[],
[AC_DEFINE(uint32_t, unsigned long, [32-bit unsigned type])],
[#include "syshead.h"])
dnl check for IPv6 types
AC_CHECK_TYPE(
[struct tun_pi],
[AC_DEFINE(HAVE_TUN_PI, 1, [struct tun_pi needed for IPv6 support])],
[],
[#include "syshead.h"])
AC_CHECK_TYPE(
[struct iphdr],
[AC_DEFINE(HAVE_IPHDR, 1, [struct iphdr needed for IPv6 support])],
[],
[#include "syshead.h"])
AC_CHECK_TYPE(
[struct iovec],
[AC_DEFINE(HAVE_IOVEC, 1, [struct iovec needed for IPv6 support])],
[],
[#include "syshead.h"])
dnl check for extended socket error types
AC_CHECK_TYPE(
[struct sock_extended_err],
[AC_DEFINE(HAVE_SOCK_EXTENDED_ERR, 1, [struct sock_extended_err needed for extended socket error support])],
[],
[#include "syshead.h"])
AC_CHECK_TYPE(
[struct msghdr],
[AC_DEFINE(HAVE_MSGHDR, 1, [struct msghdr needed for extended socket error support])],
[],
[#include "syshead.h"])
AC_CHECK_TYPE(
[struct cmsghdr],
[AC_DEFINE(HAVE_CMSGHDR, 1, [struct cmsghdr needed for extended socket error support])],
[],
[#include "syshead.h"])
AC_CHECK_SIZEOF(unsigned int)
AC_CHECK_SIZEOF(unsigned long)
AC_CACHE_SAVE
dnl check for other types
TYPE_SOCKLEN_T
AC_TYPE_SIGNAL
dnl Check for libsocket
AC_SEARCH_LIBS(socket, socket)
dnl Check for libnsl
AC_SEARCH_LIBS(inet_ntoa, nsl)
dnl Check for libresolv
AC_SEARCH_LIBS(gethostbyname, resolv nsl)
dnl optional library functions
AC_FUNC_FORK
AC_CHECK_FUNCS(daemon chroot getpwnam setuid nice system getpid dup dup2 dnl
getpass strerror syslog openlog mlockall getgrnam setgid dnl
setgroups stat flock readv writev setsockopt getsockopt dnl
setsid chdir gettimeofday putenv getpeername unlink dnl
poll chsize ftruncate)
AC_CACHE_SAVE
dnl Required library functions
AC_FUNC_MEMCMP
AC_CHECK_FUNCS(socket recv recvfrom send sendto listen dnl
accept connect bind select gethostbyname dnl
inet_ntoa time ctime memset vsnprintf, [],
[AC_MSG_ERROR([Required library function not found])])
dnl
dnl check libraries
dnl
dnl Checking for a working epoll
AC_CHECKING([for working epoll implementation])
OLDLDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS -Wl,--fatal-warnings"
AC_CHECK_FUNCS(epoll_create, AC_DEFINE([HAVE_EPOLL_CREATE], 1, []))
LDFLAGS="$OLDLDFLAGS"
dnl
dnl check for valgrind tool
dnl
if test "$MEMCHECK" = "valgrind"; then
AC_CHECKING([for valgrind tool and Header files])
AC_CHECK_HEADER(valgrind/memcheck.h,
[
AC_DEFINE(USE_VALGRIND, 1, [Use valgrind memory debugging library])
CFLAGS="-g -fno-inline"
],
[AC_MSG_ERROR([valgrind headers not found.])]
)
fi
dnl
dnl check for pthread library
dnl
if test "$PTHREAD" = "yes"; then
AC_CHECKING([for pthread support])
AC_MSG_RESULT([********* WARNING: pthread support is experimental for OpenVPN 2.0])
ACX_PTHREAD(
[
case "$target" in
*openbsd*)
AC_MSG_RESULT([WARNING: pthread support on OpenBSD is unstable!])
CFLAGS="$CFLAGS -pthread"
;;
esac
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
CC="$PTHREAD_CC"
AC_DEFINE(USE_PTHREAD, 1, [Use pthread-based multithreading])
],
[
AC_MSG_RESULT([I don't know how to build with pthread support on this platform.])
AC_MSG_ERROR([try ./configure --disable-pthread])
])
fi
dnl
dnl check for dmalloc library
dnl
if test "$MEMCHECK" = "dmalloc"; then
AC_CHECKING([for dmalloc Library and Header files])
AC_CHECK_HEADER(dmalloc.h,
[AC_CHECK_LIB(dmalloc, malloc,
[
if test "$PTHREAD" = "yes"; then
OPENVPN_ADD_LIBS(-ldmallocth)
else
OPENVPN_ADD_LIBS(-ldmalloc)
fi
AC_DEFINE(DMALLOC, 1, [Use dmalloc memory debugging library])
],
[AC_MSG_ERROR([dmalloc library not found.])]
)],
[AC_MSG_ERROR([dmalloc headers not found.])]
)
fi
dnl
dnl Check for dlopen -- first try libc then libdl.
dnl
if test "$PLUGINS" = "yes"; then
AC_CHECKING([for libdl Library and Header files])
AC_CHECK_HEADER(dlfcn.h,
[AC_CHECK_FUNC(dlopen,
[AC_DEFINE(USE_LIBDL, 1, [Use libdl for dynamic library loading])],
[AC_CHECK_LIB(dl, dlopen,
[
OPENVPN_ADD_LIBS(-ldl)
AC_DEFINE(USE_LIBDL, 1, [Use libdl for dynamic library loading])
],
[AC_MSG_RESULT([libdl library not found.])]
)],
)],
[AC_MSG_RESULT([libdl headers not found.])]
)
fi
dnl
dnl check for LZO library
dnl
if test "$LZO" = "yes"; then
LZO_H=""
AC_CHECKING([for LZO Library and Header files])
AC_CHECK_HEADER(lzo/lzo1x.h,
[ LZO_H="2"
lzolibs="lzo2 lzo"
AC_DEFINE(LZO_HEADER_DIR, 1, [Use lzo/ directory prefix for LZO header files (for LZO 2.0)])
],
[ AC_CHECK_HEADER(lzo1x.h, [ LZO_H="1" ; lzolibs=lzo ]) ]
)
if test -n "$LZO_H"; then
havelzolib=0
for i in $lzolibs ; do
if test $havelzolib = 1 ; then break ; fi
AC_CHECK_LIB($i, lzo1x_1_15_compress,
[
OPENVPN_ADD_LIBS(-l$i)
AC_DEFINE(USE_LZO, 1, [Use LZO compression library])
havelzolib=1
]
)
done
if test $havelzolib = 0 ; then
AC_MSG_ERROR([LZO headers were found but LZO library was not found])
fi
else
AC_MSG_RESULT([LZO headers were not found])
AC_MSG_RESULT([LZO library available from http://www.oberhumer.com/opensource/lzo/])
AC_MSG_ERROR([Or try ./configure --disable-lzo])
fi
fi
dnl
dnl check for OpenSSL-crypto library
dnl
if test "$CRYPTO" = "yes"; then
AC_CHECKING([for OpenSSL Crypto Library and Header files])
AC_CHECK_HEADER(openssl/evp.h,
[AC_CHECK_LIB(crypto, EVP_CIPHER_CTX_init,
[
AC_CHECKING([that OpenSSL Library is at least version 0.9.6])
AC_EGREP_CPP(yes,
[
#include "openssl/evp.h"
#if SSLEAY_VERSION_NUMBER >= 0x00906000L
yes
#endif
],
[
AC_DEFINE(USE_CRYPTO, 1, [Use OpenSSL crypto library])
OPENVPN_ADD_LIBS(-lcrypto)
AC_CHECK_FUNCS(EVP_CIPHER_CTX_set_key_length)
dnl check for OpenSSL crypto acceleration capability
AC_CHECK_HEADERS(openssl/engine.h)
AC_CHECK_FUNCS(ENGINE_load_builtin_engines)
AC_CHECK_FUNCS(ENGINE_register_all_complete)
AC_CHECK_FUNCS(ENGINE_cleanup)
],
[AC_MSG_ERROR([OpenSSL crypto Library is too old.])]
)
],
[AC_MSG_ERROR([OpenSSL Crypto library not found.])]
)],
[AC_MSG_ERROR([OpenSSL Crypto headers not found.])]
)
dnl
dnl check for OpenSSL-SSL library
dnl
if test "$SSL" = "yes"; then
AC_CHECKING([for OpenSSL SSL Library and Header files])
AC_CHECK_HEADER(openssl/ssl.h,
[AC_CHECK_LIB(ssl, SSL_CTX_new,
[
if test "$MEMCHECK" = "ssl"; then
AC_CHECKING([for Memory Debugging Capabilities in OpenSSL Library])
AC_CHECK_LIB(ssl, CRYPTO_mem_ctrl,
[
AC_DEFINE(CRYPTO_MDEBUG, 1, [Use memory debugging function in OpenSSL])
AC_MSG_RESULT([NOTE: OpenSSL library must be compiled with CRYPTO_MDEBUG])
],
[AC_MSG_ERROR([Memory Debugging function in OpenSSL library not found.])]
)
fi
],
[AC_MSG_ERROR([OpenSSL SSL library not found.])]
)],
[AC_MSG_ERROR([OpenSSL SSL headers not found.])]
)
AC_DEFINE(USE_SSL, 1, [Use OpenSSL SSL library])
OPENVPN_ADD_LIBS(-lssl)
fi
fi
dnl enable multi-client mode
if test "$MULTI" = "yes"; then
AC_DEFINE(ENABLE_CLIENT_SERVER, 1, [Enable client/server capability])
fi
dnl enable client mode only, not server
if test "$MULTI_SERVER" = "no"; then
AC_DEFINE(ENABLE_CLIENT_ONLY, 1, [Enable client capability only])
fi
dnl enable management server capability
if test "$MANAGEMENT" = "yes"; then
AC_DEFINE(ENABLE_MANAGEMENT, 1, [Enable management server capability])
fi
dnl enable socks
if test "$SOCKS" = "yes"; then
AC_DEFINE(ENABLE_SOCKS, 1, [Enable Socks proxy support])
fi
dnl enable HTTP proxy
if test "$HTTP_PROXY" = "yes"; then
AC_DEFINE(ENABLE_HTTP_PROXY, 1, [Enable HTTP proxy support])
fi
dnl enable debugging
if test "$DEBUG" = "yes"; then
AC_DEFINE(ENABLE_DEBUG, 1, [Enable debugging support])
fi
dnl enable small size optimizations
if test "$SMALL" = "yes"; then
AC_DEFINE(ENABLE_SMALL, 1, [Enable smaller executable size])
fi
dnl enable --fragment
if test "$FRAGMENT" = "yes"; then
AC_DEFINE(ENABLE_FRAGMENT, 1, [Enable internal fragmentation support])
fi
dnl enable strict compiler warnings
if test "$STRICT" = "yes"; then
CFLAGS="$CFLAGS -Wall -Wpointer-arith -Wsign-compare -Wno-unused-parameter -Wno-unused-function"
fi
dnl enable pedantic compiler warnings
if test "$PEDANTIC" = "yes"; then
CFLAGS="$CFLAGS -ansi -pedantic"
fi
dnl enable profiling
if test "$PROFILE" = "yes"; then
CFLAGS="$CFLAGS -pg -DENABLE_PROFILING"
fi
dnl enable strict options check between peers
if test "$STRICT_OPTIONS" = "yes"; then
AC_DEFINE(STRICT_OPTIONS_CHECK, 1, [Enable strict options check between peers])
fi
dnl enable password save
if test "$PASSWORD_SAVE" = "yes"; then
AC_DEFINE(ENABLE_PASSWORD_SAVE, 1, [Allow --askpass and --auth-user-pass passwords to be read from a file])
fi
AC_OUTPUT(Makefile openvpn.spec config-win32.h install-win32/openvpn.nsi)

2
contrib/README Normal file
View File

@ -0,0 +1,2 @@
This directory contains scripts and patches contributed
by users.

View File

@ -0,0 +1,79 @@
--- /etc/init.d/openvpn 2004-05-12 20:30:06.000000000 +0200
+++ openvpn 2004-05-12 20:34:33.000000000 +0200
@@ -58,13 +58,13 @@
# returning success or failure status to caller (James Yonan).
# Location of openvpn binary
-openvpn="/usr/sbin/openvpn"
+openvpn=/usr/sbin/openvpn
# Lockfile
-lock="/var/lock/subsys/openvpn"
+lock=/var/lock/subsys/openvpn
# PID directory
-piddir="/var/run/openvpn"
+piddir=/var/run/openvpn
# Our working directory
work=/etc/openvpn
@@ -106,7 +106,7 @@
if [ -f $lock ]; then
# we were not shut down correctly
- for pidf in `/bin/ls $piddir/*.pid $piddir/*/*.pid 2>/dev/null`; do
+ for pidf in `find $piddir -name "*.pid" 2>/dev/null`; do
if [ -s $pidf ]; then
kill `cat $pidf` >/dev/null 2>&1
fi
@@ -116,12 +116,12 @@
sleep 2
fi
- rm -f $piddir/*.pid $piddir/*/*.pid
+ find $piddir -name "*.pid"|xargs rm -f
# Start every .conf in $work and run .sh if exists
errors=0
successes=0
- for c in `/bin/ls *.conf */*.conf 2>/dev/null`; do
+ for c in `find * -name "*.conf" 2>/dev/null`; do
bn=${c%%.conf}
if [ -f "$bn.sh" ]; then
. $bn.sh
@@ -147,7 +147,7 @@
;;
stop)
echo -n $"Shutting down openvpn: "
- for pidf in `/bin/ls $piddir/*.pid $piddir/*/*.pid 2>/dev/null`; do
+ for pidf in `find $piddir -name "*.pid" 2>/dev/null`; do
if [ -s $pidf ]; then
kill `cat $pidf` >/dev/null 2>&1
fi
@@ -163,7 +163,7 @@
;;
reload)
if [ -f $lock ]; then
- for pidf in `/bin/ls $piddir/*.pid $piddir/*/*.pid 2>/dev/null`; do
+ for pidf in `find $piddir -name "*.pid" 2>/dev/null`; do
if [ -s $pidf ]; then
kill -HUP `cat $pidf` >/dev/null 2>&1
fi
@@ -175,7 +175,7 @@
;;
reopen)
if [ -f $lock ]; then
- for pidf in `/bin/ls $piddir/*.pid $piddir/*/*.pid 2>/dev/null`; do
+ for pidf in `find $piddir -name "*.pid" 2>/dev/null`; do
if [ -s $pidf ]; then
kill -USR1 `cat $pidf` >/dev/null 2>&1
fi
@@ -195,7 +195,7 @@
;;
status)
if [ -f $lock ]; then
- for pidf in `/bin/ls $piddir/*.pid $piddir/*/*.pid 2>/dev/null`; do
+ for pidf in `find $piddir -name "*.pid" 2>/dev/null`; do
if [ -s $pidf ]; then
kill -USR2 `cat $pidf` >/dev/null 2>&1
fi

View File

@ -0,0 +1,44 @@
OpenVPN fwmark Routing
Sean Reifschneider, <jafo@tummy.com>
Thursday November 27, 2003
==========================
These scripts can be used with OpenVPN up and down scripts to set up
routing on a Linux system such that the VPN traffic is sent via normal
network connectivity, but other traffic to that network runs over the VPN.
The idea is to allow encryption of data to the network the remote host is
on, without interfering with the VPN traffic. You can't simply add a route
to the remote network, becaues that will cause the VPN traffic to also try
to run over the VPN, and breaks the VPN.
These scripts use the Linux "fwmark" iptables rules to specify routing
based not only on IP address, but also by port and protocol. This allows
you to effectively say "if the packet is to this IP address on this port
using this protocol, then use the normal default gateway, otherwise use the
VPN gateway.
This is set up on the client VPN system, not the VPN server. These scripts
also set up all ICMP echo-responses to run across the VPN. You can
comment the lines in the scripts to disable this, but I find this useful
at coffee shops which have networks that block ICMP.
To configure this, you need to set up these scripts as your up and down
scripts in the config file. You will need to set these values in the
config file:
up /etc/openvpn/fwmarkroute.up
down /etc/openvpn/fwmarkroute.down
up-restart
up-delay
setenv remote_netmask_bits 24
Note: For this to work, you can't set the "user" or "group" config options,
because then the scripts will not run as root.
The last setting allows you to control the size of the network the remote
system is on. The remote end has to be set up to route, probably with
masquerading or NAT. The network this netmask relates to is calculated
using the value of "remote" in the conf file.
Sean

View File

@ -0,0 +1,22 @@
#!/bin/sh
#
# Bring down vpn routing.
# calculate the network address
remote_network=`ipcalc -n "$remote"/"$remote_netmask_bits"`
remote_network="${remote_network#*=}"
# clear routing via VPN
ip route del "$remote_network"/"$remote_netmask_bits" via "$5" table vpn.out
ip route del table vpnonly.out via "$5"
iptables -D OUTPUT -t mangle -p "$proto" \
-d "$remote_network"/"$remote_netmask_bits" \
--dport "$remote_port" -j ACCEPT
iptables -D OUTPUT -t mangle -d "$remote" -j MARK --set-mark 2
# undo the ICMP ping tunneling
iptables -D OUTPUT -t mangle --protocol icmp --icmp-type echo-request \
-j MARK --set-mark 3
# flush route cache
ip route flush cache

View File

@ -0,0 +1,49 @@
#!/bin/sh
#
# Bring up vpn routing.
# calculate the network address
remote_network=`ipcalc -n "$remote"/"$remote_netmask_bits"`
remote_network="${remote_network#*=}"
# add the stuff that doesn't change if it's not already there
grep -q '^202 ' /etc/iproute2/rt_tables
if [ "$?" -ne 0 ]
then
echo 202 vpn.out >> /etc/iproute2/rt_tables
fi
grep -q '^203 ' /etc/iproute2/rt_tables
if [ "$?" -ne 0 ]
then
echo 203 vpnonly.out >> /etc/iproute2/rt_tables
fi
ip rule ls | grep -q 'lookup vpn.out *$'
if [ "$?" -ne 0 ]
then
ip rule add fwmark 2 table vpn.out
fi
ip rule ls | grep -q 'lookup vpnonly.out *$'
if [ "$?" -ne 0 ]
then
ip rule add fwmark 3 table vpnonly.out
fi
# route VPN traffic using the normal table
iptables -A OUTPUT -t mangle -p "$proto" -d "$remote" --dport "$remote_port" \
-j ACCEPT
# route all other traffic to that host via VPN
iptables -A OUTPUT -t mangle -d "$remote_network"/"$remote_netmask_bits" \
-j MARK --set-mark 2
# route all ICMP pings over the VPN
iptables -A OUTPUT -t mangle --protocol icmp --icmp-type echo-request \
-j MARK --set-mark 3
# NAT traffic going over the VPN, so it doesn't have an unknown address
iptables -t nat -A POSTROUTING -o "$1" -j SNAT --to-source "$4"
# add routing commands
ip route add "$remote_network"/"$remote_netmask_bits" via "$5" table vpn.out
ip route add table vpnonly.out via "$5"
ip route flush cache

View File

@ -0,0 +1,76 @@
#!/bin/bash
# Copyright (c) 2005 by OpenVPN Solutions LLC
# Licensed under the GPL version 2
# First version by Jesse Adelman
# someone at boldandbusted dink com
# http://www.boldandbusted.com/
# PURPOSE: This script automatically removes the /etc/resolv.conf entries previously
# set by the companion script "client.up".
# INSTALL NOTES:
# Place this in /etc/openvpn/client.down
# Then, add the following to your /etc/openvpn/<clientconfig>.conf:
# client
# pull dhcp-options
# up /etc/openvpn/client.up
# down /etc/openvpn/client.down
# Next, "chmod a+x /etc/openvpn/client.down"
# USAGE NOTES:
# Note that this script is best served with the companion "client.up"
# script.
# Only tested on Gentoo Linux 2005.0 with OpenVPN 2.0
# It should work with any GNU/Linux with /etc/resolv.conf
# This runs with the context of the OpenVPN UID/GID
# at the time of execution. This generally means that
# the client "up" script will run fine, but the "down" script
# will require the use of the OpenVPN "down-root" plugin
# which is in the plugins/ directory of the OpenVPN source tree
# A horrid work around, from a security perspective,
# is to run OpenVPN as root. THIS IS NOT RECOMMENDED. You have
# been WARNED.
# init variables
i=1
j=1
unset fopt
unset dns
unset opt
# Convert ENVs to an array
while fopt=foreign_option_$i; [ -n "${!fopt}" ]; do
{
opt[i-1]=${!fopt}
case ${opt[i-1]} in
*DOMAIN* ) domain=`echo ${opt[i-1]} | \
sed -e 's/dhcp-option DOMAIN //g'` ;;
*DNS* ) dns[j-1]=`echo ${opt[i-1]} | \
sed -e 's/dhcp-option DNS //g'`
let j++ ;;
esac
let i++
}
done
# Now, do the work
if [ -n "${dns[*]}" ]; then
for i in "${dns[@]}"; do
sed -i -e "/nameserver ${i}/D" /etc/resolv.conf || die
done
fi
if [ -n "${domain}" ]; then
sed -i -e "/search ${domain}/D" /etc/resolv.conf || die
fi
# all done...
exit 0

View File

@ -0,0 +1,75 @@
#!/bin/bash
# Copyright (c) 2005 by OpenVPN Solutions LLC
# Licensed under the GPL version 2
# First version by Jesse Adelman
# someone at boldandbusted dink com
# http://www.boldandbusted.com/
# PURPOSE: This script automatically sets the proper /etc/resolv.conf entries
# as pulled down from an OpenVPN server.
# INSTALL NOTES:
# Place this in /etc/openvpn/client.up
# Then, add the following to your /etc/openvpn/<clientconfig>.conf:
# client
# pull dhcp-options
# up /etc/openvpn/client.up
# Next, "chmod a+x /etc/openvpn/client.up"
# USAGE NOTES:
# Note that this script is best served with the companion "client.down"
# script.
# Only tested on Gentoo Linux 2005.0 with OpenVPN 2.0
# It should work with any GNU/Linux with /etc/resolv.conf
# This runs with the context of the OpenVPN UID/GID
# at the time of execution. This generally means that
# the client "up" script will run fine, but the "down" script
# will require the use of the OpenVPN "down-root" plugin
# which is in the plugins/ directory of the OpenVPN source tree
# A horrid work around, from a security perspective,
# is to run OpenVPN as root. THIS IS NOT RECOMMENDED. You have
# been WARNED.
# init variables
i=1
j=1
unset fopt
unset dns
unset opt
# Convert ENVs to an array
while fopt=foreign_option_$i; [ -n "${!fopt}" ]; do
{
opt[i-1]=${!fopt}
case ${opt[i-1]} in
*DOMAIN* ) domain=`echo ${opt[i-1]} | \
sed -e 's/dhcp-option DOMAIN //g'` ;;
*DNS* ) dns[j-1]=`echo ${opt[i-1]} | \
sed -e 's/dhcp-option DNS //g'`
let j++ ;;
esac
let i++
}
done
# Now, do the work
if [ -n "${dns[*]}" ]; then
for i in "${dns[@]}"; do
sed -i -e "1,1 i nameserver ${i}" /etc/resolv.conf || die
done
fi
if [ -n "${domain}" ]; then
sed -i -e "$j,1 i search ${domain}" /etc/resolv.conf || die
fi
# all done...
exit 0

1724
crypto.c Normal file

File diff suppressed because it is too large Load Diff

393
crypto.h Normal file
View File

@ -0,0 +1,393 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CRYPTO_H
#define CRYPTO_H
#ifdef USE_CRYPTO
/*
* Does our OpenSSL library support crypto hardware acceleration?
*/
#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_LOAD_BUILTIN_ENGINES) && defined(HAVE_ENGINE_REGISTER_ALL_COMPLETE) && defined(HAVE_ENGINE_CLEANUP)
#define CRYPTO_ENGINE 1
#else
#define CRYPTO_ENGINE 0
#endif
#include <openssl/objects.h>
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/des.h>
#include <openssl/md5.h>
#if NTLM
#include <openssl/md4.h>
#endif
#include <openssl/sha.h>
#include <openssl/err.h>
#if CRYPTO_ENGINE
#include <openssl/engine.h>
#endif
#if SSLEAY_VERSION_NUMBER >= 0x00907000L
#include <openssl/des_old.h>
#endif
#include "basic.h"
#include "buffer.h"
#include "packet_id.h"
#include "mtu.h"
/*
* Workarounds for incompatibilites between OpenSSL libraries.
* Right now we accept OpenSSL libraries from 0.9.5 to 0.9.7.
*/
#if SSLEAY_VERSION_NUMBER < 0x00907000L
/* Workaround: EVP_CIPHER_mode is defined wrong in OpenSSL 0.9.6 but is fixed in 0.9.7 */
#undef EVP_CIPHER_mode
#define EVP_CIPHER_mode(e) (((e)->flags) & EVP_CIPH_MODE)
#define DES_cblock des_cblock
#define DES_is_weak_key des_is_weak_key
#define DES_check_key_parity des_check_key_parity
#define DES_set_odd_parity des_set_odd_parity
#define HMAC_CTX_init(ctx) CLEAR (*ctx)
#define HMAC_Init_ex(ctx,sec,len,md,impl) HMAC_Init(ctx, sec, len, md)
#define HMAC_CTX_cleanup(ctx) HMAC_cleanup(ctx)
#define EVP_MD_CTX_cleanup(md) CLEAR (*md)
#define INFO_CALLBACK_SSL_CONST
#endif
#ifndef INFO_CALLBACK_SSL_CONST
#define INFO_CALLBACK_SSL_CONST const
#endif
#if SSLEAY_VERSION_NUMBER < 0x00906000
#undef EVP_CIPHER_mode
#define EVP_CIPHER_mode(x) 1
#define EVP_CIPHER_CTX_mode(x) 1
#define EVP_CIPHER_flags(x) 0
#define EVP_CIPH_CBC_MODE 1
#define EVP_CIPH_CFB_MODE 0
#define EVP_CIPH_OFB_MODE 0
#define EVP_CIPH_VARIABLE_LENGTH 0
#define OPENSSL_malloc(x) malloc(x)
#define OPENSSL_free(x) free(x)
static inline int
EVP_CipherInit_ov (EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, uint8_t *key, uint8_t *iv, int enc)
{
EVP_CipherInit (ctx, type, key, iv, enc);
return 1;
}
static inline int
EVP_CipherUpdate_ov (EVP_CIPHER_CTX *ctx, uint8_t *out, int *outl, uint8_t *in, int inl)
{
EVP_CipherUpdate (ctx, out, outl, in, inl);
return 1;
}
static inline bool
cipher_ok (const char* name)
{
const int i = strlen (name) - 4;
if (i >= 0)
return !strcmp (name + i, "-CBC");
else
return false;
}
#else
static inline int
EVP_CipherInit_ov (EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, uint8_t *key, uint8_t *iv, int enc)
{
return EVP_CipherInit (ctx, type, key, iv, enc);
}
static inline int
EVP_CipherUpdate_ov (EVP_CIPHER_CTX *ctx, uint8_t *out, int *outl, uint8_t *in, int inl)
{
return EVP_CipherUpdate (ctx, out, outl, in, inl);
}
static inline bool
cipher_ok (const char* name)
{
return true;
}
#endif
#if SSLEAY_VERSION_NUMBER < 0x0090581f
#undef DES_check_key_parity
#define DES_check_key_parity(x) 1
#endif
#ifndef EVP_CIPHER_name
#define EVP_CIPHER_name(e) OBJ_nid2sn(EVP_CIPHER_nid(e))
#endif
#ifndef EVP_MD_name
#define EVP_MD_name(e) OBJ_nid2sn(EVP_MD_type(e))
#endif
/*
* Max size in bytes of any cipher key that might conceivably be used.
*
* This value is checked at compile time in crypto.c to make sure
* it is always at least EVP_MAX_KEY_LENGTH.
*
* We define our own value, since this parameter
* is used to control the size of static key files.
* If the OpenSSL library increases EVP_MAX_KEY_LENGTH,
* we don't want our key files to be suddenly rendered
* unusable.
*/
#define MAX_CIPHER_KEY_LENGTH 64
/*
* Max size in bytes of any HMAC key that might conceivably be used.
*
* This value is checked at compile time in crypto.c to make sure
* it is always at least EVP_MAX_MD_SIZE. We define our own value
* for the same reason as above.
*/
#define MAX_HMAC_KEY_LENGTH 64
/*
* Defines a key type and key length for both cipher and HMAC.
*/
struct key_type
{
uint8_t cipher_length;
uint8_t hmac_length;
const EVP_CIPHER *cipher;
const EVP_MD *digest;
};
/*
* A random key.
*/
struct key
{
uint8_t cipher[MAX_CIPHER_KEY_LENGTH];
uint8_t hmac[MAX_HMAC_KEY_LENGTH];
};
#define KEY_DIRECTION_BIDIRECTIONAL 0 /* same keys for both directions */
#define KEY_DIRECTION_NORMAL 1 /* encrypt with keys[0], decrypt with keys[1] */
#define KEY_DIRECTION_INVERSE 2 /* encrypt with keys[1], decrypt with keys[0] */
/*
* Dual random keys (for encrypt/decrypt)
*/
struct key2
{
int n;
struct key keys[2];
};
/*
* Used for controlling bidirectional keys
* vs. a separate key for each direction.
*/
struct key_direction_state
{
int out_key;
int in_key;
int need_keys;
};
/*
* A key context for cipher and/or HMAC.
*/
struct key_ctx
{
EVP_CIPHER_CTX *cipher;
HMAC_CTX *hmac;
};
/*
* Cipher/HMAC key context for both sending and receiving
* directions.
*/
struct key_ctx_bi
{
struct key_ctx encrypt;
struct key_ctx decrypt;
};
/*
* Options for encrypt/decrypt.
*/
struct crypto_options
{
struct key_ctx_bi *key_ctx_bi;
struct packet_id *packet_id;
struct packet_id_persist *pid_persist;
# define CO_PACKET_ID_LONG_FORM (1<<0)
# define CO_USE_IV (1<<1)
# define CO_IGNORE_PACKET_ID (1<<2)
# define CO_MUTE_REPLAY_WARNINGS (1<<3)
unsigned int flags;
};
void init_key_type (struct key_type *kt, const char *ciphername,
bool ciphername_defined, const char *authname,
bool authname_defined, int keysize,
bool cfb_ofb_allowed, bool warn);
void read_key_file (struct key2 *key2, const char *filename, bool must_succeed);
int write_key_file (const int nkeys, const char *filename);
int read_passphrase_hash (const char *passphrase_file,
const EVP_MD *digest,
uint8_t *output,
int len);
void generate_key_random (struct key *key, const struct key_type *kt);
void check_replay_iv_consistency(const struct key_type *kt, bool packet_id, bool use_iv);
bool check_key (struct key *key, const struct key_type *kt);
void fixup_key (struct key *key, const struct key_type *kt);
bool write_key (const struct key *key, const struct key_type *kt,
struct buffer *buf);
int read_key (struct key *key, const struct key_type *kt, struct buffer *buf);
bool cfb_ofb_mode (const struct key_type* kt);
const char *kt_cipher_name (const struct key_type *kt);
const char *kt_digest_name (const struct key_type *kt);
int kt_key_size (const struct key_type *kt);
/* enc parameter in init_key_ctx */
#define DO_ENCRYPT 1
#define DO_DECRYPT 0
void init_key_ctx (struct key_ctx *ctx, struct key *key,
const struct key_type *kt, int enc,
const char *prefix);
void free_key_ctx (struct key_ctx *ctx);
void free_key_ctx_bi (struct key_ctx_bi *ctx);
void openvpn_encrypt (struct buffer *buf, struct buffer work,
const struct crypto_options *opt,
const struct frame* frame);
bool openvpn_decrypt (struct buffer *buf, struct buffer work,
const struct crypto_options *opt,
const struct frame* frame);
void crypto_adjust_frame_parameters(struct frame *frame,
const struct key_type* kt,
bool cipher_defined,
bool use_iv,
bool packet_id,
bool packet_id_long_form);
void prng_init (void);
void prng_bytes (uint8_t *output, int len);
void test_crypto (const struct crypto_options *co, struct frame* f);
const char *md5sum(uint8_t *buf, int len, int n_print_chars, struct gc_arena *gc);
void show_available_ciphers (void);
void show_available_digests (void);
void show_available_engines (void);
void init_crypto_lib_engine (const char *engine_name);
void init_crypto_lib (void);
void uninit_crypto_lib (void);
/* key direction functions */
void key_direction_state_init (struct key_direction_state *kds, int key_direction);
void verify_fix_key2 (struct key2 *key2, const struct key_type *kt, const char *shared_secret_file);
void must_have_n_keys (const char *filename, const char *option, const struct key2 *key2, int n);
int ascii2keydirection (int msglevel, const char *str);
const char *keydirection2ascii (int kd, bool remote);
/* print keys */
void key2_print (const struct key2* k,
const struct key_type *kt,
const char* prefix0,
const char* prefix1);
/* memory debugging */
void openssl_dmalloc_init (void);
#ifdef USE_SSL
void get_tls_handshake_key (const struct key_type *key_type,
struct key_ctx_bi *ctx,
const char *passphrase_file,
bool key_direction);
#else
void init_ssl_lib (void);
void free_ssl_lib (void);
#endif /* USE_SSL */
/*
* Inline functions
*/
static inline bool
key_ctx_bi_defined(const struct key_ctx_bi* key)
{
return key->encrypt.cipher || key->encrypt.hmac || key->decrypt.cipher || key->decrypt.hmac;
}
#endif /* USE_CRYPTO */
#endif /* CRYPTO_H */

463
cryptoapi.c Normal file
View File

@ -0,0 +1,463 @@
/*
* Copyright (c) 2004 Peter 'Luna' Runestig <peter@runestig.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifi-
* cation, are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright no-
* tice, this list of conditions and the following disclaimer in the do-
* cumentation and/or other materials provided with the distribution.
*
* o The names of the contributors may not 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 REGENTS OR CONTRIBUTORS BE LI-
* ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
* TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
* ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
* LITY, 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.
*/
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#ifdef __MINGW32_VERSION
/* MinGW w32api is incomplete when it comes to CryptoAPI, as per version 3.1
* anyway. This is a hack around that problem. */
#define CALG_SSL3_SHAMD5 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SSL3SHAMD5)
#define CERT_SYSTEM_STORE_LOCATION_SHIFT 16
#define CERT_SYSTEM_STORE_CURRENT_USER_ID 1
#define CERT_SYSTEM_STORE_CURRENT_USER (CERT_SYSTEM_STORE_CURRENT_USER_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT)
#define CERT_STORE_READONLY_FLAG 0x00008000
#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
#define CRYPT_ACQUIRE_COMPARE_KEY_FLAG 0x00000004
static HINSTANCE crypt32dll = NULL;
static BOOL WINAPI (*CryptAcquireCertificatePrivateKey) (PCCERT_CONTEXT pCert, DWORD dwFlags,
void *pvReserved, HCRYPTPROV *phCryptProv, DWORD *pdwKeySpec, BOOL *pfCallerFreeProv) = NULL;
#endif
/* Size of an SSL signature: MD5+SHA1 */
#define SSL_SIG_LENGTH 36
/* try to funnel any Windows/CryptoAPI error messages to OpenSSL ERR_... */
#define ERR_LIB_CRYPTOAPI (ERR_LIB_USER + 69) /* 69 is just a number... */
#define CRYPTOAPIerr(f) err_put_ms_error(GetLastError(), (f), __FILE__, __LINE__)
#define CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE 100
#define CRYPTOAPI_F_CERT_FIND_CERTIFICATE_IN_STORE 101
#define CRYPTOAPI_F_CRYPT_ACQUIRE_CERTIFICATE_PRIVATE_KEY 102
#define CRYPTOAPI_F_CRYPT_CREATE_HASH 103
#define CRYPTOAPI_F_CRYPT_GET_HASH_PARAM 104
#define CRYPTOAPI_F_CRYPT_SET_HASH_PARAM 105
#define CRYPTOAPI_F_CRYPT_SIGN_HASH 106
#define CRYPTOAPI_F_LOAD_LIBRARY 107
#define CRYPTOAPI_F_GET_PROC_ADDRESS 108
static ERR_STRING_DATA CRYPTOAPI_str_functs[] = {
{ ERR_PACK(ERR_LIB_CRYPTOAPI, 0, 0), "microsoft cryptoapi"},
{ ERR_PACK(0, CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE, 0), "CertOpenSystemStore" },
{ ERR_PACK(0, CRYPTOAPI_F_CERT_FIND_CERTIFICATE_IN_STORE, 0), "CertFindCertificateInStore" },
{ ERR_PACK(0, CRYPTOAPI_F_CRYPT_ACQUIRE_CERTIFICATE_PRIVATE_KEY, 0), "CryptAcquireCertificatePrivateKey" },
{ ERR_PACK(0, CRYPTOAPI_F_CRYPT_CREATE_HASH, 0), "CryptCreateHash" },
{ ERR_PACK(0, CRYPTOAPI_F_CRYPT_GET_HASH_PARAM, 0), "CryptGetHashParam" },
{ ERR_PACK(0, CRYPTOAPI_F_CRYPT_SET_HASH_PARAM, 0), "CryptSetHashParam" },
{ ERR_PACK(0, CRYPTOAPI_F_CRYPT_SIGN_HASH, 0), "CryptSignHash" },
{ ERR_PACK(0, CRYPTOAPI_F_LOAD_LIBRARY, 0), "LoadLibrary" },
{ ERR_PACK(0, CRYPTOAPI_F_GET_PROC_ADDRESS, 0), "GetProcAddress" },
{ 0, NULL }
};
typedef struct _CAPI_DATA {
const CERT_CONTEXT *cert_context;
HCRYPTPROV crypt_prov;
DWORD key_spec;
BOOL free_crypt_prov;
} CAPI_DATA;
static char *ms_error_text(DWORD ms_err)
{
LPVOID lpMsgBuf = NULL;
char *rv = NULL;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, ms_err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
(LPTSTR) &lpMsgBuf, 0, NULL);
if (lpMsgBuf) {
char *p;
rv = strdup(lpMsgBuf);
LocalFree(lpMsgBuf);
/* trim to the left */
if (rv)
for (p = rv + strlen(rv) - 1; p >= rv; p--) {
if (isspace(*p))
*p = '\0';
else
break;
}
}
return rv;
}
static void err_put_ms_error(DWORD ms_err, int func, const char *file, int line)
{
static int init = 0;
# define ERR_MAP_SZ 16
static struct {
int err;
DWORD ms_err; /* I don't think we get more than 16 *different* errors */
} err_map[ERR_MAP_SZ]; /* in here, before we give up the whole thing... */
int i;
if (ms_err == 0)
/* 0 is not an error */
return;
if (!init) {
ERR_load_strings(ERR_LIB_CRYPTOAPI, CRYPTOAPI_str_functs);
memset(&err_map, 0, sizeof(err_map));
init++;
}
/* since MS error codes are 32 bit, and the ones in the ERR_... system is
* only 12, we must have a mapping table between them. */
for (i = 0; i < ERR_MAP_SZ; i++) {
if (err_map[i].ms_err == ms_err) {
ERR_PUT_error(ERR_LIB_CRYPTOAPI, func, err_map[i].err, file, line);
break;
} else if (err_map[i].ms_err == 0 ) {
/* end of table, add new entry */
ERR_STRING_DATA *esd = calloc(2, sizeof(*esd));
if (esd == NULL)
break;
err_map[i].ms_err = ms_err;
err_map[i].err = esd->error = i + 100;
esd->string = ms_error_text(ms_err);
ERR_load_strings(ERR_LIB_CRYPTOAPI, esd);
ERR_PUT_error(ERR_LIB_CRYPTOAPI, func, err_map[i].err, file, line);
break;
}
}
}
/* encrypt */
static int rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
{
/* I haven't been able to trigger this one, but I want to know if it happens... */
assert(0);
return 0;
}
/* verify arbitrary data */
static int rsa_pub_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
{
/* I haven't been able to trigger this one, but I want to know if it happens... */
assert(0);
return 0;
}
/* sign arbitrary data */
static int rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
{
CAPI_DATA *cd = (CAPI_DATA *) rsa->meth->app_data;
HCRYPTHASH hash;
DWORD hash_size, len, i;
unsigned char *buf;
if (cd == NULL) {
RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (padding != RSA_PKCS1_PADDING) {
/* AFAICS, CryptSignHash() *always* uses PKCS1 padding. */
RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
return 0;
}
/* Unfortunately, there is no "CryptSign()" function in CryptoAPI, that would
* be way to straightforward for M$, I guess... So we have to do it this
* tricky way instead, by creating a "Hash", and load the already-made hash
* from 'from' into it. */
/* For now, we only support NID_md5_sha1 */
if (flen != SSL_SIG_LENGTH) {
RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_INVALID_MESSAGE_LENGTH);
return 0;
}
if (!CryptCreateHash(cd->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash)) {
CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_CREATE_HASH);
return 0;
}
len = sizeof(hash_size);
if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len, 0)) {
CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_GET_HASH_PARAM);
CryptDestroyHash(hash);
return 0;
}
if ((int) hash_size != flen) {
RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_INVALID_MESSAGE_LENGTH);
CryptDestroyHash(hash);
return 0;
}
if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) {
CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_SET_HASH_PARAM);
CryptDestroyHash(hash);
return 0;
}
len = RSA_size(rsa);
buf = malloc(len);
if (buf == NULL) {
RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE);
CryptDestroyHash(hash);
return 0;
}
if (!CryptSignHash(hash, cd->key_spec, NULL, 0, buf, &len)) {
CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_SIGN_HASH);
CryptDestroyHash(hash);
free(buf);
return 0;
}
/* and now, we have to reverse the byte-order in the result from CryptSignHash()... */
for (i = 0; i < len; i++)
to[i] = buf[len - i - 1];
free(buf);
CryptDestroyHash(hash);
return len;
}
/* decrypt */
static int rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
{
/* I haven't been able to trigger this one, but I want to know if it happens... */
assert(0);
return 0;
}
/* called at RSA_new */
static int init(RSA *rsa)
{
return 0;
}
/* called at RSA_free */
static int finish(RSA *rsa)
{
CAPI_DATA *cd = (CAPI_DATA *) rsa->meth->app_data;
if (cd == NULL)
return 0;
if (cd->crypt_prov && cd->free_crypt_prov)
CryptReleaseContext(cd->crypt_prov, 0);
if (cd->cert_context)
CertFreeCertificateContext(cd->cert_context);
free(rsa->meth->app_data);
free((char *) rsa->meth);
rsa->meth = NULL;
return 1;
}
static const CERT_CONTEXT *find_certificate_in_store(const char *cert_prop, HCERTSTORE cert_store)
{
/* Find, and use, the desired certificate from the store. The
* 'cert_prop' certificate search string can look like this:
* SUBJ:<certificate substring to match>
* THUMB:<certificate thumbprint hex value>, e.g.
* THUMB:f6 49 24 41 01 b4 fb 44 0c ce f4 36 ae d0 c4 c9 df 7a b6 28
*/
const CERT_CONTEXT *rv = NULL;
if (!strncmp(cert_prop, "SUBJ:", 5)) {
/* skip the tag */
cert_prop += 5;
rv = CertFindCertificateInStore(cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0, CERT_FIND_SUBJECT_STR_A, cert_prop, NULL);
} else if (!strncmp(cert_prop, "THUMB:", 6)) {
unsigned char hash[255];
char *p;
int i, x = 0;
CRYPT_HASH_BLOB blob;
/* skip the tag */
cert_prop += 6;
for (p = (char *) cert_prop, i = 0; *p && i < sizeof(hash); i++) {
if (*p >= '0' && *p <= '9')
x = (*p - '0') << 4;
else if (*p >= 'A' && *p <= 'F')
x = (*p - 'A' + 10) << 4;
else if (*p >= 'a' && *p <= 'f')
x = (*p - 'a' + 10) << 4;
if (!*++p) /* unexpected end of string */
break;
if (*p >= '0' && *p <= '9')
x += *p - '0';
else if (*p >= 'A' && *p <= 'F')
x += *p - 'A' + 10;
else if (*p >= 'a' && *p <= 'f')
x += *p - 'a' + 10;
hash[i] = x;
/* skip any space(s) between hex numbers */
for (p++; *p && *p == ' '; p++);
}
blob.cbData = i;
blob.pbData = (unsigned char *) &hash;
rv = CertFindCertificateInStore(cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0, CERT_FIND_HASH, &blob, NULL);
}
return rv;
}
int SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop)
{
HCERTSTORE cs;
X509 *cert = NULL;
RSA *rsa = NULL, *pub_rsa;
CAPI_DATA *cd = calloc(1, sizeof(*cd));
RSA_METHOD *my_rsa_method = calloc(1, sizeof(*my_rsa_method));
if (cd == NULL || my_rsa_method == NULL) {
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_MALLOC_FAILURE);
goto err;
}
/* search CURRENT_USER first, then LOCAL_MACHINE */
cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER |
CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"MY");
if (cs == NULL) {
CRYPTOAPIerr(CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE);
goto err;
}
cd->cert_context = find_certificate_in_store(cert_prop, cs);
CertCloseStore(cs, 0);
if (!cd->cert_context) {
cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE |
CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"MY");
if (cs == NULL) {
CRYPTOAPIerr(CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE);
goto err;
}
cd->cert_context = find_certificate_in_store(cert_prop, cs);
CertCloseStore(cs, 0);
if (cd->cert_context == NULL) {
CRYPTOAPIerr(CRYPTOAPI_F_CERT_FIND_CERTIFICATE_IN_STORE);
goto err;
}
}
/* cert_context->pbCertEncoded is the cert X509 DER encoded. */
cert = d2i_X509(NULL, (unsigned char **) &cd->cert_context->pbCertEncoded,
cd->cert_context->cbCertEncoded);
if (cert == NULL) {
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_ASN1_LIB);
goto err;
}
/* set up stuff to use the private key */
#ifdef __MINGW32_VERSION
/* MinGW w32api is incomplete when it comes to CryptoAPI, as per version 3.1
* anyway. This is a hack around that problem. */
if (crypt32dll == NULL) {
crypt32dll = LoadLibrary("crypt32");
if (crypt32dll == NULL) {
CRYPTOAPIerr(CRYPTOAPI_F_LOAD_LIBRARY);
goto err;
}
}
if (CryptAcquireCertificatePrivateKey == NULL) {
CryptAcquireCertificatePrivateKey = GetProcAddress(crypt32dll,
"CryptAcquireCertificatePrivateKey");
if (CryptAcquireCertificatePrivateKey == NULL) {
CRYPTOAPIerr(CRYPTOAPI_F_GET_PROC_ADDRESS);
goto err;
}
}
#endif
if (!CryptAcquireCertificatePrivateKey(cd->cert_context, CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
NULL, &cd->crypt_prov, &cd->key_spec, &cd->free_crypt_prov)) {
/* if we don't have a smart card reader here, and we try to access a
* smart card certificate, we get:
* "Error 1223: The operation was canceled by the user." */
CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_ACQUIRE_CERTIFICATE_PRIVATE_KEY);
goto err;
}
/* here we don't need to do CryptGetUserKey() or anything; all necessary key
* info is in cd->cert_context, and then, in cd->crypt_prov. */
my_rsa_method->name = "Microsoft CryptoAPI RSA Method";
my_rsa_method->rsa_pub_enc = rsa_pub_enc;
my_rsa_method->rsa_pub_dec = rsa_pub_dec;
my_rsa_method->rsa_priv_enc = rsa_priv_enc;
my_rsa_method->rsa_priv_dec = rsa_priv_dec;
/* my_rsa_method->init = init; */
my_rsa_method->finish = finish;
my_rsa_method->flags = RSA_METHOD_FLAG_NO_CHECK;
my_rsa_method->app_data = (char *) cd;
rsa = RSA_new();
if (rsa == NULL) {
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_MALLOC_FAILURE);
goto err;
}
/* cert->cert_info->key->pkey is NULL until we call SSL_CTX_use_certificate(),
* so we do it here then... */
if (!SSL_CTX_use_certificate(ssl_ctx, cert))
goto err;
/* the public key */
pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
/* SSL_CTX_use_certificate() increased the reference count in 'cert', so
* we decrease it here with X509_free(), or it will never be cleaned up. */
X509_free(cert);
cert = NULL;
/* I'm not sure about what we have to fill in in the RSA, trying out stuff... */
/* rsa->n indicates the key size */
rsa->n = BN_dup(pub_rsa->n);
rsa->flags |= RSA_FLAG_EXT_PKEY;
if (!RSA_set_method(rsa, my_rsa_method))
goto err;
if (!SSL_CTX_use_RSAPrivateKey(ssl_ctx, rsa))
goto err;
/* SSL_CTX_use_RSAPrivateKey() increased the reference count in 'rsa', so
* we decrease it here with RSA_free(), or it will never be cleaned up. */
RSA_free(rsa);
return 1;
err:
if (cert)
X509_free(cert);
if (rsa)
RSA_free(rsa);
else {
if (my_rsa_method)
free(my_rsa_method);
if (cd) {
if (cd->free_crypt_prov && cd->crypt_prov)
CryptReleaseContext(cd->crypt_prov, 0);
if (cd->cert_context)
CertFreeCertificateContext(cd->cert_context);
free(cd);
}
}
return 0;
}

7
cryptoapi.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _CRYPTOAPI_H_
#define _CRYPTOAPI_H_
int SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop);
#endif /* !_CRYPTOAPI_H_ */

310
debug/valgrind-suppress Normal file
View File

@ -0,0 +1,310 @@
# Valgrind suppressions file for OpenVPN.
#
# Mostly deal with uninitialized data warnings
# in OpenSSL.
{
test1
Memcheck:Cond
fun:BN_*
}
{
test2
Memcheck:Value4
fun:BN_*
}
{
test3
Memcheck:Cond
fun:bn_*
}
{
test4
Memcheck:Value4
fun:bn_*
}
{
test5
Memcheck:Cond
fun:getrn
}
{
test6
Memcheck:Value4
fun:getrn
}
{
test7
Memcheck:Value4
fun:lh_retrieve
}
{
test8
Memcheck:Cond
fun:lh_retrieve
}
{
test10
Memcheck:Cond
fun:RSA_verify
}
{
test11
Memcheck:Value4
fun:RSA_verify
}
{
test12
Memcheck:Value4
fun:AES_set_encrypt_key
}
{
test13
Memcheck:Value4
fun:AES_set_decrypt_key
}
{
test14
Memcheck:Value4
fun:AES_decrypt
}
{
test15
Memcheck:Value4
fun:BF_encrypt
}
{
test16
Memcheck:Cond
fun:tls1_enc
}
{
test17
Memcheck:Value4
fun:tls1_enc
}
{
test18
Memcheck:Cond
fun:ssl3_read_bytes
}
{
test19
Memcheck:Cond
fun:SHA1_Update
}
{
test20
Memcheck:Value4
fun:SHA1_Update
}
{
test21
Memcheck:Cond
fun:SHA1_Final
}
{
test22
Memcheck:Value4
fun:SHA1_Final
}
{
test23
Memcheck:Value4
fun:ssl3_read_bytes
}
{
test24
Memcheck:Cond
fun:ssl3_get_message
}
{
test25
Memcheck:Cond
fun:BUF_MEM_grow_clean
}
{
test26
Memcheck:Cond
fun:memcpy
fun:ssl3_read_bytes
}
{
test27
Memcheck:Value4
fun:memcpy
fun:ssl3_read_bytes
}
{
test28
Memcheck:Cond
fun:MD5_Update
}
{
test29
Memcheck:Value4
fun:MD5_Update
}
{
test30
Memcheck:Cond
fun:ssl3_get_finished
}
{
test31
Memcheck:Value4
fun:ssl3_get_finished
}
{
test32
Memcheck:Cond
fun:MD5_Final
}
{
test33
Memcheck:Value4
fun:MD5_Final
}
{
test34
Memcheck:Value4
fun:AES_encrypt
}
{
test35
Memcheck:Cond
fun:sha1_block_asm_data_order
}
{
test36
Memcheck:Cond
fun:ssl3_read
}
{
test37
Memcheck:Cond
fun:SSL_get_error
}
{
test38
Memcheck:Cond
fun:BIO_read
}
{
test39
Memcheck:Value4
fun:memset
}
{
test40
Memcheck:Cond
fun:ssl_read
}
{
test41
Memcheck:Cond
fun:memset
}
{
test42
Memcheck:Cond
fun:ssl3_read_internal
}
{
test43
Memcheck:Cond
fun:ssl3_get_cert_verify
}
{
test44
Memcheck:Leak
fun:malloc
fun:gc_malloc
fun:alloc_buf_gc
fun:construct_name_value
}
{
test45
Memcheck:Leak
fun:malloc
fun:default_malloc_ex
}
{
test46
Memcheck:Leak
fun:malloc
fun:gc_malloc
fun:add_env_item
fun:manage_env
}
{
test47
Memcheck:Cond
fun:lzo1x_1_15_compress
}
{
test48
Memcheck:Value4
fun:DES_set_key_unchecked
}
{
test49
Memcheck:Value4
fun:DES_encrypt2
}
{
test50
Memcheck:Leak
fun:malloc
fun:_IO_getdelim
fun:getline
fun:getpass
}

16
doclean Executable file
View File

@ -0,0 +1,16 @@
#!/bin/sh
# Let's have a fresh start. Remove all files
# which are not source files.
#
# Run this script, then:
# touch *
# [apply any patches here]
# autoreconf -i -v
# ./configure
# make
# make install
rm -f *.o openvpn config.cache configure Makefile Makefile.in stamp-h* config.guess config.sub depcomp missing mkinstalldirs config.log config.status config.h config.h.in aclocal.m4 openvpn.spec config-win32.h install-sh install-win32/openvpn.nsi
rm -rf autom4te*.cache .deps

161
easy-rsa/README Normal file
View File

@ -0,0 +1,161 @@
This is a small RSA key management package,
based on the openssl command line tool, that
can be found in the easy-rsa subdirectory
of the OpenVPN distribution.
These are reference notes. For step
by step instructions, see the HOWTO:
http://openvpn.net/howto.html
INSTALL
1. Edit vars.
2. Set KEY_CONFIG to point to the openssl.cnf file
included in this distribution.
3. Set KEY_DIR to point to a directory which will
contain all keys, certificates, etc. This
directory need not exist, and if it does,
it will be deleted with rm -rf, so BE
CAREFUL how you set KEY_DIR.
4. (Optional) Edit other fields in vars
per your site data. You may want to
increase KEY_SIZE to 2048 if you are
paranoid and don't mind slower key
processing, but certainly 1024 is
fine for testing purposes. KEY_SIZE
must be compatible across both peers
participating in a secure SSL/TLS
connection.
5 . vars
6. ./clean-all
7. As you create certificates, keys, and
certificate signing requests, understand that
only .key files should be kept confidential.
.crt and .csr files can be sent over insecure
channels such as plaintext email.
8. You should never need to copy a .key file
between computers. Normally each computer
will have its own certificate/key pair.
BUILD YOUR OWN ROOT CERTIFICATE AUTHORITY (CA) CERTIFICATE/KEY
1. ./build-ca
2. ca.crt and ca.key will be built in your KEY_DIR
directory
BUILD AN INTERMEDIATE CERTIFICATE AUTHORITY CERTIFICATE/KEY (optional)
1. ./build-inter inter
2. inter.crt and inter.key will be built in your KEY_DIR
directory and signed with your root certificate.
BUILD DIFFIE-HELLMAN PARAMETERS (necessary for
the server end of a SSL/TLS connection).
1. ./build-dh
BUILD A CERTIFICATE SIGNING REQUEST (If
you want to sign your certificate with a root
certificate controlled by another individual
or organization, or residing on a different machine).
1. Get ca.crt (the root certificate) from your
certificate authority. Though this
transfer can be over an insecure channel, to prevent
man-in-the-middle attacks you must confirm that
ca.crt was not tampered with. Large CAs solve this
problem by hardwiring their root certificates into
popular web browsers. A simple way to verify a root
CA is to call the issuer on the telephone and confirm
that the md5sum or sha1sum signatures on the ca.crt
files match (such as with the command: "md5sum ca.crt").
2. Choose a name for your certificate such as your computer
name. In our example we will use "mycert".
3. ./build-req mycert
4. You can ignore most of the fields, but set
"Common Name" to something unique such as your
computer's host name. Leave all password
fields blank, unless you want your private key
to be protected by password. Using a password
is not required -- it will make your key more secure
but also more inconvenient to use, because you will
need to supply your password anytime the key is used.
NOTE: if you are using a password, use ./build-req-pass
instead of ./build-req
5. Your key will be written to $KEY_DIR/mycert.key
6. Your certificate signing request will be written to
to $KEY_DIR/mycert.csr
7. Email mycert.csr to the individual or organization
which controls the root certificate. This can be
done over an insecure channel.
8. After the .csr file is signed by the root certificate
authority, you will receive a file mycert.crt
(your certificate). Place mycert.crt in your
KEY_DIR directory.
9. The combined files of mycert.crt, mycert.key,
and ca.crt can now be used to secure one end of
an SSL/TLS connection.
SIGN A CERTIFICATE SIGNING REQUEST
1. ./sign-req mycert
2. mycert.crt will be built in your KEY_DIR
directory using mycert.csr and your root CA
file as input.
BUILD AND SIGN A CERTIFICATE SIGNING REQUEST
USING A LOCALLY INSTALLED ROOT CERTIFICATE/KEY -- this
script generates and signs a certificate in one step,
but it requires that the generated certificate and private
key files be copied to the destination host over a
secure channel.
1. ./build-key mycert (no password protection)
2. OR ./build-key-pass mycert (with password protection)
3. OR ./build-key-pkcs12 mycert (PKCS #12 format)
4. OR ./build-key-server mycert (with nsCertType=server)
5. mycert.crt and mycert.key will be built in your
KEY_DIR directory, and mycert.crt will be signed
by your root CA. If ./build-key-pkcs12 was used a
mycert.p12 file will also be created including the
private key, certificate and the ca certificate.
IMPORTANT
To avoid a possible Man-in-the-Middle attack where an authorized
client tries to connect to another client by impersonating the
server, make sure to enforce some kind of server certificate
verification by clients. There are currently four different ways
of accomplishing this, listed in the order of preference:
(1) Build your server certificates with the build-key-server
script. This will designate the certificate as a
server-only certificate by setting nsCertType=server.
Now add the following line to your client configuration:
ns-cert-type server
This will block clients from connecting to any
server which lacks the nsCertType=server designation
in its certificate, even if the certificate has been
signed by the CA which is cited in the OpenVPN configuration
file (--ca directive).
(2) Use the --tls-remote directive on the client to
accept/reject the server connection based on the common
name of the server certificate.
(3) Use a --tls-verify script or plugin to accept/reject the
server connection based on a custom test of the server
certificate's embedded X509 subject details.
(4) Sign server certificates with one CA and client certificates
with a different CA. The client config "ca" directive should
reference the server-signing CA while the server config "ca"
directive should reference the client-signing CA.
NOTES
Show certificate fields:
openssl x509 -in cert.crt -text

View File

@ -0,0 +1,44 @@
Extract all zip'd files to the OpenVPN home directory,
including the openssl.cnf file from the top-level
"easy-rsa" directory.
First run init-config.bat
Next, edit vars.bat to adapt it to your environment, and
create the directory that will hold your key files.
To generate TLS keys:
Create new empty index and serial files (once only)
1. vars
2. clean-all
Build a CA key (once only)
1. vars
2. build-ca
Build a DH file (for server side, once only)
1. vars
2. build-dh
Build a private key/certficate for the openvpn server
1. vars
2. build-key-server <machine-name>
Build key files in PEM format (for each client machine)
1. vars
2. build-key <machine-name>
(use <machine name> for specific name within script)
or
Build key files in PKCS #12 format (for each client machine)
1. vars
2. build-key-pkcs12 <machine-name>
(use <machine name> for specific name within script)
To revoke a TLS certificate and generate a CRL file:
1. vars
2. revoke-full <machine-name>
3. verify last line of output confirms revokation
4. copy crl.pem to server directory and ensure config file uses "crl-verify <crl filename>"

View File

@ -0,0 +1,4 @@
@echo off
cd %HOME%
rem build a cert authority valid for ten years, starting now
openssl req -days 3650 -nodes -new -x509 -keyout %KEY_DIR%\ca.key -out %KEY_DIR%\ca.crt -config %KEY_CONFIG%

View File

@ -0,0 +1,4 @@
@echo off
cd %HOME%
rem build a dh file for the server side
openssl dhparam -out %KEY_DIR%/dh%KEY_SIZE%.pem %KEY_SIZE%

View File

@ -0,0 +1,10 @@
@echo off
cd %HOME%
rem build a request for a cert that will be valid for ten years
openssl req -days 3650 -nodes -new -keyout %KEY_DIR%\%1.key -out %KEY_DIR%\%1.csr -config %KEY_CONFIG%
rem sign the cert request with our ca, creating a cert/key pair
openssl ca -days 3650 -out %KEY_DIR%\%1.crt -in %KEY_DIR%\%1.csr -config %KEY_CONFIG%
rem convert the key/cert and embed the ca cert into a pkcs12 file.
openssl pkcs12 -export -inkey %KEY_DIR%\%1.key -in %KEY_DIR%\%1.crt -certfile %KEY_DIR%\ca.crt -out %KEY_DIR%\%1.p12
rem delete any .old files created in this process, to avoid future file creation errors
del /q %KEY_DIR%\*.old

View File

@ -0,0 +1,8 @@
@echo off
cd %HOME%
rem build a request for a cert that will be valid for ten years
openssl req -days 3650 -nodes -new -keyout %KEY_DIR%\%1.key -out %KEY_DIR%\%1.csr -config %KEY_CONFIG%
rem sign the cert request with our ca, creating a cert/key pair
openssl ca -days 3650 -out %KEY_DIR%\%1.crt -in %KEY_DIR%\%1.csr -extensions server -config %KEY_CONFIG%
rem delete any .old files created in this process, to avoid future file creation errors
del /q %KEY_DIR%\*.old

View File

@ -0,0 +1,8 @@
@echo off
cd %HOME%
rem build a request for a cert that will be valid for ten years
openssl req -days 3650 -nodes -new -keyout %KEY_DIR%\%1.key -out %KEY_DIR%\%1.csr -config %KEY_CONFIG%
rem sign the cert request with our ca, creating a cert/key pair
openssl ca -days 3650 -out %KEY_DIR%\%1.crt -in %KEY_DIR%\%1.csr -config %KEY_CONFIG%
rem delete any .old files created in this process, to avoid future file creation errors
del /q %KEY_DIR%\*.old

View File

@ -0,0 +1,13 @@
@echo off
rem move to the HOME directory specified in VARS script
cd %HOME%
rem set a temporary KEY_DIR variable
set d=%KEY_DIR%
rem delete the KEY_DIR and any subdirs quietly
rmdir /s /q %d%
rem make a new KEY_DIR
mkdir %d%
rem copy in a fesh index file so we begin with an empty database
copy index.txt.start %d%\index.txt
rem copy in a fresh serial file so we begin generating keys at index 01
copy serial.start %d%\serial.

View File

View File

@ -0,0 +1,2 @@
copy vars.bat.sample vars.bat
copy openssl.cnf.sample openssl.cnf

View File

@ -0,0 +1,13 @@
@echo off
cd %HOME%
rem revoke cert
openssl ca -revoke %KEY_DIR%\%1.crt -config %KEY_CONFIG%
rem generate new crl
openssl ca -gencrl -out %KEY_DIR%\crl.pem -config %KEY_CONFIG%
rem test revocation
rem first concatinate ca cert with newly generated crl
copy %KEY_DIR%\ca.crt+%KEY_DIR%\crl.pem %KEY_DIR%\revoke_test_file.pem
rem now verify the revocation
openssl verify -CAfile %KEY_DIR%\revoke_test_file.pem -crl_check %KEY_DIR%\%1.crt
rem delete temporary test file
del /q %KEY_DIR%\revoke_test_file.pem

View File

@ -0,0 +1 @@
01

View File

@ -0,0 +1,35 @@
@echo off
rem Edit this variable to point to
rem the openssl.cnf file included
rem with easy-rsa.
set HOME=%ProgramFiles%\OpenVPN\easy-rsa
set KEY_CONFIG=openssl.cnf
rem Edit this variable to point to
rem your soon-to-be-created key
rem directory.
rem
rem WARNING: clean-all will do
rem a rm -rf on this directory
rem so make sure you define
rem it correctly!
set KEY_DIR=keys
rem Increase this to 2048 if you
rem are paranoid. This will slow
rem down TLS negotiation performance
rem as well as the one-time DH parms
rem generation process.
set KEY_SIZE=1024
rem These are the default values for fields
rem which will be placed in the certificate.
rem Change these to reflect your site.
rem Don't leave any of these parms blank.
set KEY_COUNTRY=US
set KEY_PROVINCE=CA
set KEY_CITY=SanFrancisco
set KEY_ORG=FortFunston
set KEY_EMAIL=mail@host.domain

13
easy-rsa/build-ca Executable file
View File

@ -0,0 +1,13 @@
#!/bin/sh
#
# Build a root certificate
#
if test $KEY_DIR; then
cd $KEY_DIR && \
openssl req -days 3650 -nodes -new -x509 -keyout ca.key -out ca.crt -config $KEY_CONFIG && \
chmod 0600 ca.key
else
echo you must define KEY_DIR
fi

12
easy-rsa/build-dh Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
#
# Build Diffie-Hellman parameters for the server side
# of an SSL/TLS connection.
#
if test $KEY_DIR; then
openssl dhparam -out ${KEY_DIR}/dh${KEY_SIZE}.pem ${KEY_SIZE}
else
echo you must define KEY_DIR
fi

19
easy-rsa/build-inter Executable file
View File

@ -0,0 +1,19 @@
#!/bin/sh
#
# Make an intermediate CA certificate/private key pair using a locally generated
# root certificate.
#
if test $# -ne 1; then
echo "usage: build-inter <name>";
exit 1
fi
if test $KEY_DIR; then
cd $KEY_DIR && \
openssl req -days 3650 -nodes -new -keyout $1.key -out $1.csr -config $KEY_CONFIG && \
openssl ca -extensions v3_ca -days 3650 -out $1.crt -in $1.csr -config $KEY_CONFIG
else
echo you must define KEY_DIR
fi

20
easy-rsa/build-key Executable file
View File

@ -0,0 +1,20 @@
#!/bin/sh
#
# Make a certificate/private key pair using a locally generated
# root certificate.
#
if test $# -ne 1; then
echo "usage: build-key <name>";
exit 1
fi
if test $KEY_DIR; then
cd $KEY_DIR && \
openssl req -days 3650 -nodes -new -keyout $1.key -out $1.csr -config $KEY_CONFIG && \
openssl ca -days 3650 -out $1.crt -in $1.csr -config $KEY_CONFIG && \
chmod 0600 $1.key
else
echo you must define KEY_DIR
fi

20
easy-rsa/build-key-pass Executable file
View File

@ -0,0 +1,20 @@
#!/bin/sh
#
# Similar to build-key, but protect the private key
# with a password.
#
if test $# -ne 1; then
echo "usage: build-key-pass <name>";
exit 1
fi
if test $KEY_DIR; then
cd $KEY_DIR && \
openssl req -days 3650 -new -keyout $1.key -out $1.csr -config $KEY_CONFIG && \
openssl ca -days 3650 -out $1.crt -in $1.csr -config $KEY_CONFIG && \
chmod 0600 $1.key
else
echo you must define KEY_DIR
fi

21
easy-rsa/build-key-pkcs12 Executable file
View File

@ -0,0 +1,21 @@
#!/bin/sh
#
# Make a certificate/private key pair using a locally generated
# root certificate and convert it to a PKCS #12 file including the
# the CA certificate as well.
if test $# -ne 1; then
echo "usage: build-key-pkcs12 <name>";
exit 1
fi
if test $KEY_DIR; then
cd $KEY_DIR && \
openssl req -days 3650 -nodes -new -keyout $1.key -out $1.csr -config $KEY_CONFIG && \
openssl ca -days 3650 -out $1.crt -in $1.csr -config $KEY_CONFIG && \
openssl pkcs12 -export -inkey $1.key -in $1.crt -certfile ca.crt -out $1.p12 && \
chmod 0600 $1.key $1.p12
else
echo you must define KEY_DIR
fi

22
easy-rsa/build-key-server Executable file
View File

@ -0,0 +1,22 @@
#!/bin/sh
#
# Make a certificate/private key pair using a locally generated
# root certificate.
#
# Explicitly set nsCertType to server using the "server"
# extension in the openssl.cnf file.
if test $# -ne 1; then
echo "usage: build-key-server <name>";
exit 1
fi
if test $KEY_DIR; then
cd $KEY_DIR && \
openssl req -days 3650 -nodes -new -keyout $1.key -out $1.csr -extensions server -config $KEY_CONFIG && \
openssl ca -days 3650 -out $1.crt -in $1.csr -extensions server -config $KEY_CONFIG && \
chmod 0600 $1.key
else
echo you must define KEY_DIR
fi

18
easy-rsa/build-req Executable file
View File

@ -0,0 +1,18 @@
#!/bin/sh
#
# Build a certificate signing request and private key. Use this
# when your root certificate and key is not available locally.
#
if test $# -ne 1; then
echo "usage: build-req <name>";
exit 1
fi
if test $KEY_DIR; then
cd $KEY_DIR && \
openssl req -days 3650 -nodes -new -keyout $1.key -out $1.csr -config $KEY_CONFIG
else
echo you must define KEY_DIR
fi

18
easy-rsa/build-req-pass Executable file
View File

@ -0,0 +1,18 @@
#!/bin/sh
#
# Like build-req, but protect your private key
# with a password.
#
if test $# -ne 1; then
echo "usage: build-req-pass <name>";
exit 1
fi
if test $KEY_DIR; then
cd $KEY_DIR && \
openssl req -days 3650 -new -keyout $1.key -out $1.csr -config $KEY_CONFIG
else
echo you must define KEY_DIR
fi

19
easy-rsa/clean-all Executable file
View File

@ -0,0 +1,19 @@
#!/bin/sh
#
# Initialize the $KEY_DIR directory.
# Note that this script does a
# rm -rf on $KEY_DIR so be careful!
#
d=$KEY_DIR
if test $d; then
rm -rf $d
mkdir $d && \
chmod go-rwx $d && \
touch $d/index.txt && \
echo 01 >$d/serial
else
echo you must define KEY_DIR
fi

18
easy-rsa/list-crl Normal file
View File

@ -0,0 +1,18 @@
#!/bin/sh
#
# list revoked certificates
#
#
if test $# -ne 1; then
echo "usage: list-crl <crlfile.pem>";
exit 1
fi
if test $KEY_DIR; then
cd $KEY_DIR && \
openssl crl -text -noout -in $1
else
echo you must define KEY_DIR
fi

18
easy-rsa/make-crl Normal file
View File

@ -0,0 +1,18 @@
#!/bin/sh
#
# generate a CRL
#
#
if test $# -ne 1; then
echo "usage: make-crl <crlfile.pem>";
exit 1
fi
if test $KEY_DIR; then
cd $KEY_DIR && \
openssl ca -gencrl -out $1 -config $KEY_CONFIG
else
echo you must define KEY_DIR
fi

255
easy-rsa/openssl.cnf Normal file
View File

@ -0,0 +1,255 @@
#
# OpenSSL example configuration file.
# This is mostly being used for generation of certificate requests.
#
# This definition stops the following lines choking if HOME isn't
# defined.
HOME = .
RANDFILE = $ENV::HOME/.rnd
# Extra OBJECT IDENTIFIER info:
#oid_file = $ENV::HOME/.oid
oid_section = new_oids
# To use this configuration file with the "-extfile" option of the
# "openssl x509" utility, name here the section containing the
# X.509v3 extensions to use:
# extensions =
# (Alternatively, use a configuration file that has only
# X.509v3 extensions in its main [= default] section.)
[ new_oids ]
# We can add new OIDs in here for use by 'ca' and 'req'.
# Add a simple OID like this:
# testoid1=1.2.3.4
# Or use config file substitution like this:
# testoid2=${testoid1}.5.6
####################################################################
[ ca ]
default_ca = CA_default # The default ca section
####################################################################
[ CA_default ]
dir = $ENV::KEY_DIR # Where everything is kept
certs = $dir # Where the issued certs are kept
crl_dir = $dir # Where the issued crl are kept
database = $dir/index.txt # database index file.
new_certs_dir = $dir # default place for new certs.
certificate = $dir/ca.crt # The CA certificate
serial = $dir/serial # The current serial number
crl = $dir/crl.pem # The current CRL
private_key = $dir/ca.key # The private key
RANDFILE = $dir/.rand # private random number file
x509_extensions = usr_cert # The extentions to add to the cert
# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
# so this is commented out by default to leave a V1 CRL.
# crl_extensions = crl_ext
default_days = 3650 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = md5 # which md to use.
preserve = no # keep passed DN ordering
# A few difference way of specifying how similar the request should look
# For type CA, the listed attributes must be the same, and the optional
# and supplied fields are just that :-)
policy = policy_match
# For the CA policy
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
# For the 'anything' policy
# At this point in time, you must list all acceptable 'object'
# types.
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
####################################################################
[ req ]
default_bits = $ENV::KEY_SIZE
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
attributes = req_attributes
x509_extensions = v3_ca # The extentions to add to the self signed cert
# Passwords for private keys if not present they will be prompted for
# input_password = secret
# output_password = secret
# This sets a mask for permitted string types. There are several options.
# default: PrintableString, T61String, BMPString.
# pkix : PrintableString, BMPString.
# utf8only: only UTF8Strings.
# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
# MASK:XXXX a literal mask value.
# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
# so use this option with caution!
string_mask = nombstr
# req_extensions = v3_req # The extensions to add to a certificate request
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = $ENV::KEY_COUNTRY
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = $ENV::KEY_PROVINCE
localityName = Locality Name (eg, city)
localityName_default = $ENV::KEY_CITY
0.organizationName = Organization Name (eg, company)
0.organizationName_default = $ENV::KEY_ORG
# we can do this but it is not needed normally :-)
#1.organizationName = Second Organization Name (eg, company)
#1.organizationName_default = World Wide Web Pty Ltd
organizationalUnitName = Organizational Unit Name (eg, section)
#organizationalUnitName_default =
commonName = Common Name (eg, your name or your server\'s hostname)
commonName_max = 64
emailAddress = Email Address
emailAddress_default = $ENV::KEY_EMAIL
emailAddress_max = 40
# SET-ex3 = SET extension number 3
[ req_attributes ]
challengePassword = A challenge password
challengePassword_min = 4
challengePassword_max = 20
unstructuredName = An optional company name
[ usr_cert ]
# These extensions are added when 'ca' signs a request.
# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.
basicConstraints=CA:FALSE
# Here are some examples of the usage of nsCertType. If it is omitted
# the certificate can be used for anything *except* object signing.
# This is OK for an SSL server.
# nsCertType = server
# For an object signing certificate this would be used.
# nsCertType = objsign
# For normal client use this is typical
# nsCertType = client, email
# and for everything including object signing:
# nsCertType = client, email, objsign
# This is typical in keyUsage for a client certificate.
# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
# This will be displayed in Netscape's comment listbox.
nsComment = "OpenSSL Generated Certificate"
# PKIX recommendations harmless if included in all certificates.
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer:always
# This stuff is for subjectAltName and issuerAltname.
# Import the email address.
# subjectAltName=email:copy
# Copy subject details
# issuerAltName=issuer:copy
#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
#nsBaseUrl
#nsRevocationUrl
#nsRenewalUrl
#nsCaPolicyUrl
#nsSslServerName
[ server ]
# JY ADDED -- Make a cert with nsCertType set to "server"
basicConstraints=CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer:always
[ v3_req ]
# Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
[ v3_ca ]
# Extensions for a typical CA
# PKIX recommendation.
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer:always
# This is what PKIX recommends but some broken software chokes on critical
# extensions.
#basicConstraints = critical,CA:true
# So we do this instead.
basicConstraints = CA:true
# Key usage: this is typical for a CA certificate. However since it will
# prevent it being used as an test self-signed certificate it is best
# left out by default.
# keyUsage = cRLSign, keyCertSign
# Some might want this also
# nsCertType = sslCA, emailCA
# Include email address in subject alt name: another PKIX recommendation
# subjectAltName=email:copy
# Copy issuer details
# issuerAltName=issuer:copy
# DER hex encoding of an extension: beware experts only!
# obj=DER:02:03
# Where 'obj' is a standard or added object
# You can even override a supported extension:
# basicConstraints= critical, DER:30:03:01:01:FF
[ crl_ext ]
# CRL extensions.
# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
# issuerAltName=issuer:copy
authorityKeyIdentifier=keyid:always,issuer:always

18
easy-rsa/revoke-crt Normal file
View File

@ -0,0 +1,18 @@
#!/bin/sh
#
# revoke a certificate
#
#
if test $# -ne 1; then
echo "usage: revoke-crt <file.crt>";
exit 1
fi
if test $KEY_DIR; then
cd $KEY_DIR && \
openssl ca -revoke $1 -config $KEY_CONFIG
else
echo you must define KEY_DIR
fi

29
easy-rsa/revoke-full Executable file
View File

@ -0,0 +1,29 @@
#!/bin/sh
# revoke a certificate, regenerate CRL,
# and verify revocation
CRL=crl.pem
RT=revoke-test.pem
if test $# -ne 1; then
echo "usage: revoke-full <name>";
exit 1
fi
if test $KEY_DIR; then
cd $KEY_DIR
rm -f $RT
# revoke key and generate a new CRL
openssl ca -revoke $1.crt -config $KEY_CONFIG
# generate a new CRL
openssl ca -gencrl -out $CRL -config $KEY_CONFIG
cat ca.crt $CRL >$RT
# verify the revocation
openssl verify -CAfile $RT -crl_check $1.crt
else
echo you must define KEY_DIR
fi

18
easy-rsa/sign-req Executable file
View File

@ -0,0 +1,18 @@
#!/bin/sh
#
# Sign a certificate signing request (a .csr file)
# with a local root certificate and key.
#
if test $# -ne 1; then
echo "usage: sign-req <name>";
exit 1
fi
if test $KEY_DIR; then
cd $KEY_DIR && \
openssl ca -days 3650 -out $1.crt -in $1.csr -config $KEY_CONFIG
else
echo you must define KEY_DIR
fi

49
easy-rsa/vars Normal file
View File

@ -0,0 +1,49 @@
# easy-rsa parameter settings
# NOTE: If you installed from an RPM,
# don't edit this file in place in
# /usr/share/openvpn/easy-rsa --
# instead, you should copy the whole
# easy-rsa directory to another location
# (such as /etc/openvpn) so that your
# edits will not be wiped out by a future
# OpenVPN package upgrade.
# This variable should point to
# the top level of the easy-rsa
# tree.
export D=`pwd`
# This variable should point to
# the openssl.cnf file included
# with easy-rsa.
export KEY_CONFIG=$D/openssl.cnf
# Edit this variable to point to
# your soon-to-be-created key
# directory.
#
# WARNING: clean-all will do
# a rm -rf on this directory
# so make sure you define
# it correctly!
export KEY_DIR=$D/keys
# Issue rm -rf warning
echo NOTE: when you run ./clean-all, I will be doing a rm -rf on $KEY_DIR
# Increase this to 2048 if you
# are paranoid. This will slow
# down TLS negotiation performance
# as well as the one-time DH parms
# generation process.
export KEY_SIZE=1024
# These are the default values for fields
# which will be placed in the certificate.
# Don't leave any of these fields blank.
export KEY_COUNTRY=KG
export KEY_PROVINCE=NA
export KEY_CITY=BISHKEK
export KEY_ORG="OpenVPN-TEST"
export KEY_EMAIL="me@myhost.mydomain"

161
errlevel.h Normal file
View File

@ -0,0 +1,161 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef ERRLEVEL_H
#define ERRLEVEL_H
#include "error.h"
/*
* Debug level at and above where we
* display time to microsecond resolution.
*/
#define DEBUG_LEVEL_USEC_TIME 4
/*
* In non-server modes, delay n milliseconds after certain kinds
* of non-fatal network errors to avoid a barrage of errors.
*
* To disable all delays, set to 0.
*/
#define P2P_ERROR_DELAY_MS 0
/*
* Enable D_LOG_RW
*/
#define LOG_RW
/*
* Debugging levels for various kinds
* of output.
*/
#define M_VERB0 LOGLEV(0, 0, 0) /* Messages displayed even at --verb 0 (fatal errors only) */
#define M_INFO LOGLEV(1, 0, 0) /* default informational messages */
#define D_LINK_ERRORS LOGLEV(1, 1, M_NONFATAL) /* show link errors from main event loop */
#define D_CRYPT_ERRORS LOGLEV(1, 2, M_NONFATAL) /* show errors from encrypt/decrypt */
#define D_TLS_ERRORS LOGLEV(1, 3, M_NONFATAL) /* show TLS control channel errors */
#define D_RESOLVE_ERRORS LOGLEV(1, 4, M_NONFATAL) /* show hostname resolve errors */
#define D_COMP_ERRORS LOGLEV(1, 5, M_NONFATAL) /* show compression errors */
#define D_REPLAY_ERRORS LOGLEV(1, 6, M_NONFATAL) /* show packet replay errors */
#define D_STREAM_ERRORS LOGLEV(1, 7, M_NONFATAL) /* TCP stream error requiring restart */
#define D_IMPORT_ERRORS LOGLEV(1, 8, M_NONFATAL) /* show server import option errors */
#define D_MULTI_ERRORS LOGLEV(1, 9, M_NONFATAL) /* show multi-client server errors */
#define D_EVENT_ERRORS LOGLEV(1, 10, M_NONFATAL) /* show event.[ch] errors */
#define D_PUSH_ERRORS LOGLEV(1, 11, M_NONFATAL) /* show push/pull errors */
#define D_PID_PERSIST LOGLEV(1, 12, M_NONFATAL) /* show packet_id persist errors */
#define D_FRAG_ERRORS LOGLEV(1, 13, M_NONFATAL) /* show fragmentation errors */
#define D_ALIGN_ERRORS LOGLEV(1, 14, M_NONFATAL) /* show bad struct alignments */
#define D_HANDSHAKE LOGLEV(2, 20, 0) /* show data & control channel handshakes */
#define D_MTU_INFO LOGLEV(2, 21, 0) /* show terse MTU info */
#define D_CLOSE LOGLEV(2, 22, 0) /* show socket and TUN/TAP close */
#define D_SHOW_OCC_HASH LOGLEV(2, 23, 0) /* show MD5 hash of option compatibility string */
#define D_PROXY LOGLEV(2, 24, 0) /* show http proxy control packets */
#define D_TLS_DEBUG_LOW LOGLEV(3, 20, 0) /* low frequency info from tls_session routines */
#define D_GREMLIN LOGLEV(3, 30, 0) /* show simulated outage info from gremlin module */
#define D_GENKEY LOGLEV(3, 31, 0) /* print message after key generation */
#define D_ROUTE LOGLEV(3, 0, 0) /* show routes added and deleted (don't mute) */
#define D_TUNTAP_INFO LOGLEV(3, 32, 0) /* show debugging info from TUN/TAP driver */
#define D_RESTART LOGLEV(3, 33, 0) /* show certain restart messages */
#define D_PUSH LOGLEV(3, 34, 0) /* show push/pull info */
#define D_IFCONFIG_POOL LOGLEV(3, 35, 0) /* show ifconfig pool info */
#define D_BACKTRACK LOGLEV(3, 36, 0) /* show replay backtracks */
#define D_AUTH LOGLEV(3, 37, 0) /* show user/pass auth info */
#define D_MULTI_LOW LOGLEV(3, 38, 0) /* show point-to-multipoint low-freq debug info */
#define D_MULTI_DROPPED LOGLEV(3, 39, 0) /* show point-to-multipoint packet drops */
#define D_PLUGIN LOGLEV(3, 40, 0) /* show plugin calls */
#define D_MANAGEMENT LOGLEV(3, 41, 0) /* show --management info */
#define D_SCHED_EXIT LOGLEV(3, 42, 0) /* show arming of scheduled exit */
#define D_ROUTE_QUOTA LOGLEV(3, 43, 0) /* show route quota exceeded messages */
#define D_SHOW_PARMS LOGLEV(4, 50, 0) /* show all parameters on program initiation */
#define D_SHOW_OCC LOGLEV(4, 51, 0) /* show options compatibility string */
#define D_LOW LOGLEV(4, 52, 0) /* miscellaneous low-frequency debug info */
#define D_DHCP_OPT LOGLEV(4, 53, 0) /* show DHCP options binary string */
#define D_OSBUF LOGLEV(4, 54, 0) /* show socket/tun/tap buffer sizes */
#define D_MBUF LOGLEV(4, 55, 0) /* mbuf.[ch] routines */
#define D_LOG_RW LOGLEV(5, 0, 0) /* Print 'R' or 'W' to stdout for read/write */
#define D_LINK_RW LOGLEV(6, 60, M_DEBUG) /* show TCP/UDP reads/writes (terse) */
#define D_TAP_WIN32_DEBUG LOGLEV(6, 60, M_DEBUG) /* show TAP-Win32 driver debug info */
#define D_SHOW_KEYS LOGLEV(7, 70, M_DEBUG) /* show data channel encryption keys */
#define D_SHOW_KEY_SOURCE LOGLEV(7, 70, M_DEBUG) /* show data channel key source entropy */
#define D_REL_LOW LOGLEV(7, 70, M_DEBUG) /* show low frequency info from reliable layer */
#define D_FRAG_DEBUG LOGLEV(7, 70, M_DEBUG) /* show fragment debugging info */
#define D_WIN32_IO_LOW LOGLEV(7, 70, M_DEBUG) /* low freq win32 I/O debugging info */
#define D_MTU_DEBUG LOGLEV(7, 70, M_DEBUG) /* show MTU debugging info */
#define D_PID_DEBUG_LOW LOGLEV(7, 70, M_DEBUG) /* show low-freq packet-id debugging info */
#define D_MULTI_DEBUG LOGLEV(7, 70, M_DEBUG) /* show medium-freq multi debugging info */
#define D_MSS LOGLEV(7, 70, M_DEBUG) /* show MSS adjustments */
#define D_COMP_LOW LOGLEV(7, 70, M_DEBUG) /* show adaptive compression state changes */
#define D_REMOTE_LIST LOGLEV(7, 70, M_DEBUG) /* show --remote list */
#define D_SCRIPT LOGLEV(7, 70, M_DEBUG) /* show parms & env vars passed to scripts */
#define D_SHOW_NET LOGLEV(7, 70, M_DEBUG) /* show routing table and adapter list */
#define D_ROUTE_DEBUG LOGLEV(7, 70, M_DEBUG) /* show verbose route.[ch] output */
#define D_TLS_STATE_ERRORS LOGLEV(7, 70, M_DEBUG) /* no TLS state for client */
#define D_SEMAPHORE_LOW LOGLEV(7, 70, M_DEBUG) /* show Win32 semaphore waits (low freq) */
#define D_SEMAPHORE LOGLEV(7, 70, M_DEBUG) /* show Win32 semaphore waits */
#define D_TEST_FILE LOGLEV(7, 70, M_DEBUG) /* show test_file() calls */
#define D_MANAGEMENT_DEBUG LOGLEV(7, 70, M_DEBUG) /* show --management debug info */
#define D_PLUGIN_DEBUG LOGLEV(7, 70, M_DEBUG) /* show verbose plugin calls */
#define D_SOCKET_DEBUG LOGLEV(7, 70, M_DEBUG) /* show socket.[ch] debugging info */
#define D_ALIGN_DEBUG LOGLEV(7, 70, M_DEBUG) /* show verbose struct alignment info */
#define D_HANDSHAKE_VERBOSE LOGLEV(8, 70, M_DEBUG) /* show detailed description of each handshake */
#define D_TLS_DEBUG_MED LOGLEV(8, 70, M_DEBUG) /* limited info from tls_session routines */
#define D_INTERVAL LOGLEV(8, 70, M_DEBUG) /* show interval.h debugging info */
#define D_SCHEDULER LOGLEV(8, 70, M_DEBUG) /* show scheduler debugging info */
#define D_GREMLIN_VERBOSE LOGLEV(8, 70, M_DEBUG) /* show verbose info from gremlin module */
#define D_REL_DEBUG LOGLEV(8, 70, M_DEBUG) /* show detailed info from reliable routines */
#define D_EVENT_WAIT LOGLEV(8, 70, M_DEBUG) /* show detailed info from event waits */
#define D_TUN_RW LOGLEV(8, 70, M_DEBUG) /* show TUN/TAP reads/writes */
#define D_MULTI_TCP LOGLEV(8, 70, M_DEBUG) /* show debug info from mtcp.c */
#define D_TLS_DEBUG LOGLEV(9, 70, M_DEBUG) /* show detailed info from TLS routines */
#define D_CRYPTO_DEBUG LOGLEV(9, 70, M_DEBUG) /* show detailed info from crypto.c routines */
#define D_COMP LOGLEV(9, 70, M_DEBUG) /* show compression info */
#define D_READ_WRITE LOGLEV(9, 70, M_DEBUG) /* show all tun/tcp/udp reads/writes/opens */
#define D_PACKET_CONTENT LOGLEV(9, 70, M_DEBUG) /* show before/after encryption packet content */
#define D_TLS_NO_SEND_KEY LOGLEV(9, 70, M_DEBUG) /* show when no data channel send-key exists */
#define D_PID_DEBUG LOGLEV(9, 70, M_DEBUG) /* show packet-id debugging info */
#define D_PID_PERSIST_DEBUG LOGLEV(9, 70, M_DEBUG) /* show packet-id persist debugging info */
#define D_LINK_RW_VERBOSE LOGLEV(9, 70, M_DEBUG) /* show link reads/writes with greater verbosity */
#define D_STREAM_DEBUG LOGLEV(9, 70, M_DEBUG) /* show TCP stream debug info */
#define D_WIN32_IO LOGLEV(9, 70, M_DEBUG) /* win32 I/O debugging info */
#define D_SHAPER_DEBUG LOGLEV(10, 70, M_DEBUG) /* show traffic shaper info */
#define D_REGISTRY LOGLEV(11, 70, M_DEBUG) /* win32 registry debugging info */
#define D_OPENSSL_LOCK LOGLEV(11, 70, M_DEBUG) /* show OpenSSL locks */
#define D_THREAD_DEBUG LOGLEV(4, 70, M_DEBUG) /* JYFIXME -- show pthread debug information */
#endif

852
error.c Normal file
View File

@ -0,0 +1,852 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef WIN32
#include "config-win32.h"
#else
#include "config.h"
#endif
#include "syshead.h"
#include "error.h"
#include "buffer.h"
#include "thread.h"
#include "misc.h"
#include "win32.h"
#include "socket.h"
#include "tun.h"
#include "otime.h"
#include "perf.h"
#include "status.h"
#include "integer.h"
#ifdef USE_CRYPTO
#include <openssl/err.h>
#endif
#include "memdbg.h"
#if SYSLOG_CAPABILITY
#ifndef LOG_OPENVPN
#define LOG_OPENVPN LOG_DAEMON
#endif
#endif
/* Globals */
unsigned int x_debug_level; /* GLOBAL */
/* Mute state */
static int mute_cutoff; /* GLOBAL */
static int mute_count; /* GLOBAL */
static int mute_category; /* GLOBAL */
/*
* Output mode priorities are as follows:
*
* (1) --log-x overrides everything
* (2) syslog is used if --daemon or --inetd is defined and not --log-x
* (3) if OPENVPN_DEBUG_COMMAND_LINE is defined, output
* to constant logfile name.
* (4) Output to stdout.
*/
/* If true, indicates that stdin/stdout/stderr
have been redirected due to --log */
static bool std_redir; /* GLOBAL */
/* Should messages be written to the syslog? */
static bool use_syslog; /* GLOBAL */
/* Should timestamps be included on messages to stdout/stderr? */
static bool suppress_timestamps; /* GLOBAL */
/* The program name passed to syslog */
static char *pgmname_syslog; /* GLOBAL */
/* If non-null, messages should be written here (used for debugging only) */
static FILE *msgfp; /* GLOBAL */
bool
set_debug_level (const int level, const unsigned int flags)
{
const int ceiling = 15;
if (level >= 0 && level <= ceiling)
{
x_debug_level = level;
return true;
}
else if (flags & SDL_CONSTRAIN)
{
x_debug_level = constrain_int (level, 0, ceiling);
return true;
}
return false;
}
bool
set_mute_cutoff (const int cutoff)
{
if (cutoff >= 0)
{
mute_cutoff = cutoff;
return true;
}
else
return false;
}
int
get_debug_level (void)
{
return x_debug_level;
}
int
get_mute_cutoff (void)
{
return mute_cutoff;
}
void
set_suppress_timestamps (bool suppressed)
{
suppress_timestamps = suppressed;
}
void
error_reset ()
{
use_syslog = std_redir = false;
suppress_timestamps = false;
x_debug_level = 1;
mute_cutoff = 0;
mute_count = 0;
mute_category = 0;
#ifdef OPENVPN_DEBUG_COMMAND_LINE
msgfp = fopen (OPENVPN_DEBUG_FILE, "w");
if (!msgfp)
openvpn_exit (OPENVPN_EXIT_STATUS_CANNOT_OPEN_DEBUG_FILE); /* exit point */
#else
msgfp = NULL;
#endif
}
/*
* Return a file to print messages to before syslog is opened.
*/
FILE *
msg_fp()
{
FILE *fp = msgfp;
if (!fp)
fp = OPENVPN_MSG_FP;
if (!fp)
openvpn_exit (OPENVPN_EXIT_STATUS_CANNOT_OPEN_DEBUG_FILE); /* exit point */
return fp;
}
#define SWAP { tmp = m1; m1 = m2; m2 = tmp; }
int x_msg_line_num; /* GLOBAL */
void x_msg (const unsigned int flags, const char *format, ...)
{
struct gc_arena gc;
va_list arglist;
#if SYSLOG_CAPABILITY
int level;
#endif
char *m1;
char *m2;
char *tmp;
int e;
const char *prefix;
const char *prefix_sep;
void usage_small (void);
#ifndef HAVE_VARARG_MACROS
/* the macro has checked this otherwise */
if (!MSG_TEST (flags))
return;
#endif
if (flags & M_ERRNO_SOCK)
e = openvpn_errno_socket ();
else
e = openvpn_errno ();
/*
* Apply muting filter.
*/
#ifndef HAVE_VARARG_MACROS
/* the macro has checked this otherwise */
if (!dont_mute (flags))
return;
#endif
gc_init (&gc);
mutex_lock_static (L_MSG);
m1 = (char *) gc_malloc (ERR_BUF_SIZE, false, &gc);
m2 = (char *) gc_malloc (ERR_BUF_SIZE, false, &gc);
va_start (arglist, format);
vsnprintf (m1, ERR_BUF_SIZE, format, arglist);
va_end (arglist);
m1[ERR_BUF_SIZE - 1] = 0; /* windows vsnprintf needs this */
if ((flags & (M_ERRNO|M_ERRNO_SOCK)) && e)
{
openvpn_snprintf (m2, ERR_BUF_SIZE, "%s: %s (errno=%d)",
m1, strerror_ts (e, &gc), e);
SWAP;
}
#ifdef USE_CRYPTO
if (flags & M_SSL)
{
int nerrs = 0;
int err;
while ((err = ERR_get_error ()))
{
openvpn_snprintf (m2, ERR_BUF_SIZE, "%s: %s",
m1, ERR_error_string (err, NULL));
SWAP;
++nerrs;
}
if (!nerrs)
{
openvpn_snprintf (m2, ERR_BUF_SIZE, "%s (OpenSSL)", m1);
SWAP;
}
}
#endif
if (flags & M_OPTERR)
{
openvpn_snprintf (m2, ERR_BUF_SIZE, "Options error: %s", m1);
SWAP;
}
#if SYSLOG_CAPABILITY
if (flags & (M_FATAL|M_NONFATAL|M_USAGE_SMALL))
level = LOG_ERR;
else if (flags & M_WARN)
level = LOG_WARNING;
else
level = LOG_NOTICE;
#endif
/* set up client prefix */
prefix = msg_get_prefix ();
prefix_sep = " ";
if (!prefix)
prefix_sep = prefix = "";
/* virtual output capability used to copy output to management subsystem */
{
const struct virtual_output *vo = msg_get_virtual_output ();
if (vo)
{
openvpn_snprintf (m2, ERR_BUF_SIZE, "%s%s%s",
prefix,
prefix_sep,
m1);
virtual_output_print (vo, flags, m2);
}
}
if (!(flags & M_MSG_VIRT_OUT))
{
if (use_syslog && !std_redir)
{
#if SYSLOG_CAPABILITY
syslog (level, "%s%s%s",
prefix,
prefix_sep,
m1);
#endif
}
else
{
FILE *fp = msg_fp();
const bool show_usec = check_debug_level (DEBUG_LEVEL_USEC_TIME);
if ((flags & M_NOPREFIX) || suppress_timestamps)
{
fprintf (fp, "%s%s%s\n",
prefix,
prefix_sep,
m1);
}
else
{
#ifdef USE_PTHREAD
fprintf (fp, "%s [%d] %s%s%s\n",
time_string (0, 0, show_usec, &gc),
(int) openvpn_thread_self (),
prefix,
prefix_sep,
m1);
#else
fprintf (fp, "%s %s%s%s\n",
time_string (0, 0, show_usec, &gc),
prefix,
prefix_sep,
m1);
#endif
}
fflush(fp);
++x_msg_line_num;
}
}
if (flags & M_FATAL)
msg (M_INFO, "Exiting");
mutex_unlock_static (L_MSG);
if (flags & M_FATAL)
openvpn_exit (OPENVPN_EXIT_STATUS_ERROR); /* exit point */
if (flags & M_USAGE_SMALL)
usage_small ();
gc_free (&gc);
}
/*
* Apply muting filter.
*/
bool
dont_mute (unsigned int flags)
{
bool ret = true;
if (mute_cutoff > 0 && !(flags & M_NOMUTE))
{
const int mute_level = DECODE_MUTE_LEVEL (flags);
if (mute_level > 0 && mute_level == mute_category)
{
if (mute_count == mute_cutoff)
msg (M_INFO | M_NOMUTE, "NOTE: --mute triggered...");
if (++mute_count > mute_cutoff)
ret = false;
}
else
{
const int suppressed = mute_count - mute_cutoff;
if (suppressed > 0)
msg (M_INFO | M_NOMUTE,
"%d variation(s) on previous %d message(s) suppressed by --mute",
suppressed,
mute_cutoff);
mute_count = 1;
mute_category = mute_level;
}
}
return ret;
}
void
assert_failed (const char *filename, int line)
{
msg (M_FATAL, "Assertion failed at %s:%d", filename, line);
}
/*
* Fail memory allocation. Don't use msg() because it tries
* to allocate memory as part of its operation.
*/
void
out_of_memory (void)
{
fprintf (stderr, PACKAGE_NAME ": Out of Memory\n");
exit (1);
}
void
open_syslog (const char *pgmname, bool stdio_to_null)
{
#if SYSLOG_CAPABILITY
if (!msgfp && !std_redir)
{
if (!use_syslog)
{
pgmname_syslog = string_alloc (pgmname ? pgmname : PACKAGE, NULL);
openlog (pgmname_syslog, LOG_PID, LOG_OPENVPN);
use_syslog = true;
/* Better idea: somehow pipe stdout/stderr output to msg() */
if (stdio_to_null)
set_std_files_to_null (false);
}
}
#else
msg (M_WARN, "Warning on use of --daemon/--inetd: this operating system lacks daemon logging features, therefore when I become a daemon, I won't be able to log status or error messages");
#endif
}
void
close_syslog ()
{
#if SYSLOG_CAPABILITY
if (use_syslog)
{
closelog();
use_syslog = false;
if (pgmname_syslog)
{
free (pgmname_syslog);
pgmname_syslog = NULL;
}
}
#endif
}
#ifdef WIN32
static HANDLE orig_stderr;
HANDLE
get_orig_stderr (void)
{
if (orig_stderr)
return orig_stderr;
else
return GetStdHandle (STD_ERROR_HANDLE);
}
#endif
void
redirect_stdout_stderr (const char *file, bool append)
{
#if defined(WIN32)
if (!std_redir)
{
HANDLE log_handle;
int log_fd;
struct security_attributes sa;
init_security_attributes_allow_all (&sa);
log_handle = CreateFile (file,
GENERIC_WRITE,
FILE_SHARE_READ,
&sa.sa,
append ? OPEN_ALWAYS : CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (log_handle == INVALID_HANDLE_VALUE)
{
msg (M_WARN|M_ERRNO, "Warning: cannot open --log file: %s", file);
return;
}
/* append to logfile? */
if (append)
{
if (SetFilePointer (log_handle, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
msg (M_ERR, "Error: cannot seek to end of --log file: %s", file);
}
/* save original stderr for password prompts */
orig_stderr = GetStdHandle (STD_ERROR_HANDLE);
/* set up for redirection */
if (!SetStdHandle (STD_OUTPUT_HANDLE, log_handle)
|| !SetStdHandle (STD_ERROR_HANDLE, log_handle))
msg (M_ERR, "Error: cannot redirect stdout/stderr to --log file: %s", file);
/* direct stdout/stderr to point to log_handle */
log_fd = _open_osfhandle ((intptr_t)log_handle, _O_TEXT);
if (log_fd == -1)
msg (M_ERR, "Error: --log redirect failed due to _open_osfhandle failure");
/* open log_handle as FILE stream */
ASSERT (msgfp == NULL);
msgfp = _fdopen (log_fd, "w");
if (msgfp == NULL)
msg (M_ERR, "Error: --log redirect failed due to _fdopen");
std_redir = true;
}
#elif defined(HAVE_DUP2)
if (!std_redir)
{
int out = open (file,
O_CREAT | O_WRONLY | (append ? O_APPEND : O_TRUNC),
S_IRUSR | S_IWUSR);
if (out < 0)
{
msg (M_WARN|M_ERRNO, "Warning: Error redirecting stdout/stderr to --log file: %s", file);
return;
}
if (dup2 (out, 1) == -1)
msg (M_ERR, "--log file redirection error on stdout");
if (dup2 (out, 2) == -1)
msg (M_ERR, "--log file redirection error on stderr");
if (out > 2)
close (out);
std_redir = true;
}
#else
msg (M_WARN, "WARNING: The --log option is not supported on this OS because it lacks the dup2 function");
#endif
}
/*
* Functions used to check return status
* of I/O operations.
*/
unsigned int x_cs_info_level; /* GLOBAL */
unsigned int x_cs_verbose_level; /* GLOBAL */
unsigned int x_cs_err_delay_ms; /* GLOBAL */
void
reset_check_status ()
{
x_cs_info_level = 0;
x_cs_verbose_level = 0;
}
void
set_check_status (unsigned int info_level, unsigned int verbose_level)
{
x_cs_info_level = info_level;
x_cs_verbose_level = verbose_level;
}
/*
* Called after most socket or tun/tap operations, via the inline
* function check_status().
*
* Decide if we should print an error message, and see if we can
* extract any useful info from the error, such as a Path MTU hint
* from the OS.
*/
void
x_check_status (int status,
const char *description,
struct link_socket *sock,
struct tuntap *tt)
{
const int my_errno = (sock ? openvpn_errno_socket () : openvpn_errno ());
const char *extended_msg = NULL;
msg (x_cs_verbose_level, "%s %s returned %d",
sock ? proto2ascii (sock->info.proto, true) : "",
description,
status);
if (status < 0)
{
struct gc_arena gc = gc_new ();
#if EXTENDED_SOCKET_ERROR_CAPABILITY
/* get extended socket error message and possible PMTU hint from OS */
if (sock)
{
int mtu;
extended_msg = format_extended_socket_error (sock->sd, &mtu, &gc);
if (mtu > 0 && sock->mtu != mtu)
{
sock->mtu = mtu;
sock->info.mtu_changed = true;
}
}
#elif defined(WIN32)
/* get possible driver error from TAP-Win32 driver */
extended_msg = tap_win32_getinfo (tt, &gc);
#endif
if (!ignore_sys_error (my_errno))
{
if (extended_msg)
msg (x_cs_info_level, "%s %s [%s]: %s (code=%d)",
description,
sock ? proto2ascii (sock->info.proto, true) : "",
extended_msg,
strerror_ts (my_errno, &gc),
my_errno);
else
msg (x_cs_info_level, "%s %s: %s (code=%d)",
description,
sock ? proto2ascii (sock->info.proto, true) : "",
strerror_ts (my_errno, &gc),
my_errno);
if (x_cs_err_delay_ms)
sleep_milliseconds (x_cs_err_delay_ms);
}
gc_free (&gc);
}
}
/*
* In multiclient mode, put a client-specific prefix
* before each message.
*/
const char *x_msg_prefix; /* GLOBAL */
#ifdef USE_PTHREAD
pthread_key_t x_msg_prefix_key; /* GLOBAL */
#endif
/*
* Allow MSG to be redirected through a virtual_output object
*/
const struct virtual_output *x_msg_virtual_output; /* GLOBAL */
/*
* Init thread-local variables
*/
void
msg_thread_init (void)
{
#ifdef USE_PTHREAD
ASSERT (!pthread_key_create (&x_msg_prefix_key, NULL));
#endif
}
void
msg_thread_uninit (void)
{
#ifdef USE_PTHREAD
pthread_key_delete (x_msg_prefix_key);
#endif
}
/*
* Exiting.
*/
void
openvpn_exit (const int status)
{
#ifdef ENABLE_PLUGIN
void plugin_abort (void);
#endif
#ifdef WIN32
uninit_win32 ();
#endif
close_syslog ();
#ifdef ENABLE_PLUGIN
plugin_abort ();
#endif
#ifdef ABORT_ON_ERROR
if (status == OPENVPN_EXIT_STATUS_ERROR)
abort ();
#endif
if (status == OPENVPN_EXIT_STATUS_GOOD)
perf_output_results ();
exit (status);
}
/*
* Translate msg flags into a string
*/
const char *
msg_flags_string (const unsigned int flags, struct gc_arena *gc)
{
struct buffer out = alloc_buf_gc (16, gc);
if (flags == M_INFO)
buf_printf (&out, "I");
if (flags & M_FATAL)
buf_printf (&out, "F");
if (flags & M_NONFATAL)
buf_printf (&out, "N");
if (flags & M_WARN)
buf_printf (&out, "W");
if (flags & M_DEBUG)
buf_printf (&out, "D");
return BSTR (&out);
}
#ifdef WIN32
const char *
strerror_win32 (DWORD errnum, struct gc_arena *gc)
{
/*
* This code can be omitted, though often the Windows
* WSA error messages are less informative than the
* Posix equivalents.
*/
#if 1
switch (errnum) {
/*
* When the TAP-Win32 driver returns STATUS_UNSUCCESSFUL, this code
* gets returned to user space.
*/
case ERROR_GEN_FAILURE:
return "General failure (ERROR_GEN_FAILURE)";
case ERROR_IO_PENDING:
return "I/O Operation in progress (ERROR_IO_PENDING)";
case WSA_IO_INCOMPLETE:
return "I/O Operation in progress (WSA_IO_INCOMPLETE)";
case WSAEINTR:
return "Interrupted system call (WSAEINTR)";
case WSAEBADF:
return "Bad file number (WSAEBADF)";
case WSAEACCES:
return "Permission denied (WSAEACCES)";
case WSAEFAULT:
return "Bad address (WSAEFAULT)";
case WSAEINVAL:
return "Invalid argument (WSAEINVAL)";
case WSAEMFILE:
return "Too many open files (WSAEMFILE)";
case WSAEWOULDBLOCK:
return "Operation would block (WSAEWOULDBLOCK)";
case WSAEINPROGRESS:
return "Operation now in progress (WSAEINPROGRESS)";
case WSAEALREADY:
return "Operation already in progress (WSAEALREADY)";
case WSAEDESTADDRREQ:
return "Destination address required (WSAEDESTADDRREQ)";
case WSAEMSGSIZE:
return "Message too long (WSAEMSGSIZE)";
case WSAEPROTOTYPE:
return "Protocol wrong type for socket (WSAEPROTOTYPE)";
case WSAENOPROTOOPT:
return "Bad protocol option (WSAENOPROTOOPT)";
case WSAEPROTONOSUPPORT:
return "Protocol not supported (WSAEPROTONOSUPPORT)";
case WSAESOCKTNOSUPPORT:
return "Socket type not supported (WSAESOCKTNOSUPPORT)";
case WSAEOPNOTSUPP:
return "Operation not supported on socket (WSAEOPNOTSUPP)";
case WSAEPFNOSUPPORT:
return "Protocol family not supported (WSAEPFNOSUPPORT)";
case WSAEAFNOSUPPORT:
return "Address family not supported by protocol family (WSAEAFNOSUPPORT)";
case WSAEADDRINUSE:
return "Address already in use (WSAEADDRINUSE)";
case WSAENETDOWN:
return "Network is down (WSAENETDOWN)";
case WSAENETUNREACH:
return "Network is unreachable (WSAENETUNREACH)";
case WSAENETRESET:
return "Net dropped connection or reset (WSAENETRESET)";
case WSAECONNABORTED:
return "Software caused connection abort (WSAECONNABORTED)";
case WSAECONNRESET:
return "Connection reset by peer (WSAECONNRESET)";
case WSAENOBUFS:
return "No buffer space available (WSAENOBUFS)";
case WSAEISCONN:
return "Socket is already connected (WSAEISCONN)";
case WSAENOTCONN:
return "Socket is not connected (WSAENOTCONN)";
case WSAETIMEDOUT:
return "Connection timed out (WSAETIMEDOUT)";
case WSAECONNREFUSED:
return "Connection refused (WSAECONNREFUSED)";
case WSAELOOP:
return "Too many levels of symbolic links (WSAELOOP)";
case WSAENAMETOOLONG:
return "File name too long (WSAENAMETOOLONG)";
case WSAEHOSTDOWN:
return "Host is down (WSAEHOSTDOWN)";
case WSAEHOSTUNREACH:
return "No Route to Host (WSAEHOSTUNREACH)";
case WSAENOTEMPTY:
return "Directory not empty (WSAENOTEMPTY)";
case WSAEPROCLIM:
return "Too many processes (WSAEPROCLIM)";
case WSAEUSERS:
return "Too many users (WSAEUSERS)";
case WSAEDQUOT:
return "Disc Quota Exceeded (WSAEDQUOT)";
case WSAESTALE:
return "Stale NFS file handle (WSAESTALE)";
case WSASYSNOTREADY:
return "Network SubSystem is unavailable (WSASYSNOTREADY)";
case WSAVERNOTSUPPORTED:
return "WINSOCK DLL Version out of range (WSAVERNOTSUPPORTED)";
case WSANOTINITIALISED:
return "Successful WSASTARTUP not yet performed (WSANOTINITIALISED)";
case WSAEREMOTE:
return "Too many levels of remote in path (WSAEREMOTE)";
case WSAHOST_NOT_FOUND:
return "Host not found (WSAHOST_NOT_FOUND)";
default:
break;
}
#endif
/* format a windows error message */
{
char message[256];
struct buffer out = alloc_buf_gc (256, gc);
const int status = FormatMessage (
FORMAT_MESSAGE_IGNORE_INSERTS
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL,
errnum,
0,
message,
sizeof (message),
NULL);
if (!status)
{
buf_printf (&out, "[Unknown Win32 Error]");
}
else
{
char *cp;
for (cp = message; *cp != '\0'; ++cp)
{
if (*cp == '\n' || *cp == '\r')
*cp = ' ';
}
buf_printf(&out, "%s", message);
}
return BSTR (&out);
}
}
#endif

342
error.h Normal file
View File

@ -0,0 +1,342 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef ERROR_H
#define ERROR_H
#include "basic.h"
#include "thread.h"
/* #define ABORT_ON_ERROR */
#define ERR_BUF_SIZE 1024
struct gc_arena;
/*
* Where should messages be printed before syslog is opened?
* Not used if OPENVPN_DEBUG_COMMAND_LINE is defined.
*/
#define OPENVPN_MSG_FP stdout
/*
* Exit status codes
*/
#define OPENVPN_EXIT_STATUS_GOOD 0
#define OPENVPN_EXIT_STATUS_ERROR 1
#define OPENVPN_EXIT_STATUS_USAGE 1
#define OPENVPN_EXIT_STATUS_CANNOT_OPEN_DEBUG_FILE 1
/*
* Special command line debugging mode.
* If OPENVPN_DEBUG_COMMAND_LINE
* is defined, contents of argc/argv will
* be dumped to OPENVPN_DEBUG_FILE as well
* as all other OpenVPN messages.
*/
/* #define OPENVPN_DEBUG_COMMAND_LINE */
#define OPENVPN_DEBUG_FILE PACKAGE ".log"
/* String and Error functions */
#ifdef WIN32
# define openvpn_errno() GetLastError()
# define openvpn_errno_socket() WSAGetLastError()
# define openvpn_strerror(e, gc) strerror_win32(e, gc)
const char *strerror_win32 (DWORD errnum, struct gc_arena *gc);
#else
# define openvpn_errno() errno
# define openvpn_errno_socket() errno
# define openvpn_strerror(x, gc) strerror(x)
#endif
/*
* These globals should not be accessed directly,
* but rather through macros or inline functions defined below.
*/
extern unsigned int x_debug_level;
extern int x_msg_line_num;
/* msg() flags */
#define M_DEBUG_LEVEL (0x0F) /* debug level mask */
#define M_FATAL (1<<4) /* exit program */
#define M_NONFATAL (1<<5) /* non-fatal error */
#define M_WARN (1<<6) /* call syslog with LOG_WARNING */
#define M_DEBUG (1<<7)
#define M_ERRNO (1<<8) /* show errno description */
#define M_ERRNO_SOCK (1<<9) /* show socket errno description */
#define M_SSL (1<<10) /* show SSL error */
#define M_NOMUTE (1<<11) /* don't do mute processing */
#define M_NOPREFIX (1<<12) /* don't show date/time prefix */
#define M_USAGE_SMALL (1<<13) /* fatal options error, call usage_small */
#define M_MSG_VIRT_OUT (1<<14) /* output message through msg_status_output callback */
#define M_OPTERR (1<<15) /* print "Options error:" prefix */
/* flag combinations which are frequently used */
#define M_ERR (M_FATAL | M_ERRNO)
#define M_SOCKERR (M_FATAL | M_ERRNO_SOCK)
#define M_SSLERR (M_FATAL | M_SSL)
#define M_USAGE (M_USAGE_SMALL | M_NOPREFIX | M_OPTERR)
#define M_CLIENT (M_MSG_VIRT_OUT|M_NOMUTE)
/*
* Mute levels are designed to avoid large numbers of
* mostly similar messages clogging the log file.
*
* A mute level of 0 is always printed.
*/
#define MUTE_LEVEL_SHIFT 16
#define MUTE_LEVEL_MASK 0xFF
#define ENCODE_MUTE_LEVEL(mute_level) (((mute_level) & MUTE_LEVEL_MASK) << MUTE_LEVEL_SHIFT)
#define DECODE_MUTE_LEVEL(flags) (((flags) >> MUTE_LEVEL_SHIFT) & MUTE_LEVEL_MASK)
/*
* log_level: verbosity level n (--verb n) must be >= log_level to print.
* mute_level: don't print more than n (--mute n) consecutive messages at
* a given mute level, or if 0 disable muting and print everything.
*/
#define LOGLEV(log_level, mute_level, other) ((log_level) | ENCODE_MUTE_LEVEL(mute_level) | other)
/*
* If compiler supports variable arguments in macros, define
* msg() as a macro for optimization win.
*/
bool dont_mute (unsigned int flags); /* check muting filter */
#define MSG_TEST(flags) (((((unsigned int)flags) & M_DEBUG_LEVEL) <= x_debug_level) && dont_mute (flags))
#if defined(HAVE_CPP_VARARG_MACRO_ISO) && !defined(__LCLINT__)
# define HAVE_VARARG_MACROS
# define msg(flags, ...) do { if (MSG_TEST(flags)) x_msg((flags), __VA_ARGS__); } while (false)
# ifdef ENABLE_DEBUG
# define dmsg(flags, ...) do { if (MSG_TEST(flags)) x_msg((flags), __VA_ARGS__); } while (false)
# else
# define dmsg(flags, ...)
# endif
#elif defined(HAVE_CPP_VARARG_MACRO_GCC) && !defined(__LCLINT__)
# define HAVE_VARARG_MACROS
# define msg(flags, args...) do { if (MSG_TEST(flags)) x_msg((flags), args); } while (false)
# ifdef ENABLE_DEBUG
# define dmsg(flags, args...) do { if (MSG_TEST(flags)) x_msg((flags), args); } while (false)
# else
# define dmsg(flags, args...)
# endif
#else
# if !PEDANTIC
# ifdef _MSC_VER
# pragma message("this compiler appears to lack vararg macros which will cause a significant degradation in efficiency")
# else
# warning this compiler appears to lack vararg macros which will cause a significant degradation in efficiency (you can ignore this warning if you are using LCLINT)
# endif
# endif
# define msg x_msg
# define dmsg x_msg
#endif
void x_msg (const unsigned int flags, const char *format, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 2, 3)))
#endif
; /* should be called via msg above */
/*
* Function prototypes
*/
void error_reset (void);
void set_suppress_timestamps (bool suppressed);
#define SDL_CONSTRAIN (1<<0)
bool set_debug_level (const int level, const unsigned int flags);
bool set_mute_cutoff (const int cutoff);
int get_debug_level (void);
int get_mute_cutoff (void);
const char *msg_flags_string (const unsigned int flags, struct gc_arena *gc);
/*
* File to print messages to before syslog is opened.
*/
FILE *msg_fp(void);
/* Fatal logic errors */
#define ASSERT(x) do { if (!(x)) assert_failed(__FILE__, __LINE__); } while (false)
void assert_failed (const char *filename, int line);
/* Inline functions */
static inline bool
check_debug_level (unsigned int level)
{
return (level & M_DEBUG_LEVEL) <= x_debug_level;
}
/* syslog output */
void open_syslog (const char *pgmname, bool stdio_to_null);
void close_syslog ();
/* log file output */
void redirect_stdout_stderr (const char *file, bool append);
#ifdef WIN32
/* get original stderr handle, even if redirected by --log/--log-append */
HANDLE get_orig_stderr (void);
#endif
/* exit program */
void openvpn_exit (const int status);
/*
* Check the return status of read/write routines.
*/
struct link_socket;
struct tuntap;
extern unsigned int x_cs_info_level;
extern unsigned int x_cs_verbose_level;
extern unsigned int x_cs_err_delay_ms;
void reset_check_status (void);
void set_check_status (unsigned int info_level, unsigned int verbose_level);
void x_check_status (int status,
const char *description,
struct link_socket *sock,
struct tuntap *tt);
static inline void
check_status (int status, const char *description, struct link_socket *sock, struct tuntap *tt)
{
if (status < 0 || check_debug_level (x_cs_verbose_level))
x_check_status (status, description, sock, tt);
}
static inline void
set_check_status_error_delay (unsigned int milliseconds)
{
x_cs_err_delay_ms = milliseconds;
}
/*
* In multiclient mode, put a client-specific prefix
* before each message.
*
* TODO: x_msg_prefix should be thread-local
*/
extern const char *x_msg_prefix;
#ifdef USE_PTHREAD
extern pthread_key_t x_msg_prefix_key;
#endif
void msg_thread_init (void);
void msg_thread_uninit (void);
static inline void
msg_set_prefix (const char *prefix)
{
#ifdef USE_PTHREAD
if (openvpn_thread_enabled ())
{
ASSERT (!pthread_setspecific (x_msg_prefix_key, prefix));
}
else
#endif
x_msg_prefix = prefix;
}
static inline const char *
msg_get_prefix (void)
{
#ifdef USE_PTHREAD
if (openvpn_thread_enabled ())
return (const char *) pthread_getspecific (x_msg_prefix_key);
else
#endif
return x_msg_prefix;
}
/*
* Allow MSG to be redirected through a virtual_output object
*/
struct virtual_output;
extern const struct virtual_output *x_msg_virtual_output;
static inline void
msg_set_virtual_output (const struct virtual_output *vo)
{
x_msg_virtual_output = vo;
}
static inline const struct virtual_output *
msg_get_virtual_output (void)
{
return x_msg_virtual_output;
}
/*
* Return true if this is a system error
* which can be safely ignored.
*/
static inline bool
ignore_sys_error (const int err)
{
/* I/O operation pending */
#ifdef WIN32
if (err == WSAEWOULDBLOCK || err == WSAEINVAL)
return true;
#else
if (err == EAGAIN)
return true;
#endif
#if 0 /* if enabled, suppress ENOBUFS errors */
#ifdef ENOBUFS
/* No buffer space available */
if (err == ENOBUFS)
return true;
#endif
#endif
return false;
}
#include "errlevel.h"
#endif

1061
event.c Normal file

File diff suppressed because it is too large Load Diff

157
event.h Normal file
View File

@ -0,0 +1,157 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef EVENT_H
#define EVENT_H
#include "win32.h"
#include "sig.h"
#include "perf.h"
/*
* rwflags passed to event_ctl and returned by
* struct event_set_return.
*/
#define EVENT_READ (1<<0)
#define EVENT_WRITE (1<<1)
/*
* Initialization flags passed to event_set_init
*/
#define EVENT_METHOD_US_TIMEOUT (1<<0)
#define EVENT_METHOD_FAST (1<<1)
#ifdef WIN32
typedef const struct rw_handle *event_t;
#define UNDEFINED_EVENT (NULL)
#else
typedef int event_t;
#define UNDEFINED_EVENT (-1)
#endif
struct event_set;
struct event_set_return;
struct event_set_functions
{
void (*free)(struct event_set *es);
void (*reset)(struct event_set *es);
void (*del)(struct event_set *es, event_t event);
void (*ctl)(struct event_set *es, event_t event, unsigned int rwflags, void *arg);
/*
* Return status for wait:
* -1 on signal or error
* 0 on timeout
* length of event_set_return if at least 1 event is returned
*/
int (*wait)(struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen);
};
struct event_set_return
{
unsigned int rwflags;
void *arg;
};
struct event_set
{
struct event_set_functions func;
};
/*
* maxevents on input: desired max number of event_t descriptors
* simultaneously set with event_ctl
* maxevents on output: may be modified down, depending on limitations
* of underlying API
* flags: EVENT_METHOD_x flags
*/
struct event_set *event_set_init (int *maxevents, unsigned int flags);
static inline void
event_free (struct event_set *es)
{
(*es->func.free)(es);
}
static inline void
event_reset (struct event_set *es)
{
(*es->func.reset)(es);
}
static inline void
event_del (struct event_set *es, event_t event)
{
(*es->func.del)(es, event);
}
static inline void
event_ctl (struct event_set *es, event_t event, unsigned int rwflags, void *arg)
{
(*es->func.ctl)(es, event, rwflags, arg);
}
static inline int
event_wait (struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen)
{
int ret;
perf_push (PERF_IO_WAIT);
ret = (*es->func.wait)(es, tv, out, outlen);
perf_pop ();
return ret;
}
static inline void
event_set_return_init (struct event_set_return *esr)
{
esr->rwflags = 0;
esr->arg = NULL;
}
#ifdef WIN32
static inline void
wait_signal (struct event_set *es, void *arg)
{
if (HANDLE_DEFINED (win32_signal.in.read))
event_ctl (es, &win32_signal.in, EVENT_READ, arg);
}
#else
static inline void
wait_signal (struct event_set *es, void *arg)
{
}
#endif
#endif

60
fdmisc.c Normal file
View File

@ -0,0 +1,60 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef WIN32
#include "config-win32.h"
#else
#include "config.h"
#endif
#include "syshead.h"
#include "fdmisc.h"
#include "error.h"
#include "memdbg.h"
/* Set a file descriptor to non-blocking */
void
set_nonblock (int fd)
{
#ifdef WIN32
u_long arg = 1;
if (ioctlsocket (fd, FIONBIO, &arg))
msg (M_SOCKERR, "Set socket to non-blocking mode failed");
#else
if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0)
msg (M_ERR, "Set file descriptor to non-blocking mode failed");
#endif
}
/* Set a file descriptor to not be passed across execs */
void
set_cloexec (int fd)
{
#ifndef WIN32
if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0)
msg (M_ERR, "Set FD_CLOEXEC flag on file descriptor failed");
#endif
}

26
fdmisc.h Normal file
View File

@ -0,0 +1,26 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
void set_nonblock (int fd);
void set_cloexec (int fd);

276
forward-inline.h Normal file
View File

@ -0,0 +1,276 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef FORWARD_INLINE_H
#define FORWARD_INLINE_H
/*
* Inline functions
*/
/*
* Does TLS session need service?
*/
static inline void
check_tls (struct context *c)
{
#if defined(USE_CRYPTO) && defined(USE_SSL)
void check_tls_dowork (struct context *c);
if (c->c2.tls_multi)
check_tls_dowork (c);
#endif
}
/*
* TLS errors are fatal in TCP mode.
* Also check for --tls-exit trigger.
*/
static inline void
check_tls_errors (struct context *c)
{
#if defined(USE_CRYPTO) && defined(USE_SSL)
void check_tls_errors_co (struct context *c);
void check_tls_errors_nco (struct context *c);
if (c->c2.tls_multi && c->c2.tls_exit_signal)
{
if (link_socket_connection_oriented (c->c2.link_socket))
{
if (c->c2.tls_multi->n_soft_errors)
check_tls_errors_co (c);
}
else
{
if (c->c2.tls_multi->n_hard_errors)
check_tls_errors_nco (c);
}
}
#endif
}
/*
* Check for possible incoming configuration
* messages on the control channel.
*/
static inline void
check_incoming_control_channel (struct context *c)
{
#if P2MP
void check_incoming_control_channel_dowork (struct context *c);
if (tls_test_payload_len (c->c2.tls_multi) > 0)
check_incoming_control_channel_dowork (c);
#endif
}
/*
* Options like --up-delay need to be triggered by this function which
* checks for connection establishment.
*/
static inline void
check_connection_established (struct context *c)
{
void check_connection_established_dowork (struct context *c);
if (event_timeout_defined (&c->c2.wait_for_connect))
check_connection_established_dowork (c);
}
/*
* Should we add routes?
*/
static inline void
check_add_routes (struct context *c)
{
void check_add_routes_dowork (struct context *c);
if (event_timeout_trigger (&c->c2.route_wakeup, &c->c2.timeval, ETT_DEFAULT))
check_add_routes_dowork (c);
}
/*
* Should we exit due to inactivity timeout?
*/
static inline void
check_inactivity_timeout (struct context *c)
{
void check_inactivity_timeout_dowork (struct context *c);
if (c->options.inactivity_timeout
&& event_timeout_trigger (&c->c2.inactivity_interval, &c->c2.timeval, ETT_DEFAULT))
check_inactivity_timeout_dowork (c);
}
#if P2MP
/*
* Scheduled exit?
*/
static inline void
check_scheduled_exit (struct context *c)
{
void check_scheduled_exit_dowork (struct context *c);
if (event_timeout_defined (&c->c2.scheduled_exit))
{
if (event_timeout_trigger (&c->c2.scheduled_exit, &c->c2.timeval, ETT_DEFAULT))
check_scheduled_exit_dowork (c);
}
}
#endif
/*
* Should we write timer-triggered status file.
*/
static inline void
check_status_file (struct context *c)
{
void check_status_file_dowork (struct context *c);
if (c->c1.status_output)
{
if (status_trigger_tv (c->c1.status_output, &c->c2.timeval))
check_status_file_dowork (c);
}
}
#ifdef ENABLE_FRAGMENT
/*
* Should we deliver a datagram fragment to remote?
*/
static inline void
check_fragment (struct context *c)
{
void check_fragment_dowork (struct context *c);
if (c->c2.fragment)
check_fragment_dowork (c);
}
#endif
#if P2MP
/*
* see if we should send a push_request in response to --pull
*/
static inline void
check_push_request (struct context *c)
{
void check_push_request_dowork (struct context *c);
if (event_timeout_trigger (&c->c2.push_request_interval, &c->c2.timeval, ETT_DEFAULT))
check_push_request_dowork (c);
}
#endif
#ifdef USE_CRYPTO
/*
* Should we persist our anti-replay packet ID state to disk?
*/
static inline void
check_packet_id_persist_flush (struct context *c)
{
if (packet_id_persist_enabled (&c->c1.pid_persist)
&& event_timeout_trigger (&c->c2.packet_id_persist_interval, &c->c2.timeval, ETT_DEFAULT))
packet_id_persist_save (&c->c1.pid_persist);
}
#endif
/*
* Set our wakeup to 0 seconds, so we will be rescheduled
* immediately.
*/
static inline void
context_immediate_reschedule (struct context *c)
{
c->c2.timeval.tv_sec = 0; /* ZERO-TIMEOUT */
c->c2.timeval.tv_usec = 0;
}
static inline void
context_reschedule_sec (struct context *c, int sec)
{
if (sec < 0)
sec = 0;
if (sec < c->c2.timeval.tv_sec)
{
c->c2.timeval.tv_sec = sec;
c->c2.timeval.tv_usec = 0;
}
}
static inline struct link_socket_info *
get_link_socket_info (struct context *c)
{
if (c->c2.link_socket_info)
return c->c2.link_socket_info;
else
return &c->c2.link_socket->info;
}
static inline void
register_activity (struct context *c)
{
if (c->options.inactivity_timeout)
event_timeout_reset (&c->c2.inactivity_interval);
}
/*
* Return the io_wait() flags appropriate for
* a point-to-point tunnel.
*/
static inline unsigned int
p2p_iow_flags (const struct context *c)
{
unsigned int flags = (IOW_SHAPER|IOW_CHECK_RESIDUAL|IOW_FRAG|IOW_READ|IOW_WAIT_SIGNAL);
if (c->c2.to_link.len > 0)
flags |= IOW_TO_LINK;
if (c->c2.to_tun.len > 0)
flags |= IOW_TO_TUN;
return flags;
}
/*
* This is the core I/O wait function, used for all I/O waits except
* for TCP in server mode.
*/
static inline void
io_wait (struct context *c, const unsigned int flags)
{
void io_wait_dowork (struct context *c, const unsigned int flags);
if (c->c2.fast_io && (flags & (IOW_TO_TUN|IOW_TO_LINK|IOW_MBUF)))
{
/* fast path -- only for TUN/TAP/UDP writes */
unsigned int ret = 0;
if (flags & IOW_TO_TUN)
ret |= TUN_WRITE;
if (flags & (IOW_TO_LINK|IOW_MBUF))
ret |= SOCKET_WRITE;
c->c2.event_set_status = ret;
}
else
{
/* slow path */
io_wait_dowork (c, flags);
}
}
#define CONNECTION_ESTABLISHED(c) (get_link_socket_info(c)->connection_established)
#endif /* EVENT_INLINE_H */

1402
forward.c Normal file

File diff suppressed because it is too large Load Diff

84
forward.h Normal file
View File

@ -0,0 +1,84 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef FORWARD_H
#define FORWARD_H
#include "openvpn.h"
#include "occ.h"
#include "ping.h"
#define TUN_OUT(c) (BLEN(&(c)->c2.to_tun) > 0)
#define LINK_OUT(c) (BLEN(&(c)->c2.to_link) > 0)
#define ANY_OUT(c) (TUN_OUT(c) || LINK_OUT(c))
#ifdef ENABLE_FRAGMENT
#define TO_LINK_FRAG(c) ((c)->c2.fragment && fragment_outgoing_defined ((c)->c2.fragment))
#else
#define TO_LINK_FRAG(c) (false)
#endif
#define TO_LINK_DEF(c) (LINK_OUT(c) || TO_LINK_FRAG(c))
#define IOW_TO_TUN (1<<0)
#define IOW_TO_LINK (1<<1)
#define IOW_READ_TUN (1<<2)
#define IOW_READ_LINK (1<<3)
#define IOW_SHAPER (1<<4)
#define IOW_CHECK_RESIDUAL (1<<5)
#define IOW_FRAG (1<<6)
#define IOW_MBUF (1<<7)
#define IOW_READ_TUN_FORCE (1<<8)
#define IOW_WAIT_SIGNAL (1<<9)
#define IOW_READ (IOW_READ_TUN|IOW_READ_LINK)
void pre_select (struct context *c);
void process_io (struct context *c);
void encrypt_sign (struct context *c, bool comp_frag);
const char *wait_status_string (struct context *c, struct gc_arena *gc);
void show_wait_status (struct context *c);
void read_incoming_link (struct context *c);
void process_incoming_link (struct context *c);
void read_incoming_tun (struct context *c);
void process_incoming_tun (struct context *c);
void process_outgoing_link (struct context *c);
void process_outgoing_tun (struct context *c);
bool send_control_channel_string (struct context *c, const char *str, int msglevel);
#define PIPV4_PASSTOS (1<<0)
#define PIPV4_MSSFIX (1<<1)
void process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf);
#if P2MP
void schedule_exit (struct context *c, const int n_seconds);
#endif
#endif /* FORWARD_H */

414
fragment.c Normal file
View File

@ -0,0 +1,414 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef WIN32
#include "config-win32.h"
#else
#include "config.h"
#endif
#include "syshead.h"
#ifdef ENABLE_FRAGMENT
#include "misc.h"
#include "fragment.h"
#include "integer.h"
#include "memdbg.h"
#define FRAG_ERR(s) { errmsg = s; goto error; }
static void
fragment_list_buf_init (struct fragment_list *list, const struct frame *frame)
{
int i;
for (i = 0; i < N_FRAG_BUF; ++i)
list->fragments[i].buf = alloc_buf (BUF_SIZE (frame));
}
static void
fragment_list_buf_free (struct fragment_list *list)
{
int i;
for (i = 0; i < N_FRAG_BUF; ++i)
free_buf (&list->fragments[i].buf);
}
/*
* Given a sequence ID number, get a fragment buffer. Use a sliding window,
* similar to packet_id code.
*/
static struct fragment *
fragment_list_get_buf (struct fragment_list *list, int seq_id)
{
int diff;
if (abs (diff = modulo_subtract (seq_id, list->seq_id, N_SEQ_ID)) >= N_FRAG_BUF)
{
int i;
for (i = 0; i < N_FRAG_BUF; ++i)
list->fragments[i].defined = false;
list->index = 0;
list->seq_id = seq_id;
diff = 0;
}
while (diff > 0)
{
list->fragments[list->index = modulo_add (list->index, 1, N_FRAG_BUF)].defined = false;
list->seq_id = modulo_add (list->seq_id, 1, N_SEQ_ID);
--diff;
}
return &list->fragments[modulo_add (list->index, diff, N_FRAG_BUF)];
}
struct fragment_master *
fragment_init (struct frame *frame)
{
struct fragment_master *ret;
/* code that initializes other parts of
fragment_master assume an initial CLEAR */
ALLOC_OBJ_CLEAR (ret, struct fragment_master);
/* add in the size of our contribution to the expanded frame size */
frame_add_to_extra_frame (frame, sizeof(fragment_header_type));
/*
* Outgoing sequence ID is randomized to reduce
* the probability of sequence number collisions
* when openvpn sessions are restarted. This is
* not done out of any need for security, as all
* fragmentation control information resides
* inside of the encrypted/authenticated envelope.
*/
ret->outgoing_seq_id = (int)get_random() & (N_SEQ_ID - 1);
event_timeout_init (&ret->wakeup, FRAG_WAKEUP_INTERVAL, now);
return ret;
}
void
fragment_free (struct fragment_master *f)
{
fragment_list_buf_free (&f->incoming);
free_buf (&f->outgoing);
free_buf (&f->outgoing_return);
free (f);
}
void
fragment_frame_init (struct fragment_master *f, const struct frame *frame)
{
fragment_list_buf_init (&f->incoming, frame);
f->outgoing = alloc_buf (BUF_SIZE (frame));
f->outgoing_return = alloc_buf (BUF_SIZE (frame));
}
/*
* Accept an incoming datagram (which may be a fragment) from remote.
* If the datagram is whole (i.e not a fragment), pass through.
* If the datagram is a fragment, join with other fragments received so far.
* If a fragment fully completes the datagram, return the datagram.
*/
void
fragment_incoming (struct fragment_master *f, struct buffer *buf,
const struct frame* frame)
{
const char *errmsg = NULL;
fragment_header_type flags = 0;
int frag_type = 0;
if (buf->len > 0)
{
/* get flags from packet head */
if (!buf_read (buf, &flags, sizeof (flags)))
FRAG_ERR ("flags not found in packet");
flags = ntoh_fragment_header_type (flags);
/* get fragment type from flags */
frag_type = ((flags >> FRAG_TYPE_SHIFT) & FRAG_TYPE_MASK);
#if 0
/*
* If you want to extract FRAG_EXTRA_MASK/FRAG_EXTRA_SHIFT bits,
* do it here.
*/
if (frag_type == FRAG_WHOLE || frag_type == FRAG_YES_NOTLAST)
{
}
#endif
/* handle the fragment type */
if (frag_type == FRAG_WHOLE)
{
dmsg (D_FRAG_DEBUG,
"FRAG_IN buf->len=%d type=FRAG_WHOLE flags="
fragment_header_format,
buf->len,
flags);
if (flags & (FRAG_SEQ_ID_MASK | FRAG_ID_MASK))
FRAG_ERR ("spurrious FRAG_WHOLE flags");
}
else if (frag_type == FRAG_YES_NOTLAST || frag_type == FRAG_YES_LAST)
{
const int seq_id = ((flags >> FRAG_SEQ_ID_SHIFT) & FRAG_SEQ_ID_MASK);
const int n = ((flags >> FRAG_ID_SHIFT) & FRAG_ID_MASK);
const int size = ((frag_type == FRAG_YES_LAST)
? (int)(((flags >> FRAG_SIZE_SHIFT) & FRAG_SIZE_MASK) << FRAG_SIZE_ROUND_SHIFT)
: buf->len);
/* get the appropriate fragment buffer based on received seq_id */
struct fragment *frag = fragment_list_get_buf (&f->incoming, seq_id);
dmsg (D_FRAG_DEBUG,
"FRAG_IN len=%d type=%d seq_id=%d frag_id=%d size=%d flags="
fragment_header_format,
buf->len,
frag_type,
seq_id,
n,
size,
flags);
/* make sure that size is an even multiple of 1<<FRAG_SIZE_ROUND_SHIFT */
if (size & FRAG_SIZE_ROUND_MASK)
FRAG_ERR ("bad fragment size");
/* is this the first fragment for our sequence number? */
if (!frag->defined || (frag->defined && frag->max_frag_size != size))
{
frag->defined = true;
frag->max_frag_size = size;
frag->map = 0;
ASSERT (buf_init (&frag->buf, FRAME_HEADROOM_ADJ (frame, FRAME_HEADROOM_MARKER_FRAGMENT)));
}
/* copy the data to fragment buffer */
if (!buf_copy_range (&frag->buf, n * size, buf, 0, buf->len))
FRAG_ERR ("fragment buffer overflow");
/* set elements in bit array to reflect which fragments have been received */
frag->map |= (((frag_type == FRAG_YES_LAST) ? FRAG_MAP_MASK : 1) << n);
/* update timestamp on partially built datagram */
frag->timestamp = now;
/* received full datagram? */
if ((frag->map & FRAG_MAP_MASK) == FRAG_MAP_MASK)
{
frag->defined = false;
*buf = frag->buf;
}
else
{
buf->len = 0;
}
}
else if (frag_type == FRAG_TEST)
{
FRAG_ERR ("FRAG_TEST not implemented");
}
else
{
FRAG_ERR ("unknown fragment type");
}
}
return;
error:
if (errmsg)
msg (D_FRAG_ERRORS, "FRAG_IN error flags=" fragment_header_format ": %s", flags, errmsg);
buf->len = 0;
return;
}
/* pack fragment parms into a uint32_t and prepend to buffer */
static void
fragment_prepend_flags (struct buffer *buf,
int type,
int seq_id,
int frag_id,
int frag_size)
{
fragment_header_type flags = ((type & FRAG_TYPE_MASK) << FRAG_TYPE_SHIFT)
| ((seq_id & FRAG_SEQ_ID_MASK) << FRAG_SEQ_ID_SHIFT)
| ((frag_id & FRAG_ID_MASK) << FRAG_ID_SHIFT);
if (type == FRAG_WHOLE || type == FRAG_YES_NOTLAST)
{
/*
* If you want to set FRAG_EXTRA_MASK/FRAG_EXTRA_SHIFT bits,
* do it here.
*/
dmsg (D_FRAG_DEBUG,
"FRAG_OUT len=%d type=%d seq_id=%d frag_id=%d frag_size=%d flags="
fragment_header_format,
buf->len, type, seq_id, frag_id, frag_size, flags);
}
else
{
flags |= (((frag_size >> FRAG_SIZE_ROUND_SHIFT) & FRAG_SIZE_MASK) << FRAG_SIZE_SHIFT);
dmsg (D_FRAG_DEBUG,
"FRAG_OUT len=%d type=%d seq_id=%d frag_id=%d frag_size=%d flags="
fragment_header_format,
buf->len, type, seq_id, frag_id, frag_size, flags);
}
flags = hton_fragment_header_type (flags);
ASSERT (buf_write_prepend (buf, &flags, sizeof (flags)));
}
/*
* Without changing the number of fragments, return a possibly smaller
* max fragment size that will allow for the last fragment to be of
* similar size as previous fragments.
*/
static inline int
optimal_fragment_size (int len, int max_frag_size)
{
const int mfs_aligned = (max_frag_size & ~FRAG_SIZE_ROUND_MASK);
const int div = len / mfs_aligned;
const int mod = len % mfs_aligned;
if (div > 0 && mod > 0 && mod < mfs_aligned * 3 / 4)
return min_int (mfs_aligned, (max_frag_size - ((max_frag_size - mod) / (div + 1))
+ FRAG_SIZE_ROUND_MASK) & ~FRAG_SIZE_ROUND_MASK);
else
return mfs_aligned;
}
/* process an outgoing datagram, possibly breaking it up into fragments */
void
fragment_outgoing (struct fragment_master *f, struct buffer *buf,
const struct frame* frame)
{
const char *errmsg = NULL;
if (buf->len > 0)
{
/* The outgoing buffer should be empty so we can put new data in it */
if (f->outgoing.len)
msg (D_FRAG_ERRORS, "FRAG: outgoing buffer is not empty, len=[%d,%d]",
buf->len, f->outgoing.len);
if (buf->len > PAYLOAD_SIZE_DYNAMIC(frame)) /* should we fragment? */
{
/*
* Send the datagram as a series of 2 or more fragments.
*/
f->outgoing_frag_size = optimal_fragment_size (buf->len, PAYLOAD_SIZE_DYNAMIC(frame));
if (buf->len > f->outgoing_frag_size * MAX_FRAGS)
FRAG_ERR ("too many fragments would be required to send datagram");
ASSERT (buf_init (&f->outgoing, FRAME_HEADROOM (frame)));
ASSERT (buf_copy (&f->outgoing, buf));
f->outgoing_seq_id = modulo_add (f->outgoing_seq_id, 1, N_SEQ_ID);
f->outgoing_frag_id = 0;
buf->len = 0;
ASSERT (fragment_ready_to_send (f, buf, frame));
}
else
{
/*
* Send the datagram whole.
*/
fragment_prepend_flags (buf,
FRAG_WHOLE,
0,
0,
0);
}
}
return;
error:
if (errmsg)
msg (D_FRAG_ERRORS, "FRAG_OUT error, len=%d frag_size=%d MAX_FRAGS=%d: %s",
buf->len, f->outgoing_frag_size, MAX_FRAGS, errmsg);
buf->len = 0;
return;
}
/* return true (and set buf) if we have an outgoing fragment which is ready to send */
bool
fragment_ready_to_send (struct fragment_master *f, struct buffer *buf,
const struct frame* frame)
{
if (fragment_outgoing_defined (f))
{
/* get fragment size, and determine if it is the last fragment */
int size = f->outgoing_frag_size;
int last = false;
if (f->outgoing.len <= size)
{
size = f->outgoing.len;
last = true;
}
/* initialize return buffer */
*buf = f->outgoing_return;
ASSERT (buf_init (buf, FRAME_HEADROOM (frame)));
ASSERT (buf_copy_n (buf, &f->outgoing, size));
/* fragment flags differ based on whether or not we are sending the last fragment */
fragment_prepend_flags (buf,
last ? FRAG_YES_LAST : FRAG_YES_NOTLAST,
f->outgoing_seq_id,
f->outgoing_frag_id++,
f->outgoing_frag_size);
ASSERT (!last || !f->outgoing.len); /* outgoing buffer length should be zero after last fragment sent */
return true;
}
else
return false;
}
static void
fragment_ttl_reap (struct fragment_master *f)
{
int i;
for (i = 0; i < N_FRAG_BUF; ++i)
{
struct fragment *frag = &f->incoming.fragments[i];
if (frag->defined && frag->timestamp + FRAG_TTL_SEC <= now)
{
msg (D_FRAG_ERRORS, "FRAG TTL expired i=%d", i);
frag->defined = false;
}
}
}
/* called every FRAG_WAKEUP_INTERVAL seconds */
void
fragment_wakeup (struct fragment_master *f, struct frame *frame)
{
/* delete fragments with expired TTLs */
fragment_ttl_reap (f);
}
#else
static void dummy(void) {}
#endif

188
fragment.h Normal file
View File

@ -0,0 +1,188 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef FRAGMENT_H
#define FRAGMENT_H
#ifdef ENABLE_FRAGMENT
#include "common.h"
#include "buffer.h"
#include "interval.h"
#include "mtu.h"
#include "shaper.h"
#include "error.h"
#define N_FRAG_BUF 25 /* number of packet buffers */
#define FRAG_TTL_SEC 10 /* number of seconds time-to-live for a fragment */
#define FRAG_WAKEUP_INTERVAL 5 /* wakeup code called once per n seconds */
struct fragment {
bool defined;
int max_frag_size; /* maximum size of each fragment */
/*
* 32 bit array corresponding to each fragment. A 1 bit in element n means that
* the fragment n has been received. Needs to have at least MAX_FRAGS bits.
*/
# define FRAG_MAP_MASK 0xFFFFFFFF
# define MAX_FRAGS 32 /* maximum number of fragments per packet */
unsigned int map;
time_t timestamp; /* timestamp for time-to-live purposes */
struct buffer buf; /* fragment assembly buffer for received datagrams */
};
struct fragment_list {
int seq_id;
int index;
struct fragment fragments[N_FRAG_BUF];
};
struct fragment_master {
struct event_timeout wakeup; /* when should main openvpn event loop wake us up */
/* true if the OS has explicitly recommended an MTU value */
bool received_os_mtu_hint;
/* a sequence ID describes a set of fragments that make up one datagram */
# define N_SEQ_ID 256 /* sequence number wraps to 0 at this value (should be a power of 2) */
int outgoing_seq_id; /* sent as FRAG_SEQ_ID below */
/* outgoing packet is possibly sent as a series of fragments */
# define MAX_FRAG_PKT_SIZE 65536 /* maximum packet size */
int outgoing_frag_size; /* sent to peer via FRAG_SIZE when FRAG_YES_LAST set */
int outgoing_frag_id; /* each fragment in a datagram is numbered 0 to MAX_FRAGS-1 */
struct buffer outgoing; /* outgoing datagram, free if current_frag_id == 0 */
struct buffer outgoing_return; /* buffer to return outgoing fragment */
/* incoming fragments from remote */
struct fragment_list incoming;
};
/*
* Fragment header sent over the wire.
*/
typedef uint32_t fragment_header_type;
/* convert a fragment_header_type from host to network order */
#define hton_fragment_header_type(x) htonl(x)
/* convert a fragment_header_type from network to host order */
#define ntoh_fragment_header_type(x) ntohl(x)
/* FRAG_TYPE 2 bits */
#define FRAG_TYPE_MASK 0x00000003
#define FRAG_TYPE_SHIFT 0
#define FRAG_WHOLE 0 /* packet is whole, FRAG_N_PACKETS_RECEIVED echoed back to peer */
#define FRAG_YES_NOTLAST 1 /* packet is a fragment, but is not the last fragment,
FRAG_N_PACKETS_RECEIVED set as above */
#define FRAG_YES_LAST 2 /* packet is the last fragment, FRAG_SIZE = size of non-last frags */
#define FRAG_TEST 3 /* control packet for establishing MTU size (not implemented yet) */
/* FRAG_SEQ_ID 8 bits */
#define FRAG_SEQ_ID_MASK 0x000000ff
#define FRAG_SEQ_ID_SHIFT 2
/* FRAG_ID 5 bits */
#define FRAG_ID_MASK 0x0000001f
#define FRAG_ID_SHIFT 10
/*
* FRAG_SIZE 14 bits
*
* IF FRAG_YES_LAST (FRAG_SIZE):
* The max size of a fragment. If a fragment is not the last fragment in the packet,
* then the fragment size is guaranteed to be equal to the max fragment size. Therefore,
* max_frag_size is only sent over the wire if FRAG_LAST is set. Otherwise it is assumed
* to be the actual fragment size received.
*/
/* FRAG_SIZE 14 bits */
#define FRAG_SIZE_MASK 0x00003fff
#define FRAG_SIZE_SHIFT 15
#define FRAG_SIZE_ROUND_SHIFT 2 /* fragment/datagram sizes represented as multiple of 4 */
#define FRAG_SIZE_ROUND_MASK ((1 << FRAG_SIZE_ROUND_SHIFT) - 1)
/*
* FRAG_EXTRA 16 bits
*
* IF FRAG_WHOLE or FRAG_YES_NOTLAST, these 16 bits are available (not currently used)
*/
/* FRAG_EXTRA 16 bits */
#define FRAG_EXTRA_MASK 0x0000ffff
#define FRAG_EXTRA_SHIFT 15
/*
* Public functions
*/
struct fragment_master *fragment_init (struct frame *frame);
void fragment_frame_init (struct fragment_master *f, const struct frame *frame);
void fragment_free (struct fragment_master *f);
void fragment_incoming (struct fragment_master *f, struct buffer *buf,
const struct frame* frame);
void fragment_outgoing (struct fragment_master *f, struct buffer *buf,
const struct frame* frame);
bool fragment_ready_to_send (struct fragment_master *f, struct buffer *buf,
const struct frame* frame);
/*
* Private functions.
*/
void fragment_wakeup (struct fragment_master *f, struct frame *frame);
/*
* Inline functions
*/
static inline void
fragment_housekeeping (struct fragment_master *f, struct frame *frame, struct timeval *tv)
{
if (event_timeout_trigger (&f->wakeup, tv, ETT_DEFAULT))
fragment_wakeup (f, frame);
}
static inline bool
fragment_outgoing_defined (struct fragment_master *f)
{
return f->outgoing.len > 0;
}
#endif
#endif

111
gentoo/openvpn.init Executable file
View File

@ -0,0 +1,111 @@
#!/sbin/runscript
# OpenVPN start/stop script
# Adapted to Gentoo by James Yonan
# Originally Contributed to the OpenVPN project by
# Douglas Keller <doug@voidstar.dyndns.org>
# 2002.05.15
# This script does the following:
#
# - Starts an openvpn process for each .conf file it finds in
# /etc/openvpn.
#
# - If /etc/openvpn/xxx.sh exists for a xxx.conf file then it executes
# it before starting openvpn (useful for doing openvpn --mktun...).
# - In addition to start/stop you can do:
#
# service openvpn reload - SIGHUP
# service openvpn reopen - SIGUSR1
# service openvpn status - SIGUSR2
# Location of openvpn binary
openvpn=/usr/local/sbin/openvpn
# PID directory
piddir=/var/run/openvpn
# Our working directory (.conf files should be here)
work=/etc/openvpn
# Our options
opts="start stop restart condrestart"
depend() {
need net
use dns
}
start() {
ebegin "Starting OpenVPN"
# Load the TUN/TAP module
/sbin/modprobe tun >/dev/null 2>&1
if [ ! -d $piddir ]; then
mkdir $piddir
fi
cd $work
# Start every .conf in $work and run .sh if exists
local errors=0
local successes=0
local retstatus=0
for c in `/bin/ls *.conf 2>/dev/null`; do
bn=${c%%.conf}
if [ -f "$bn.sh" ]; then
. $bn.sh
fi
rm -f $piddir/$bn.pid
$openvpn --daemon openvpn-$bn --writepid $piddir/$bn.pid --config $c --cd $work
if [ $? = 0 ]; then
successes=1
else
errors=1
fi
done
# Decide status based on errors/successes.
# If at least one tunnel succeeded, we return success.
# If some tunnels succeeded and some failed, we return
# success but give a warning.
if [ $successes = 1 ]; then
if [ $errors = 1 ]; then
ewarn "Note: At least one OpenVPN tunnel failed to start"
fi
else
retstatus=1
if [ $errors = 0 ]; then
ewarn "Note: No OpenVPN configuration files were found in $work"
fi
fi
eend $retstatus "Error starting OpenVPN"
}
stop() {
ebegin "Stopping OpenVPN"
for pidf in `/bin/ls $piddir/*.pid 2>/dev/null`; do
if [ -s $pidf ]; then
kill `cat $pidf` >/dev/null 2>&1
fi
rm -f $pidf
done
eend 0
}
# this should really be in runscript.sh
started() {
if [ -L "${svcdir}/started/${myservice}" ]; then
return 1
else
return 0
fi
}
# attempt to restart ONLY if we are already started
condrestart() {
started || restart
}

221
gremlin.c Normal file
View File

@ -0,0 +1,221 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Test protocol robustness by simulating dropped packets and
* network outages when the --gremlin option is used.
*/
#ifdef WIN32
#include "config-win32.h"
#else
#include "config.h"
#endif
#include "syshead.h"
#ifdef ENABLE_DEBUG
#include "error.h"
#include "common.h"
#include "misc.h"
#include "otime.h"
#include "gremlin.h"
#include "memdbg.h"
/*
* Parameters for packet corruption and droppage.
* Each parameter has 4 possible levels, 0 = disabled,
* while 1, 2, and 3 are enumerated in the below arrays.
* The parameter is a 2-bit field within the --gremlin
* parameter.
*/
/*
* Probability that we will drop a packet is 1 / n
*/
static const int drop_freq[] = { 500, 100, 50 };
/*
* Probability that we will corrupt a packet is 1 / n
*/
static const int corrupt_freq[] = { 500, 100, 50 };
/*
* When network goes up, it will be up for between
* UP_LOW and UP_HIGH seconds.
*/
static const int up_low[] = { 60, 10, 5 };
static const int up_high[] = { 600, 60, 10 };
/*
* When network goes down, it will be down for between
* DOWN_LOW and DOWN_HIGH seconds.
*/
static const int down_low[] = { 5, 10, 10 };
static const int down_high[] = { 10, 60, 120 };
/*
* Packet flood levels:
* { number of packets, packet size }
*/
static const struct packet_flood_parms packet_flood_data[] =
{{10, 100}, {10, 1500}, {100, 1500}};
struct packet_flood_parms
get_packet_flood_parms (int level)
{
ASSERT (level > 0 && level < 4);
return packet_flood_data [level - 1];
}
/*
* Return true with probability 1/n
*/
static bool flip(int n) {
return (get_random() % n) == 0;
}
/*
* Return uniformly distributed random number between
* low and high.
*/
static int roll(int low, int high) {
int ret;
ASSERT (low <= high);
ret = low + (get_random() % (high - low + 1));
ASSERT (ret >= low && ret <= high);
return ret;
}
static bool initialized; /* GLOBAL */
static bool up; /* GLOBAL */
static time_t next; /* GLOBAL */
/*
* Return false if we should drop a packet.
*/
bool
ask_gremlin (int flags)
{
const int up_down_level = GREMLIN_UP_DOWN_LEVEL (flags);
const int drop_level = GREMLIN_DROP_LEVEL (flags);
if (!initialized)
{
initialized = true;
if (up_down_level)
up = false;
else
up = true;
next = now;
}
if (up_down_level) /* change up/down state? */
{
if (now >= next)
{
int delta;
if (up)
{
delta = roll (down_low[up_down_level-1], down_high[up_down_level-1]);
up = false;
}
else
{
delta = roll (up_low[up_down_level-1], up_high[up_down_level-1]);
up = true;
}
msg (D_GREMLIN,
"GREMLIN: CONNECTION GOING %s FOR %d SECONDS",
(up ? "UP" : "DOWN"),
delta);
next = now + delta;
}
}
if (drop_level)
{
if (up && flip (drop_freq[drop_level-1]))
{
dmsg (D_GREMLIN_VERBOSE, "GREMLIN: Random packet drop");
return false;
}
}
return up;
}
/*
* Possibly corrupt a packet.
*/
void corrupt_gremlin (struct buffer *buf, int flags) {
const int corrupt_level = GREMLIN_CORRUPT_LEVEL (flags);
if (corrupt_level)
{
if (flip (corrupt_freq[corrupt_level-1]))
{
do
{
if (buf->len > 0)
{
uint8_t r = roll (0, 255);
int method = roll (0, 5);
switch (method) {
case 0: /* corrupt the first byte */
*BPTR (buf) = r;
break;
case 1: /* corrupt the last byte */
*(BPTR (buf) + buf->len - 1) = r;
break;
case 2: /* corrupt a random byte */
*(BPTR(buf) + roll (0, buf->len - 1)) = r;
break;
case 3: /* append a random byte */
buf_write (buf, &r, 1);
break;
case 4: /* reduce length by 1 */
--buf->len;
break;
case 5: /* reduce length by a random amount */
buf->len -= roll (0, buf->len - 1);
break;
}
dmsg (D_GREMLIN_VERBOSE, "GREMLIN: Packet Corruption, method=%d", method);
}
else
break;
} while (flip (2)); /* a 50% chance we will corrupt again */
}
}
}
#else
static void dummy(void) {}
#endif

70
gremlin.h Normal file
View File

@ -0,0 +1,70 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef GREMLIN_H
#define GREMLIN_H
#ifdef ENABLE_DEBUG
/*
* Gremlin options, presented as bitmask argument to --gremlin directive
*/
#define GREMLIN_CONNECTION_FLOOD_SHIFT (0)
#define GREMLIN_CONNECTION_FLOOD_MASK (0x07)
#define GREMLIN_PACKET_FLOOD_SHIFT (3)
#define GREMLIN_PACKET_FLOOD_MASK (0x03)
#define GREMLIN_CORRUPT_SHIFT (5)
#define GREMLIN_CORRUPT_MASK (0x03)
#define GREMLIN_UP_DOWN_SHIFT (7)
#define GREMLIN_UP_DOWN_MASK (0x03)
#define GREMLIN_DROP_SHIFT (9)
#define GREMLIN_DROP_MASK (0x03)
/* extract gremlin parms */
#define GREMLIN_CONNECTION_FLOOD_LEVEL(x) (((x)>>GREMLIN_CONNECTION_FLOOD_SHIFT) & GREMLIN_CONNECTION_FLOOD_MASK)
#define GREMLIN_PACKET_FLOOD_LEVEL(x) (((x)>>GREMLIN_PACKET_FLOOD_SHIFT) & GREMLIN_PACKET_FLOOD_MASK)
#define GREMLIN_CORRUPT_LEVEL(x) (((x)>>GREMLIN_CORRUPT_SHIFT) & GREMLIN_CORRUPT_MASK)
#define GREMLIN_UP_DOWN_LEVEL(x) (((x)>>GREMLIN_UP_DOWN_SHIFT) & GREMLIN_UP_DOWN_MASK)
#define GREMLIN_DROP_LEVEL(x) (((x)>>GREMLIN_DROP_SHIFT) & GREMLIN_DROP_MASK)
#include "buffer.h"
struct packet_flood_parms
{
int n_packets;
int packet_size;
};
bool ask_gremlin (int flags);
void corrupt_gremlin (struct buffer* buf, int flags);
struct packet_flood_parms get_packet_flood_parms (int level);
#endif
#endif

369
helper.c Normal file
View File

@ -0,0 +1,369 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef WIN32
#include "config-win32.h"
#else
#include "config.h"
#endif
#include "syshead.h"
#include "forward.h"
#include "helper.h"
#include "pool.h"
#include "push.h"
#include "memdbg.h"
#if P2MP_SERVER
static const char *
print_netmask (int netbits, struct gc_arena *gc)
{
struct buffer out = alloc_buf_gc (128, gc);
const in_addr_t netmask = netbits_to_netmask (netbits);
buf_printf (&out, "%s (/%d)", print_in_addr_t (netmask, 0, gc), netbits);
return BSTR (&out);
}
static const char *
print_opt_route_gateway (const in_addr_t route_gateway, struct gc_arena *gc)
{
struct buffer out = alloc_buf_gc (128, gc);
ASSERT (route_gateway);
buf_printf (&out, "route-gateway %s", print_in_addr_t (route_gateway, 0, gc));
return BSTR (&out);
}
static const char *
print_opt_route (const in_addr_t network, const in_addr_t netmask, struct gc_arena *gc)
{
struct buffer out = alloc_buf_gc (128, gc);
ASSERT (network);
if (netmask)
buf_printf (&out, "route %s %s",
print_in_addr_t (network, 0, gc),
print_in_addr_t (netmask, 0, gc));
else
buf_printf (&out, "route %s",
print_in_addr_t (network, 0, gc));
return BSTR (&out);
}
static const char *
print_str_int (const char *str, const int i, struct gc_arena *gc)
{
struct buffer out = alloc_buf_gc (128, gc);
buf_printf (&out, "%s %d", str, i);
return BSTR (&out);
}
static void
helper_add_route (const in_addr_t network, const in_addr_t netmask, struct options *o)
{
rol_check_alloc (o);
add_route_to_option_list (o->routes,
print_in_addr_t (network, 0, &o->gc),
print_in_addr_t (netmask, 0, &o->gc),
NULL,
NULL);
}
static void
verify_common_subnet (const char *opt, const in_addr_t a, const in_addr_t b, const in_addr_t subnet)
{
struct gc_arena gc = gc_new ();
if ((a & subnet) != (b & subnet))
msg (M_USAGE, "%s IP addresses %s and %s are not in the same %s subnet",
opt,
print_in_addr_t (a, 0, &gc),
print_in_addr_t (b, 0, &gc),
print_in_addr_t (subnet, 0, &gc));
gc_free (&gc);
}
#endif
/*
* Process server, server-bridge, and client helper
* directives after the parameters themselves have been
* parsed and placed in struct options.
*/
void
helper_client_server (struct options *o)
{
struct gc_arena gc = gc_new ();
#if P2MP
#if P2MP_SERVER
/*
*
* HELPER DIRECTIVE:
*
* server 10.8.0.0 255.255.255.0
*
* EXPANDS TO:
*
* mode server
* tls-server
*
* if tun:
* ifconfig 10.8.0.1 10.8.0.2
* ifconfig-pool 10.8.0.4 10.8.0.251
* route 10.8.0.0 255.255.255.0
* if client-to-client:
* push "route 10.8.0.0 255.255.255.0"
* else if !linear-addr:
* push "route 10.8.0.1"
*
* if tap:
* ifconfig 10.8.0.1 255.255.255.0
* ifconfig-pool 10.8.0.2 10.8.0.254 255.255.255.0
* push "route-gateway 10.8.0.1"
*/
/*
* Get tun/tap/null device type
*/
const int dev = dev_type_enum (o->dev, o->dev_type);
if (o->server_defined)
{
int netbits = -2;
bool status = false;
if (o->client)
msg (M_USAGE, "--server and --client cannot be used together");
if (o->server_bridge_defined)
msg (M_USAGE, "--server and --server-bridge cannot be used together");
if (o->shared_secret_file)
msg (M_USAGE, "--server and --secret cannot be used together (you must use SSL/TLS keys)");
if (o->ifconfig_pool_defined)
msg (M_USAGE, "--server already defines an ifconfig-pool, so you can't also specify --ifconfig-pool explicitly");
if (!(dev == DEV_TYPE_TAP || dev == DEV_TYPE_TUN))
msg (M_USAGE, "--server directive only makes sense with --dev tun or --dev tap");
status = netmask_to_netbits (o->server_network, o->server_netmask, &netbits);
if (!status)
msg (M_USAGE, "--server directive network/netmask combination is invalid");
if (netbits < 0)
msg (M_USAGE, "--server directive netmask is invalid");
if (netbits < IFCONFIG_POOL_MIN_NETBITS)
msg (M_USAGE, "--server directive netmask allows for too many host addresses (subnet must be %s or higher)",
print_netmask (IFCONFIG_POOL_MIN_NETBITS, &gc));
if (dev == DEV_TYPE_TUN)
{
int pool_end_reserve = 4;
if (netbits > 29)
msg (M_USAGE, "--server directive when used with --dev tun must define a subnet of %s or lower",
print_netmask (29, &gc));
if (netbits == 29)
pool_end_reserve = 0;
o->mode = MODE_SERVER;
o->tls_server = true;
o->ifconfig_local = print_in_addr_t (o->server_network + 1, 0, &o->gc);
o->ifconfig_remote_netmask = print_in_addr_t (o->server_network + 2, 0, &o->gc);
o->ifconfig_pool_defined = true;
o->ifconfig_pool_start = o->server_network + 4;
o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - pool_end_reserve;
helper_add_route (o->server_network, o->server_netmask, o);
if (o->enable_c2c)
push_option (o, print_opt_route (o->server_network, o->server_netmask, &o->gc), M_USAGE);
else if (!o->ifconfig_pool_linear)
push_option (o, print_opt_route (o->server_network + 1, 0, &o->gc), M_USAGE);
}
else if (dev == DEV_TYPE_TAP)
{
if (netbits >= 30)
msg (M_USAGE, "--server directive when used with --dev tap must define a subnet of %s or lower",
print_netmask (30, &gc));
o->mode = MODE_SERVER;
o->tls_server = true;
o->ifconfig_local = print_in_addr_t (o->server_network + 1, 0, &o->gc);
o->ifconfig_remote_netmask = print_in_addr_t (o->server_netmask, 0, &o->gc);
o->ifconfig_pool_defined = true;
o->ifconfig_pool_start = o->server_network + 2;
o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - 1;
o->ifconfig_pool_netmask = o->server_netmask;
push_option (o, print_opt_route_gateway (o->server_network + 1, &o->gc), M_USAGE);
}
else
{
ASSERT (0);
}
if (o->proto == PROTO_TCPv4)
o->proto = PROTO_TCPv4_SERVER;
}
/*
* HELPER DIRECTIVE:
*
* server-bridge 10.8.0.4 255.255.255.0 10.8.0.128 10.8.0.254
*
* EXPANDS TO:
*
* mode server
* tls-server
*
* ifconfig-pool 10.8.0.128 10.8.0.254 255.255.255.0
* push "route-gateway 10.8.0.4"
*/
else if (o->server_bridge_defined)
{
if (o->client)
msg (M_USAGE, "--server-bridge and --client cannot be used together");
if (o->ifconfig_pool_defined)
msg (M_USAGE, "--server-bridge already defines an ifconfig-pool, so you can't also specify --ifconfig-pool explicitly");
if (o->shared_secret_file)
msg (M_USAGE, "--server-bridge and --secret cannot be used together (you must use SSL/TLS keys)");
if (dev != DEV_TYPE_TAP)
msg (M_USAGE, "--server-bridge directive only makes sense with --dev tap");
verify_common_subnet ("--server-bridge", o->server_bridge_ip, o->server_bridge_pool_start, o->server_bridge_netmask);
verify_common_subnet ("--server-bridge", o->server_bridge_pool_start, o->server_bridge_pool_end, o->server_bridge_netmask);
verify_common_subnet ("--server-bridge", o->server_bridge_ip, o->server_bridge_pool_end, o->server_bridge_netmask);
o->mode = MODE_SERVER;
o->tls_server = true;
o->ifconfig_pool_defined = true;
o->ifconfig_pool_start = o->server_bridge_pool_start;
o->ifconfig_pool_end = o->server_bridge_pool_end;
o->ifconfig_pool_netmask = o->server_bridge_netmask;
push_option (o, print_opt_route_gateway (o->server_bridge_ip, &o->gc), M_USAGE);
if (o->proto == PROTO_TCPv4)
o->proto = PROTO_TCPv4_SERVER;
}
else
#endif /* P2MP_SERVER */
/*
* HELPER DIRECTIVE:
*
* client
*
* EXPANDS TO:
*
* pull
* tls-client
*/
if (o->client)
{
if (o->key_method != 2)
msg (M_USAGE, "--client requires --key-method 2");
o->pull = true;
o->tls_client = true;
if (o->proto == PROTO_TCPv4)
o->proto = PROTO_TCPv4_CLIENT;
}
#endif /* P2MP */
if (o->proto == PROTO_TCPv4)
msg (M_USAGE, "--proto tcp is ambiguous in this context. Please specify --proto tcp-server or --proto tcp-client");
gc_free (&gc);
}
/*
*
* HELPER DIRECTIVE:
*
* keepalive 10 60
*
* EXPANDS TO:
*
* if mode server:
* ping 10
* ping-restart 120
* push "ping 10"
* push "ping-restart 60"
* else
* ping 10
* ping-restart 60
*/
void
helper_keepalive (struct options *o)
{
if (o->keepalive_ping || o->keepalive_timeout)
{
/*
* Sanity checks.
*/
if (o->keepalive_ping <= 0 || o->keepalive_timeout <= 0)
msg (M_USAGE, "--keepalive parameters must be > 0");
if (o->keepalive_ping * 2 > o->keepalive_timeout)
msg (M_USAGE, "the second parameter to --keepalive (restart timeout=%d) must be at least twice the value of the first parameter (ping interval=%d). A ratio of 1:5 or 1:6 would be even better. Recommended setting is --keepalive 10 60.",
o->keepalive_timeout,
o->keepalive_ping);
if (o->ping_send_timeout || o->ping_rec_timeout)
msg (M_USAGE, "--keepalive conflicts with --ping, --ping-exit, or --ping-restart. If you use --keepalive, you don't need any of the other --ping directives.");
/*
* Expand.
*/
if (o->mode == MODE_POINT_TO_POINT)
{
o->ping_rec_timeout_action = PING_RESTART;
o->ping_send_timeout = o->keepalive_ping;
o->ping_rec_timeout = o->keepalive_timeout;
}
#if P2MP_SERVER
else if (o->mode == MODE_SERVER)
{
o->ping_rec_timeout_action = PING_RESTART;
o->ping_send_timeout = o->keepalive_ping;
o->ping_rec_timeout = o->keepalive_timeout * 2;
push_option (o, print_str_int ("ping", o->keepalive_ping, &o->gc), M_USAGE);
push_option (o, print_str_int ("ping-restart", o->keepalive_timeout, &o->gc), M_USAGE);
}
#endif
else
{
ASSERT (0);
}
}
}

37
helper.h Normal file
View File

@ -0,0 +1,37 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Process helper directives such as server, client, and keepalive.
*/
#ifndef HELPER_H
#define HELPER_H
#include "options.h"
void helper_keepalive (struct options *o);
void helper_client_server (struct options *o);
#endif

BIN
images/install-whirl.bmp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
images/openvpn.ico Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

2727
init.c Normal file

File diff suppressed because it is too large Load Diff

120
init.h Normal file
View File

@ -0,0 +1,120 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef INIT_H
#define INIT_H
#include "openvpn.h"
/*
* Baseline maximum number of events
* to wait for.
*/
#define BASE_N_EVENTS 4
void context_clear (struct context *c);
void context_clear_1 (struct context *c);
void context_clear_2 (struct context *c);
void context_init_1 (struct context *c);
void context_clear_all_except_first_time (struct context *c);
bool init_static (void);
void uninit_static (void);
#define IVM_LEVEL_1 (1<<0)
#define IVM_LEVEL_2 (1<<1)
void init_verb_mute (struct context *c, unsigned int flags);
void init_options_dev (struct options *options);
bool print_openssl_info (const struct options *options);
bool do_genkey (const struct options *options);
bool do_persist_tuntap (const struct options *options);
void pre_setup (const struct options *options);
void init_instance_handle_signals (struct context *c, const struct env_set *env, const unsigned int flags);
void init_instance (struct context *c, const struct env_set *env, const unsigned int flags);
void do_route (const struct options *options,
struct route_list *route_list,
const struct tuntap *tt,
const struct plugin_list *plugins,
struct env_set *es);
void close_instance (struct context *c);
bool do_test_crypto (const struct options *o);
void context_gc_free (struct context *c);
void do_up (struct context *c,
bool pulled_options,
unsigned int option_types_found);
unsigned int pull_permission_mask (void);
const char *format_common_name (struct context *c, struct gc_arena *gc);
void reset_coarse_timers (struct context *c);
void do_deferred_options (struct context *c, const unsigned int found);
void inherit_context_child (struct context *dest,
const struct context *src);
void inherit_context_top (struct context *dest,
const struct context *src);
#define CC_GC_FREE (1<<0)
#define CC_USR1_TO_HUP (1<<1)
#define CC_HARD_USR1_TO_HUP (1<<2)
void close_context (struct context *c, int sig, unsigned int flags);
struct context_buffers *init_context_buffers (const struct frame *frame);
void free_context_buffers (struct context_buffers *b);
#define ISC_ERRORS (1<<0)
#define ISC_SERVER (1<<1)
void initialization_sequence_completed (struct context *c, const unsigned int flags);
#ifdef ENABLE_MANAGEMENT
void init_management (struct context *c);
bool open_management (struct context *c);
void close_management (void);
void management_show_net_callback (void *arg, const int msglevel);
#endif
void init_management_callback_p2p (struct context *c);
void uninit_management_callback (void);
#endif

View File

@ -0,0 +1,3 @@
REM set path for OpenSSL build
set PATH=c:\bin;C:\Perl\bin\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;c:\MinGW\bin;c:\msys\1.0\bin

5
install-win32/openssl.bat Executable file
View File

@ -0,0 +1,5 @@
REM Build openssl.exe with DLL linkage to OpenSSL library
REM Run this script from top level of OpenSSL source tree
REM eg.: cp /y/openvpn/20/openvpn/install-win32/openssl.bat .
gcc -o openssl tmp\verify.o tmp\asn1pars.o tmp\req.o tmp\dgst.o tmp\dh.o tmp\dhparam.o tmp\enc.o tmp\passwd.o tmp\gendh.o tmp\errstr.o tmp\ca.o tmp\pkcs7.o tmp\crl2p7.o tmp\crl.o tmp\rsa.o tmp\rsautl.o tmp\dsa.o tmp\dsaparam.o tmp\x509.o tmp\genrsa.o tmp\gendsa.o tmp\s_server.o tmp\s_client.o tmp\speed.o tmp\s_time.o tmp\apps.o tmp\s_cb.o tmp\s_socket.o tmp\app_rand.o tmp\version.o tmp\sess_id.o tmp\ciphers.o tmp\nseq.o tmp\pkcs12.o tmp\pkcs8.o tmp\spkac.o tmp\smime.o tmp\rand.o tmp\engine.o tmp\ocsp.o tmp\prime.o tmp\openssl.o -leay32 -lssl32 -L. -lwsock32 -lgdi32

570
install-win32/openvpn.nsi.in Executable file
View File

@ -0,0 +1,570 @@
; ****************************************************************************
; * Copyright (C) 2002-2005 OpenVPN Solutions LLC *
; * 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. *
; ****************************************************************************
; OpenVPN install script for Windows, using NSIS
!include "MUI.nsh"
!include "setpath.nsi"
!define HOME "c:\src\openvpn"
!define BIN "${HOME}\bin"
!define PRODUCT_NAME "OpenVPN"
!define VERSION "@VERSION@" # AUTO_VERSION
!define TAP "tap0801"
!define TAPDRV "${TAP}.sys"
; something like "-DBG2"
!define OUTFILE_LABEL ""
; something like "DEBUG2"
!define TITLE_LABEL ""
; Default service settings
!define SERV_CONFIG_DIR "$INSTDIR\config"
!define SERV_CONFIG_EXT "ovpn"
!define SERV_EXE_PATH "$INSTDIR\bin\openvpn.exe"
!define SERV_LOG_DIR "$INSTDIR\log"
!define SERV_PRIORITY "NORMAL_PRIORITY_CLASS"
!define SERV_LOG_APPEND "0"
;--------------------------------
;Configuration
;General
OutFile "openvpn-${VERSION}${OUTFILE_LABEL}-install.exe"
SetCompressor bzip2
ShowInstDetails show
ShowUninstDetails show
;Folder selection page
InstallDir "$PROGRAMFILES\${PRODUCT_NAME}"
;Remember install folder
InstallDirRegKey HKCU "Software\${PRODUCT_NAME}" ""
;--------------------------------
;Modern UI Configuration
Name "${PRODUCT_NAME} ${VERSION} ${TITLE_LABEL}"
!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of OpenVPN, an Open Source VPN package by James Yonan.\r\n\r\nNote that the Windows version of OpenVPN will only run on Win 2000, XP, or higher.\r\n\r\n\r\n"
!define MUI_COMPONENTSPAGE_TEXT_TOP "Select the components to install/upgrade. Stop any OpenVPN processes or the OpenVPN service if it is running. All DLLs are installed locally."
!define MUI_COMPONENTSPAGE_SMALLDESC
!define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\INSTALL-win32.txt"
!define MUI_FINISHPAGE_NOAUTOCLOSE
!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED
!define MUI_ABORTWARNING
!define MUI_ICON "${HOME}\install-win32\openvpn.ico"
!define MUI_UNICON "${HOME}\install-win32\openvpn.ico"
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_BITMAP "${HOME}\install-win32\install-whirl.bmp"
!define MUI_UNFINISHPAGE_NOAUTOCLOSE
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "${HOME}\install-win32\license.txt"
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH
;--------------------------------
;Languages
!insertmacro MUI_LANGUAGE "English"
;--------------------------------
;Language Strings
LangString DESC_SecOpenVPNUserSpace ${LANG_ENGLISH} "Install OpenVPN user-space components, including openvpn.exe."
LangString DESC_SecOpenVPNEasyRSA ${LANG_ENGLISH} "Install OpenVPN RSA scripts for X509 certificate management."
LangString DESC_SecOpenSSLDLLs ${LANG_ENGLISH} "Install OpenSSL DLLs locally (may be omitted if DLLs are already installed globally)."
LangString DESC_SecTAP ${LANG_ENGLISH} "Install/Upgrade the TAP-Win32 virtual device driver. Will not interfere with CIPE."
LangString DESC_SecService ${LANG_ENGLISH} "Install the OpenVPN service wrapper (openvpnserv.exe)"
LangString DESC_SecOpenSSLUtilities ${LANG_ENGLISH} "Install the OpenSSL Utilities (used for generating public/private key pairs)."
LangString DESC_SecAddPath ${LANG_ENGLISH} "Add OpenVPN executable directory to the current user's PATH."
LangString DESC_SecAddShortcuts ${LANG_ENGLISH} "Add OpenVPN shortcuts to the current user's Start Menu."
LangString DESC_SecFileAssociation ${LANG_ENGLISH} "Register OpenVPN config file association (*.${SERV_CONFIG_EXT})"
;--------------------------------
;Reserve Files
;Things that need to be extracted on first (keep these lines before any File command!)
;Only useful for BZIP2 compression
ReserveFile "${HOME}\install-win32\install-whirl.bmp"
;--------------------------------
;Macros
!macro WriteRegStringIfUndef ROOT SUBKEY KEY VALUE
Push $R0
ReadRegStr $R0 "${ROOT}" "${SUBKEY}" "${KEY}"
StrCmp $R0 "" +1 +2
WriteRegStr "${ROOT}" "${SUBKEY}" "${KEY}" '${VALUE}'
Pop $R0
!macroend
!macro DelRegStringIfUnchanged ROOT SUBKEY KEY VALUE
Push $R0
ReadRegStr $R0 "${ROOT}" "${SUBKEY}" "${KEY}"
StrCmp $R0 '${VALUE}' +1 +2
DeleteRegValue "${ROOT}" "${SUBKEY}" "${KEY}"
Pop $R0
!macroend
!macro DelRegKeyIfUnchanged ROOT SUBKEY VALUE
Push $R0
ReadRegStr $R0 "${ROOT}" "${SUBKEY}" ""
StrCmp $R0 '${VALUE}' +1 +2
DeleteRegKey "${ROOT}" "${SUBKEY}"
Pop $R0
!macroend
!macro DelRegKeyIfEmpty ROOT SUBKEY
Push $R0
EnumRegValue $R0 "${ROOT}" "${SUBKEY}" 1
StrCmp $R0 "" +1 +2
DeleteRegKey /ifempty "${ROOT}" "${SUBKEY}"
Pop $R0
!macroend
;------------------------------------------
;Set reboot flag based on tapinstall return
Function CheckReboot
IntCmp $R0 1 "" noreboot noreboot
IntOp $R0 0 & 0
SetRebootFlag true
DetailPrint "REBOOT flag set"
noreboot:
FunctionEnd
;--------------------------------
;Installer Sections
Function .onInit
ClearErrors
UserInfo::GetName
IfErrors ok
Pop $R0
UserInfo::GetAccountType
Pop $R1
StrCmp $R1 "Admin" ok
Messagebox MB_OK "Administrator privileges required to install OpenVPN [$R0/$R1]"
Abort
ok:
FunctionEnd
!define SF_SELECTED 1
Section "OpenVPN User-Space Components" SecOpenVPNUserSpace
SetOverwrite on
SetOutPath "$INSTDIR\bin"
File "${HOME}\openvpn.exe"
SectionEnd
Section "OpenVPN RSA Certificate Management Scripts" SecOpenVPNEasyRSA
SetOverwrite on
SetOutPath "$INSTDIR\easy-rsa"
File "${HOME}\install-win32\openssl.cnf.sample"
File "${HOME}\easy-rsa\Windows\vars.bat.sample"
File "${HOME}\easy-rsa\Windows\init-config.bat"
File "${HOME}\easy-rsa\Windows\README.txt"
File "${HOME}\easy-rsa\Windows\build-ca.bat"
File "${HOME}\easy-rsa\Windows\build-dh.bat"
File "${HOME}\easy-rsa\Windows\build-key-server.bat"
File "${HOME}\easy-rsa\Windows\build-key.bat"
File "${HOME}\easy-rsa\Windows\build-key-pkcs12.bat"
File "${HOME}\easy-rsa\Windows\clean-all.bat"
File "${HOME}\easy-rsa\Windows\index.txt.start"
File "${HOME}\easy-rsa\Windows\revoke-full.bat"
File "${HOME}\easy-rsa\Windows\serial.start"
SectionEnd
Section "OpenVPN Service" SecService
SetOverwrite on
SetOutPath "$INSTDIR\bin"
File "${HOME}\service-win32\openvpnserv.exe"
SetOutPath "$INSTDIR\config"
FileOpen $R0 "$INSTDIR\config\README.txt" w
FileWrite $R0 "This directory should contain OpenVPN configuration files$\r$\n"
FileWrite $R0 "each having an extension of .${SERV_CONFIG_EXT}$\r$\n"
FileWrite $R0 "$\r$\n"
FileWrite $R0 "When OpenVPN is started as a service, a separate OpenVPN$\r$\n"
FileWrite $R0 "process will be instantiated for each configuration file.$\r$\n"
FileClose $R0
SetOutPath "$INSTDIR\sample-config"
File "${HOME}\install-win32\sample.${SERV_CONFIG_EXT}"
File "${HOME}\install-win32\client.${SERV_CONFIG_EXT}"
File "${HOME}\install-win32\server.${SERV_CONFIG_EXT}"
CreateDirectory "$INSTDIR\log"
FileOpen $R0 "$INSTDIR\log\README.txt" w
FileWrite $R0 "This directory will contain the log files for OpenVPN$\r$\n"
FileWrite $R0 "sessions which are being run as a service.$\r$\n"
FileClose $R0
SectionEnd
Section "OpenVPN File Associations" SecFileAssociation
SectionEnd
Section "OpenSSL DLLs" SecOpenSSLDLLs
SetOverwrite on
SetOutPath "$INSTDIR\bin"
File "${BIN}\libeay32.dll"
File "${BIN}\libssl32.dll"
SectionEnd
Section "OpenSSL Utilities" SecOpenSSLUtilities
SetOverwrite on
SetOutPath "$INSTDIR\bin"
File "${BIN}\openssl.exe"
SectionEnd
Section "TAP-Win32 Virtual Ethernet Adapter" SecTAP
SetOverwrite on
SetOutPath "$INSTDIR\bin"
File "${BIN}\ti3790\tapinstall.exe"
FileOpen $R0 "$INSTDIR\bin\addtap.bat" w
FileWrite $R0 "rem Add a new TAP-Win32 virtual ethernet adapter$\r$\n"
FileWrite $R0 '"$INSTDIR\bin\tapinstall.exe" install "$INSTDIR\driver\OemWin2k.inf" ${TAP}$\r$\n'
FileWrite $R0 "pause$\r$\n"
FileClose $R0
FileOpen $R0 "$INSTDIR\bin\deltapall.bat" w
FileWrite $R0 "echo WARNING: this script will delete ALL TAP-Win32 virtual adapters (use the device manager to delete adapters one at a time)$\r$\n"
FileWrite $R0 "pause$\r$\n"
FileWrite $R0 '"$INSTDIR\bin\tapinstall.exe" remove ${TAP}$\r$\n'
FileWrite $R0 "pause$\r$\n"
FileClose $R0
SetOutPath "$INSTDIR\driver"
File "${HOME}\tap-win32\i386\OemWin2k.inf"
File "${HOME}\tap-win32\i386\${TAPDRV}"
SectionEnd
Section "Add OpenVPN to PATH" SecAddPath
; remove previously set path (if any)
Push "$INSTDIR\bin"
Call RemoveFromPath
; append our bin directory to end of current user path
Push "$INSTDIR\bin"
Call AddToPath
SectionEnd
Section "Add Shortcuts to Start Menu" SecAddShortcuts
SetOverwrite on
CreateDirectory "$SMPROGRAMS\OpenVPN"
WriteINIStr "$SMPROGRAMS\OpenVPN\OpenVPN Windows Notes.url" "InternetShortcut" "URL" "http://openvpn.net/INSTALL-win32.html"
WriteINIStr "$SMPROGRAMS\OpenVPN\OpenVPN Manual Page.url" "InternetShortcut" "URL" "http://openvpn.net/man.html"
WriteINIStr "$SMPROGRAMS\OpenVPN\OpenVPN HOWTO.url" "InternetShortcut" "URL" "http://openvpn.net/howto.html"
WriteINIStr "$SMPROGRAMS\OpenVPN\OpenVPN Web Site.url" "InternetShortcut" "URL" "http://openvpn.net/"
CreateShortCut "$SMPROGRAMS\OpenVPN\Uninstall OpenVPN.lnk" "$INSTDIR\Uninstall.exe"
SectionEnd
;--------------------
;Post-install section
Section -post
; delete old devcon.exe
Delete "$INSTDIR\bin\devcon.exe"
;
; install/upgrade TAP-Win32 driver if selected, using tapinstall.exe
;
SectionGetFlags ${SecTAP} $R0
IntOp $R0 $R0 & ${SF_SELECTED}
IntCmp $R0 ${SF_SELECTED} "" notap notap
; TAP install/update was selected.
; Should we install or update?
; If tapinstall error occurred, $5 will
; be nonzero.
IntOp $5 0 & 0
nsExec::ExecToStack '"$INSTDIR\bin\tapinstall.exe" hwids ${TAP}'
Pop $R0 # return value/error/timeout
IntOp $5 $5 | $R0
DetailPrint "tapinstall hwids returned: $R0"
; If tapinstall output string contains "${TAP}" we assume
; that TAP device has been previously installed,
; therefore we will update, not install.
Push "${TAP}"
Call StrStr
Pop $R0
IntCmp $5 0 "" tapinstall_check_error tapinstall_check_error
IntCmp $R0 -1 tapinstall
;tapupdate:
DetailPrint "TAP-Win32 UPDATE"
nsExec::ExecToLog '"$INSTDIR\bin\tapinstall.exe" update "$INSTDIR\driver\OemWin2k.inf" ${TAP}'
Pop $R0 # return value/error/timeout
Call CheckReboot
IntOp $5 $5 | $R0
DetailPrint "tapinstall update returned: $R0"
Goto tapinstall_check_error
tapinstall:
DetailPrint "TAP-Win32 REMOVE OLD TAP"
nsExec::ExecToLog '"$INSTDIR\bin\tapinstall.exe" remove TAP'
Pop $R0 # return value/error/timeout
DetailPrint "tapinstall remove TAP returned: $R0"
nsExec::ExecToLog '"$INSTDIR\bin\tapinstall.exe" remove TAPDEV'
Pop $R0 # return value/error/timeout
DetailPrint "tapinstall remove TAPDEV returned: $R0"
DetailPrint "TAP-Win32 INSTALL (${TAP})"
nsExec::ExecToLog '"$INSTDIR\bin\tapinstall.exe" install "$INSTDIR\driver\OemWin2k.inf" ${TAP}'
Pop $R0 # return value/error/timeout
Call CheckReboot
IntOp $5 $5 | $R0
DetailPrint "tapinstall install returned: $R0"
tapinstall_check_error:
DetailPrint "tapinstall cumulative status: $5"
IntCmp $5 0 notap
MessageBox MB_OK "An error occurred installing the TAP-Win32 device driver."
notap:
; Store install folder in registry
WriteRegStr HKLM SOFTWARE\OpenVPN "" $INSTDIR
; install as a service if requested
SectionGetFlags ${SecService} $R0
IntOp $R0 $R0 & ${SF_SELECTED}
IntCmp $R0 ${SF_SELECTED} "" noserv noserv
; set registry parameters for openvpnserv
!insertmacro WriteRegStringIfUndef HKLM "SOFTWARE\OpenVPN" "config_dir" "${SERV_CONFIG_DIR}"
!insertmacro WriteRegStringIfUndef HKLM "SOFTWARE\OpenVPN" "config_ext" "${SERV_CONFIG_EXT}"
!insertmacro WriteRegStringIfUndef HKLM "SOFTWARE\OpenVPN" "exe_path" "${SERV_EXE_PATH}"
!insertmacro WriteRegStringIfUndef HKLM "SOFTWARE\OpenVPN" "log_dir" "${SERV_LOG_DIR}"
!insertmacro WriteRegStringIfUndef HKLM "SOFTWARE\OpenVPN" "priority" "${SERV_PRIORITY}"
!insertmacro WriteRegStringIfUndef HKLM "SOFTWARE\OpenVPN" "log_append" "${SERV_LOG_APPEND}"
; install openvpnserv as a service
DetailPrint "Previous Service REMOVE (if exists)"
nsExec::ExecToLog '"$INSTDIR\bin\openvpnserv.exe" -remove'
Pop $R0 # return value/error/timeout
DetailPrint "Service INSTALL"
nsExec::ExecToLog '"$INSTDIR\bin\openvpnserv.exe" -install'
Pop $R0 # return value/error/timeout
noserv:
; Store README, license, icon
SetOverwrite on
SetOutPath $INSTDIR
File "${HOME}\install-win32\INSTALL-win32.txt"
File "${HOME}\install-win32\license.txt"
File "${HOME}\install-win32\openvpn.ico"
; Create file association if requested
SectionGetFlags ${SecFileAssociation} $R0
IntOp $R0 $R0 & ${SF_SELECTED}
IntCmp $R0 ${SF_SELECTED} "" noass noass
!insertmacro WriteRegStringIfUndef HKCR ".${SERV_CONFIG_EXT}" "" "OpenVPNFile"
!insertmacro WriteRegStringIfUndef HKCR "OpenVPNFile" "" "OpenVPN Config File"
!insertmacro WriteRegStringIfUndef HKCR "OpenVPNFile\shell" "" "open"
!insertmacro WriteRegStringIfUndef HKCR "OpenVPNFile\DefaultIcon" "" "$INSTDIR\openvpn.ico,0"
!insertmacro WriteRegStringIfUndef HKCR "OpenVPNFile\shell\open\command" "" 'notepad.exe "%1"'
!insertmacro WriteRegStringIfUndef HKCR "OpenVPNFile\shell\run" "" "Start OpenVPN on this config file"
!insertmacro WriteRegStringIfUndef HKCR "OpenVPNFile\shell\run\command" "" '"$INSTDIR\bin\openvpn.exe" --pause-exit --config "%1"'
; Create start menu shortcuts to addtap.bat and deltapall.bat
noass:
IfFileExists "$INSTDIR\bin\addtap.bat" "" trydeltap
CreateShortCut "$SMPROGRAMS\OpenVPN\Add a new TAP-Win32 virtual ethernet adapter.lnk" "$INSTDIR\bin\addtap.bat" ""
trydeltap:
IfFileExists "$INSTDIR\bin\deltapall.bat" "" config_shortcut
CreateShortCut "$SMPROGRAMS\OpenVPN\Delete ALL TAP-Win32 virtual ethernet adapters.lnk" "$INSTDIR\bin\deltapall.bat" ""
; Create start menu shortcuts for config and log directories
config_shortcut:
IfFileExists "$INSTDIR\config" "" log_shortcut
CreateShortCut "$SMPROGRAMS\OpenVPN\OpenVPN configuration file directory.lnk" "$INSTDIR\config" ""
log_shortcut:
IfFileExists "$INSTDIR\log" "" samp_shortcut
CreateShortCut "$SMPROGRAMS\OpenVPN\OpenVPN log file directory.lnk" "$INSTDIR\log" ""
samp_shortcut:
IfFileExists "$INSTDIR\sample-config" "" genkey_shortcut
CreateShortCut "$SMPROGRAMS\OpenVPN\OpenVPN Sample Configuration Files.lnk" "$INSTDIR\sample-config" ""
genkey_shortcut:
IfFileExists "$INSTDIR\bin\openvpn.exe" "" noshortcuts
IfFileExists "$INSTDIR\config" "" noshortcuts
CreateShortCut "$SMPROGRAMS\OpenVPN\Generate a static OpenVPN key.lnk" "$INSTDIR\bin\openvpn.exe" '--pause-exit --verb 3 --genkey --secret "$INSTDIR\config\key.txt"' "$INSTDIR\openvpn.ico" 0
noshortcuts:
; Create uninstaller
WriteUninstaller "$INSTDIR\Uninstall.exe"
; Show up in Add/Remove programs
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "DisplayName" "${PRODUCT_NAME} ${VERSION}"
WriteRegExpandStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "UninstallString" "$INSTDIR\Uninstall.exe"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "DisplayIcon" "$INSTDIR\openvpn.ico"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "DisplayVersion" "${VERSION}"
; Advise a reboot
;Messagebox MB_OK "IMPORTANT: Rebooting the system is advised in order to finalize TAP-Win32 driver installation/upgrade (this is an informational message only, pressing OK will not reboot)."
SectionEnd
;--------------------------------
;Descriptions
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${SecOpenVPNUserSpace} $(DESC_SecOpenVPNUserSpace)
!insertmacro MUI_DESCRIPTION_TEXT ${SecOpenVPNEasyRSA} $(DESC_SecOpenVPNEasyRSA)
!insertmacro MUI_DESCRIPTION_TEXT ${SecTAP} $(DESC_SecTAP)
!insertmacro MUI_DESCRIPTION_TEXT ${SecOpenSSLUtilities} $(DESC_SecOpenSSLUtilities)
!insertmacro MUI_DESCRIPTION_TEXT ${SecOpenSSLDLLs} $(DESC_SecOpenSSLDLLs)
!insertmacro MUI_DESCRIPTION_TEXT ${SecAddPath} $(DESC_SecAddPath)
!insertmacro MUI_DESCRIPTION_TEXT ${SecAddShortcuts} $(DESC_SecAddShortcuts)
!insertmacro MUI_DESCRIPTION_TEXT ${SecService} $(DESC_SecService)
!insertmacro MUI_DESCRIPTION_TEXT ${SecFileAssociation} $(DESC_SecFileAssociation)
!insertmacro MUI_FUNCTION_DESCRIPTION_END
;--------------------------------
;Uninstaller Section
Function un.onInit
ClearErrors
UserInfo::GetName
IfErrors ok
Pop $R0
UserInfo::GetAccountType
Pop $R1
StrCmp $R1 "Admin" ok
Messagebox MB_OK "Administrator privileges required to uninstall OpenVPN [$R0/$R1]"
Abort
ok:
FunctionEnd
Section "Uninstall"
DetailPrint "Service REMOVE"
nsExec::ExecToLog '"$INSTDIR\bin\openvpnserv.exe" -remove'
Pop $R0 # return value/error/timeout
Sleep 2000
DetailPrint "TAP-Win32 REMOVE"
nsExec::ExecToLog '"$INSTDIR\bin\tapinstall.exe" remove ${TAP}'
Pop $R0 # return value/error/timeout
DetailPrint "tapinstall remove returned: $R0"
Push "$INSTDIR\bin"
Call un.RemoveFromPath
RMDir /r $SMPROGRAMS\OpenVPN
Delete "$INSTDIR\bin\openvpn.exe"
Delete "$INSTDIR\bin\openvpnserv.exe"
Delete "$INSTDIR\bin\libeay32.dll"
Delete "$INSTDIR\bin\libssl32.dll"
Delete "$INSTDIR\bin\tapinstall.exe"
Delete "$INSTDIR\bin\addtap.bat"
Delete "$INSTDIR\bin\deltapall.bat"
Delete "$INSTDIR\config\README.txt"
Delete "$INSTDIR\config\sample.${SERV_CONFIG_EXT}.txt"
Delete "$INSTDIR\log\README.txt"
Delete "$INSTDIR\driver\OemWin2k.inf"
Delete "$INSTDIR\driver\${TAPDRV}"
Delete "$INSTDIR\bin\openssl.exe"
Delete "$INSTDIR\INSTALL-win32.txt"
Delete "$INSTDIR\openvpn.ico"
Delete "$INSTDIR\license.txt"
Delete "$INSTDIR\Uninstall.exe"
Delete "$INSTDIR\easy-rsa\openssl.cnf.sample"
Delete "$INSTDIR\easy-rsa\vars.bat.sample"
Delete "$INSTDIR\easy-rsa\init-config.bat"
Delete "$INSTDIR\easy-rsa\README.txt"
Delete "$INSTDIR\easy-rsa\build-ca.bat"
Delete "$INSTDIR\easy-rsa\build-dh.bat"
Delete "$INSTDIR\easy-rsa\build-key-server.bat"
Delete "$INSTDIR\easy-rsa\build-key.bat"
Delete "$INSTDIR\easy-rsa\build-key-pkcs12.bat"
Delete "$INSTDIR\easy-rsa\clean-all.bat"
Delete "$INSTDIR\easy-rsa\index.txt.start"
Delete "$INSTDIR\easy-rsa\revoke-key.bat"
Delete "$INSTDIR\easy-rsa\revoke-full.bat"
Delete "$INSTDIR\easy-rsa\serial.start"
Delete "$INSTDIR\sample-config\*.ovpn"
RMDir "$INSTDIR\bin"
RMDir "$INSTDIR\driver"
RMDir "$INSTDIR\easy-rsa"
RMDir "$INSTDIR\sample-config"
RMDir "$INSTDIR"
!insertmacro DelRegKeyIfUnchanged HKCR ".${SERV_CONFIG_EXT}" "OpenVPNFile"
DeleteRegKey HKCR "OpenVPNFile"
DeleteRegKey HKLM SOFTWARE\OpenVPN
DeleteRegKey HKCU "Software\${PRODUCT_NAME}"
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenVPN"
;Messagebox MB_OK "IMPORTANT: If you intend on reinstalling OpenVPN after this uninstall, and you are running Win2K, you are strongly urged to reboot before reinstalling (this is an informational message only, pressing OK will not reboot)."
SectionEnd

145
install-win32/prebuild Executable file
View File

@ -0,0 +1,145 @@
# Given a standard OpenVPN tarball tree,
# build a Windows tree which is NSIS-ready.
#
# Requires:
# MinGW
# MSYS GNU shell environment
# See other requirements below
# Top level directory.
H=/c/src
# Output NSIS-ready tree here (will be deleted
# if already exists).
OUT=$H/openvpn-build
# Source distribution is here. Can be the top
# level directory of exploded tarball.
IN=/y/openvpn/20/openvpn
# Already built OpenSSL tree.
SSL=$H/openssl-0.9.7g
# Already built LZO tree.
LZO=$H/lzo-1.08
# Already built dmalloc tree.
# Optional, but leave defined even if you are not using
# dmalloc.
DMALLOC=$H/dmalloc-5.4.2
# TAP binaries should be here: tap0801.sys and tapinstall.exe
# These must be built with MS DDK.
TAPBIN=$H/tapbin
# u2d.c should exist here.
SCRIPTS=$IN/install-win32
# Put service.[ch] here from MS Platform SDK.
SVC_TEMPLATE=$H/svc-template
# Misc files/directories which should be copied to OUT (optional)
MISC=$H/add
# Temporary directory
TMP=/tmp
# End of user-defined parameters.
U2D=$TMP/u2d
echo BUILD u2d
gcc -O2 $SCRIPTS/u2d.c -o $U2D
echo BUILD output dir from source
rm -rf $OUT
mkdir $OUT
cp $IN/*.[ch] $OUT
rm -f $OUT/config.h
if [ $MISC ]; then
cp $MISC/*.* $OUT
fi
echo BUILD makefile
sed "s#^OPENSSL = .*\$#OPENSSL = $SSL#" <$IN/makefile.w32 | \
sed "s#^LZO = .*\$#LZO = $LZO#" | \
sed "s#^DMALLOC = .*\$#DMALLOC = $DMALLOC#" >$OUT/Makefile
echo BUILD bin
mkdir $OUT/bin
for f in libeay32.dll libssl32.dll openssl.exe ; do
cp $SSL/$f $OUT/bin
strip $OUT/bin/$f
done
echo BUILD install-win32
mkdir $OUT/install-win32
cp $IN/install-win32/openvpn.nsi $OUT/install-win32
cp $IN/install-win32/setpath.nsi $OUT/install-win32
cp $IN/images/install-whirl.bmp $OUT/install-win32
cp $IN/images/openvpn.ico $OUT/install-win32
cp $IN/INSTALL-win32.txt $OUT/install-win32
cat $IN/COPYING $IN/COPYRIGHT.GPL | $U2D >$OUT/install-win32/license.txt
$U2D <$IN/sample-config-files/client.conf >$OUT/install-win32/client.ovpn
$U2D <$IN/sample-config-files/server.conf >$OUT/install-win32/server.ovpn
cp $IN/install-win32/sample.ovpn $OUT/install-win32
$U2D <$IN/easy-rsa/openssl.cnf >$OUT/install-win32/openssl.cnf.sample
echo BUILD tap-win32
mkdir $OUT/tap-win32
cp $IN/tap-win32/*.[ch] $OUT/tap-win32
cp $IN/tap-win32/*.rc $OUT/tap-win32
cp $IN/tap-win32/MAKEFILE $OUT/tap-win32
cp $IN/tap-win32/SOURCES $OUT/tap-win32
mkdir $OUT/tap-win32/i386
cp $IN/tap-win32/i386/OemWin2k.inf $OUT/tap-win32/i386
cp $IN/tap-win32/i386/tap.cat $OUT/tap-win32/i386
cp $TAPBIN/tap0801.sys $OUT/tap-win32/i386
mkdir $OUT/bin/ti3790
cp $TAPBIN/tapinstall.exe $OUT/bin/ti3790
echo BUILD service-win32
mkdir $OUT/service-win32
cp $IN/service-win32/Makefile $OUT/service-win32
cp $IN/service-win32/mkpatch $OUT/service-win32
cp $IN/service-win32/openvpnserv.c $OUT/service-win32
cp $IN/service-win32/service.patch $OUT/service-win32
cp $SVC_TEMPLATE/service.[ch] $OUT/service-win32
cp $OUT/service-win32/service.h $OUT/service-win32/service.h.orig
cp $OUT/service-win32/service.c $OUT/service-win32/service.c.orig
pushd $OUT/service-win32
patch <service.patch
popd
echo BUILD easy-rsa
cp -a $IN/easy-rsa $OUT
echo BUILD sample-keys
cp -a $IN/sample-keys $OUT
echo COMPILE OpenVPN
pushd $OUT
make
strip openvpn.exe
popd
echo COMPILE OpenVPN Service
pushd $OUT/service-win32
make clean
make
strip openvpnserv.exe
popd

103
install-win32/sample.ovpn Executable file
View File

@ -0,0 +1,103 @@
# Edit this file, and save to a .ovpn extension
# so that OpenVPN will activate it when run
# as a service.
# Change 'myremote' to be your remote host,
# or comment out to enter a listening
# server mode.
remote myremote
# Uncomment this line to use a different
# port number than the default of 1194.
; port 1194
# Choose one of three protocols supported by
# OpenVPN. If left commented out, defaults
# to udp.
; proto [tcp-server | tcp-client | udp]
# You must specify one of two possible network
# protocols, 'dev tap' or 'dev tun' to be used
# on both sides of the connection. 'tap' creates
# a VPN using the ethernet protocol while 'tun'
# uses the IP protocol. You must use 'tap'
# if you are ethernet bridging or want to route
# broadcasts. 'tun' is somewhat more efficient
# but requires configuration of client software
# to not depend on broadcasts. Some platforms
# such as Solaris, OpenBSD, and Mac OS X only
# support 'tun' interfaces, so if you are
# connecting to such a platform, you must also
# use a 'tun' interface on the Windows side.
# Enable 'dev tap' or 'dev tun' but not both!
dev tap
# This is a 'dev tap' ifconfig that creates
# a virtual ethernet subnet.
# 10.3.0.1 is the local VPN IP address
# and 255.255.255.0 is the VPN subnet.
# Only define this option for 'dev tap'.
ifconfig 10.3.0.1 255.255.255.0
# This is a 'dev tun' ifconfig that creates
# a point-to-point IP link.
# 10.3.0.1 is the local VPN IP address and
# 10.3.0.2 is the remote VPN IP address.
# Only define this option for 'dev tun'.
# Make sure to include the "tun-mtu" option
# on the remote machine, but swap the order
# of the ifconfig addresses.
;tun-mtu 1500
;ifconfig 10.3.0.1 10.3.0.2
# If you have fragmentation issues or misconfigured
# routers in the path which block Path MTU discovery,
# lower the TCP MSS and internally fragment non-TCP
# protocols.
;fragment 1300
;mssfix
# If you have set up more than one TAP-Win32 adapter
# on your system, you must refer to it by name.
;dev-node my-tap
# You can generate a static OpenVPN key
# by selecting the Generate Key option
# in the start menu.
#
# You can also generate key.txt manually
# with the following command:
# openvpn --genkey --secret key.txt
#
# key must match on both ends of the connection,
# so you should generate it on one machine and
# copy it to the other over a secure medium.
# Place key.txt in the same directory as this
# config file.
secret key.txt
# Uncomment this section for a more reliable
# detection when a system loses its connection.
# For example, dial-ups or laptops that travel
# to other locations.
#
# If this section is enabled and "myremote"
# above is a dynamic DNS name (i.e. dyndns.org),
# OpenVPN will dynamically "follow" the IP
# address of "myremote" if it changes.
; ping-restart 60
; ping-timer-rem
; persist-tun
; persist-key
; resolv-retry 86400
# keep-alive ping
ping 10
# enable LZO compression
comp-lzo
# moderate verbosity
verb 4
mute 10

231
install-win32/setpath.nsi Executable file
View File

@ -0,0 +1,231 @@
; Modify the user's PATH variable.
;
; Modified by JY to have both a RemoveFromPath
; and an un.RemoveFromPath which are basically
; copies of each other. Why does NSIS demand
; this nonsense?
;
; Modified Feb 14, 2005 by Mathias Sundman:
; Added code to remove the semicolon at the end of the path
; when uninstalling.
;
; Added code to make sure we don't insert an extra semicolon
; before our path if there already exist one at the end of
; the original path.
;
; Removed duplicated "un. and install" functions and made
; macros to duplicate the code instead.
; example usage
;
;Section "Add to path"
; Push $INSTDIR
; Call AddToPath
;SectionEnd
;
;# ...
;
;Section "uninstall"
; # ...
; Push $INSTDIR
; Call un.RemoveFromPath
; # ...
;SectionEnd
!verbose 3
!include "WinMessages.NSH"
!verbose 4
;====================================================
; AddToPath - Adds the given dir to the search path.
; Input - head of the stack
; Note - Win9x systems requires reboot
;====================================================
Function AddToPath
Exch $0
Push $1
Push $2
Call IsNT
Pop $1
StrCmp $1 1 AddToPath_NT
; Not on NT
StrCpy $1 $WINDIR 2
FileOpen $1 "$1\autoexec.bat" a
FileSeek $1 0 END
GetFullPathName /SHORT $0 $0
FileWrite $1 "$\r$\nSET PATH=%PATH%;$0$\r$\n"
FileClose $1
Goto AddToPath_done
AddToPath_NT:
ReadRegStr $1 HKCU "Environment" "PATH"
StrCpy $2 $1 1 -1 # copy last char
StrCmp $2 ";" 0 +2 # if last char == ;
StrCpy $1 $1 -1 # remove last char
StrCmp $1 "" AddToPath_NTdoIt
StrCpy $0 "$1;$0"
Goto AddToPath_NTdoIt
AddToPath_NTdoIt:
WriteRegExpandStr HKCU "Environment" "PATH" $0
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
AddToPath_done:
Pop $2
Pop $1
Pop $0
FunctionEnd
;====================================================
; RemoveFromPath - Remove a given dir from the path
; Input: head of the stack
;====================================================
!macro RemoveFromPath un
Function ${un}RemoveFromPath
Exch $0
Push $1
Push $2
Push $3
Push $4
Push $5
Call ${un}IsNT
Pop $1
StrCmp $1 1 RemoveFromPath_NT
; Not on NT
StrCpy $1 $WINDIR 2
FileOpen $1 "$1\autoexec.bat" r
GetTempFileName $4
FileOpen $2 $4 w
GetFullPathName /SHORT $0 $0
StrCpy $0 "SET PATH=%PATH%;$0"
SetRebootFlag true
Goto RemoveFromPath_dosLoop
RemoveFromPath_dosLoop:
FileRead $1 $3
StrCmp $3 "$0$\r$\n" RemoveFromPath_dosLoop
StrCmp $3 "$0$\n" RemoveFromPath_dosLoop
StrCmp $3 "$0" RemoveFromPath_dosLoop
StrCmp $3 "" RemoveFromPath_dosLoopEnd
FileWrite $2 $3
Goto RemoveFromPath_dosLoop
RemoveFromPath_dosLoopEnd:
FileClose $2
FileClose $1
StrCpy $1 $WINDIR 2
Delete "$1\autoexec.bat"
CopyFiles /SILENT $4 "$1\autoexec.bat"
Delete $4
Goto RemoveFromPath_done
RemoveFromPath_NT:
StrLen $2 $0
ReadRegStr $1 HKCU "Environment" "PATH"
Push $1
Push $0
Call ${un}StrStr ; Find $0 in $1
Pop $0 ; pos of our dir
IntCmp $0 -1 RemoveFromPath_done
; else, it is in path
StrCpy $3 $1 $0 ; $3 now has the part of the path before our dir
IntOp $2 $2 + $0 ; $2 now contains the pos after our dir in the path (';')
IntOp $2 $2 + 1 ; $2 now containts the pos after our dir and the semicolon.
StrLen $0 $1
StrCpy $1 $1 $0 $2
StrCpy $3 "$3$1"
StrCpy $5 $3 1 -1 # copy last char
StrCmp $5 ";" 0 +2 # if last char == ;
StrCpy $3 $3 -1 # remove last char
WriteRegExpandStr HKCU "Environment" "PATH" $3
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
RemoveFromPath_done:
Pop $5
Pop $4
Pop $3
Pop $2
Pop $1
Pop $0
FunctionEnd
!macroend
!insertmacro RemoveFromPath ""
!insertmacro RemoveFromPath "un."
;====================================================
; StrStr - Finds a given string in another given string.
; Returns -1 if not found and the pos if found.
; Input: head of the stack - string to find
; second in the stack - string to find in
; Output: head of the stack
;====================================================
!macro StrStr un
Function ${un}StrStr
Push $0
Exch
Pop $0 ; $0 now have the string to find
Push $1
Exch 2
Pop $1 ; $1 now have the string to find in
Exch
Push $2
Push $3
Push $4
Push $5
StrCpy $2 -1
StrLen $3 $0
StrLen $4 $1
IntOp $4 $4 - $3
StrStr_loop:
IntOp $2 $2 + 1
IntCmp $2 $4 0 0 StrStrReturn_notFound
StrCpy $5 $1 $3 $2
StrCmp $5 $0 StrStr_done StrStr_loop
StrStrReturn_notFound:
StrCpy $2 -1
StrStr_done:
Pop $5
Pop $4
Pop $3
Exch $2
Exch 2
Pop $0
Pop $1
FunctionEnd
!macroend
!insertmacro StrStr ""
!insertmacro StrStr "un."
;====================================================
; IsNT - Returns 1 if the current system is NT, 0
; otherwise.
; Output: head of the stack
;====================================================
!macro IsNT un
Function ${un}IsNT
Push $0
ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
StrCmp $0 "" 0 IsNT_yes
; we are not NT.
Pop $0
Push 0
Return
IsNT_yes:
; NT!!!
Pop $0
Push 1
FunctionEnd
!macroend
!insertmacro IsNT ""
!insertmacro IsNT "un."

20
install-win32/u2d.c Executable file
View File

@ -0,0 +1,20 @@
#include <stdio.h>
int
main (int argc, char *argv[])
{
int c;
int enable = 1;
while ((c = getchar()) != EOF)
{
#if 0
if (c == '\r')
enable = 0;
if (enable && c == '\n')
putchar ('\r');
#endif
putchar (c);
}
return 0;
}

114
integer.h Normal file
View File

@ -0,0 +1,114 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef INTEGER_H
#define INTEGER_H
#include "error.h"
/*
* min/max functions
*/
static inline int
max_int (int x, int y)
{
if (x > y)
return x;
else
return y;
}
static inline int
min_int (int x, int y)
{
if (x < y)
return x;
else
return y;
}
static inline int
constrain_int (int x, int min, int max)
{
if (min > max)
return min;
if (x < min)
return min;
else if (x > max)
return max;
else
return x;
}
/*
* Functions used for circular buffer index arithmetic.
*/
/*
* Return x - y on a circle of circumference mod by shortest path.
*
* 0 <= x < mod
* 0 <= y < mod
*/
static inline int
modulo_subtract(int x, int y, int mod)
{
const int d1 = x - y;
const int d2 = (x > y ? -mod : mod) + d1;
ASSERT (0 <= x && x < mod && 0 <= y && y < mod);
return abs(d1) > abs(d2) ? d2 : d1;
}
/*
* Return x + y on a circle of circumference mod.
*
* 0 <= x < mod
* -mod <= y <= mod
*/
static inline int
modulo_add(int x, int y, int mod)
{
int sum = x + y;
ASSERT (0 <= x && x < mod && -mod <= y && y <= mod);
if (sum >= mod)
sum -= mod;
if (sum < 0)
sum += mod;
return sum;
}
static inline int
index_verify (int index, int size, const char *file, int line)
{
if (index < 0 || index >= size)
msg (M_FATAL, "Assertion Failed: Array index=%d out of bounds for array size=%d in %s:%d",
index,
size,
file,
line);
return index;
}
#endif

83
interval.c Normal file
View File

@ -0,0 +1,83 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef WIN32
#include "config-win32.h"
#else
#include "config.h"
#endif
#include "syshead.h"
#include "interval.h"
#include "memdbg.h"
void
interval_init (struct interval *top, int horizon, int refresh)
{
CLEAR (*top);
top->refresh = refresh;
top->horizon = horizon;
}
bool
event_timeout_trigger (struct event_timeout *et,
struct timeval *tv,
const int et_const_retry)
{
bool ret = false;
const time_t local_now = now;
if (et->defined)
{
int wakeup = (int) et->last + et->n - local_now;
if (wakeup <= 0)
{
#if INTERVAL_DEBUG
dmsg (D_INTERVAL, "EVENT event_timeout_trigger (%d) etcr=%d", et->n, et_const_retry);
#endif
if (et_const_retry < 0)
{
et->last = local_now;
wakeup = et->n;
ret = true;
}
else
{
wakeup = et_const_retry;
}
}
if (tv && wakeup < tv->tv_sec)
{
#if INTERVAL_DEBUG
dmsg (D_INTERVAL, "EVENT event_timeout_wakeup (%d/%d) etcr=%d", wakeup, et->n, et_const_retry);
#endif
tv->tv_sec = wakeup;
tv->tv_usec = 0;
}
}
return ret;
}

239
interval.h Normal file
View File

@ -0,0 +1,239 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* The interval_ routines are designed to optimize the calling of a routine
* (normally tls_multi_process()) which can be called less frequently
* between triggers.
*/
#ifndef INTERVAL_H
#define INTERVAL_H
#include "otime.h"
#define INTERVAL_DEBUG 0
/*
* Designed to limit calls to expensive functions that need to be called
* regularly.
*/
struct interval
{
interval_t refresh;
interval_t horizon;
time_t future_trigger;
time_t last_action;
time_t last_test_true;
};
void interval_init (struct interval *top, int horizon, int refresh);
/*
* IF
* last_action less than horizon seconds ago
* OR last_test_true more than refresh seconds ago
* OR hit future_trigger
* THEN
* return true
* ELSE
* set wakeup to the number of seconds until a true return
* return false
*/
static inline bool
interval_test (struct interval* top)
{
bool trigger = false;
const time_t local_now = now;
if (top->future_trigger && local_now >= top->future_trigger)
{
trigger = true;
top->future_trigger = 0;
}
if (top->last_action + top->horizon > local_now ||
top->last_test_true + top->refresh <= local_now ||
trigger)
{
top->last_test_true = local_now;
#if INTERVAL_DEBUG
dmsg (D_INTERVAL, "INTERVAL interval_test true");
#endif
return true;
}
else
{
return false;
}
}
static inline void
interval_schedule_wakeup (struct interval* top, interval_t *wakeup)
{
const time_t local_now = now;
interval_earliest_wakeup (wakeup, top->last_test_true + top->refresh, local_now);
interval_earliest_wakeup (wakeup, top->future_trigger, local_now);
#if INTERVAL_DEBUG
dmsg (D_INTERVAL, "INTERVAL interval_schedule wakeup=%d", (int)*wakeup);
#endif
}
/*
* In wakeup seconds, interval_test will return true once.
*/
static inline void
interval_future_trigger (struct interval* top, interval_t wakeup) {
if (wakeup)
{
#if INTERVAL_DEBUG
dmsg (D_INTERVAL, "INTERVAL interval_future_trigger %d", (int)wakeup);
#endif
top->future_trigger = now + wakeup;
}
}
/*
* Once an action is triggered, interval_test will remain true for
* horizon seconds.
*/
static inline void
interval_action (struct interval* top)
{
#if INTERVAL_DEBUG
dmsg (D_INTERVAL, "INTERVAL action");
#endif
top->last_action = now;
}
/*
* Measure when n seconds beyond an event have elapsed
*/
struct event_timeout
{
bool defined;
interval_t n;
time_t last; /* time of last event */
};
static inline bool
event_timeout_defined (const struct event_timeout* et)
{
return et->defined;
}
static inline void
event_timeout_clear (struct event_timeout* et)
{
et->defined = false;
et->n = 0;
et->last = 0;
}
static inline struct event_timeout
event_timeout_clear_ret ()
{
struct event_timeout ret;
event_timeout_clear (&ret);
return ret;
}
static inline void
event_timeout_init (struct event_timeout* et, interval_t n, const time_t local_now)
{
et->defined = true;
et->n = (n >= 0) ? n : 0;
et->last = local_now;
}
static inline void
event_timeout_reset (struct event_timeout* et)
{
if (et->defined)
et->last = now;
}
/*
* This is the principal function for testing and triggering recurring
* timers and will return true on a timer signal event.
* If et_const_retry == ETT_DEFAULT and a signal occurs,
* the function will return true and *et will be armed for the
* next event. If et_const_retry >= 0 and a signal occurs,
* *et will not be touched, but *tv will be set to
* minimum (*tv, et_const_retry) for a future re-test,
* and the function will return true.
*/
#define ETT_DEFAULT (-1)
bool event_timeout_trigger (struct event_timeout *et,
struct timeval *tv,
const int et_const_retry);
/*
* Measure time intervals in microseconds
*/
#define USEC_TIMER_MAX 60 /* maximum interval size in seconds */
#define USEC_TIMER_MAX_USEC (USEC_TIMER_MAX * 1000000)
struct usec_timer {
struct timeval start;
struct timeval end;
};
#ifdef HAVE_GETTIMEOFDAY
static inline void
usec_timer_start (struct usec_timer *obj)
{
CLEAR (*obj);
gettimeofday (&obj->start, NULL);
}
static inline void
usec_timer_end (struct usec_timer *obj)
{
gettimeofday (&obj->end, NULL);
}
#endif /* HAVE_GETTIMEOFDAY */
static inline bool
usec_timer_interval_defined (struct usec_timer *obj)
{
return obj->start.tv_sec && obj->end.tv_sec;
}
static inline int
usec_timer_interval (struct usec_timer *obj)
{
return tv_subtract (&obj->end, &obj->start, USEC_TIMER_MAX);
}
#endif /* INTERVAL_H */

664
list.c Normal file
View File

@ -0,0 +1,664 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef WIN32
#include "config-win32.h"
#else
#include "config.h"
#endif
#include "syshead.h"
#if P2MP_SERVER
#include "list.h"
#include "misc.h"
#include "memdbg.h"
struct hash *
hash_init (const int n_buckets,
uint32_t (*hash_function)(const void *key, uint32_t iv),
bool (*compare_function)(const void *key1, const void *key2))
{
struct hash *h;
int i;
ASSERT (n_buckets > 0);
ALLOC_OBJ_CLEAR (h, struct hash);
h->n_buckets = (int) adjust_power_of_2 (n_buckets);
h->mask = h->n_buckets - 1;
h->hash_function = hash_function;
h->compare_function = compare_function;
h->iv = get_random ();
ALLOC_ARRAY (h->buckets, struct hash_bucket, h->n_buckets);
for (i = 0; i < h->n_buckets; ++i)
{
struct hash_bucket *b = &h->buckets[i];
b->list = NULL;
mutex_init (&b->mutex);
}
return h;
}
void
hash_free (struct hash *hash)
{
int i;
for (i = 0; i < hash->n_buckets; ++i)
{
struct hash_bucket *b = &hash->buckets[i];
struct hash_element *he = b->list;
mutex_destroy (&b->mutex);
while (he)
{
struct hash_element *next = he->next;
free (he);
he = next;
}
}
free (hash->buckets);
free (hash);
}
struct hash_element *
hash_lookup_fast (struct hash *hash,
struct hash_bucket *bucket,
const void *key,
uint32_t hv)
{
struct hash_element *he;
struct hash_element *prev = NULL;
he = bucket->list;
while (he)
{
if (hv == he->hash_value && (*hash->compare_function)(key, he->key))
{
/* move to head of list */
if (prev)
{
prev->next = he->next;
he->next = bucket->list;
bucket->list = he;
}
return he;
}
prev = he;
he = he->next;
}
return NULL;
}
bool
hash_remove_fast (struct hash *hash,
struct hash_bucket *bucket,
const void *key,
uint32_t hv)
{
struct hash_element *he;
struct hash_element *prev = NULL;
he = bucket->list;
while (he)
{
if (hv == he->hash_value && (*hash->compare_function)(key, he->key))
{
if (prev)
prev->next = he->next;
else
bucket->list = he->next;
free (he);
--hash->n_elements;
return true;
}
prev = he;
he = he->next;
}
return false;
}
bool
hash_add (struct hash *hash, const void *key, void *value, bool replace)
{
uint32_t hv;
struct hash_bucket *bucket;
struct hash_element *he;
bool ret = false;
hv = hash_value (hash, key);
bucket = &hash->buckets[hv & hash->mask];
mutex_lock (&bucket->mutex);
if ((he = hash_lookup_fast (hash, bucket, key, hv))) /* already exists? */
{
if (replace)
{
he->value = value;
ret = true;
}
}
else
{
hash_add_fast (hash, bucket, key, hv, value);
ret = true;
}
mutex_unlock (&bucket->mutex);
return ret;
}
void
hash_remove_by_value (struct hash *hash, void *value, bool autolock)
{
struct hash_iterator hi;
struct hash_element *he;
hash_iterator_init (hash, &hi, autolock);
while ((he = hash_iterator_next (&hi)))
{
if (he->value == value)
hash_iterator_delete_element (&hi);
}
hash_iterator_free (&hi);
}
static void
hash_remove_marked (struct hash *hash, struct hash_bucket *bucket)
{
struct hash_element *prev = NULL;
struct hash_element *he = bucket->list;
while (he)
{
if (!he->key) /* marked? */
{
struct hash_element *newhe;
if (prev)
newhe = prev->next = he->next;
else
newhe = bucket->list = he->next;
free (he);
--hash->n_elements;
he = newhe;
}
else
{
prev = he;
he = he->next;
}
}
}
uint32_t
void_ptr_hash_function (const void *key, uint32_t iv)
{
return hash_func ((const void *)&key, sizeof (key), iv);
}
bool
void_ptr_compare_function (const void *key1, const void *key2)
{
return key1 == key2;
}
void
hash_iterator_init_range (struct hash *hash,
struct hash_iterator *hi,
bool autolock,
int start_bucket,
int end_bucket)
{
if (end_bucket > hash->n_buckets)
end_bucket = hash->n_buckets;
ASSERT (start_bucket >= 0 && start_bucket <= end_bucket);
hi->hash = hash;
hi->elem = NULL;
hi->bucket = NULL;
hi->autolock = autolock;
hi->last = NULL;
hi->bucket_marked = false;
hi->bucket_index_start = start_bucket;
hi->bucket_index_end = end_bucket;
hi->bucket_index = hi->bucket_index_start - 1;
}
void
hash_iterator_init (struct hash *hash,
struct hash_iterator *hi,
bool autolock)
{
hash_iterator_init_range (hash, hi, autolock, 0, hash->n_buckets);
}
static inline void
hash_iterator_lock (struct hash_iterator *hi, struct hash_bucket *b)
{
if (hi->autolock)
{
mutex_lock (&b->mutex);
}
hi->bucket = b;
hi->last = NULL;
hi->bucket_marked = false;
}
static inline void
hash_iterator_unlock (struct hash_iterator *hi)
{
if (hi->bucket)
{
if (hi->bucket_marked)
{
hash_remove_marked (hi->hash, hi->bucket);
hi->bucket_marked = false;
}
if (hi->autolock)
{
mutex_unlock (&hi->bucket->mutex);
}
hi->bucket = NULL;
hi->last = NULL;
}
}
static inline void
hash_iterator_advance (struct hash_iterator *hi)
{
hi->last = hi->elem;
hi->elem = hi->elem->next;
}
void
hash_iterator_free (struct hash_iterator *hi)
{
hash_iterator_unlock (hi);
}
struct hash_element *
hash_iterator_next (struct hash_iterator *hi)
{
struct hash_element *ret = NULL;
if (hi->elem)
{
ret = hi->elem;
hash_iterator_advance (hi);
}
else
{
while (++hi->bucket_index < hi->bucket_index_end)
{
struct hash_bucket *b;
hash_iterator_unlock (hi);
b = &hi->hash->buckets[hi->bucket_index];
if (b->list)
{
hash_iterator_lock (hi, b);
hi->elem = b->list;
if (hi->elem)
{
ret = hi->elem;
hash_iterator_advance (hi);
break;
}
}
}
}
return ret;
}
void
hash_iterator_delete_element (struct hash_iterator *hi)
{
ASSERT (hi->last);
hi->last->key = NULL;
hi->bucket_marked = true;
}
#ifdef LIST_TEST
/*
* Test the hash code by implementing a simple
* word frequency algorithm.
*/
struct word
{
const char *word;
int n;
};
static uint32_t
word_hash_function (const void *key, uint32_t iv)
{
const char *str = (const char *) key;
const int len = strlen (str);
return hash_func ((const uint8_t *)str, len, iv);
}
static bool
word_compare_function (const void *key1, const void *key2)
{
return strcmp ((const char *)key1, (const char *)key2) == 0;
}
static void
print_nhash (struct hash *hash)
{
struct hash_iterator hi;
struct hash_element *he;
int count = 0;
hash_iterator_init (hash, &hi, true);
while ((he = hash_iterator_next (&hi)))
{
printf ("%d ", (int) he->value);
++count;
}
printf ("\n");
hash_iterator_free (&hi);
ASSERT (count == hash_n_elements (hash));
}
static void
rmhash (struct hash *hash, const char *word)
{
hash_remove (hash, word);
}
void
list_test (void)
{
openvpn_thread_init ();
{
struct gc_arena gc = gc_new ();
struct hash *hash = hash_init (10000, word_hash_function, word_compare_function);
struct hash *nhash = hash_init (256, word_hash_function, word_compare_function);
printf ("hash_init n_buckets=%d mask=0x%08x\n", hash->n_buckets, hash->mask);
/* parse words from stdin */
while (true)
{
char buf[256];
char wordbuf[256];
int wbi;
int bi;
char c;
if (!fgets(buf, sizeof(buf), stdin))
break;
bi = wbi = 0;
do
{
c = buf[bi++];
if (isalnum (c) || c == '_')
{
ASSERT (wbi < (int) sizeof (wordbuf));
wordbuf[wbi++] = c;
}
else
{
if (wbi)
{
struct word *w;
ASSERT (wbi < (int) sizeof (wordbuf));
wordbuf[wbi++] = '\0';
/* word is parsed from stdin */
/* does it already exist in table? */
w = (struct word *) hash_lookup (hash, wordbuf);
if (w)
{
/* yes, increment count */
++w->n;
}
else
{
/* no, make a new object */
ALLOC_OBJ_GC (w, struct word, &gc);
w->word = string_alloc (wordbuf, &gc);
w->n = 1;
ASSERT (hash_add (hash, w->word, w, false));
ASSERT (hash_add (nhash, w->word, (void*) ((random() & 0x0F) + 1), false));
}
}
wbi = 0;
}
} while (c);
}
#if 1
/* remove some words from the table */
{
rmhash (hash, "true");
rmhash (hash, "false");
}
#endif
/* output contents of hash table */
{
int base;
int inc = 0;
int count = 0;
for (base = 0; base < hash_n_buckets (hash); base += inc) {
struct hash_iterator hi;
struct hash_element *he;
inc = (get_random () % 3) + 1;
hash_iterator_init_range (hash, &hi, true, base, base + inc);
while ((he = hash_iterator_next (&hi)))
{
struct word *w = (struct word *) he->value;
printf ("%6d '%s'\n", w->n, w->word);
++count;
}
hash_iterator_free (&hi);
}
ASSERT (count == hash_n_elements (hash));
}
#if 1
/* test hash_remove_by_value function */
{
int i;
for (i = 1; i <= 16; ++i)
{
printf ("[%d] ***********************************\n", i);
print_nhash (nhash);
hash_remove_by_value (nhash, (void *) i, true);
}
printf ("FINAL **************************\n");
print_nhash (nhash);
}
#endif
hash_free (hash);
hash_free (nhash);
gc_free (&gc);
}
openvpn_thread_cleanup ();
}
#endif
/*
--------------------------------------------------------------------
hash() -- hash a variable-length key into a 32-bit value
k : the key (the unaligned variable-length array of bytes)
len : the length of the key, counting by bytes
level : can be any 4-byte value
Returns a 32-bit value. Every bit of the key affects every bit of
the return value. Every 1-bit and 2-bit delta achieves avalanche.
About 36+6len instructions.
The best hash table sizes are powers of 2. There is no need to do
mod a prime (mod is sooo slow!). If you need less than 32 bits,
use a bitmask. For example, if you need only 10 bits, do
h = (h & hashmask(10));
In which case, the hash table should have hashsize(10) elements.
If you are hashing n strings (uint8_t **)k, do it like this:
for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h);
By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this
code any way you wish, private, educational, or commercial. It's free.
See http://burlteburtle.net/bob/hash/evahash.html
Use for hash table lookup, or anything where one collision in 2^32 is
acceptable. Do NOT use for cryptographic purposes.
--------------------------------------------------------------------
mix -- mix 3 32-bit values reversibly.
For every delta with one or two bit set, and the deltas of all three
high bits or all three low bits, whether the original value of a,b,c
is almost all zero or is uniformly distributed,
* If mix() is run forward or backward, at least 32 bits in a,b,c
have at least 1/4 probability of changing.
* If mix() is run forward, every bit of c will change between 1/3 and
2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
mix() was built out of 36 single-cycle latency instructions in a
structure that could supported 2x parallelism, like so:
a -= b;
a -= c; x = (c>>13);
b -= c; a ^= x;
b -= a; x = (a<<8);
c -= a; b ^= x;
c -= b; x = (b>>13);
...
Unfortunately, superscalar Pentiums and Sparcs can't take advantage
of that parallelism. They've also turned some of those single-cycle
latency instructions into multi-cycle latency instructions. Still,
this is the fastest good hash I could find. There were about 2^^68
to choose from. I only looked at a billion or so.
James Yonan Notes:
* This function is faster than it looks, and appears to be
appropriate for our usage in OpenVPN which is primarily
for hash-table based address lookup (IPv4, IPv6, and Ethernet MAC).
NOTE: This function is never used for cryptographic purposes, only
to produce evenly-distributed indexes into hash tables.
* Benchmark results: 11.39 machine cycles per byte on a P2 266Mhz,
and 12.1 machine cycles per byte on a
2.2 Ghz P4 when hashing a 6 byte string.
--------------------------------------------------------------------
*/
#define mix(a,b,c) \
{ \
a -= b; a -= c; a ^= (c>>13); \
b -= c; b -= a; b ^= (a<<8); \
c -= a; c -= b; c ^= (b>>13); \
a -= b; a -= c; a ^= (c>>12); \
b -= c; b -= a; b ^= (a<<16); \
c -= a; c -= b; c ^= (b>>5); \
a -= b; a -= c; a ^= (c>>3); \
b -= c; b -= a; b ^= (a<<10); \
c -= a; c -= b; c ^= (b>>15); \
}
uint32_t
hash_func (const uint8_t *k, uint32_t length, uint32_t initval)
{
uint32_t a, b, c, len;
/* Set up the internal state */
len = length;
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
c = initval; /* the previous hash value */
/*---------------------------------------- handle most of the key */
while (len >= 12)
{
a += (k[0] + ((uint32_t) k[1] << 8)
+ ((uint32_t) k[2] << 16)
+ ((uint32_t) k[3] << 24));
b += (k[4] + ((uint32_t) k[5] << 8)
+ ((uint32_t) k[6] << 16)
+ ((uint32_t) k[7] << 24));
c += (k[8] + ((uint32_t) k[9] << 8)
+ ((uint32_t) k[10] << 16)
+ ((uint32_t) k[11] << 24));
mix (a, b, c);
k += 12;
len -= 12;
}
/*------------------------------------- handle the last 11 bytes */
c += length;
switch (len) /* all the case statements fall through */
{
case 11:
c += ((uint32_t) k[10] << 24);
case 10:
c += ((uint32_t) k[9] << 16);
case 9:
c += ((uint32_t) k[8] << 8);
/* the first byte of c is reserved for the length */
case 8:
b += ((uint32_t) k[7] << 24);
case 7:
b += ((uint32_t) k[6] << 16);
case 6:
b += ((uint32_t) k[5] << 8);
case 5:
b += k[4];
case 4:
a += ((uint32_t) k[3] << 24);
case 3:
a += ((uint32_t) k[2] << 16);
case 2:
a += ((uint32_t) k[1] << 8);
case 1:
a += k[0];
/* case 0: nothing left to add */
}
mix (a, b, c);
/*-------------------------------------- report the result */
return c;
}
#else
static void dummy(void) {}
#endif /* P2MP_SERVER */

220
list.h Normal file
View File

@ -0,0 +1,220 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef LIST_H
#define LIST_H
/*
* This code is a fairly straightforward hash
* table implementation using Bob Jenkins'
* hash function.
*
* Hash tables are used in OpenVPN to keep track of
* client instances over various key spaces.
*/
#if P2MP_SERVER
/* define this to enable special list test mode */
/*#define LIST_TEST*/
#include "basic.h"
#include "thread.h"
#include "buffer.h"
#define hashsize(n) ((uint32_t)1<<(n))
#define hashmask(n) (hashsize(n)-1)
struct hash_element
{
void *value;
const void *key;
unsigned int hash_value;
struct hash_element *next;
};
struct hash_bucket
{
MUTEX_DEFINE (mutex);
struct hash_element * volatile list;
};
struct hash
{
int n_buckets;
int n_elements;
int mask;
uint32_t iv;
uint32_t (*hash_function)(const void *key, uint32_t iv);
bool (*compare_function)(const void *key1, const void *key2); /* return true if equal */
struct hash_bucket *buckets;
};
struct hash *hash_init (const int n_buckets,
uint32_t (*hash_function)(const void *key, uint32_t iv),
bool (*compare_function)(const void *key1, const void *key2));
void hash_free (struct hash *hash);
bool hash_add (struct hash *hash, const void *key, void *value, bool replace);
struct hash_element *hash_lookup_fast (struct hash *hash,
struct hash_bucket *bucket,
const void *key,
uint32_t hv);
bool hash_remove_fast (struct hash *hash,
struct hash_bucket *bucket,
const void *key,
uint32_t hv);
void hash_remove_by_value (struct hash *hash, void *value, bool autolock);
struct hash_iterator
{
struct hash *hash;
int bucket_index;
struct hash_bucket *bucket;
struct hash_element *elem;
struct hash_element *last;
bool bucket_marked;
bool autolock;
int bucket_index_start;
int bucket_index_end;
};
void hash_iterator_init_range (struct hash *hash,
struct hash_iterator *hi,
bool autolock,
int start_bucket,
int end_bucket);
void hash_iterator_init (struct hash *hash, struct hash_iterator *iter, bool autolock);
struct hash_element *hash_iterator_next (struct hash_iterator *hi);
void hash_iterator_delete_element (struct hash_iterator *hi);
void hash_iterator_free (struct hash_iterator *hi);
uint32_t hash_func (const uint8_t *k, uint32_t length, uint32_t initval);
uint32_t void_ptr_hash_function (const void *key, uint32_t iv);
bool void_ptr_compare_function (const void *key1, const void *key2);
#ifdef LIST_TEST
void list_test (void);
#endif
static inline uint32_t
hash_value (const struct hash *hash, const void *key)
{
return (*hash->hash_function)(key, hash->iv);
}
static inline int
hash_n_elements (const struct hash *hash)
{
return hash->n_elements;
}
static inline int
hash_n_buckets (const struct hash *hash)
{
return hash->n_buckets;
}
static inline struct hash_bucket *
hash_bucket (struct hash *hash, uint32_t hv)
{
return &hash->buckets[hv & hash->mask];
}
static inline void
hash_bucket_lock (struct hash_bucket *bucket)
{
mutex_lock (&bucket->mutex);
}
static inline void
hash_bucket_unlock (struct hash_bucket *bucket)
{
mutex_unlock (&bucket->mutex);
}
static inline void *
hash_lookup_lock (struct hash *hash, const void *key, uint32_t hv)
{
void *ret = NULL;
struct hash_element *he;
struct hash_bucket *bucket = &hash->buckets[hv & hash->mask];
mutex_lock (&bucket->mutex);
he = hash_lookup_fast (hash, bucket, key, hv);
if (he)
ret = he->value;
mutex_unlock (&bucket->mutex);
return ret;
}
static inline void *
hash_lookup (struct hash *hash, const void *key)
{
return hash_lookup_lock (hash, key, hash_value (hash, key));
}
/* NOTE: assumes that key is not a duplicate */
static inline void
hash_add_fast (struct hash *hash,
struct hash_bucket *bucket,
const void *key,
uint32_t hv,
void *value)
{
struct hash_element *he;
ALLOC_OBJ (he, struct hash_element);
he->value = value;
he->key = key;
he->hash_value = hv;
he->next = bucket->list;
bucket->list = he;
++hash->n_elements;
}
static inline bool
hash_remove (struct hash *hash, const void *key)
{
uint32_t hv;
struct hash_bucket *bucket;
bool ret;
hv = hash_value (hash, key);
bucket = &hash->buckets[hv & hash->mask];
mutex_lock (&bucket->mutex);
ret = hash_remove_fast (hash, bucket, key, hv);
mutex_unlock (&bucket->mutex);
return ret;
}
#endif /* P2MP_SERVER */
#endif /* LIST */

251
lzo.c Normal file
View File

@ -0,0 +1,251 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef WIN32
#include "config-win32.h"
#else
#include "config.h"
#endif
#ifdef USE_LZO
#include "syshead.h"
#include "lzo.h"
#include "error.h"
#include "otime.h"
#include "memdbg.h"
static bool
lzo_adaptive_compress_test (struct lzo_adaptive_compress *ac)
{
const bool save = ac->compress_state;
const time_t local_now = now;
if (!ac->enabled)
return true;
if (!ac->compress_state)
{
if (local_now >= ac->next)
{
if (ac->n_total > AC_MIN_BYTES
&& (ac->n_total - ac->n_comp) < (ac->n_total / (100 / AC_SAVE_PCT)))
{
ac->compress_state = true;
ac->next = local_now + AC_OFF_SEC;
}
else
{
ac->next = local_now + AC_SAMP_SEC;
}
dmsg (D_COMP, "lzo_adaptive_compress_test: comp=%d total=%d", ac->n_comp, ac->n_total);
ac->n_total = ac->n_comp = 0;
}
}
else
{
if (local_now >= ac->next)
{
ac->next = local_now + AC_SAMP_SEC;
ac->n_total = ac->n_comp = 0;
ac->compress_state = false;
}
}
if (ac->compress_state != save)
dmsg (D_COMP_LOW, "Adaptive compression state %s", (ac->compress_state ? "OFF" : "ON"));
return !ac->compress_state;
}
inline static void
lzo_adaptive_compress_data (struct lzo_adaptive_compress *ac, int n_total, int n_comp)
{
if (ac->enabled)
{
ac->n_total += n_total;
ac->n_comp += n_comp;
}
}
void lzo_adjust_frame_parameters (struct frame *frame)
{
/* Leave room for our one-byte compressed/didn't-compress prefix byte. */
frame_add_to_extra_frame (frame, LZO_PREFIX_LEN);
/* Leave room for compression buffer to expand in worst case scenario
where data is totally uncompressible */
frame_add_to_extra_buffer (frame, LZO_EXTRA_BUFFER (EXPANDED_SIZE(frame)));
}
void
lzo_compress_init (struct lzo_compress_workspace *lzowork, bool adaptive)
{
CLEAR (*lzowork);
lzowork->wmem_size = LZO_WORKSPACE;
lzowork->ac.enabled = adaptive;
if (lzo_init () != LZO_E_OK)
msg (M_FATAL, "Cannot initialize LZO compression library");
lzowork->wmem = (lzo_voidp) lzo_malloc (lzowork->wmem_size);
check_malloc_return (lzowork->wmem);
msg (M_INFO, "LZO compression initialized");
}
void
lzo_compress_uninit (struct lzo_compress_workspace *lzowork)
{
if (lzowork)
{
lzo_free (lzowork->wmem);
lzowork->wmem = NULL;
}
}
/* Magic numbers to tell our peer if we compressed or not */
#define YES_COMPRESS 0x66
#define NO_COMPRESS 0xFA
void
lzo_compress (struct buffer *buf, struct buffer work,
struct lzo_compress_workspace *lzowork,
const struct frame* frame)
{
lzo_uint zlen = 0;
int err;
bool compressed = false;
if (buf->len <= 0)
return;
/*
* In order to attempt compression, length must be at least COMPRESS_THRESHOLD,
* and our adaptive level must give the OK.
*/
if (buf->len >= COMPRESS_THRESHOLD && lzo_adaptive_compress_test (&lzowork->ac))
{
ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
ASSERT (buf_safe (&work, LZO_EXTRA_BUFFER (PAYLOAD_SIZE (frame))));
ASSERT (buf->len <= PAYLOAD_SIZE (frame));
err = LZO_COMPRESS (BPTR (buf), BLEN (buf), BPTR (&work), &zlen, lzowork->wmem);
if (err != LZO_E_OK)
{
dmsg (D_COMP_ERRORS, "LZO compression error: %d", err);
buf->len = 0;
return;
}
ASSERT (buf_safe (&work, zlen));
work.len = zlen;
compressed = true;
dmsg (D_COMP, "compress %d -> %d", buf->len, work.len);
lzowork->pre_compress += buf->len;
lzowork->post_compress += work.len;
/* tell adaptive level about our success or lack thereof in getting any size reduction */
lzo_adaptive_compress_data(&lzowork->ac, buf->len, work.len);
}
/* did compression save us anything ? */
if (compressed && work.len < buf->len)
{
uint8_t *header = buf_prepend (&work, 1);
*header = YES_COMPRESS;
*buf = work;
}
else
{
uint8_t *header = buf_prepend (buf, 1);
*header = NO_COMPRESS;
}
}
void
lzo_decompress (struct buffer *buf, struct buffer work,
struct lzo_compress_workspace *lzowork,
const struct frame* frame)
{
lzo_uint zlen = EXPANDED_SIZE (frame);
uint8_t c; /* flag indicating whether or not our peer compressed */
int err;
if (buf->len <= 0)
return;
ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
c = *BPTR (buf);
ASSERT (buf_advance (buf, 1));
if (c == YES_COMPRESS) /* packet was compressed */
{
ASSERT (buf_safe (&work, zlen));
err = LZO_DECOMPRESS (BPTR (buf), BLEN (buf), BPTR (&work), &zlen,
lzowork->wmem);
if (err != LZO_E_OK)
{
dmsg (D_COMP_ERRORS, "LZO decompression error: %d", err);
buf->len = 0;
return;
}
ASSERT (buf_safe (&work, zlen));
work.len = zlen;
dmsg (D_COMP, "decompress %d -> %d", buf->len, work.len);
lzowork->pre_decompress += buf->len;
lzowork->post_decompress += work.len;
*buf = work;
}
else if (c == NO_COMPRESS) /* packet was not compressed */
{
;
}
else
{
dmsg (D_COMP_ERRORS, "Bad LZO decompression header byte: %d", c);
buf->len = 0;
}
}
/*
* Print statistics
*/
void lzo_print_stats (const struct lzo_compress_workspace *lzo_compwork, struct status_output *so)
{
status_printf (so, "pre-compress bytes," counter_format, lzo_compwork->pre_compress);
status_printf (so, "post-compress bytes," counter_format, lzo_compwork->post_compress);
status_printf (so, "pre-decompress bytes," counter_format, lzo_compwork->pre_decompress);
status_printf (so, "post-decompress bytes," counter_format, lzo_compwork->post_decompress);
}
#else
static void dummy(void) {}
#endif /* USE_LZO */

117
lzo.h Normal file
View File

@ -0,0 +1,117 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef USE_LZO
#ifdef LZO_HEADER_DIR
#include "lzo/lzoutil.h"
#include "lzo/lzo1x.h"
#else
#include "lzoutil.h"
#include "lzo1x.h"
#endif
#include "buffer.h"
#include "mtu.h"
#include "common.h"
#include "status.h"
/*
* Use LZO compress routine lzo1x_1_15_compress which is described
* as faster but needs a bit more memory than the standard routine.
* Use safe decompress (i.e. check for buffer overflows).
* You may want to use the non-safe version
* of decompress if speed is essential and if you know
* that you will always be using a MAC to verify the
* integrity of incoming packets.
*/
#define LZO_COMPRESS lzo1x_1_15_compress
#define LZO_WORKSPACE LZO1X_1_15_MEM_COMPRESS
#define LZO_DECOMPRESS lzo1x_decompress_safe
#define LZO_EXTRA_BUFFER(len) ((len)/8 + 128 + 3) /* LZO 2.0 worst case size expansion. */
/*
* Don't try to compress any packet smaller than this.
*/
#define COMPRESS_THRESHOLD 100
/*
* Length of prepended prefix on LZO packets
*/
#define LZO_PREFIX_LEN 1
/*
* Adaptive compress parameters
*/
#define AC_SAMP_SEC 2 /* number of seconds in sample period */
#define AC_MIN_BYTES 1000 /* sample period must have at least n bytes
to be valid for testing */
#define AC_SAVE_PCT 5 /* turn off compress if we didn't save at
least this % during sample period */
#define AC_OFF_SEC 60 /* if we turn off compression, don't do sample
retest for n seconds */
struct lzo_adaptive_compress {
bool enabled;
bool compress_state;
time_t next;
int n_total;
int n_comp;
};
/*
* Compress and Uncompress routines.
*/
struct lzo_compress_workspace
{
lzo_voidp wmem;
int wmem_size;
struct lzo_adaptive_compress ac;
/* statistics */
counter_type pre_decompress;
counter_type post_decompress;
counter_type pre_compress;
counter_type post_compress;
};
void lzo_adjust_frame_parameters(struct frame *frame);
void lzo_compress_init (struct lzo_compress_workspace *lzowork, bool adaptive);
void lzo_compress_uninit (struct lzo_compress_workspace *lzowork);
void lzo_compress (struct buffer *buf, struct buffer work,
struct lzo_compress_workspace *lzowork,
const struct frame* frame);
void lzo_decompress (struct buffer *buf, struct buffer work,
struct lzo_compress_workspace *lzowork,
const struct frame* frame);
void lzo_print_stats (const struct lzo_compress_workspace *lzo_compwork, struct status_output *so);
#endif /* USE_LZO */

197
makefile.w32 Executable file
View File

@ -0,0 +1,197 @@
# This Makefile builds the user-mode component
# of OpenVPN for WIN32 in the MinGW environment.
#
# Build Dependencies:
# mingw (GNU C compiler for windows)
# msys (GNU utilities and shell for windows)
# OpenSSL (SSL/TLS/crypto library)
# LZO (real-time compression library)
# Dmalloc (debugging only)
#
# Targets:
# static -- link statically with OpenSSL
# dynamic -- link dynamically with OpenSSL
# dmalloc -- enable memory debugging using the dmalloc library
#
# Note that LZO is always linked statically.
#
# To build openssl-0.9.7d, remember to edit ms\mw.bat
# adding '--win32' flag to make command:
#
# make --win32 -f ms/mingw32.mak
#
# Now cd to top level openssl directory in a Windows
# command-prompt window, and type:
#
# ms\mw
#
# See additional .bat scripts in install-win32 for OpenSSL
# build setup.
#
# If you are building with dmalloc debugging support
# see windbg.h for additional dmalloc notes.
#########################################################
# Change these to point to your OpenSSL, LZO, and
# (optionally) dmalloc top-level directories.
OPENSSL = /c/src/openssl-0.9.7g
LZO = /c/src/lzo-1.08
DMALLOC = /c/src/dmalloc-5.4.2
#########################################################
CC = gcc -g -O2 -Wall -Wno-unused-function -Wno-unused-variable -mno-cygwin
CC_DMALLOC = gcc -g -O2 -Wall -Wno-unused-function -Wno-unused-variable -mno-cygwin -fno-inline -DDMALLOC
INCLUDE_DIRS = -I${OPENSSL}/include -I${LZO}/include
INCLUDE_DIRS_DMALLOC = ${INCLUDE_DIRS} -I${DMALLOC}
LIBS = -llzo -lcrypt32 -lws2_32 -lgdi32 -liphlpapi -lwinmm
LIBS_DMALLOC = ${LIBS} -ldmalloc
LIB_DIRS = -L${OPENSSL}/out -L${LZO}
LIB_DIRS_DMALLOC = ${LIB_DIRS} -L${DMALLOC}
EXE = openvpn.exe
HEADERS = \
base64.h \
basic.h \
buffer.h \
circ_list.h \
common.h \
tap-win32/common.h \
config-win32.h \
crypto.h \
cryptoapi.h \
errlevel.h \
error.h \
event.h \
fdmisc.h \
forward-inline.h \
forward.h \
fragment.h \
gremlin.h \
helper.h \
init.h \
integer.h \
interval.h \
list.h \
lzo.h \
manage.h \
mbuf.h \
memdbg.h \
misc.h \
mroute.h \
mss.h \
mtcp.h \
mtu.h \
mudp.h \
multi.h \
ntlm.h \
occ-inline.h \
occ.h \
openvpn.h \
openvpn-plugin.h \
options.h \
otime.h \
packet_id.h \
perf.h \
ping-inline.h \
ping.h \
plugin.h \
pool.h \
proto.h \
proxy.h \
push.h \
reliable.h \
route.h \
schedule.h \
session_id.h \
shaper.h \
sig.h \
socket.h \
socks.h \
ssl.h \
status.h \
syshead.h \
thread.h \
tun.h \
win32.h
OBJS = base64.o \
buffer.o \
crypto.o \
cryptoapi.o \
error.o \
event.o \
fdmisc.o \
forward.o \
fragment.o \
gremlin.o \
helper.o \
init.o \
interval.o \
list.o \
lzo.o \
manage.o \
mbuf.o \
misc.o \
mroute.o \
mss.o \
mtcp.o \
mtu.o \
mudp.o \
multi.o \
ntlm.o \
occ.o \
openvpn.o \
options.o \
otime.o \
packet_id.o \
perf.o \
ping.o \
plugin.o \
pool.o \
proto.o \
proxy.o \
push.o \
reliable.o \
route.o \
schedule.o \
session_id.o \
shaper.o \
sig.o \
socket.o \
socks.o \
ssl.o \
status.o \
thread.o \
tun.o \
win32.o
dynamic : MY_CC = ${CC}
dynamic : MY_INCLUDE_DIRS = ${INCLUDE_DIRS}
dynamic : ${OBJS}
${MY_CC} -o ${EXE} ${OBJS} ${LIB_DIRS} -lssl32 -leay32 ${LIBS}
static : MY_CC = ${CC}
static : MY_INCLUDE_DIRS = ${INCLUDE_DIRS}
static : ${OBJS}
${CC} -o ${EXE} ${OBJS} ${LIB_DIRS} -lssl -lcrypto ${LIBS}
dmalloc : MY_CC = ${CC_DMALLOC}
dmalloc : MY_INCLUDE_DIRS = ${INCLUDE_DIRS_DMALLOC}
dmalloc : ${OBJS}
${MY_CC} -o ${EXE} ${OBJS} ${LIB_DIRS_DMALLOC} -lssl32 -leay32 ${LIBS_DMALLOC}
clean :
rm -f ${OBJS} ${EXE}
%.o : %.c ${HEADERS}
${MY_CC} ${MY_INCLUDE_DIRS} -c $< -o $@

179
makefile.w32-vc Normal file
View File

@ -0,0 +1,179 @@
# This makefile builds the user-mode component
# of OpenVPN for WIN32 in the MSVC++ environment.
#
# Build Dependencies:
# OpenSSL (SSL/TLS/crypto library)
# LZO (real-time compression library)
#
# Targets:
# static -- link statically with OpenSSL
# dynamic -- link dynamically with OpenSSL
#
# Note that LZO is always linked statically.
# Change these to point to your OpenSSL and LZO top-level
# directories.
OPENSSL = \src\openssl-0.9.7d
OPENSSL_STATIC = libeay32s.lib ssleay32s.lib
#OPENSSL_STATIC = libeay32sd.lib ssleay32sd.lib
OPENSSL_DYNAMIC = libeay32.lib ssleay32.lib
#OPENSSL_DYNAMIC = libeay32d.lib ssleay32d.lib
LZO = \src\lzo-1.08.vc
INCLUDE_DIRS = -I$(OPENSSL)/include -I$(LZO)/include
LIBS = lzo.lib ws2_32.lib crypt32.lib iphlpapi.lib winmm.lib gdi32.lib advapi32.lib
LIB_DIRS = -LIBPATH:$(OPENSSL)\out -LIBPATH:$(LZO)
EXE = openvpn.exe
CPP=cl.exe
# release:
CPP_PROJ=/nologo /MD /W3 /G5 /O2 -DNDEBUG -DWIN32 -DWIN32_LEAN_AND_MEAN -D_CONSOLE -D_MBCS $(INCLUDE_DIRS) /FD /c
# debug:
#CPP_PROJ=/nologo /MDd /W3 /G5 /Zi /Od -D_DEBUG -DWIN32 -DWIN32_LEAN_AND_MEAN -D_CONSOLE -D_MBCS $(INCLUDE_DIRS) /FD /c
LINK32=link.exe
# release:
LINK32_FLAGS=/nologo /subsystem:console /incremental:no /out:"$(EXE)"
# debug:
#LINK32_FLAGS=/nologo /subsystem:console /incremental:no /debug /out:"$(EXE)"
# Make sure the HEADERS and OBJS definitions below match the same
# definitions in makefile.w32.
HEADERS = \
base64.h \
basic.h \
buffer.h \
circ_list.h common.h \
tap-win32/common.h \
config-win32.h \
crypto.h \
cryptoapi.h \
errlevel.h \
error.h \
event.h \
fdmisc.h \
forward-inline.h \
forward.h \
fragment.h \
gremlin.h \
helper.h \
init.h \
integer.h \
interval.h \
list.h \
lzo.h \
manage.h \
mbuf.h \
memdbg.h \
misc.h \
mroute.h \
mss.h \
mtcp.h \
mtu.h \
mudp.h \
multi.h \
ntlm.h \
occ-inline.h \
occ.h \
openvpn.h \
openvpn-plugin.h \
options.h \
otime.h \
packet_id.h \
perf.h \
ping-inline.h \
ping.h \
plugin.h \
pool.h \
proto.h \
proxy.h \
push.h \
reliable.h \
route.h \
schedule.h \
session_id.h \
shaper.h \
sig.h \
socket.h \
socks.h \
ssl.h \
status.h \
syshead.h \
thread.h \
tun.h \
win32.h
OBJS = base64.obj \
buffer.obj \
crypto.obj \
cryptoapi.obj \
error.obj \
event.obj \
fdmisc.obj \
forward.obj \
fragment.obj \
gremlin.obj \
helper.obj \
init.obj \
interval.obj \
list.obj \
lzo.obj \
manage.obj \
mbuf.obj \
misc.obj \
mroute.obj \
mss.obj \
mtcp.obj \
mtu.obj \
mudp.obj \
multi.obj \
ntlm.obj \
occ.obj \
openvpn.obj \
options.obj \
otime.obj \
packet_id.obj \
perf.obj \
ping.obj \
plugin.obj \
pool.obj \
proto.obj \
proxy.obj \
push.obj \
reliable.obj \
route.obj \
schedule.obj \
session_id.obj \
shaper.obj \
sig.obj \
socket.obj \
socks.obj \
ssl.obj \
status.obj \
thread.obj \
tun.obj \
win32.obj
dynamic : $(OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LIB_DIRS) $(LIBS) $(OPENSSL_DYNAMIC) $(OBJS)
<<
static : $(OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LIB_DIRS) $(LIBS) $(OPENSSL_STATIC) $(OBJS)
<<
clean :
del /Q $(OBJS) $(EXE) *.idb *.pdb
.c.obj::
$(CPP) @<<
$(CPP_PROJ) $<
<<

Some files were not shown because too many files have changed in this diff Show More