Implement connect() and disconnect()

master
Max Moser 2018-02-11 23:18:28 +01:00
parent 03ccd23708
commit 5811801078
1 changed files with 105 additions and 176 deletions

View File

@ -42,9 +42,12 @@
#include <locale.h> #include <locale.h>
#include <pwd.h> #include <pwd.h>
#include <grp.h> #include <grp.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <glib-unix.h> #include <glib-unix.h>
#include "utils.h" #include "utils.h"
#include "import-export.h"
#include "nm-utils/nm-shared-utils.h" #include "nm-utils/nm-shared-utils.h"
#include "nm-utils/nm-vpn-plugin-macros.h" #include "nm-utils/nm-vpn-plugin-macros.h"
@ -136,6 +139,8 @@ typedef struct {
NMWireguardPluginIOData *io_data; NMWireguardPluginIOData *io_data;
gboolean interactive; gboolean interactive;
char *mgt_path; char *mgt_path;
char *connection_file;
GString *connection_config;
} NMWireguardPluginPrivate; } NMWireguardPluginPrivate;
G_DEFINE_TYPE (NMWireguardPlugin, nm_wireguard_plugin, NM_TYPE_VPN_SERVICE_PLUGIN) G_DEFINE_TYPE (NMWireguardPlugin, nm_wireguard_plugin, NM_TYPE_VPN_SERVICE_PLUGIN)
@ -416,7 +421,9 @@ pids_pending_add (GPid pid, NMWireguardPlugin *plugin)
} }
// TODO implement me right // TODO implement me right
wg_quick_closed(GPid pid, gint status, gpointer user_data){ static void
wg_quick_closed(GPid pid, gint status, gpointer user_data)
{
PidsPendingData *pid_data = user_data; PidsPendingData *pid_data = user_data;
NMWireguardPlugin *plugin; NMWireguardPlugin *plugin;
@ -1002,12 +1009,12 @@ nm_openvpn_socket_data_cb (GIOChannel *source, GIOCondition condition, gpointer
static gboolean static gboolean
nm_openvpn_connect_timer_cb (gpointer data) nm_openvpn_connect_timer_cb (gpointer data)
{ {
printf("Connect Timer Callback!\n");
NMWireguardPlugin *plugin = NM_WIREGUARD_PLUGIN (data); NMWireguardPlugin *plugin = NM_WIREGUARD_PLUGIN (data);
NMWireguardPluginPrivate *priv = NM_WIREGUARD_PLUGIN_GET_PRIVATE (plugin); NMWireguardPluginPrivate *priv = NM_WIREGUARD_PLUGIN_GET_PRIVATE (plugin);
NMWireguardPluginIOData *io_data = priv->io_data; NMWireguardPluginIOData *io_data = priv->io_data;
struct sockaddr_un remote = { 0 }; struct sockaddr_un remote = { 0 };
int fd; int fd;
printf("Connect Timer Callback!\n");
priv->connect_count++; priv->connect_count++;
@ -1047,8 +1054,8 @@ out:
static void static void
nm_openvpn_schedule_connect_timer (NMWireguardPlugin *plugin) nm_openvpn_schedule_connect_timer (NMWireguardPlugin *plugin)
{ {
printf("Scheduling timer\n");
NMWireguardPluginPrivate *priv = NM_WIREGUARD_PLUGIN_GET_PRIVATE (plugin); NMWireguardPluginPrivate *priv = NM_WIREGUARD_PLUGIN_GET_PRIVATE (plugin);
printf("Scheduling timer\n");
if (priv->connect_timer == 0) if (priv->connect_timer == 0)
priv->connect_timer = g_timeout_add (200, nm_openvpn_connect_timer_cb, plugin); priv->connect_timer = g_timeout_add (200, nm_openvpn_connect_timer_cb, plugin);
@ -1342,8 +1349,8 @@ nm_wireguard_start_interface(NMWireguardPlugin *plugin,
NMConnection *connection, NMConnection *connection,
GError **error) GError **error)
{ {
NMWireguardPluginPrivate *priv = NM_WIREGUARD_PLUGIN_GET_PRIVATE(plugin); // NMWireguardPluginPrivate *priv = NM_WIREGUARD_PLUGIN_GET_PRIVATE(plugin);
const char *wg_connection_name = NULL; // const char *wg_connection_name = NULL;
return TRUE; return TRUE;
} }
@ -2083,11 +2090,13 @@ check_need_secrets (NMSettingVpn *s_vpn, gboolean *need_secrets)
// IMPLEMENT ME RIGHT // IMPLEMENT ME RIGHT
static gboolean static gboolean
test_disconnect(NMVpnServicePlugin *plugin, wg_disconnect(NMVpnServicePlugin *plugin,
GError **err) GError **error)
{ {
char *wg_quick_path = wg_quick_find_exepath(); NMWireguardPluginPrivate *priv = NM_WIREGUARD_PLUGIN_GET_PRIVATE(plugin);
char *connection_name = "mullvad"; const char *wg_quick_path = wg_quick_find_exepath();
char *filename = priv->connection_file;
GString *cfg_content = priv->connection_config;
char *command; char *command;
int retcode = 1; int retcode = 1;
@ -2095,16 +2104,36 @@ test_disconnect(NMVpnServicePlugin *plugin,
_LOGW("Error: Could not find wg-quick!"); _LOGW("Error: Could not find wg-quick!");
return FALSE; return FALSE;
} }
// join together our command
command = g_strjoin("", wg_quick_path, " down ", connection_name);
if(!g_spawn_command_line_sync(command, NULL, NULL, &retcode, err)){ if(!filename || !cfg_content){
_LOGW("An error occured while spawning wg-quick! (Error: %s)", (*err)->message); _LOGW("Error: Cannot remember the connection details for Disconnect");
g_set_error_literal(error,
NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_FAILED,
"Cannot remember the connection details for Disconnect");
return FALSE;
} }
g_free(command); // create the temporary configuration file
g_file_set_contents(filename, cfg_content->str, cfg_content->len, error);
g_chmod(filename, 0400);
_LOGI("Did a disconnect!"); // join together our command
command = g_strdup_printf("%s down %s", wg_quick_path, filename);
if(!g_spawn_command_line_sync(command, NULL, NULL, &retcode, error)){
_LOGW("An error occured while spawning wg-quick! (Error: %s)", (*error)->message);
}
// delete the file and free temporary private data
g_remove(filename);
g_free(command);
g_string_free(priv->connection_config, TRUE);
g_free(priv->connection_file);
priv->connection_config = NULL;
priv->connection_file = NULL;
_LOGI("Disconnected from Wireguard Connection!");
return TRUE; return TRUE;
} }
@ -2129,173 +2158,71 @@ real_disconnect (NMVpnServicePlugin *plugin,
return TRUE; return TRUE;
} }
// read the configuration and set the Plugin's private data accordingly
static gboolean static gboolean
read_config(NMVpnServicePlugin *plugin, connect_common(NMVpnServicePlugin *plugin,
const char *connection_name,
GError **error){
printf("A:%s\n", connection_name);
NMWireguardPlugin *wg_plugin = NM_WIREGUARD_PLUGIN(plugin);
printf("A2\n"); // do not remove this, or we get a segfault in the next line. because reasons
char *filename = g_strjoin("", "/etc/nm-wireguard/", connection_name, ".conf");
//printf("A3:%s\n", filename);
gchar *contents = NULL;
gchar *line = NULL;
gchar **lines = NULL;
gboolean success = TRUE;
gsize length;
int i = 0;
GError *local = NULL;
printf("B:%s\n", filename);
if(!g_file_get_contents(filename, &contents, &length, &local)){
// TODO the file could not be read
_LOGW("Error while reading configuration: %s", (local)->message);
success = FALSE;
}else{
// TODO set the private data of the plugin such that it contains the read information
//wg_plugin->priv
// TODO find
printf("--- %s (length:%d)\n", filename, length);
lines = g_strsplit(contents, "\n", 0);
while((line = lines[i]) != NULL){
if(g_strrstr(line, "Address") != NULL){
printf(">> %s\n", line);
}
printf("> %s\n", line);
i++;
}
printf("---\n");
}
printf("C\n");
g_strfreev(lines);
g_free(filename);
g_free(contents);
return success;
}
// IMPLEMENT ME RIGHT
static gboolean
test_connect (NMVpnServicePlugin *plugin,
NMConnection *connection, NMConnection *connection,
GError **err) GVariant *details,
GError **error)
{ {
NMWireguardPluginPrivate *priv = NM_WIREGUARD_PLUGIN_GET_PRIVATE(plugin);
NMSettingVpn *setting = nm_connection_get_setting_vpn(connection); const char *wg_quick_path = wg_quick_find_exepath();
char *secret = nm_setting_vpn_get_secret(setting, "name"); const char *connection_name = nm_connection_get_id(connection);
char *str_setting = nm_setting_to_string(setting);
char *wg_quick_path = wg_quick_find_exepath();
char *connection_name = "mullvad";
char *command; char *command;
int retcode = 1; int retcode = 1;
char *filename = NULL;
GString *connection_config = NULL;
GVariantBuilder builder, ip4builder, ip6builder;
GVariant *config, *ip4config, *ip6config;
_LOGI("Setting up Wireguard Connection ('%s')", connection_name);
if(wg_quick_path == NULL){ if(wg_quick_path == NULL){
_LOGW("Error: Could not find wg-quick!"); _LOGW("Error: Could not find wg-quick!");
return FALSE; return FALSE;
} }
printf("Setting to String: %s\n", str_setting); // take the connection details and create the configuration string from it
printf("Secret: %s\n", secret); connection_config = create_config_string(connection, error);
if(!connection_config){
// join together our command _LOGW("Error: Could not create configuration for connection '%s'!", connection_name);
command = g_strjoin("", wg_quick_path, " up ", connection_name); g_set_error_literal(error,
NM_VPN_PLUGIN_ERROR,
printf("Command: %s\n", command); NM_VPN_PLUGIN_ERROR_FAILED,
if(!g_spawn_command_line_sync(command, NULL, NULL, &retcode, err)){ "Could not create configuration from connection");
_LOGW("An error occured while spawning wg-quick! (Error: %s)", (*err)->message);
}
g_free(command);
//pids_pending_add_wg(pid, plugin);
//printf("PID of spawned command: %d\n", pid);
printf("Return code of spawned command: %d\n", retcode);
// note: exit code 139 means SIGSEV (program died because of segfault or so)
{
printf("WG set up and ready to go!\n");
}
_LOGI("Did a dummy connect");
return TRUE;
}
// print the keys and values in a dictionary
static void printme(const char *key, const char *value, gpointer user_data){
printf("Key: %s\n", key);
printf("Value: %s\n", value);
}
// IMPLEMENT ME RIGHT
// this is the function that is actually called when the user clicks the connection in the GUI
static gboolean
test_connect_interactive(NMVpnServicePlugin *plugin,
NMConnection *connection,
GError **error){
NMSettingVpn *setting = nm_connection_get_setting_vpn(connection);
char *secret = nm_setting_vpn_get_secret(setting, "name");
char *str_setting = nm_setting_to_string(setting);
char *wg_quick_path = wg_quick_find_exepath();
char *connection_name = nm_connection_get_id(connection);
char *command;
int retcode = 1;
read_config(plugin, connection_name, error);
printf("Connecting interactively to '%s'\n", connection_name);
printf("===\n");
printf(">>> Data:\n");
nm_setting_vpn_foreach_data_item(setting, printme, NULL);
printf(">>> Secret:\n");
nm_setting_vpn_foreach_secret(setting, printme, NULL);
printf("===\n");
if(wg_quick_path == NULL){
_LOGW("Error: Could not find wg-quick!");
return FALSE; return FALSE;
} }
priv->connection_config = connection_config;
filename = g_strdup_printf("/tmp/%s.conf", connection_name);
priv->connection_file = filename;
printf("Setting to String: %s\n", str_setting); if(!do_export(filename, connection, error)){
printf("Secret: %s\n", secret); _LOGW("Error: Could not create temporary configuration file for connection '%s'", connection_name);
return FALSE;
}
g_chmod(filename, 0400);
// join together our command // join together our command
// TODO sanitize the connection name before using it command = g_strdup_printf("%s up %s", wg_quick_path, filename);
command = g_strjoin("", wg_quick_path, " up ", connection_name);
printf("Command: %s\n", command);
if(!g_spawn_command_line_sync(command, NULL, NULL, &retcode, error)){ if(!g_spawn_command_line_sync(command, NULL, NULL, &retcode, error)){
_LOGW("An error occured while spawning wg-quick! (Error: %s)", (*error)->message); _LOGW("An error occured while spawning wg-quick! (Error: %s)", (*error)->message);
return FALSE;
} }
// remove the file and free the command string
g_remove(filename);
g_free(command); g_free(command);
//pids_pending_add_wg(pid, plugin);
//printf("PID of spawned command: %d\n", pid);
printf("Return code of spawned command: %d\n", retcode);
// note: exit code 139 means SIGSEV (program died because of segfault or so)
{
printf("WG set up and ready to go!\n");
}
_LOGI("Did an interactive dummy connect");
NM_WIREGUARD_PLUGIN_GET_PRIVATE(plugin)->interactive = TRUE;
// get ready to build the IP4 stuff and send it // get ready to build the IP4 stuff and send it
// (required that the connection does not time-out) // (required that the connection does not time-out)
char* tmp;
GVariantBuilder builder, ip4builder;
g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
g_variant_builder_init(&ip4builder, G_VARIANT_TYPE_VARDICT); g_variant_builder_init(&ip4builder, G_VARIANT_TYPE_VARDICT);
GVariant *config = g_variant_builder_end(&builder); g_variant_builder_init(&ip6builder, G_VARIANT_TYPE_VARDICT);
GVariant *ip4config = g_variant_builder_end(&ip4builder); config = g_variant_builder_end(&builder);
ip4config = g_variant_builder_end(&ip4builder);
ip6config = g_variant_builder_end(&ip6builder);
nm_vpn_service_plugin_set_config(plugin, config); nm_vpn_service_plugin_set_config(plugin, config);
nm_vpn_service_plugin_set_ip4_config(plugin, ip4config); nm_vpn_service_plugin_set_ip4_config(plugin, ip4config);
nm_vpn_service_plugin_set_ip6_config(plugin, ip6config);
/* /*
[1] https://git.gnome.org/browse/network-manager-openvpn/tree/src/nm-openvpn-service-openvpn-helper.c?id=40e522aea2146ec20e0232545aa574664184be39#n114 [1] https://git.gnome.org/browse/network-manager-openvpn/tree/src/nm-openvpn-service-openvpn-helper.c?id=40e522aea2146ec20e0232545aa574664184be39#n114
@ -2304,22 +2231,30 @@ test_connect_interactive(NMVpnServicePlugin *plugin,
[4] https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/src/vpn/nm-vpn-connection.c?id=7044febf97debaf04b7f9ca4fbb2dc24fcf1b0b0#n2072 [4] https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/src/vpn/nm-vpn-connection.c?id=7044febf97debaf04b7f9ca4fbb2dc24fcf1b0b0#n2072
*/ */
/* return TRUE;
// it might be easier to just do something valid, actually than trying to pull this hack }
s = g_signal_new ("state-changed", // IMPLEMENT ME RIGHT
G_OBJECT_CLASS_TYPE (object_class), static gboolean
G_SIGNAL_RUN_FIRST, wg_connect (NMVpnServicePlugin *plugin,
G_STRUCT_OFFSET (NMVpnServicePluginClass, state_changed), NMConnection *connection,
NULL, NULL, GError **error)
NULL, {
G_TYPE_NONE, 1, return connect_common(plugin, connection, NULL, error);
G_TYPE_UINT); }
g_signal_emit (plugin, s, 0, NM_VPN_SERVICE_STATE_STARTED);
// what is this? // nmdbus_vpn_plugin_emit_state_changed (priv->dbus_vpn_service_plugin, NM_VPN_SERVICE_STATE_STARTED); // IMPLEMENT ME RIGHT
//nm_vpn_service_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STARTED); // this is the function that is actually called when the user clicks the connection in the GUI
*/ static gboolean
wg_connect_interactive(NMVpnServicePlugin *plugin,
NMConnection *connection,
GVariant *details,
GError **error)
{
if(!connect_common(plugin, connection, details, error)){
return FALSE;
}
NM_WIREGUARD_PLUGIN_GET_PRIVATE(plugin)->interactive = TRUE;
return TRUE; return TRUE;
} }
@ -2369,12 +2304,6 @@ test_need_secrets (NMVpnServicePlugin *plugin,
const char **setting_name, const char **setting_name,
GError **error) GError **error)
{ {
NMSettingVpn *setting = nm_connection_get_setting_vpn(connection);
char *secret = nm_setting_vpn_get_secret(setting, "name");
char *str_setting = nm_setting_to_string(setting);
char *ptr = setting_name;
*setting_name = NM_SETTING_VPN_SETTING_NAME;
_LOGI("I require no secrets!"); _LOGI("I require no secrets!");
return FALSE; return FALSE;
} }
@ -2522,10 +2451,10 @@ nm_wireguard_plugin_class_init (NMWireguardPluginClass *plugin_class)
/* virtual methods */ /* virtual methods */
// IMPLEMENT ME RIGHT // IMPLEMENT ME RIGHT
parent_class->connect = test_connect; parent_class->connect = wg_connect;
parent_class->connect_interactive = test_connect_interactive; parent_class->connect_interactive = wg_connect_interactive;
parent_class->need_secrets = test_need_secrets; parent_class->need_secrets = test_need_secrets;
parent_class->disconnect = test_disconnect; parent_class->disconnect = wg_disconnect;
parent_class->new_secrets = test_new_secrets; parent_class->new_secrets = test_new_secrets;
} }