OpenVPN
|
This section describes how OpenVPN stores its VPN tunnel state during operation.
OpenVPN uses several data structures as storage containers for state information of active VPN tunnels. These are described in this section, together with a little bit of history to help understand the origin of the current architecture.
Whether an OpenVPN process is running in client-mode or server-mode determines whether it can support only one or multiple simultaneously active VPN tunnels. This consequently also determines how the associated state information is wrapped up internally. This section gives an overview of the differences.
In the old v1.x series, an OpenVPN process managed only one single VPN tunnel. This allowed the VPN tunnel state to be stored together with process-global information in one single context
structure.
This changed, however, in the v2.x series, as new OpenVPN versions running in server-mode can support multiple simultaneously active VPN tunnels. This necessitated a redesign of the VPN tunnel state container structures, and modification of the External Multiplexer and Internal Multiplexer systems. The majority of these changes are only relevant for OpenVPN processes running in server-mode, and the client-mode structure has remained very similar to the v1.x single-tunnel form.
An OpenVPN process running in client-mode can manage at most one single VPN tunnel at any one time. The state information for a client's VPN tunnel is stored in a context
structure.
The context
structure is created in the main()
function. That is also where process-wide initialization takes place, such as parsing command line options and reading configuration files. The context
is then passed to tunnel_point_to_point()
which drives OpenVPN's main event processing loop. These functions are both part of the Main Event Loop module.
Because there is only one context
structure present, it can be initialized and cleaned up from the client's main event processing function. Before the tunnel_point_to_point()
function enters its event loop, it calls init_instance_handle_signals()
which calls init_instance()
to initialize the single context
structure. After the event loop stops, it calls close_instance()
to clean up the context
.
When the main event processing loop activates the external or internal multiplexer to handle a network event, it is not necessary to determine which VPN tunnel the event is associated with, because there is only one VPN tunnel active.
An OpenVPN process running in server-mode can manage multiple simultaneously active VPN tunnels. For every VPN tunnel active, in other words for every OpenVPN client which is connected to a server, the OpenVPN server has one context
structure in which it stores that particular VPN tunnel's state information.
To support multiple context
structures, each is wrapped in a multi_instance
structure, and all the multi_instance
structures are registered in one single multi_context
structure. The External Multiplexer and Internal Multiplexer then use the multi_context
to retrieve the correct multi_instance
and context
associated with a given network address.
An OpenVPN process running in server-mode starts in the same main()
function as it would in client-mode. The same process-wide initialization is performed, and the resulting state and configuration is stored in a context
structure. The server-mode and client-mode processes diverge when the main()
function calls one of tunnel_point_to_point()
or tunnel_server()
.
In server-mode, main()
calls the tunnel_server()
function, which transfers control to tunnel_server_udp()
or tunnel_server_tcp()
depending on the external transport protocol.
These functions receive the context
created in main()
. This object has a special status in server-mode, as it does not represent an active VPN tunnel, but does contain process-wide configuration parameters. In the source code, it is often stored in "top" variables. To distinguish this object from other instances of the same type, its context.mode
value is set to CM_TOP
. Other context
objects, which do represent active VPN tunnels, have a context.mode
set to CM_CHILD_UDP
or CM_CHILD_TCP
, depending on the external transport protocol.
Both tunnel_server_udp_single_threaded()
and tunnel_server_tcp()
perform similar initialization. In either case, a multi_context
structure is created, and it is initialized according to the configuration stored in the top context
by the multi_init()
and multi_top_init()
functions.
When an OpenVPN client makes a new connection to a server, the server creates a new context
and multi_instance
. The latter is registered in the multi_context
, which makes it possible for the external and internal multiplexers to retrieve the correct multi_instance
and context
when a network event occurs.
After the main event loop exits, both tunnel_server_udp_single_threaded()
and tunnel_server_tcp()
perform similar cleanup. They call multi_uninit()
followed by multi_top_free()
to clean up the multi_context
structure.