summaryrefslogtreecommitdiff
path: root/src/nm-device.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-device.c')
-rw-r--r--src/nm-device.c168
1 files changed, 145 insertions, 23 deletions
diff --git a/src/nm-device.c b/src/nm-device.c
index a97986cd08..37cb500496 100644
--- a/src/nm-device.c
+++ b/src/nm-device.c
@@ -33,6 +33,7 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <arpa/inet.h>
+#include <fcntl.h>
#include "nm-device-interface.h"
#include "nm-device.h"
@@ -1199,6 +1200,140 @@ nm_device_activate_schedule_stage4_ip_config_timeout (NMDevice *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
@@ -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));
s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
if (s_ip4 && !strcmp (s_ip4->method, "shared")) {
- GError *error = NULL;
-
- 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);
+ if (!start_sharing (self)) {
+ nm_warning ("Activation (%s) Stage 5 of 5 (IP Configure Commit) start sharing failed.", iface);
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SHARED_START_FAILED);
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);
@@ -1329,8 +1457,6 @@ nm_device_deactivate_quickly (NMDevice *self)
priv = NM_DEVICE_GET_PRIVATE (self);
- nm_system_shutdown_nis ();
-
/* Break the activation chain */
if (priv->act_source_id) {
g_source_remove (priv->act_source_id);
@@ -1363,13 +1489,13 @@ nm_device_deactivate_quickly (NMDevice *self)
aipd_cleanup (self);
- /* Tear down an existing activation request */
- clear_act_request (self);
-
/* Call device type-specific deactivation */
if (NM_DEVICE_GET_CLASS (self)->deactivate_quickly)
NM_DEVICE_GET_CLASS (self)->deactivate_quickly (self);
+ /* Tear down an existing activation request */
+ clear_act_request (self);
+
return TRUE;
}
@@ -1736,13 +1862,14 @@ nm_device_set_ip4_config (NMDevice *self, NMIP4Config *config, NMDeviceStateReas
g_return_val_if_fail (reason != NULL, FALSE);
priv = NM_DEVICE_GET_PRIVATE (self);
+ ip_iface = nm_device_get_ip_iface (self);
if (priv->ip4_config) {
NMNamedManager *named_mgr;
/* Remove any previous IP4 Config from the named manager */
named_mgr = nm_named_manager_get ();
- nm_named_manager_remove_ip4_config (named_mgr, priv->ip4_config);
+ nm_named_manager_remove_ip4_config (named_mgr, ip_iface, priv->ip4_config);
g_object_unref (named_mgr);
g_object_unref (priv->ip4_config);
@@ -1754,14 +1881,9 @@ nm_device_set_ip4_config (NMDevice *self, NMIP4Config *config, NMDeviceStateReas
priv->ip4_config = g_object_ref (config);
- ip_iface = nm_device_get_ip_iface (self);
-
success = nm_system_device_set_from_ip4_config (ip_iface, config);
- if (success) {
+ if (success)
nm_device_update_ip4_address (self);
- nm_system_set_hostname (config);
- nm_system_activate_nis (config);
- }
g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_IP4_CONFIG);
@@ -2062,9 +2184,9 @@ get_property (GObject *object, guint prop_id,
case NM_DEVICE_INTERFACE_PROP_DHCP4_CONFIG:
if ( ((state == NM_DEVICE_STATE_ACTIVATED) || (state == NM_DEVICE_STATE_IP_CONFIG))
&& nm_device_get_use_dhcp (self))
- g_value_set_object (value, priv->dhcp4_config);
+ g_value_set_boxed (value, nm_dhcp4_config_get_dbus_path (priv->dhcp4_config));
else
- g_value_set_object (value, NULL);
+ g_value_set_boxed (value, "/");
break;
case NM_DEVICE_INTERFACE_PROP_STATE:
g_value_set_uint (value, priv->state);