6fbf66fa |
/*
* 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.
* |
49979459 |
* Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net> |
6fbf66fa |
*
* 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.
* |
caa54ac3 |
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
6fbf66fa |
*/
|
c110b289 |
#ifdef HAVE_CONFIG_H
#include "config.h"
#elif defined(_MSC_VER)
#include "config-msvc.h"
#endif
|
6fbf66fa |
#include "syshead.h"
#include "init.h"
#include "forward.h"
#include "multi.h" |
5a2e9a25 |
#include "win32.h" |
c5b12817 |
#include "platform.h" |
6fbf66fa |
#include "memdbg.h"
#include "forward-inline.h"
|
81d882d5 |
#define P2P_CHECK_SIG() EVENT_LOOP_CHECK_SIGNAL(c, process_signal_p2p, c); |
6fbf66fa |
static bool |
81d882d5 |
process_signal_p2p(struct context *c) |
6fbf66fa |
{ |
81d882d5 |
remap_signal(c);
return process_signal(c); |
6fbf66fa |
}
|
c5b12817 |
/* Write our PID to a file */
static void
write_pid(const char *filename)
{
if (filename)
{
unsigned int pid = 0;
FILE *fp = platform_fopen(filename, "w");
if (!fp)
{
msg(M_ERR, "Open error on pid file %s", filename);
}
pid = platform_getpid();
fprintf(fp, "%u\n", pid);
if (fclose(fp))
{
msg(M_ERR, "Close error on pid file %s", filename);
}
}
} |
98619012 |
/**************************************************************************/
/**
* Main event loop for OpenVPN in client mode, where only one VPN tunnel
* is active.
* @ingroup eventloop
*
* @param c - The context structure of the single active VPN tunnel.
*/ |
6fbf66fa |
static void |
81d882d5 |
tunnel_point_to_point(struct context *c) |
6fbf66fa |
{ |
81d882d5 |
context_clear_2(c); |
6fbf66fa |
|
81d882d5 |
/* set point-to-point mode */
c->mode = CM_P2P; |
6fbf66fa |
|
81d882d5 |
/* initialize tunnel instance */
init_instance_handle_signals(c, c->es, CC_HARD_USR1_TO_HUP);
if (IS_SIG(c))
{
return;
} |
6fbf66fa |
|
81d882d5 |
/* main event loop */
while (true) |
6fbf66fa |
{ |
81d882d5 |
perf_push(PERF_EVENT_LOOP); |
6fbf66fa |
|
81d882d5 |
/* process timers, TLS, etc. */
pre_select(c);
P2P_CHECK_SIG(); |
6fbf66fa |
|
81d882d5 |
/* set up and do the I/O wait */
io_wait(c, p2p_iow_flags(c));
P2P_CHECK_SIG(); |
6fbf66fa |
|
81d882d5 |
/* timeout? */
if (c->c2.event_set_status == ES_TIMEOUT)
{
perf_pop();
continue;
} |
6fbf66fa |
|
81d882d5 |
/* process the I/O which triggered select */
process_io(c);
P2P_CHECK_SIG(); |
6fbf66fa |
|
81d882d5 |
perf_pop(); |
6fbf66fa |
}
|
81d882d5 |
uninit_management_callback(); |
6fbf66fa |
|
81d882d5 |
/* tear down tunnel instance (unless --persist-tun) */
close_instance(c); |
6fbf66fa |
}
#undef PROCESS_SIGNAL_P2P
|
98619012 |
/**************************************************************************/
/**
* OpenVPN's main init-run-cleanup loop.
* @ingroup eventloop
*
* This function contains the two outer OpenVPN loops. Its structure is
* as follows:
* - Once-per-process initialization.
* - Outer loop, run at startup and then once per \c SIGHUP:
* - Level 1 initialization
* - Inner loop, run at startup and then once per \c SIGUSR1:
* - Call event loop function depending on client or server mode:
* - \c tunnel_point_to_point()
* - \c tunnel_server()
* - Level 1 cleanup
* - Once-per-process cleanup.
*
* @param argc - Commandline argument count.
* @param argv - Commandline argument values.
*/ |
74370aa8 |
static |
6fbf66fa |
int |
81d882d5 |
openvpn_main(int argc, char *argv[]) |
6fbf66fa |
{ |
81d882d5 |
struct context c; |
6fbf66fa |
#if PEDANTIC |
81d882d5 |
fprintf(stderr, "Sorry, I was built with --enable-pedantic and I am incapable of doing any real work!\n");
return 1; |
6fbf66fa |
#endif
|
445b192a |
#ifdef _WIN32 |
81d882d5 |
SetConsoleOutputCP(CP_UTF8); |
6ba68180 |
#endif
|
81d882d5 |
CLEAR(c); |
6fbf66fa |
|
81d882d5 |
/* signify first time for components which can
* only be initialized once per program instantiation. */
c.first_time = true; |
6fbf66fa |
|
81d882d5 |
/* initialize program-wide statics */
if (init_static()) |
6fbf66fa |
{ |
81d882d5 |
/*
* This loop is initially executed on startup and then
* once per SIGHUP.
*/
do
{
/* enter pre-initialization mode with regard to signal handling */
pre_init_signal_catch();
/* zero context struct but leave first_time member alone */
context_clear_all_except_first_time(&c);
/* static signal info object */
CLEAR(siginfo_static);
c.sig = &siginfo_static;
/* initialize garbage collector scoped to context object */
gc_init(&c.gc);
/* initialize environmental variable store */
c.es = env_set_create(NULL); |
445b192a |
#ifdef _WIN32 |
81d882d5 |
set_win_sys_path_via_env(c.es); |
5a2e9a25 |
#endif |
6fbf66fa |
#ifdef ENABLE_MANAGEMENT |
81d882d5 |
/* initialize management subsystem */
init_management(&c); |
6fbf66fa |
#endif
|
81d882d5 |
/* initialize options to default state */
init_options(&c.options, true); |
6fbf66fa |
|
81d882d5 |
/* parse command line options, and read configuration file */
parse_argv(&c.options, argc, argv, M_USAGE, OPT_P_DEFAULT, NULL, c.es); |
6fbf66fa |
|
3c7f2f55 |
#ifdef ENABLE_PLUGIN |
81d882d5 |
/* plugins may contribute options configuration */
init_verb_mute(&c, IVM_LEVEL_1);
init_plugins(&c);
open_plugins(&c, true, OPENVPN_PLUGIN_INIT_PRE_CONFIG_PARSE); |
3c7f2f55 |
#endif
|
81d882d5 |
/* init verbosity and mute levels */
init_verb_mute(&c, IVM_LEVEL_1); |
6fbf66fa |
|
81d882d5 |
/* set dev options */
init_options_dev(&c.options); |
6fbf66fa |
|
81d882d5 |
/* openssl print info? */
if (print_openssl_info(&c.options))
{
break;
} |
6fbf66fa |
|
81d882d5 |
/* --genkey mode? */
if (do_genkey(&c.options))
{
break;
} |
6fbf66fa |
|
81d882d5 |
/* tun/tap persist command? */
if (do_persist_tuntap(&c.options))
{
break;
} |
6fbf66fa |
|
81d882d5 |
/* sanity check on options */
options_postprocess(&c.options); |
6fbf66fa |
|
81d882d5 |
/* show all option settings */
show_settings(&c.options); |
6fbf66fa |
|
81d882d5 |
/* print version number */
msg(M_INFO, "%s", title_string); |
445b192a |
#ifdef _WIN32 |
81d882d5 |
show_windows_version(M_INFO); |
cdc65ea0 |
#endif |
81d882d5 |
show_library_versions(M_INFO); |
6fbf66fa |
|
81d882d5 |
/* misc stuff */
pre_setup(&c.options); |
6fbf66fa |
|
81d882d5 |
/* test crypto? */
if (do_test_crypto(&c.options))
{
break;
} |
315f6fbc |
|
81d882d5 |
/* Query passwords before becoming a daemon if we don't use the
* management interface to get them. */ |
d4fbe287 |
#ifdef ENABLE_MANAGEMENT |
81d882d5 |
if (!(c.options.management_flags & MF_QUERY_PASSWORDS)) |
d4fbe287 |
#endif |
81d882d5 |
init_query_passwords(&c); |
315f6fbc |
|
81d882d5 |
/* become a daemon if --daemon */
if (c.first_time)
{
c.did_we_daemonize = possibly_become_daemon(&c.options);
write_pid(c.options.writepid);
} |
da9b2927 |
|
6fbf66fa |
#ifdef ENABLE_MANAGEMENT |
81d882d5 |
/* open management subsystem */
if (!open_management(&c))
{
break;
}
/* query for passwords through management interface, if needed */
if (c.options.management_flags & MF_QUERY_PASSWORDS)
{
init_query_passwords(&c);
} |
6fbf66fa |
#endif |
6add6b2f |
|
81d882d5 |
/* set certain options as environmental variables */
setenv_settings(c.es, &c.options); |
6fbf66fa |
|
81d882d5 |
/* finish context init */
context_init_1(&c);
do
{
/* run tunnel depending on mode */
switch (c.options.mode)
{
case MODE_POINT_TO_POINT:
tunnel_point_to_point(&c);
break; |
6fbf66fa |
#if P2MP_SERVER |
81d882d5 |
case MODE_SERVER:
tunnel_server(&c);
break;
|
6fbf66fa |
#endif |
81d882d5 |
default:
ASSERT(0);
}
/* indicates first iteration -- has program-wide scope */
c.first_time = false;
/* any signals received? */
if (IS_SIG(&c))
{
print_signal(c.sig, NULL, M_INFO);
}
/* pass restart status to management subsystem */
signal_restart_status(c.sig);
}
while (c.sig->signal_received == SIGUSR1);
uninit_options(&c.options);
gc_reset(&c.gc);
}
while (c.sig->signal_received == SIGHUP); |
6fbf66fa |
}
|
81d882d5 |
context_gc_free(&c); |
6fbf66fa |
|
81d882d5 |
env_set_destroy(c.es); |
f7a66767 |
|
6fbf66fa |
#ifdef ENABLE_MANAGEMENT |
81d882d5 |
/* close management interface */
close_management(); |
6fbf66fa |
#endif
|
81d882d5 |
/* uninitialize program-wide statics */
uninit_static(); |
6fbf66fa |
|
81d882d5 |
openvpn_exit(OPENVPN_EXIT_STATUS_GOOD); /* exit point */
return 0; /* NOTREACHED */ |
6fbf66fa |
} |
74370aa8 |
|
445b192a |
#ifdef _WIN32 |
74370aa8 |
int |
4cd4899e |
wmain(int argc, wchar_t *wargv[])
{ |
81d882d5 |
char **argv;
int ret;
int i; |
74370aa8 |
|
81d882d5 |
if ((argv = calloc(argc+1, sizeof(char *))) == NULL)
{
return 1;
} |
74370aa8 |
|
81d882d5 |
for (i = 0; i < argc; i++) |
74370aa8 |
{ |
81d882d5 |
int n = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, NULL, 0, NULL, NULL);
argv[i] = malloc(n);
WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i], n, NULL, NULL); |
74370aa8 |
}
|
81d882d5 |
ret = openvpn_main(argc, argv); |
74370aa8 |
|
81d882d5 |
for (i = 0; i < argc; i++) |
74370aa8 |
{ |
81d882d5 |
free(argv[i]); |
74370aa8 |
} |
81d882d5 |
free(argv); |
74370aa8 |
|
81d882d5 |
return ret; |
74370aa8 |
} |
81d882d5 |
#else /* ifdef _WIN32 */ |
74370aa8 |
int |
4cd4899e |
main(int argc, char *argv[])
{ |
81d882d5 |
return openvpn_main(argc, argv); |
74370aa8 |
} |
81d882d5 |
#endif /* ifdef _WIN32 */ |