summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2017-03-22 12:21:56 +0100
committerLubomir Rintel <lkundrak@v3.sk>2017-03-22 12:21:56 +0100
commitedaa7d064e5efef2abcb08d44355a2a8f5a09e87 (patch)
tree0355e419953688659c2a5fe6d352e2a856f5f49b
parent8d4570d28d1825d52de936b21d785c75b602394a (diff)
parentcae3cef60fe6b37929e69d103663882274ad46bc (diff)
downloadNetworkManager-edaa7d064e5efef2abcb08d44355a2a8f5a09e87.tar.gz
merge: branch 'lr/rp-filter'
https://bugzilla.gnome.org/show_bug.cgi?id=780155
-rw-r--r--src/devices/nm-device.c81
-rw-r--r--src/nm-route-manager.c43
-rw-r--r--src/nm-route-manager.h3
3 files changed, 127 insertions, 0 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index de9bf78bc7..017d55a3a5 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -339,6 +339,8 @@ typedef struct _NMDevicePrivate {
NMPlatformIP4Route v4;
NMPlatformIP6Route v6;
} default_route;
+ bool v4_has_shadowed_routes;
+ const char *ip4_rp_filter;
/* DHCPv4 tracking */
struct {
@@ -704,6 +706,38 @@ init_ip6_config_dns_priority (NMDevice *self, NMIP6Config *config)
/*****************************************************************************/
+static gboolean
+nm_device_ipv4_sysctl_set (NMDevice *self, const char *property, const char *value)
+{
+ NMPlatform *platform = NM_PLATFORM_GET;
+ gs_free char *value_to_free = NULL;
+ const char *value_to_set;
+
+ if (value) {
+ value_to_set = value;
+ } else {
+ /* Set to a default value when we've got a NULL @value. */
+ value_to_free = nm_platform_sysctl_get (platform,
+ NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip4_property_path ("default", property)));
+ value_to_set = value_to_free;
+ }
+
+ return nm_platform_sysctl_set (platform,
+ NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip4_property_path (nm_device_get_ip_iface (self), property)),
+ value_to_set);
+}
+
+static guint32
+nm_device_ipv4_sysctl_get_uint32 (NMDevice *self, const char *property, guint32 fallback)
+{
+ return nm_platform_sysctl_get_int_checked (NM_PLATFORM_GET,
+ NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip4_property_path (nm_device_get_ip_iface (self), property)),
+ 10,
+ 0,
+ G_MAXUINT32,
+ fallback);
+}
+
gboolean
nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const char *value)
{
@@ -2362,6 +2396,45 @@ link_changed_cb (NMPlatform *platform,
}
static void
+ip4_rp_filter_update (NMDevice *self)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ const char *ip4_rp_filter;
+
+ if ( priv->v4_has_shadowed_routes
+ || priv->default_route.v4_has) {
+ if (nm_device_ipv4_sysctl_get_uint32 (self, "rp_filter", 0) != 1) {
+ /* Don't touch the rp_filter if it's not strict. */
+ return;
+ }
+ /* Loose rp_filter */
+ ip4_rp_filter = "2";
+ } else {
+ /* Default rp_filter */
+ ip4_rp_filter = NULL;
+ }
+
+ if (ip4_rp_filter != priv->ip4_rp_filter) {
+ nm_device_ipv4_sysctl_set (self, "rp_filter", ip4_rp_filter);
+ priv->ip4_rp_filter = ip4_rp_filter;
+ }
+}
+
+static void
+ip4_routes_changed_changed_cb (NMRouteManager *route_manager, NMDevice *self)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ int ifindex = nm_device_get_ip_ifindex (self);
+
+ if (nm_device_sys_iface_state_is_external_or_assume (self))
+ return;
+
+ priv->v4_has_shadowed_routes = nm_route_manager_ip4_routes_shadowed (route_manager,
+ ifindex);
+ ip4_rp_filter_update (self);
+}
+
+static void
link_changed (NMDevice *self, const NMPlatformLink *pllink)
{
/* stub implementation of virtual function to allow subclasses to chain up. */
@@ -9410,6 +9483,8 @@ nm_device_set_ip4_config (NMDevice *self,
}
nm_default_route_manager_ip4_update_default_route (nm_default_route_manager_get (), self);
+ if (!nm_device_sys_iface_state_is_external_or_assume (self))
+ ip4_rp_filter_update (self);
if (has_changes) {
NMSettingsConnection *settings_connection;
@@ -13343,6 +13418,9 @@ constructed (GObject *object)
g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (device_ipx_changed), self);
g_signal_connect (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (link_changed_cb), self);
+ g_signal_connect (nm_route_manager_get (), NM_ROUTE_MANAGER_IP4_ROUTES_CHANGED,
+ G_CALLBACK (ip4_routes_changed_changed_cb), self);
+
priv->settings = g_object_ref (NM_SETTINGS_GET);
g_assert (priv->settings);
@@ -13381,6 +13459,9 @@ dispose (GObject *object)
g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (device_ipx_changed), self);
g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (link_changed_cb), self);
+ g_signal_handlers_disconnect_by_func (nm_route_manager_get (),
+ G_CALLBACK (ip4_routes_changed_changed_cb), self);
+
g_slist_free_full (priv->arping.dad_list, (GDestroyNotify) nm_arping_manager_destroy);
priv->arping.dad_list = NULL;
diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c
index a8778e2a7d..0a8f1f635e 100644
--- a/src/nm-route-manager.c
+++ b/src/nm-route-manager.c
@@ -63,6 +63,12 @@ typedef struct {
/*****************************************************************************/
+enum {
+ IP4_ROUTES_CHANGED,
+ LAST_SIGNAL,
+};
+static guint signals[LAST_SIGNAL] = { 0 };
+
NM_GOBJECT_PROPERTIES_DEFINE_BASE (
PROP_PLATFORM,
);
@@ -904,6 +910,9 @@ next:
}
}
+ if (vtable->vt->is_ip4 && ipx_routes_changed)
+ g_signal_emit (self, signals[IP4_ROUTES_CHANGED], 0);
+
g_free (known_routes_idx);
g_free (plat_routes_idx);
g_array_unref (plat_routes);
@@ -967,6 +976,33 @@ nm_route_manager_route_flush (NMRouteManager *self, int ifindex)
return success;
}
+/**
+ * nm_route_manager_ip4_routes_shadowed:
+ * @ifindex: Interface index
+ *
+ * Returns: %TRUE if some other link has a route to the same destination
+ * with a lower metric.
+ */
+gboolean
+nm_route_manager_ip4_routes_shadowed (NMRouteManager *self, int ifindex)
+{
+ NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self);
+ RouteIndex *index = priv->ip4_routes.index;
+ const NMPlatformIP4Route *route;
+ guint i;
+
+ for (i = 1; i < index->len; i++) {
+ route = (const NMPlatformIP4Route *) index->entries[i];
+
+ if (route->ifindex != ifindex)
+ continue;
+ if (_v4_route_dest_cmp (route, (const NMPlatformIP4Route *) index->entries[i - 1]) == 0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
/*****************************************************************************/
static gboolean
@@ -1258,4 +1294,11 @@ nm_route_manager_class_init (NMRouteManagerClass *klass)
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
+ signals[IP4_ROUTES_CHANGED] =
+ g_signal_new (NM_ROUTE_MANAGER_IP4_ROUTES_CHANGED,
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
}
diff --git a/src/nm-route-manager.h b/src/nm-route-manager.h
index d12f025603..328fa8cba6 100644
--- a/src/nm-route-manager.h
+++ b/src/nm-route-manager.h
@@ -30,6 +30,8 @@
#define NM_ROUTE_MANAGER_PLATFORM "platform"
+#define NM_ROUTE_MANAGER_IP4_ROUTES_CHANGED "ip4-routes-changed"
+
typedef struct _NMRouteManagerClass NMRouteManagerClass;
GType nm_route_manager_get_type (void);
@@ -38,6 +40,7 @@ gboolean nm_route_manager_ip4_route_sync (NMRouteManager *self, int ifindex, con
gboolean nm_route_manager_ip6_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes, gboolean full_sync);
gboolean nm_route_manager_route_flush (NMRouteManager *self, int ifindex);
+gboolean nm_route_manager_ip4_routes_shadowed (NMRouteManager *self, int ifindex);
void nm_route_manager_ip4_route_register_device_route_purge_list (NMRouteManager *self, GArray *device_route_purge_list);
NMRouteManager *nm_route_manager_get (void);