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:
24
ChangeLog
24
ChangeLog
@@ -1,3 +1,27 @@
|
|||||||
|
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
|
||||||
|
|
||||||
2008-08-15 Dan Williams <dcbw@redhat.com>
|
2008-08-15 Dan Williams <dcbw@redhat.com>
|
||||||
|
|
||||||
* src/dnsmasq-manager/nm-dnsmasq-manager.c
|
* src/dnsmasq-manager/nm-dnsmasq-manager.c
|
||||||
|
@@ -20,17 +20,7 @@
|
|||||||
* (C) Copyright 2005 Red Hat, Inc.
|
* (C) Copyright 2005 Red Hat, Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/select.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
|
|
||||||
#include "NetworkManagerPolicy.h"
|
#include "NetworkManagerPolicy.h"
|
||||||
#include "NetworkManagerUtils.h"
|
#include "NetworkManagerUtils.h"
|
||||||
@@ -345,178 +335,6 @@ get_device_connection (NMDevice *device)
|
|||||||
return nm_act_request_get_connection (req);
|
return nm_act_request_get_connection (req);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
do_cmd (const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
char *cmd;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
va_start (args, fmt);
|
|
||||||
cmd = g_strdup_vprintf (fmt, args);
|
|
||||||
va_end (args);
|
|
||||||
|
|
||||||
nm_info ("Executing: %s", cmd);
|
|
||||||
ret = system (cmd);
|
|
||||||
g_free (cmd);
|
|
||||||
|
|
||||||
if (ret == -1) {
|
|
||||||
nm_info ("** Error executing command.");
|
|
||||||
return FALSE;
|
|
||||||
} else if (WEXITSTATUS (ret)) {
|
|
||||||
nm_info ("** Command returned exit status %d.", WEXITSTATUS (ret));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sharing_init (void)
|
|
||||||
{
|
|
||||||
do_cmd ("echo \"1\" > /proc/sys/net/ipv4/ip_forward");
|
|
||||||
do_cmd ("echo \"1\" > /proc/sys/net/ipv4/ip_dynaddr");
|
|
||||||
do_cmd ("/sbin/modprobe ip_tables iptable_nat ip_nat_ftp ip_nat_irc");
|
|
||||||
do_cmd ("/sbin/iptables -P INPUT ACCEPT");
|
|
||||||
do_cmd ("/sbin/iptables -F INPUT");
|
|
||||||
do_cmd ("/sbin/iptables -P OUTPUT ACCEPT");
|
|
||||||
do_cmd ("/sbin/iptables -F OUTPUT");
|
|
||||||
do_cmd ("/sbin/iptables -P FORWARD DROP");
|
|
||||||
do_cmd ("/sbin/iptables -F FORWARD");
|
|
||||||
do_cmd ("/sbin/iptables -t nat -F");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sharing_stop (NMActRequest *req)
|
|
||||||
{
|
|
||||||
do_cmd ("/sbin/iptables -F INPUT");
|
|
||||||
do_cmd ("/sbin/iptables -F OUTPUT");
|
|
||||||
do_cmd ("/sbin/iptables -P FORWARD DROP");
|
|
||||||
do_cmd ("/sbin/iptables -F FORWARD");
|
|
||||||
do_cmd ("/sbin/iptables -F -t nat");
|
|
||||||
|
|
||||||
// Delete all User-specified chains
|
|
||||||
do_cmd ("/sbin/iptables -X");
|
|
||||||
|
|
||||||
// Reset all IPTABLES counters
|
|
||||||
do_cmd ("/sbin/iptables -Z");
|
|
||||||
|
|
||||||
nm_act_request_set_shared (req, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Given a default activation request, start NAT-ing if there are any shared
|
|
||||||
* connections.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
sharing_restart (NMPolicy *policy, NMActRequest *req)
|
|
||||||
{
|
|
||||||
GSList *devices, *iter;
|
|
||||||
const char *extif;
|
|
||||||
gboolean have_shared = FALSE;
|
|
||||||
|
|
||||||
if (nm_act_request_get_shared (req))
|
|
||||||
sharing_stop (req);
|
|
||||||
|
|
||||||
extif = nm_device_get_ip_iface (NM_DEVICE (nm_act_request_get_device (req)));
|
|
||||||
g_assert (extif);
|
|
||||||
|
|
||||||
/* Start NAT-ing every 'shared' connection */
|
|
||||||
devices = nm_manager_get_devices (policy->manager);
|
|
||||||
for (iter = devices; iter; iter = g_slist_next (iter)) {
|
|
||||||
NMDevice *candidate = NM_DEVICE (iter->data);
|
|
||||||
NMSettingIP4Config *s_ip4;
|
|
||||||
NMConnection *connection;
|
|
||||||
const char *intif;
|
|
||||||
|
|
||||||
if (nm_device_get_state (candidate) != NM_DEVICE_STATE_ACTIVATED)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
connection = get_device_connection (candidate);
|
|
||||||
g_assert (connection);
|
|
||||||
|
|
||||||
s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
|
|
||||||
if (!s_ip4 || strcmp (s_ip4->method, "shared"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Init sharing if there's a shared connection to NAT */
|
|
||||||
if (!have_shared) {
|
|
||||||
sharing_init ();
|
|
||||||
have_shared = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FWD: Allow all connections OUT and only existing and related ones IN
|
|
||||||
intif = nm_device_get_ip_iface (candidate);
|
|
||||||
g_assert (intif);
|
|
||||||
do_cmd ("/sbin/iptables -A FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT", extif, intif);
|
|
||||||
do_cmd ("/sbin/iptables -A FORWARD -i %s -o %s -j ACCEPT", extif, intif);
|
|
||||||
do_cmd ("/sbin/iptables -A FORWARD -i %s -o %s -j ACCEPT", intif, extif);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (have_shared) {
|
|
||||||
// Enabling SNAT (MASQUERADE) functionality on $EXTIF
|
|
||||||
do_cmd ("/sbin/iptables -t nat -A POSTROUTING -o %s -j MASQUERADE", extif);
|
|
||||||
|
|
||||||
nm_act_request_set_shared (req, TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
check_sharing (NMPolicy *policy, NMDevice *device, NMConnection *connection)
|
|
||||||
{
|
|
||||||
NMSettingIP4Config *s_ip4;
|
|
||||||
GSList *devices, *iter;
|
|
||||||
NMActRequest *default_req = NULL;
|
|
||||||
|
|
||||||
if (!connection)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* We only care about 'shared' connections going up or down */
|
|
||||||
s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
|
|
||||||
if (!s_ip4 || strcmp (s_ip4->method, "shared"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Find the default connection, if any */
|
|
||||||
devices = nm_manager_get_devices (policy->manager);
|
|
||||||
for (iter = devices; iter; iter = g_slist_next (iter)) {
|
|
||||||
NMDevice *candidate = NM_DEVICE (iter->data);
|
|
||||||
NMActRequest *req = nm_device_get_act_request (candidate);
|
|
||||||
|
|
||||||
if (req && nm_act_request_get_default (req)) {
|
|
||||||
default_req = req;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Restart sharing if there's a default active connection */
|
|
||||||
if (default_req)
|
|
||||||
sharing_restart (policy, default_req);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
active_connection_default_changed (NMActRequest *req,
|
|
||||||
GParamSpec *pspec,
|
|
||||||
NMPolicy *policy)
|
|
||||||
{
|
|
||||||
gboolean is_default = nm_act_request_get_default (req);
|
|
||||||
|
|
||||||
if (is_default) {
|
|
||||||
if (nm_act_request_get_shared (req)) {
|
|
||||||
/* Already shared, shouldn't get here */
|
|
||||||
nm_warning ("%s: Active connection '%s' already shared.",
|
|
||||||
__func__, nm_act_request_get_active_connection_path (req));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sharing_restart (policy, req);
|
|
||||||
} else {
|
|
||||||
if (!nm_act_request_get_shared (req))
|
|
||||||
return; /* Don't care about non-shared connections */
|
|
||||||
|
|
||||||
/* Tear down all NAT-ing */
|
|
||||||
sharing_stop (req);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
device_state_changed (NMDevice *device,
|
device_state_changed (NMDevice *device,
|
||||||
NMDeviceState new_state,
|
NMDeviceState new_state,
|
||||||
@@ -535,27 +353,19 @@ device_state_changed (NMDevice *device,
|
|||||||
nm_info ("Marking connection '%s' invalid.", get_connection_id (connection));
|
nm_info ("Marking connection '%s' invalid.", get_connection_id (connection));
|
||||||
}
|
}
|
||||||
schedule_activate_check (policy, device);
|
schedule_activate_check (policy, device);
|
||||||
check_sharing (policy, device, connection);
|
|
||||||
break;
|
break;
|
||||||
case NM_DEVICE_STATE_ACTIVATED:
|
case NM_DEVICE_STATE_ACTIVATED:
|
||||||
/* Clear the invalid tag on the connection */
|
/* Clear the invalid tag on the connection */
|
||||||
if (connection)
|
if (connection)
|
||||||
g_object_set_data (G_OBJECT (connection), INVALID_TAG, NULL);
|
g_object_set_data (G_OBJECT (connection), INVALID_TAG, NULL);
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (nm_device_get_act_request (device)),
|
|
||||||
"notify::default",
|
|
||||||
G_CALLBACK (active_connection_default_changed),
|
|
||||||
policy);
|
|
||||||
|
|
||||||
update_routing_and_dns (policy, FALSE);
|
update_routing_and_dns (policy, FALSE);
|
||||||
check_sharing (policy, device, connection);
|
|
||||||
break;
|
break;
|
||||||
case NM_DEVICE_STATE_UNMANAGED:
|
case NM_DEVICE_STATE_UNMANAGED:
|
||||||
case NM_DEVICE_STATE_UNAVAILABLE:
|
case NM_DEVICE_STATE_UNAVAILABLE:
|
||||||
case NM_DEVICE_STATE_DISCONNECTED:
|
case NM_DEVICE_STATE_DISCONNECTED:
|
||||||
update_routing_and_dns (policy, FALSE);
|
update_routing_and_dns (policy, FALSE);
|
||||||
schedule_activate_check (policy, device);
|
schedule_activate_check (policy, device);
|
||||||
check_sharing (policy, device, connection);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@@ -20,6 +20,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <dbus/dbus-glib.h>
|
#include <dbus/dbus-glib.h>
|
||||||
|
|
||||||
#include "nm-activation-request.h"
|
#include "nm-activation-request.h"
|
||||||
@@ -49,6 +52,10 @@ enum {
|
|||||||
|
|
||||||
static guint signals[LAST_SIGNAL] = { 0 };
|
static guint signals[LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *table;
|
||||||
|
char *rule;
|
||||||
|
} ShareRule;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gboolean disposed;
|
gboolean disposed;
|
||||||
@@ -63,6 +70,7 @@ typedef struct {
|
|||||||
NMActiveConnectionState state;
|
NMActiveConnectionState state;
|
||||||
gboolean is_default;
|
gboolean is_default;
|
||||||
gboolean shared;
|
gboolean shared;
|
||||||
|
GSList *share_rules;
|
||||||
|
|
||||||
char *ac_path;
|
char *ac_path;
|
||||||
} NMActRequestPrivate;
|
} NMActRequestPrivate;
|
||||||
@@ -206,11 +214,32 @@ dispose (GObject *object)
|
|||||||
|
|
||||||
cleanup_secrets_dbus_call (NM_ACT_REQUEST (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_unref (priv->connection);
|
||||||
|
|
||||||
G_OBJECT_CLASS (nm_act_request_parent_class)->dispose (object);
|
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
|
static void
|
||||||
finalize (GObject *object)
|
finalize (GObject *object)
|
||||||
{
|
{
|
||||||
@@ -219,6 +248,8 @@ finalize (GObject *object)
|
|||||||
g_free (priv->specific_object);
|
g_free (priv->specific_object);
|
||||||
g_free (priv->ac_path);
|
g_free (priv->ac_path);
|
||||||
|
|
||||||
|
clear_share_rules (NM_ACT_REQUEST (object));
|
||||||
|
|
||||||
G_OBJECT_CLASS (nm_act_request_parent_class)->finalize (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;
|
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
|
void
|
||||||
nm_act_request_set_shared (NMActRequest *req, gboolean shared)
|
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));
|
g_return_if_fail (NM_IS_ACT_REQUEST (req));
|
||||||
|
|
||||||
NM_ACT_REQUEST_GET_PRIVATE (req)->shared = shared;
|
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
|
gboolean
|
||||||
@@ -662,6 +750,24 @@ nm_act_request_get_shared (NMActRequest *req)
|
|||||||
return NM_ACT_REQUEST_GET_PRIVATE (req)->shared;
|
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 *
|
GObject *
|
||||||
nm_act_request_get_device (NMActRequest *req)
|
nm_act_request_get_device (NMActRequest *req)
|
||||||
{
|
{
|
||||||
|
@@ -95,6 +95,10 @@ gboolean nm_act_request_get_shared (NMActRequest *req);
|
|||||||
|
|
||||||
void nm_act_request_set_shared (NMActRequest *req, gboolean shared);
|
void nm_act_request_set_shared (NMActRequest *req, gboolean shared);
|
||||||
|
|
||||||
|
void nm_act_request_add_share_rule (NMActRequest *req,
|
||||||
|
const char *table,
|
||||||
|
const char *rule);
|
||||||
|
|
||||||
GObject * nm_act_request_get_device (NMActRequest *req);
|
GObject * nm_act_request_get_device (NMActRequest *req);
|
||||||
|
|
||||||
#endif /* NM_ACTIVATION_REQUEST_H */
|
#endif /* NM_ACTIVATION_REQUEST_H */
|
||||||
|
146
src/nm-device.c
146
src/nm-device.c
@@ -33,6 +33,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include "nm-device-interface.h"
|
#include "nm-device-interface.h"
|
||||||
#include "nm-device.h"
|
#include "nm-device.h"
|
||||||
@@ -1199,6 +1200,140 @@ nm_device_activate_schedule_stage4_ip_config_timeout (NMDevice *self)
|
|||||||
nm_device_get_iface (self));
|
nm_device_get_iface (self));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
share_init (void)
|
||||||
|
{
|
||||||
|
int fd, count, status;
|
||||||
|
char *modules[] = { "ip_tables", "iptable_nat", "nf_nat_ftp", "nf_nat_irc",
|
||||||
|
"nf_nat_sip", "nf_nat_tftp", "nf_nat_pptp", "nf_nat_h323",
|
||||||
|
NULL };
|
||||||
|
char **iter;
|
||||||
|
|
||||||
|
fd = open ("/proc/sys/net/ipv4/ip_forward", O_WRONLY | O_TRUNC);
|
||||||
|
if (fd) {
|
||||||
|
count = write (fd, "1\n", 2);
|
||||||
|
if (count != 2) {
|
||||||
|
nm_warning ("%s: Error starting IP forwarding: (%d) %s",
|
||||||
|
__func__, errno, strerror (errno));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
close (fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = open ("/proc/sys/net/ipv4/ip_dynaddr", O_WRONLY | O_TRUNC);
|
||||||
|
if (fd) {
|
||||||
|
count = write (fd, "1\n", 2);
|
||||||
|
if (count != 2) {
|
||||||
|
nm_warning ("%s: Error starting IP forwarding: (%d) %s",
|
||||||
|
__func__, errno, strerror (errno));
|
||||||
|
}
|
||||||
|
close (fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (iter = modules; *iter; iter++) {
|
||||||
|
char *argv[3] = { "/sbin/modprobe", *iter, NULL };
|
||||||
|
char *envp[1] = { NULL };
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
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 ("%s: Error loading NAT module %s: (%d) %s",
|
||||||
|
__func__, *iter, error ? error->code : 0,
|
||||||
|
(error && error->message) ? error->message : "unknown");
|
||||||
|
if (error)
|
||||||
|
g_error_free (error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_share_rule (NMActRequest *req, const char *table, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
char *cmd;
|
||||||
|
|
||||||
|
va_start (args, fmt);
|
||||||
|
cmd = g_strdup_vprintf (fmt, args);
|
||||||
|
va_end (args);
|
||||||
|
|
||||||
|
nm_act_request_add_share_rule (req, table, cmd);
|
||||||
|
g_free (cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
start_sharing (NMDevice *self)
|
||||||
|
{
|
||||||
|
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||||
|
NMActRequest *req;
|
||||||
|
GError *error = NULL;
|
||||||
|
char str_addr[INET_ADDRSTRLEN + 1];
|
||||||
|
char str_mask[INET_ADDRSTRLEN + 1];
|
||||||
|
guint32 netmask, network;
|
||||||
|
NMIP4Config *ip4_config;
|
||||||
|
const NMSettingIP4Address *ip4_addr;
|
||||||
|
const char *iface;
|
||||||
|
|
||||||
|
iface = nm_device_get_ip_iface (self);
|
||||||
|
if (!iface)
|
||||||
|
iface = nm_device_get_iface (self);
|
||||||
|
|
||||||
|
ip4_config = nm_device_get_ip4_config (self);
|
||||||
|
if (!ip4_config)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
ip4_addr = nm_ip4_config_get_address (ip4_config, 0);
|
||||||
|
if (!ip4_addr || !ip4_addr->address)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
netmask = nm_utils_ip4_prefix_to_netmask (ip4_addr->prefix);
|
||||||
|
if (!inet_ntop (AF_INET, &netmask, str_mask, sizeof (str_mask)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
network = ip4_addr->address & netmask;
|
||||||
|
if (!inet_ntop (AF_INET, &network, str_addr, sizeof (str_addr)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!share_init ())
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
req = nm_device_get_act_request (self);
|
||||||
|
g_assert (req);
|
||||||
|
|
||||||
|
add_share_rule (req, "filter", "INPUT --in-interface %s --protocol tcp --destination-port 53 --jump ACCEPT", iface);
|
||||||
|
add_share_rule (req, "filter", "INPUT --in-interface %s --protocol udp --destination-port 53 --jump ACCEPT", iface);
|
||||||
|
add_share_rule (req, "filter", "INPUT --in-interface %s --protocol tcp --destination-port 67 --jump ACCEPT", iface);
|
||||||
|
add_share_rule (req, "filter", "INPUT --in-interface %s --protocol udp --destination-port 67 --jump ACCEPT", iface);
|
||||||
|
add_share_rule (req, "filter", "FORWARD --in-interface %s --jump REJECT", iface);
|
||||||
|
add_share_rule (req, "filter", "FORWARD --out-interface %s --jump REJECT", iface);
|
||||||
|
add_share_rule (req, "filter", "FORWARD --in-interface %s --out-interface %s --jump ACCEPT", iface, iface);
|
||||||
|
add_share_rule (req, "filter", "FORWARD --source %s/%s --in-interface %s --jump ACCEPT", str_addr, str_mask, iface);
|
||||||
|
add_share_rule (req, "filter", "FORWARD --destination %s/%s --out-interface %s --match state --state ESTABLISHED,RELATED --jump ACCEPT", str_addr, str_mask, iface);
|
||||||
|
add_share_rule (req, "nat", "POSTROUTING --source %s/%s --destination ! %s/%s --jump MASQUERADE", str_addr, str_mask, str_addr, str_mask);
|
||||||
|
|
||||||
|
nm_act_request_set_shared (req, TRUE);
|
||||||
|
|
||||||
|
if (!nm_dnsmasq_manager_start (priv->dnsmasq_manager, ip4_config, &error)) {
|
||||||
|
nm_warning ("(%s): failed to start dnsmasq: %s", iface, error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
nm_act_request_set_shared (req, FALSE);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->dnsmasq_state_id = g_signal_connect (priv->dnsmasq_manager, "state-changed",
|
||||||
|
G_CALLBACK (dnsmasq_state_changed_cb),
|
||||||
|
self);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* nm_device_activate_stage5_ip_config_commit
|
* nm_device_activate_stage5_ip_config_commit
|
||||||
@@ -1237,18 +1372,11 @@ nm_device_activate_stage5_ip_config_commit (gpointer user_data)
|
|||||||
connection = nm_act_request_get_connection (nm_device_get_act_request (self));
|
connection = nm_act_request_get_connection (nm_device_get_act_request (self));
|
||||||
s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
|
s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
|
||||||
if (s_ip4 && !strcmp (s_ip4->method, "shared")) {
|
if (s_ip4 && !strcmp (s_ip4->method, "shared")) {
|
||||||
GError *error = NULL;
|
if (!start_sharing (self)) {
|
||||||
|
nm_warning ("Activation (%s) Stage 5 of 5 (IP Configure Commit) start sharing failed.", iface);
|
||||||
if (!nm_dnsmasq_manager_start (priv->dnsmasq_manager, ip4_config, &error)) {
|
|
||||||
nm_warning ("(%s): failed to start dnsmasq: %s", iface, error->message);
|
|
||||||
g_error_free (error);
|
|
||||||
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SHARED_START_FAILED);
|
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SHARED_START_FAILED);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->dnsmasq_state_id = g_signal_connect (priv->dnsmasq_manager, "state-changed",
|
|
||||||
G_CALLBACK (dnsmasq_state_changed_cb),
|
|
||||||
self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nm_device_state_changed (self, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_REASON_NONE);
|
nm_device_state_changed (self, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_REASON_NONE);
|
||||||
|
Reference in New Issue
Block a user