[network-manager-applet/jk/editor-gateway-check] editor: check gateway to be in the network specified by addr/prefix (rh #1167491)



commit 00a386df01e4dd68cdc1e726abe8932c705dee91
Author: Jiří Klimeš <jklimes redhat com>
Date:   Fri Apr 17 13:25:22 2015 +0200

    editor: check gateway to be in the network specified by addr/prefix (rh #1167491)
    
    If the gateway doesn't match address/prefix network, highlight it in yellow,
    because it may be invalid.
    
    https://bugzilla.redhat.com/show_bug.cgi?id=1167491

 src/connection-editor/page-ip4.c |   91 +++++++++++++++++++++++++++++-----
 src/connection-editor/page-ip6.c |  100 ++++++++++++++++++++++++++++++++-----
 2 files changed, 163 insertions(+), 28 deletions(-)
---
diff --git a/src/connection-editor/page-ip4.c b/src/connection-editor/page-ip4.c
index a6ec715..b431552 100644
--- a/src/connection-editor/page-ip4.c
+++ b/src/connection-editor/page-ip4.c
@@ -716,11 +716,50 @@ is_address_unspecified (const char *str)
 }
 
 static gboolean
+gateway_matches_address (const char *gw_str, const char *addr_str, guint32 prefix)
+{
+       struct in_addr gw, addr;
+       guint32 netmask;
+
+       if (!gw_str || inet_pton (AF_INET, gw_str, &gw) != 1)
+               return FALSE;
+       if (!addr_str || inet_pton (AF_INET, addr_str, &addr) != 1)
+               return FALSE;
+
+       netmask = nm_utils_ip4_prefix_to_netmask (prefix);
+       return ((addr.s_addr & netmask) == (gw.s_addr & netmask));
+}
+
+static gboolean
+possibly_wrong_gateway (GtkTreeModel *model, GtkTreeIter *iter, const char *gw_str)
+{
+       char *addr_str, *prefix_str;
+       gboolean addr_valid;
+       guint32 prefix;
+
+       gtk_tree_model_get (model, iter, COL_ADDRESS, &addr_str, -1);
+       gtk_tree_model_get (model, iter, COL_PREFIX, &prefix_str, -1);
+       addr_valid =   addr_str && *addr_str && nm_utils_ipaddr_valid (AF_INET, addr_str) && 
!is_address_unspecified (addr_str)
+                   && parse_netmask (prefix_str, &prefix);
+
+       if (addr_valid && !gateway_matches_address (gw_str, addr_str, prefix))
+               return TRUE;
+       else
+               return FALSE;
+}
+
+typedef struct {
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       guint column;
+} AddressLineInfo;
+
+static gboolean
 cell_changed_cb (GtkEditable *editable,
                  gpointer user_data)
 {
+       AddressLineInfo *info = (AddressLineInfo *) user_data;
        char *cell_text;
-       guint column;
        GdkRGBA rgba;
        gboolean value_valid = FALSE;
        const char *colorname = NULL;
@@ -728,8 +767,7 @@ cell_changed_cb (GtkEditable *editable,
        cell_text = gtk_editable_get_chars (editable, 0, -1);
 
        /* The COL_PREFIX can contain IP address or prefix */
-       column = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (user_data), "column"));
-       if (column == COL_PREFIX) {
+       if (info->column == COL_PREFIX) {
                guint32 tmp_prefix;
 
                value_valid = parse_netmask (cell_text, &tmp_prefix);
@@ -740,16 +778,22 @@ cell_changed_cb (GtkEditable *editable,
                        value_valid = TRUE;
 
                 /* 0.0.0.0 is not accepted for address */
-               if (column == COL_ADDRESS && tmp_addr.s_addr == 0)
+               if (info->column == COL_ADDRESS && tmp_addr.s_addr == 0)
                        value_valid = FALSE;
                /* Consider empty gateway as valid */
-               if (!*cell_text && column == COL_GATEWAY)
+               if (!*cell_text && info->column == COL_GATEWAY)
                        value_valid = TRUE;
        }
 
        /* Change cell's background color while editing */
        colorname = value_valid ? "lightgreen" : "red";
 
+       /* Check gateway against address and prefix */
+       if (   info->column == COL_GATEWAY
+           && value_valid
+           && possibly_wrong_gateway (info->model, &info->iter, cell_text))
+               colorname = "yellow";
+
        gdk_rgba_parse (&rgba, colorname);
        utils_override_bg_color (GTK_WIDGET (editable), &rgba);
 
@@ -803,6 +847,12 @@ key_pressed_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
 }
 
 static void
+address_line_info_destroy (AddressLineInfo *info)
+{
+       g_slice_free (AddressLineInfo, info);
+}
+
+static void
 cell_editing_started (GtkCellRenderer *cell,
                       GtkCellEditable *editable,
                       const gchar     *path,
@@ -810,6 +860,9 @@ cell_editing_started (GtkCellRenderer *cell,
 {
        CEPageIP4 *self = CE_PAGE_IP4 (user_data);
        CEPageIP4Private *priv = CE_PAGE_IP4_GET_PRIVATE (self);
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       AddressLineInfo *info;
 
        if (!GTK_IS_ENTRY (editable)) {
                g_warning ("%s: Unexpected cell editable type.", __func__);
@@ -833,9 +886,16 @@ cell_editing_started (GtkCellRenderer *cell,
                                user_data);
 
        /* Set up handler for IP verifying and changing cell background */
-       g_signal_connect (G_OBJECT (editable), "changed",
-                         (GCallback) cell_changed_cb,
-                         cell);
+       model = gtk_tree_view_get_model (priv->addr_list);
+       gtk_tree_model_get_iter_from_string (model, &iter, priv->last_path);
+       info = g_slice_new0 (AddressLineInfo);
+       info->model = model;
+       info->iter = iter;
+       info->column = priv->last_column;
+       g_signal_connect_data (G_OBJECT (editable), "changed",
+                              (GCallback) cell_changed_cb,
+                              info,
+                              (GClosureNotify) address_line_info_destroy, 0);
 
        /* Set up key pressed handler - need to handle Tab key */
        g_signal_connect (G_OBJECT (editable), "key-press-event",
@@ -946,7 +1006,7 @@ cell_error_data_func (GtkTreeViewColumn *tree_column,
 {
        guint32 col = GPOINTER_TO_UINT (data);
        char *value = NULL;
-       const char *color = "red";
+       const char *color = NULL;
        guint32 prefix;
        gboolean invalid = FALSE;
 
@@ -957,15 +1017,18 @@ cell_error_data_func (GtkTreeViewColumn *tree_column,
                          || is_address_unspecified (value);
        else if (col == COL_PREFIX)
                invalid = !parse_netmask (value, &prefix);
-       else if (col == COL_GATEWAY)
+       else if (col == COL_GATEWAY) {
                invalid = value && *value && !nm_utils_ipaddr_valid (AF_INET, value);
-       else
+
+               /* Check gateway against address and prefix */
+               if (!invalid && possibly_wrong_gateway (tree_model, iter, value))
+                       color = "#DDC000"; /* darker than "yellow", else selected text is hard to read */
+       } else
                g_warn_if_reached ();
 
        if (invalid)
-               utils_set_cell_background (cell, color, value);
-       else
-               utils_set_cell_background (cell, NULL, NULL);
+               color = "red";
+       utils_set_cell_background (cell, color, color ? value : NULL);
        g_free (value);
 }
 
diff --git a/src/connection-editor/page-ip6.c b/src/connection-editor/page-ip6.c
index 35ef713..69dfd3a 100644
--- a/src/connection-editor/page-ip6.c
+++ b/src/connection-editor/page-ip6.c
@@ -714,11 +714,59 @@ delete_text_cb (GtkEditable *editable,
 }
 
 static gboolean
+gateway_matches_address (const char *gw_str, const char *addr_str, guint32 prefix)
+{
+       struct in6_addr gw, addr;
+       guint32 x, y, mask;
+       int i;
+
+       if (!gw_str || inet_pton (AF_INET6, gw_str, &gw) != 1)
+               return FALSE;
+       if (!addr_str || inet_pton (AF_INET6, addr_str, &addr) != 1)
+               return FALSE;
+
+       x = prefix / 32;
+       y = prefix % 32;
+       mask = ~htonl (0xFFFFFFFF >> y);
+       for (i = 0; i < x; i++) {
+               if (addr.s6_addr32[i] != gw.s6_addr32[i])
+                       return FALSE;
+       }
+       if ((addr.s6_addr32[i] & mask) != (gw.s6_addr32[i] & mask))
+               return FALSE;
+       return TRUE;
+}
+
+static gboolean
+possibly_wrong_gateway (GtkTreeModel *model, GtkTreeIter *iter, const char *gw_str)
+{
+       char *addr_str, *prefix_str;
+       gboolean addr_valid;
+       guint32 prefix;
+
+       gtk_tree_model_get (model, iter, COL_ADDRESS, &addr_str, -1);
+       gtk_tree_model_get (model, iter, COL_PREFIX, &prefix_str, -1);
+       addr_valid =   addr_str && *addr_str && nm_utils_ipaddr_valid (AF_INET6, addr_str) && 
!is_address_unspecified (addr_str)
+                   && is_prefix_valid (prefix_str, &prefix);
+
+       if (addr_valid && !gateway_matches_address (gw_str, addr_str, prefix))
+               return TRUE;
+       else
+               return FALSE;
+}
+
+typedef struct {
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       guint column;
+} AddressLineInfo;
+
+static gboolean
 cell_changed_cb (GtkEditable *editable,
                  gpointer user_data)
 {
+       AddressLineInfo *info = (AddressLineInfo *) user_data;
        char *cell_text;
-       guint column;
        GdkRGBA rgba;
        gboolean value_valid = FALSE;
        const char *colorname = NULL;
@@ -726,8 +774,7 @@ cell_changed_cb (GtkEditable *editable,
        cell_text = gtk_editable_get_chars (editable, 0, -1);
 
        /* The Prefix column is 1..128 */
-       column = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (user_data), "column"));
-       if (column == COL_PREFIX)
+       if (info->column == COL_PREFIX)
                value_valid = is_prefix_valid (cell_text, NULL);
        else {
                struct in6_addr tmp_addr;
@@ -736,16 +783,22 @@ cell_changed_cb (GtkEditable *editable,
                        value_valid = TRUE;
 
                /* :: is not accepted for address */
-               if (column == COL_ADDRESS && IN6_IS_ADDR_UNSPECIFIED (&tmp_addr))
+               if (info->column == COL_ADDRESS && IN6_IS_ADDR_UNSPECIFIED (&tmp_addr))
                         value_valid = FALSE;
                /* Consider empty gateway as valid */
-               if (!*cell_text && column == COL_GATEWAY)
+               if (!*cell_text && info->column == COL_GATEWAY)
                        value_valid = TRUE;
        }
 
        /* Change cell's background color while editing */
        colorname = value_valid ? "lightgreen" : "red";
 
+       /* Check gateway against address and prefix */
+       if (   info->column == COL_GATEWAY
+           && value_valid
+           && possibly_wrong_gateway (info->model, &info->iter, cell_text))
+               colorname = "yellow";
+
        gdk_rgba_parse (&rgba, colorname);
        utils_override_bg_color (GTK_WIDGET (editable), &rgba);
 
@@ -799,6 +852,12 @@ key_pressed_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
 }
 
 static void
+address_line_info_destroy (AddressLineInfo *info)
+{
+       g_slice_free (AddressLineInfo, info);
+}
+
+static void
 cell_editing_started (GtkCellRenderer *cell,
                       GtkCellEditable *editable,
                       const gchar     *path,
@@ -807,6 +866,9 @@ cell_editing_started (GtkCellRenderer *cell,
        CEPageIP6 *self = CE_PAGE_IP6 (user_data);
        CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (self);
        guint column;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       AddressLineInfo *info;
 
        if (!GTK_IS_ENTRY (editable)) {
                g_warning ("%s: Unexpected cell editable type.", __func__);
@@ -834,9 +896,16 @@ cell_editing_started (GtkCellRenderer *cell,
                                user_data);
 
        /* Set up handler for value verifying and changing cell background */
-       g_signal_connect (G_OBJECT (editable), "changed",
-                         (GCallback) cell_changed_cb,
-                         cell);
+       model = gtk_tree_view_get_model (priv->addr_list);
+       gtk_tree_model_get_iter_from_string (model, &iter, priv->last_path);
+       info = g_slice_new0 (AddressLineInfo);
+       info->model = model;
+       info->iter = iter;
+       info->column = priv->last_column;
+       g_signal_connect_data (G_OBJECT (editable), "changed",
+                              (GCallback) cell_changed_cb,
+                              info,
+                              (GClosureNotify) address_line_info_destroy, 0);
 
        /* Set up key pressed handler - need to handle Tab key */
        g_signal_connect (G_OBJECT (editable), "key-press-event",
@@ -947,7 +1016,7 @@ cell_error_data_func (GtkTreeViewColumn *tree_column,
 {
        guint32 col = GPOINTER_TO_UINT (data);
        char *value = NULL;
-       const char *color = "red";
+       const char *color = NULL;
        gboolean invalid = FALSE;
 
        gtk_tree_model_get (tree_model, iter, col, &value, -1);
@@ -957,15 +1026,18 @@ cell_error_data_func (GtkTreeViewColumn *tree_column,
                          || is_address_unspecified (value);
        else if (col == COL_PREFIX)
                invalid = !is_prefix_valid (value, NULL);
-       else if (col == COL_GATEWAY)
+       else if (col == COL_GATEWAY) {
                invalid = value && *value && !nm_utils_ipaddr_valid (AF_INET6, value);
-       else
+
+               /* Check gateway against address and prefix */
+               if (!invalid && possibly_wrong_gateway (tree_model, iter, value))
+                       color = "#DDC000"; /* darker than "yellow", else selected text is hard to read */
+       } else
                g_warn_if_reached ();
 
        if (invalid)
-               utils_set_cell_background (cell, color, value);
-       else
-               utils_set_cell_background (cell, NULL, NULL);
+               color = "red";
+       utils_set_cell_background (cell, color, color ? value : NULL);
        g_free (value);
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]