/* static forward declarations */
static void man_output_standalone (struct management *man, volatile int *signal_received);
-static void man_reset_client_socket (struct management *man, const bool listen);
+static void man_reset_client_socket (struct management *man, const bool exiting);
static void
man_help ()
if (out)
{
man_output_list_push (man, out);
- man_reset_client_socket (man, false);
+ man_reset_client_socket (man, true);
}
}
}
#endif
static void
-man_accept (struct management *man)
+man_connection_settings_reset (struct management *man)
+{
+ man->connection.state_realtime = false;
+ man->connection.log_realtime = false;
+ man->connection.echo_realtime = false;
+ man->connection.password_verified = false;
+ man->connection.password_tries = 0;
+ man->connection.halt = false;
+ man->connection.state = MS_CC_WAIT_WRITE;
+}
+
+static void
+man_new_connection_post (struct management *man, const char *description)
{
struct gc_arena gc = gc_new ();
+
+ set_nonblock (man->connection.sd_cli);
+ set_cloexec (man->connection.sd_cli);
+
+ man_connection_settings_reset (man);
+
+#ifdef WIN32
+ man_start_ne32 (man);
+#endif
+
+ msg (D_MANAGEMENT, "MANAGEMENT: %s %s",
+ description,
+ print_sockaddr (&man->settings.local, &gc));
+
+ output_list_reset (man->connection.out);
+
+ if (!man_password_needed (man))
+ man_welcome (man);
+ man_prompt (man);
+ man_update_io_state (man);
+
+ gc_free (&gc);
+}
+
+static void
+man_accept (struct management *man)
+{
struct link_socket_actual act;
/*
#endif
}
- /*
- * Set misc socket properties
- */
- set_nonblock (man->connection.sd_cli);
- set_cloexec (man->connection.sd_cli);
-
- man->connection.state_realtime = false;
- man->connection.log_realtime = false;
- man->connection.echo_realtime = false;
- man->connection.password_verified = false;
- man->connection.password_tries = 0;
- man->connection.halt = false;
- man->connection.state = MS_CC_WAIT_WRITE;
-
-#ifdef WIN32
- man_start_ne32 (man);
-#endif
-
- msg (D_MANAGEMENT, "MANAGEMENT: Client connected from %s",
- print_sockaddr (&man->settings.local, &gc));
-
- output_list_reset (man->connection.out);
-
- if (!man_password_needed (man))
- man_welcome (man);
- man_prompt (man);
- man_update_io_state (man);
+ man_new_connection_post (man, "Client connected from");
}
-
- gc_free (&gc);
}
static void
}
static void
-man_reset_client_socket (struct management *man, const bool listen)
+man_connect (struct management *man)
+{
+ struct gc_arena gc = gc_new ();
+ int status;
+ int signal_received = 0;
+
+ /*
+ * Initialize state
+ */
+ man->connection.state = MS_INITIAL;
+ man->connection.sd_top = SOCKET_UNDEFINED;
+
+ man->connection.sd_cli = create_socket_tcp ();
+
+ status = openvpn_connect (man->connection.sd_cli,
+ &man->settings.local,
+ 5,
+ &signal_received);
+
+ if (signal_received)
+ {
+ throw_signal (signal_received);
+ goto done;
+ }
+
+ if (status)
+ {
+ msg (D_LINK_ERRORS,
+ "MANAGEMENT: connect to %s failed: %s",
+ print_sockaddr (&man->settings.local, &gc),
+ strerror_ts (status, &gc));
+ throw_signal_soft (SIGTERM, "management-connect-failed");
+ goto done;
+ }
+
+ man_new_connection_post (man, "Connected to management server at");
+
+ done:
+ gc_free (&gc);
+}
+
+static void
+man_reset_client_socket (struct management *man, const bool exiting)
{
if (socket_defined (man->connection.sd_cli))
{
man_stop_ne32 (man);
#endif
man_close_socket (man, man->connection.sd_cli);
+ man->connection.sd_cli = SOCKET_UNDEFINED;
command_line_reset (man->connection.in);
output_list_reset (man->connection.out);
}
- if (listen)
- man_listen (man);
+ if (!exiting)
+ {
+ if (man->settings.connect_as_client)
+ throw_signal_soft (SIGTERM, "management-exit");
+ else
+ man_listen (man);
+ }
}
static void
len = recv (man->connection.sd_cli, buf, sizeof (buf), MSG_NOSIGNAL);
if (len == 0)
{
- man_reset_client_socket (man, true);
+ man_reset_client_socket (man, false);
}
else if (len > 0)
{
*/
if (man->connection.halt)
{
- man_reset_client_socket (man, true);
+ man_reset_client_socket (man, false);
len = 0;
}
else
else /* len < 0 */
{
if (man_io_error (man, "recv"))
- man_reset_client_socket (man, true);
+ man_reset_client_socket (man, false);
}
return len;
}
else if (sent < 0)
{
if (man_io_error (man, "send"))
- man_reset_client_socket (man, true);
+ man_reset_client_socket (man, false);
}
}
const int log_history_cache,
const int echo_buffer_size,
const int state_buffer_size,
- const bool hold)
+ const bool hold,
+ const bool connect_as_client)
{
if (!ms->defined)
{
*/
ms->hold = hold;
+ /*
+ * Should OpenVPN connect to management interface as a client
+ * rather than a server?
+ */
+ ms->connect_as_client = connect_as_client;
+
/*
* Initialize socket address
*/
* Run management over tunnel, or
* separate channel?
*/
- if (streq (addr, "tunnel"))
+ if (streq (addr, "tunnel") && !connect_as_client)
{
ms->management_over_tunnel = true;
}
}
/*
- * Listen on socket
+ * Listen/connect socket
*/
- man_listen (man);
+ if (man->settings.connect_as_client)
+ man_connect (man);
+ else
+ man_listen (man);
}
}
const int log_history_cache,
const int echo_buffer_size,
const int state_buffer_size,
- const bool hold)
+ const bool hold,
+ const bool connect_as_client)
{
bool ret = false;
log_history_cache,
echo_buffer_size,
state_buffer_size,
- hold);
+ hold,
+ connect_as_client);
/*
* The log is initially sized to MANAGEMENT_LOG_HISTORY_INITIAL_SIZE,
if (net_events & FD_CLOSE)
{
- man_reset_client_socket (man, true);
+ man_reset_client_socket (man, false);
}
else
{
"--management ip port [pass] : Enable a TCP server on ip:port to handle\n"
" management functions. pass is a password file\n"
" or 'stdin' to prompt from console.\n"
+ "--management-client : Management interface will connect as a TCP client to\n"
+ " ip/port rather than listen as a TCP server.\n"
"--management-query-passwords : Query management channel for private key\n"
" and auth-user-pass passwords.\n"
"--management-hold : Start " PACKAGE_NAME " in a hibernating state, until a client\n"
SHOW_INT (management_echo_buffer_size);
SHOW_BOOL (management_query_passwords);
SHOW_BOOL (management_hold);
+ SHOW_BOOL (management_client);
#endif
#ifdef ENABLE_PLUGIN
if (o->plugin_list)
*/
#ifdef ENABLE_MANAGEMENT
if (!options->management_addr &&
- (options->management_query_passwords || options->management_hold
+ (options->management_query_passwords || options->management_hold || options->management_client
|| options->management_log_history_cache != defaults.management_log_history_cache))
msg (M_USAGE, "--management is not specified, however one or more options which modify the behavior of --management were specified");
#endif
VERIFY_PERMISSION (OPT_P_GENERAL);
options->management_hold = true;
}
+ else if (streq (p[0], "management-client"))
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->management_client = true;
+ }
else if (streq (p[0], "management-log-cache") && p[1])
{
int cache;