diff --git a/README.rst b/README.rst index 36e8a1a8..4641532d 100644 --- a/README.rst +++ b/README.rst @@ -31,68 +31,79 @@ Building the OpenVPN 3 client on Linux These instructions were tested on Ubuntu 20. -Prepare directory structure:: +Prepare directory structure: +:: - $ sudo apt install g++ make libmbedtls-dev libssl-dev liblz4-dev cmake - $ export O3=~/O3 && mkdir $O3 - $ export DEP_DIR=$O3/deps && mkdir $DEP_DIR - $ export DL=$O3/dl && mkdir $DL + $ sudo apt install g++ make libmbedtls-dev libssl-dev liblz4-dev cmake + $ export O3=~/O3 && mkdir $O3 + $ export DEP_DIR=$O3/deps && mkdir $DEP_DIR + $ export DL=$O3/dl && mkdir $DL -Clone the OpenVPN 3 source repo:: +Clone the OpenVPN 3 source repo: +:: - $ cd $O3 - $ git clone https://github.com/OpenVPN/openvpn3.git core + $ cd $O3 + $ git clone https://github.com/OpenVPN/openvpn3.git core -Build dependencies:: +Build dependencies: +:: - $ cd core/scripts/linux/ - $ ./build-all + $ cd core/scripts/linux/ + $ ./build-all -Build the OpenVPN 3 client wrapper (cli) with OpenSSL library:: +Build the OpenVPN 3 client wrapper (cli) with OpenSSL library: +:: - $ cd $O3/core && mkdir build && cd build - $ cmake .. - $ cmake --build . + $ cd $O3/core && mkdir build && cd build + $ cmake .. + $ cmake --build . -To use mbedTLS, use `cmake -DUSE_MBEDTLS=on ..`. +To use mbed TLS, use: +:: -Run OpenVPN 3 client:: + $ cmake -DUSE_MBEDTLS=on .. - $ sudo test/ovpncli/ovpncli myprofile.ovpn route-nopull +Run OpenVPN 3 client: +:: -Options used:: + $ sudo test/ovpncli/ovpncli myprofile.ovpn route-nopull - myprofile.ovpn : OpenVPN config file (must have .ovpn extension) - route-nopull : if you are connected via ssh, prevent ssh session lockout +Options used: + +- :code:`myprofile.ovpn` : OpenVPN config file (must have .ovpn extension) +- :code:`route-nopull` : if you are connected via ssh, prevent ssh session lockout Using cli with ovpn-dco -....................... +""""""""""""""""""""""" -ovpn-dco is a kernel module which handles data channel -and provides better proformance. +ovpn-dco is a kernel module which optimises data channel encryption and +transport, providing better performance. -Download, build and install ovpn-dco:: +Download, build and install ovpn-dco: +:: - $ cd $O3 - $ git clone https://github.com/OpenVPN/ovpn-dco.git - $ cd ovpn-dco - $ make && sudo make install - $ sudo modprobe ovpn-dco + $ cd $O3 + $ git clone https://github.com/OpenVPN/ovpn-dco.git + $ cd ovpn-dco + $ make && sudo make install + $ sudo modprobe ovpn-dco -Install core dependencies:: +Install core dependencies: +:: - $ sudo apt install pkg-config libnl-genl-3-dev + $ sudo apt install pkg-config libnl-genl-3-dev -Build cli with ovpn-dco support:: +Build cli with ovpn-dco support: +:: - $ cd $O3/core/build - $ cmake -DCLI_OVPNDCO=on .. && make - $ sudo test/ovpncli/ovpncliovpndco --dco myprofile.ovpn + $ cd $O3/core/build + $ cmake -DCLI_OVPNDCO=on .. && make + $ sudo test/ovpncli/ovpncliovpndco --dco myprofile.ovpn -Options used:: +Options used: - myprofile.ovpn : OpenVPN config file (must have .ovpn extension) - --dco : enable data channel offload +- :code:`myprofile.ovpn` : OpenVPN config file (must have .ovpn extension) +- :code:`--dco` : enable data channel offload Building the OpenVPN 3 client on Mac OS X @@ -102,21 +113,24 @@ OpenVPN 3 should be built in a non-root Mac OS X account. Make sure that Xcode is installed with optional command-line tools. (These instructions have been tested with Xcode 5.1.1). -Create the directories ``~/src`` and ``~/src/mac``:: +Create the directories ``~/src`` and ``~/src/mac``: +:: - $ mkdir -p ~/src/mac + $ mkdir -p ~/src/mac -Clone the OpenVPN 3 repo:: +Clone the OpenVPN 3 repo: +:: - $ cd ~/src - $ mkdir ovpn3 - $ cd ovpn3 - $ git clone https://github.com/OpenVPN/openvpn3.git core + $ cd ~/src + $ mkdir ovpn3 + $ cd ovpn3 + $ git clone https://github.com/OpenVPN/openvpn3.git core Export the shell variable ``O3`` to point to the OpenVPN 3 top level -directory:: +directory: +:: - export O3=~/src/ovpn3 + $ export O3=~/src/ovpn3 Download source tarballs (``.tar.gz`` or ``.tgz``) for these dependency libraries into ``~/Downloads`` @@ -125,9 +139,9 @@ See the file ``$O3/core/deps/lib-versions`` for the expected version numbers of each dependency. If you want to use a different version of the library than listed here, you can edit this file. -1. Asio — https://github.com/chriskohlhoff/asio -2. mbed TLS (2.3.0 or higher) — https://tls.mbed.org/ -3. LZ4 — https://github.com/Cyan4973/lz4 +1. Asio - https://github.com/chriskohlhoff/asio +2. mbed TLS (2.3.0 or higher) - https://tls.mbed.org/ +3. LZ4 - https://github.com/Cyan4973/lz4 For dependencies that are typically cloned from github vs. provided as a .tar.gz file, tools are provided to convert @@ -137,12 +151,14 @@ the github to a .tar.gz file. See "snapshot" scripts under Note that while OpenSSL is listed in lib-versions, it is not required for Mac builds. -Build the dependencies:: +Build the dependencies: +:: $ DL=~/Downloads $ OSX_ONLY=1 $O3/core/scripts/mac/build-all -Now build the OpenVPN 3 client executable:: +Now build the OpenVPN 3 client executable: +:: $ cd $O3/core $ . vars/vars-osx64 @@ -152,7 +168,7 @@ Now build the OpenVPN 3 client executable:: This will build the OpenVPN 3 client library with a small client wrapper (``cli``). It will also statically link in all external -dependencies (Asio, mbedTLS, and LZ4), so ``cli`` may be distributed +dependencies (Asio, mbed TLS, and LZ4), so ``cli`` may be distributed to other Macs and will run as a standalone executable. These build scripts will create a **x86_x64** Mac OS X executable, @@ -160,11 +176,13 @@ with a minimum deployment target of 10.8.x. The Mac OS X tuntap driver is not required, as OpenVPN 3 can use the integrated utun interface if available. -To view the client wrapper options:: +To view the client wrapper options: +:: $ ./cli -h -To connect:: +To connect: +:: $ ./cli client.ovpn @@ -178,19 +196,21 @@ Prerequisites: * CMake * vcpkg -Download and build dependencies:: +Download and build dependencies: +:: - > git clone https://github.com/Microsoft/vcpkg.git - > cd vcpkg - > bootstrap-vcpkg.bat - > vcpkg integrate install - > vcpkg install openssl-windows:x64-windows asio:x64-windows tap-windows6:x64-windows lz4:x64-windows gtest:x64-windows + > git clone https://github.com/Microsoft/vcpkg.git + > cd vcpkg + > bootstrap-vcpkg.bat + > vcpkg integrate install + > vcpkg install openssl-windows:x64-windows asio:x64-windows tap-windows6:x64-windows lz4:x64-windows gtest:x64-windows -Download and build core test client:: +Download and build core test client: +:: - > git clone https://github.com/OpenVPN/openvpn3.git - > cmake -DCMAKE_TOOLCHAIN_FILE=\scripts\buildsystems\vcpkg.cmake -A x64 -B build openvpn3 - > cmake --build build --config Release --target ovpncli + > git clone https://github.com/OpenVPN/openvpn3.git + > cmake -DCMAKE_TOOLCHAIN_FILE=\scripts\buildsystems\vcpkg.cmake -A x64 -B build openvpn3 + > cmake --build build --config Release --target ovpncli Testing ------- @@ -208,50 +228,57 @@ is here: ``_ The test code itself is here: ``_ -Build the test:: +Build the test: +:: - $ cd ovpn3/core/test/ssl - $ ECHO=1 PROF=linux ASIO_DIR=~/asio MTLS_SYS=1 NOSSL=1 $O3/core/scripts/build proto + $ cd ovpn3/core/test/ssl + $ ECHO=1 PROF=linux ASIO_DIR=~/asio MTLS_SYS=1 NOSSL=1 $O3/core/scripts/build proto -Run the test:: +Run the test: +:: - $ time ./proto - *** app bytes=72777936 net_bytes=122972447 data_bytes=415892854 prog=0000216599/0000216598 D=12700/600/12700/600 N=109/109 SH=17400/15300 HE=0/0 + $ time ./proto + *** app bytes=72777936 net_bytes=122972447 data_bytes=415892854 prog=0000216599/0000216598 D=12700/600/12700/600 N=109/109 SH=17400/15300 HE=0/0 - real 0m15.813s - user 0m15.800s - sys 0m0.004s + real 0m15.813s + user 0m15.800s + sys 0m0.004s The OpenVPN 3 core also includes unit tests, which are based on Google Test framework. To run unit tests, you need to install CMake and build Google Test. -Building Google Test on Linux:: +Building Google Test on Linux: +:: - $ git clone https://github.com/google/googletest.git - $ cd googletest - $ cmake . && cmake --build . + $ git clone https://github.com/google/googletest.git + $ cd googletest + $ cmake . && cmake --build . -Building Google Test on Windows:: +Building Google Test on Windows: +:: - > git clone https://github.com/google/googletest.git - > cd googletest - > cmake -G "Visual Studio 14 2015 Win64" . - > cmake --build . + > git clone https://github.com/google/googletest.git + > cd googletest + > cmake -G "Visual Studio 14 2015 Win64" . + > cmake --build . After Google Test is built you are ready to build and run unit tests. -Build and run tests on Linux:: +Build and run tests on Linux: +:: - $ cd ovpn3/core/test/unittests - $ GTEST_DIR=~/googletest ECHO=1 PROF=linux ASIO_DIR=~/asio MTLS_SYS=1 LZ4_SYS=1 NOSSL=1 $O3/core/scripts/build test_log - $ ./test_log + $ cd ovpn3/core/test/unittests + $ GTEST_DIR=~/googletest ECHO=1 PROF=linux ASIO_DIR=~/asio MTLS_SYS=1 LZ4_SYS=1 NOSSL=1 $O3/core/scripts/build test_log + $ ./test_log -Build and run tests on Windows:: +Build and run tests on Windows: +:: + + $ cd ovpn3/core/win + $ python build.py ../test/unittests/test_log.cpp unittest + $ test_log.exe - $ cd ovpn3/core/win - $ python build.py ../test/unittests/test_log.cpp unittest - $ test_log.exe Developer Guide --------------- @@ -263,7 +290,7 @@ key C++ design patterns such as *RAII*: https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization OpenVPN 3 Client Core -+++++++++++++++++++++ +""""""""""""""""""""" OpenVPN 3 is designed as a class library, with an API that is essentially defined inside of namespace ``ClientAPI`` @@ -274,17 +301,17 @@ The consise definition of the client API is essentially ``class OpenVPNClient`` in ``_ with several imporant extensions to the API found in: -* **class TunBuilderBase** in ``_ — +* :code:`class TunBuilderBase` in ``_ — Provides an abstraction layer defining the *tun* interface, and is especially useful for interfacing with an OS-layer VPN API. -* **class ExternalPKIBase** in ``_ — +* :code:`class ExternalPKIBase` in ``_ — Provides a callback for external private key operations, and is useful for interfacing with an OS-layer Keychain such as the Keychain on iOS, Mac OS X, and Android, and the Crypto API on Windows. -* **class LogReceiver** in ``_ — +* :code:`class LogReceiver` in ``_ — Provides an abstraction layer for the delivery of logging messages. OpenVPN 3 includes a command-line reference client (``cli``) for @@ -292,14 +319,13 @@ testing the API. See ``_. The basic approach to building an OpenVPN 3 client is to define a client class that derives from -``ClientAPI::OpenVPNClient``, then provide implementations +:code:`ClientAPI::OpenVPNClient`, then provide implementations for callbacks including event and logging notifications: +:: -.. code:: c++ - - class Client : public ClientAPI::OpenVPNClient - { - public: + class Client : public ClientAPI::OpenVPNClient + { + public: virtual void event(const Event&) override { // events delivered here ... } @@ -308,37 +334,34 @@ for callbacks including event and logging notifications: } ... - }; + }; -To start the client, first create a ``ClientAPI::Config`` object +To start the client, first create a :code:`ClientAPI::Config` object and initialize it with the OpenVPN config file and other options: +:: -.. code:: c++ - - ClientAPI::Config config; - config.content = ; - ... + ClientAPI::Config config; + config.content = ; + ... Next, create a client object and evaluate the configuration: +:: -.. code:: c++ - - Client client; - ClientAPI::EvalConfig eval = client.eval_config(config); - if (eval.error) - throw ...; + Client client; + ClientAPI::EvalConfig eval = client.eval_config(config); + if (eval.error) + throw ...; Finally, in a new worker thread, start the connection: +:: -.. code:: c++ + ClientAPI::Status connect_status = client.connect(); - ClientAPI::Status connect_status = client.connect(); - -Note that ``client.connect()`` will not return until +Note that :code:`client.connect()` will not return until the session has terminated. Top Layer -......... +""""""""" The top layer of the OpenVPN 3 client is implemented in ``_ and ``_. @@ -347,9 +370,9 @@ dispatching the higher-level objects that implement the OpenVPN client session. Connection -.......... +"""""""""" -``class ClientConnect`` in ``_ +:code:`class ClientConnect` in ``_ implements the top-level connection logic for an OpenVPN client connection. It is concerned with starting, stopping, pausing, and resuming OpenVPN client connections. It deals with retrying a connection and handles @@ -366,21 +389,22 @@ to the actual connection thread. In an OpenVPN client connection, the following object stack would be used: -1. **class ClientConnect** in ``_ — +1. :code:`class ClientConnect` in ``_ — The top-layer object in an OpenVPN client connection. -2. **class ClientProto::Session** in ``_ — +2. :code:`class ClientProto::Session` in ``_ — The OpenVPN client protocol object that subinstantiates the transport and tun layer objects. -3. **class ProtoContext** in ``_ — +3. :code:`class ProtoContext` in ``_ — The core OpenVPN protocol implementation that is common to both client and server. -4. **class ProtoStackBase** in ``_ — +4. :code:`class ProtoStackBase` in ``_ — The bottom-layer class that implements the basic functionality of tunneling a protocol over a reliable or unreliable transport layer, but isn't specific to OpenVPN per-se. + Transport Layer -............... +""""""""""""""" OpenVPN 3 defines abstract base classes for Transport layer implementations in ``_. @@ -391,8 +415,9 @@ Currently, transport layer implementations are provided for: * **TCP** — ``_ * **HTTP Proxy** — ``_ + Tun Layer -......... +""""""""" OpenVPN 3 defines abstract base classes for Tun layer implementations in ``_. @@ -406,21 +431,23 @@ layer implementation: 2. Use an OS-specific model such as: - * **Linux** — ``_ - * **Windows** — ``_ - * **Mac OS X** — ``_ + * **Linux** — ``_ + * **Windows** — ``_ + * **Mac OS X** — ``_ + Protocol Layer -.............. +"""""""""""""" The OpenVPN protocol is implemented in **class ProtoContext** in ``_. + Options Processing -.................. +"""""""""""""""""" The parsing and query of the OpenVPN config file -is implemented by ``class OptionList`` in +is implemented by :code:`class OptionList` in ``_. Note that OpenVPN 3 always assumes an *inline* style of @@ -429,14 +456,14 @@ defined inline rather than through an external file reference. For config files that do use external file references, -``class ProfileMerge`` in ``_ +:code:`class ProfileMerge` in ``_ is provided to merge those external file references into an inline form. Calling the Client API from other languages -........................................... +""""""""""""""""""""""""""""""""""""""""""" -The OpenVPN 3 client API, as defined by ``class OpenVPNClient`` +The OpenVPN 3 client API, as defined by :code:`class OpenVPNClient` in ``_, can be wrapped by the Swig_ tool to create bindings for other languages. @@ -446,7 +473,7 @@ For example, OpenVPN Connect for Android creates a Java binding of the API using ``_. Security -++++++++ +-------- When developing security software in C++, it's very important to take advantage of the language and OpenVPN library code @@ -455,88 +482,84 @@ bugs that can introduce security vulnerabilities. Here is a brief set of guidelines: -* When dealing with strings, use a ``std::string`` - rather than a ``char *``. +* When dealing with strings, use a :code:`std::string` + rather than a :code:`char *`. -* When dealing with binary data or buffers, always try to use a ``Buffer``, - ``ConstBuffer``, ``BufferAllocated``, or ``BufferPtr`` object to - provide managed access to the buffer, to protect against security - bugs that arise when using raw buffer pointers. - See ``_ for the OpenVPN ``Buffer`` classes. +* When dealing with binary data or buffers, always try to use a + :code:`Buffer`, :code:`ConstBuffer`, :code:`BufferAllocated`, or + :code:`BufferPtr` object to provide managed access to the buffer, to + protect against security bugs that arise when using raw buffer pointers. + See ``_ for the OpenVPN :code:`Buffer` classes. * When it's necessary to have a pointer to an object, use - ``std::unique_ptr<>`` for non-shared objects and reference-counted + :code:`std::unique_ptr<>` for non-shared objects and reference-counted smart pointers for shared objects. For shared-pointers, OpenVPN code should use the smart pointer classes defined in ``_. Please see the comments in this file for documentation. -* Never use ``malloc`` or ``free``. When allocating objects, - use the C++ ``new`` operator and then immediately construct +* Never use :code:`malloc` or :code:`free`. When allocating objects, + use the C++ :code:`new` operator and then immediately construct a smart pointer to reference the object: - - .. code:: c++ + :: std::unique_ptr ptr = new MyObject(); ptr->method(); * When interfacing with C functions that deal with raw pointers, memory allocation, etc., consider wrapping - the functionality in C++. For an example, see ``enum_dir()`` + the functionality in C++. For an example, see :code:`enum_dir()` in ``_, a function that returns a list of files in a directory (Unix only) via a high-level string vector, while internally calling the low level libc methods - ``opendir``, ``readdir``, and ``closedir``. - Notice how ``unique_ptr_del`` is used to wrap the + :code:`opendir`, :code:`readdir`, and :code:`closedir`. + Notice how :code:`unique_ptr_del` is used to wrap the ``DIR`` struct in a smart pointer with a custom deletion function. * When grabbing random entropy that is to be used for cryptographic purposes (i.e. for keys, tokens, etc.), always ensure that the RNG is crypto-grade by calling - ``assert_crypto()`` on the RNG. This will throw + :code:`assert_crypto()` on the RNG. This will throw an exception if the RNG is not crypto-grade: - - .. code:: c++ + :: void set_rng(RandomAPI::Ptr rng_arg) { - rng_arg->assert_crypto(); - rng = std::move(rng_arg); + rng_arg->assert_crypto(); + rng = std::move(rng_arg); } * Any variable whose value is not expected to change should - be declared ``const``. + be declared :code:`const`. * Don't use non-const global or static variables unless absolutely necessary. -* When formatting strings, don't use ``snprintf``. Instead, use - ``std::ostringstream`` or build the string using the '+' ``std::string`` - operator: - - .. code:: c++ +* When formatting strings, don't use :code:`snprintf`. Instead, use + :code:`std::ostringstream` or build the string using the :code:`+` + :code:`std::string` operator: + :: std::string format_reconnecting(const int n_seconds) { - return "Reconnecting in " + openvpn::to_string(n_seconds) + " seconds."; + return "Reconnecting in " + openvpn::to_string(n_seconds) + " seconds."; } or: - - .. code:: c++ + :: std::string format_reconnecting(const int n_seconds) { - std::ostringstream os; - os << "Reconnecting in " << n_seconds << " seconds."; - return os.str(); + std::ostringstream os; + os << "Reconnecting in " << n_seconds << " seconds."; + return os.str(); } * OpenVPN 3 is a "header-only" library, therefore all free functions - outside of classes should have the ``inline`` attribute. + outside of classes should have the :code:`inline` attribute. Conventions -+++++++++++ +""""""""""" * Use the **Asio** library for I/O and timers. Don't deal with sockets directly. @@ -544,18 +567,18 @@ Conventions * Never block. If you need to wait for something, use **Asio** timers or sockets. -* Use the ``OPENVPN_LOG()`` macro to log stuff. Don't use ``printf``. +* Use the :code:`OPENVPN_LOG()` macro to log stuff. Don't use :code:`printf`. * Don't call crypto/ssl libraries directly. Instead use the abstraction layers (``_ and ``_) that allow OpenVPN to link with different crypto/ssl libraries (such as **OpenSSL** or **mbed TLS**). -* Use ``RandomAPI`` as a wrapper for random number +* Use :code:`RandomAPI` as a wrapper for random number generators (``_). * If you need to deal with configuration file options, - see ``class OptionList`` in ``_. + see :code:`class OptionList` in ``_. * If you need to deal with time or time durations, use the classes under ``_. @@ -581,37 +604,35 @@ Conventions object is also a common use case for weak pointers. * Use C++ exceptions for error handling and as an alternative - to ``goto``. See OpenVPN's general exception classes + to :code:`goto`. See OpenVPN's general exception classes and macros in ``_. * Use C++ destructors for automatic object cleanup, and so that thrown exceptions will not leak objects. Alternatively, - use ``Cleanup`` in ``_ when + use :code:`Cleanup` in ``_ when you need to specify a code block to execute prior to scope - exit. For example, ensure that the file ``pid_fn`` is + exit. For example, ensure that the file :code:`pid_fn` is deleted before scope exit: - - .. code:: c++ + :: auto clean = Cleanup([pid_fn]() { - if (pid_fn) - ::unlink(pid_fn); + if (pid_fn) + ::unlink(pid_fn); }); -* When calling global methods (such as libc ``fork``), - prepend "::" to the symbol name, e.g.: - - .. code:: c++ +* When calling global methods (such as libc :code:`fork`), + prepend :code:`::` to the symbol name, e.g.: + :: struct dirent *e; while ((e = ::readdir(dir.get())) != nullptr) { - ... + ... } -* Use ``nullptr`` instead of ``NULL``. +* Use :code:`nullptr` instead of :code:`NULL`. Threading -+++++++++ +""""""""" The OpenVPN 3 client core is designed to run in a single thread, with the UI or controller driving the OpenVPN API running in a different @@ -630,4 +651,3 @@ License ------- See ``_. - \ No newline at end of file