2008-08-15 Dan Williams <dcbw@redhat.com>

Do connection sharing in a cleaner manner; all required iptables rules
	are now stored in the activation request and pertain only to the device
	which is being shared to other computers.

	* src/nm-activation-request.c
	  src/nm-activation-request.h
		- (nm_act_request_add_share_rule): new function; add a sharing rule to
			the activation request which will get torn down automatically when
			the activation request dies
		- (nm_act_request_set_shared): push sharing rules to iptables when sharing
			is started, and tear them down when sharing is stopped

	* src/nm-device.c
		- (start_sharing): start up sharing by doing the required iptables magic
		- (share_init): poke the right bits of the kernel and load the right
			modules for NAT
		- (nm_device_activate_stage5_ip_config_commit): start NAT-ing this
			connection if it's a 'shared' connection

	* src/NetworkManagerPolicy.c
		- Remove all sharing stuff; done in the device code itself



git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3969 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
Dan Williams
2008-08-15 15:34:28 +00:00
parent d682f35bf0
commit 02b28e6cd2
5 changed files with 271 additions and 199 deletions

View File

@@ -20,6 +20,9 @@
*/
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <dbus/dbus-glib.h>
#include "nm-activation-request.h"
@@ -49,6 +52,10 @@ enum {
static guint signals[LAST_SIGNAL] = { 0 };
typedef struct {
char *table;
char *rule;
} ShareRule;
typedef struct {
gboolean disposed;
@@ -63,6 +70,7 @@ typedef struct {
NMActiveConnectionState state;
gboolean is_default;
gboolean shared;
GSList *share_rules;
char *ac_path;
} NMActRequestPrivate;
@@ -206,11 +214,32 @@ dispose (GObject *object)
cleanup_secrets_dbus_call (NM_ACT_REQUEST (object));
/* Clear any share rules */
nm_act_request_set_shared (NM_ACT_REQUEST (object), FALSE);
g_object_unref (priv->connection);
G_OBJECT_CLASS (nm_act_request_parent_class)->dispose (object);
}
static void
clear_share_rules (NMActRequest *req)
{
NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (req);
GSList *iter;
for (iter = priv->share_rules; iter; iter = g_slist_next (iter)) {
ShareRule *rule = (ShareRule *) iter->data;
g_free (rule->table);
g_free (rule->rule);
g_free (rule);
}
g_slist_free (priv->share_rules);
priv->share_rules = NULL;
}
static void
finalize (GObject *object)
{
@@ -219,6 +248,8 @@ finalize (GObject *object)
g_free (priv->specific_object);
g_free (priv->ac_path);
clear_share_rules (NM_ACT_REQUEST (object));
G_OBJECT_CLASS (nm_act_request_parent_class)->finalize (object);
}
@@ -646,12 +677,69 @@ nm_act_request_get_default (NMActRequest *req)
return NM_ACT_REQUEST_GET_PRIVATE (req)->is_default;
}
static void
share_child_setup (gpointer user_data G_GNUC_UNUSED)
{
/* We are in the child process at this point */
pid_t pid = getpid ();
setpgid (pid, pid);
}
void
nm_act_request_set_shared (NMActRequest *req, gboolean shared)
{
NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (req);
GSList *list, *iter;
g_return_if_fail (NM_IS_ACT_REQUEST (req));
NM_ACT_REQUEST_GET_PRIVATE (req)->shared = shared;
/* Tear the rules down in reverse order when sharing is stopped */
list = g_slist_copy (priv->share_rules);
if (!shared)
list = g_slist_reverse (list);
/* Send the rules to iptables */
for (iter = list; iter; iter = g_slist_next (iter)) {
ShareRule *rule = (ShareRule *) iter->data;
char *envp[1] = { NULL };
char **argv;
char *cmd;
int status;
GError *error = NULL;
if (shared)
cmd = g_strdup_printf ("/sbin/iptables --table %s --insert %s", rule->table, rule->rule);
else
cmd = g_strdup_printf ("/sbin/iptables --table %s --delete %s", rule->table, rule->rule);
argv = g_strsplit (cmd, " ", 0);
if (!argv || !argv[0]) {
continue;
g_free (cmd);
}
nm_info ("Executing: %s", cmd);
g_free (cmd);
if (!g_spawn_sync ("/", argv, envp, G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
share_child_setup, NULL, NULL, NULL, &status, &error)) {
nm_info ("Error executing command: (%d) %s",
error ? error->code : 0, (error && error->message) ? error->message : "unknown");
if (error)
g_error_free (error);
} else if (WEXITSTATUS (status))
nm_info ("** Command returned exit status %d.", WEXITSTATUS (status));
g_strfreev (argv);
}
g_slist_free (list);
/* Clear the share rule list when sharing is stopped */
if (!shared)
clear_share_rules (req);
}
gboolean
@@ -662,6 +750,24 @@ nm_act_request_get_shared (NMActRequest *req)
return NM_ACT_REQUEST_GET_PRIVATE (req)->shared;
}
void
nm_act_request_add_share_rule (NMActRequest *req,
const char *table,
const char *table_rule)
{
NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (req);
ShareRule *rule;
g_return_if_fail (NM_IS_ACT_REQUEST (req));
g_return_if_fail (table != NULL);
g_return_if_fail (table_rule != NULL);
rule = g_malloc0 (sizeof (ShareRule));
rule->table = g_strdup (table);
rule->rule = g_strdup (table_rule);
priv->share_rules = g_slist_append (priv->share_rules, rule);
}
GObject *
nm_act_request_get_device (NMActRequest *req)
{