From 506fca65b337aa49a4b246f40f720b840673711e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 4 Sep 2017 14:03:33 +0200 Subject: [PATCH] tui: guess the prefix length (netmask) of private IPv4 addresses and routes based on network class For RFC1918 private IPv4addresses, guess a better prefix length for addresses and routes. nmtui is an interactive program. It makes sense to be a bit smarter about what the user probably meant. It would be nice if nmtui would update the entry field immediately when the cursor leaves the field, to show the guessed prefix length. However, that is not easily possible, so lets to that another time. For IPv6 addresses, default to /64 instead of /128. https://bugzilla.redhat.com/show_bug.cgi?id=1474295 --- clients/tui/nm-editor-bindings.c | 75 +++++++++++++------------------ clients/tui/nmt-ip-entry.c | 33 ++------------ shared/nm-utils/nm-shared-utils.c | 73 ++++++++++++++++++++++++++++++ shared/nm-utils/nm-shared-utils.h | 9 ++++ 4 files changed, 117 insertions(+), 73 deletions(-) diff --git a/clients/tui/nm-editor-bindings.c b/clients/tui/nm-editor-bindings.c index 3753aaa9ac..7ac7f0c7e2 100644 --- a/clients/tui/nm-editor-bindings.c +++ b/clients/tui/nm-editor-bindings.c @@ -70,45 +70,6 @@ nm_editor_bindings_init (void) g_value_register_transform_func (G_TYPE_STRING, G_TYPE_UINT, value_transform_string_uint); } -static gboolean -parse_addr_prefix (const char *text, - int family, - char **addr, - guint32 *prefix) -{ - const char *slash; - char *addrstr, *end; - gboolean valid; - - slash = strchr (text, '/'); - - if (slash) - addrstr = g_strndup (text, slash - text); - else - addrstr = g_strdup (text); - valid = nm_utils_ipaddr_valid (family, addrstr); - - if (slash) { - *prefix = strtoul (slash + 1, &end, 10); - if ( *end - || *prefix == 0 - || (family == AF_INET && *prefix > 32) - || (family == AF_INET6 && *prefix > 128)) - valid = FALSE; - } else if (prefix) { - if (family == AF_INET) - *prefix = 32; - else - *prefix = 128; - } - - if (addr && valid) - *addr = addrstr; - else - g_free (addrstr); - return valid; -} - static gboolean ip_addresses_with_prefix_to_strv (GBinding *binding, const GValue *source_value, @@ -151,7 +112,7 @@ ip_addresses_with_prefix_from_strv (GBinding *binding, GPtrArray *addrs; NMIPAddress *addr; char *addrstr; - guint32 prefix; + int prefix; int i; strings = g_value_get_boxed (source_value); @@ -170,11 +131,24 @@ ip_addresses_with_prefix_from_strv (GBinding *binding, } else addr = addrs->pdata[i]; - if (!parse_addr_prefix (strings[i], family, &addrstr, &prefix)) { + if (!nm_utils_parse_inaddr_prefix (strings[i], family, &addrstr, &prefix)) { g_ptr_array_unref (addrs); return FALSE; } + if (prefix == -1) { + if (family == AF_INET) { + in_addr_t v4; + + inet_pton (family, addrstr, &v4); + if (nm_utils_ip_is_site_local (AF_INET, &v4)) + prefix = nm_utils_ip4_get_default_prefix (v4); + else + prefix = 32; + } else + prefix = 64; + } + nm_ip_address_set_address (addr, addrstr); nm_ip_address_set_prefix (addr, prefix); g_free (addrstr); @@ -451,10 +425,10 @@ ip_route_transform_from_dest_string (GBinding *binding, NMIPRoute *route; const char *text; char *addrstr; - guint32 prefix; + int prefix; text = g_value_get_string (source_value); - if (!parse_addr_prefix (text, family, &addrstr, &prefix)) + if (!nm_utils_parse_inaddr_prefix (text, family, &addrstr, &prefix)) return FALSE; /* Fetch the original property value */ @@ -462,6 +436,21 @@ ip_route_transform_from_dest_string (GBinding *binding, g_binding_get_source_property (binding), &route, NULL); + if (prefix == -1) { + if (family == AF_INET) { + in_addr_t v4; + + inet_pton (family, addrstr, &v4); + if (nm_utils_ip_is_site_local (AF_INET, &v4)) { + prefix = nm_utils_ip4_get_default_prefix (v4); + if (v4 & (~nm_utils_ip4_prefix_to_netmask (prefix))) + prefix = 32; + } else + prefix = 32; + } else + prefix = 64; + } + nm_ip_route_set_dest (route, addrstr); nm_ip_route_set_prefix (route, prefix); g_free (addrstr); diff --git a/clients/tui/nmt-ip-entry.c b/clients/tui/nmt-ip-entry.c index 8d8f888f0d..1556c8d7fe 100644 --- a/clients/tui/nmt-ip-entry.c +++ b/clients/tui/nmt-ip-entry.c @@ -123,39 +123,12 @@ ip_entry_validate (NmtNewtEntry *entry, gpointer user_data) { NmtIPEntryPrivate *priv = NMT_IP_ENTRY_GET_PRIVATE (entry); - guchar buf[16]; - guint32 prefix; - const char *slash; - char *addrstr, *end; - gboolean valid; if (!*text) return priv->optional; - - slash = strchr (text, '/'); - - if (slash) { - if (!priv->prefix) - return FALSE; - addrstr = g_strndup (text, slash - text); - } else - addrstr = g_strdup (text); - valid = (inet_pton (priv->family, addrstr, buf) == 1); - g_free (addrstr); - - if (!valid) - return FALSE; - - if (slash) { - prefix = strtoul (slash + 1, &end, 10); - if ( *end - || prefix == 0 - || (priv->family == AF_INET && prefix > 32) - || (priv->family == AF_INET6 && prefix > 128)) - valid = FALSE; - } - - return valid; + if (priv->prefix) + return nm_utils_parse_inaddr_prefix (text, priv->family, NULL, NULL); + return nm_utils_parse_inaddr (text, priv->family, NULL); } static void diff --git a/shared/nm-utils/nm-shared-utils.c b/shared/nm-utils/nm-shared-utils.c index aa1e9f02dd..b512e52a57 100644 --- a/shared/nm-utils/nm-shared-utils.c +++ b/shared/nm-utils/nm-shared-utils.c @@ -169,6 +169,79 @@ nm_utils_ip_is_site_local (int addr_family, /*****************************************************************************/ +gboolean +nm_utils_parse_inaddr (const char *text, + int family, + char **out_addr) +{ + union { + in_addr_t v4; + struct in6_addr v6; + } addrbin; + char addrstr_buf[MAX (INET_ADDRSTRLEN, INET6_ADDRSTRLEN)]; + + g_return_val_if_fail (text, FALSE); + + if (family == AF_UNSPEC) + family = strchr (text, ':') ? AF_INET6 : AF_INET; + else + g_return_val_if_fail (NM_IN_SET (family, AF_INET, AF_INET6), FALSE); + + if (inet_pton (family, text, &addrbin) != 1) + return FALSE; + + NM_SET_OUT (out_addr, g_strdup (inet_ntop (family, &addrbin, addrstr_buf, sizeof (addrstr_buf)))); + return TRUE; +} + +gboolean +nm_utils_parse_inaddr_prefix (const char *text, + int family, + char **out_addr, + int *out_prefix) +{ + gs_free char *addrstr_free = NULL; + int prefix = -1; + const char *slash; + const char *addrstr; + union { + in_addr_t v4; + struct in6_addr v6; + } addrbin; + char addrstr_buf[MAX (INET_ADDRSTRLEN, INET6_ADDRSTRLEN)]; + + g_return_val_if_fail (text, FALSE); + + if (family == AF_UNSPEC) + family = strchr (text, ':') ? AF_INET6 : AF_INET; + else + g_return_val_if_fail (NM_IN_SET (family, AF_INET, AF_INET6), FALSE); + + slash = strchr (text, '/'); + if (slash) + addrstr = addrstr_free = g_strndup (text, slash - text); + else + addrstr = text; + + if (inet_pton (family, addrstr, &addrbin) != 1) + return FALSE; + + if (slash) { + prefix = _nm_utils_ascii_str_to_int64 (slash + 1, 10, + 0, + family == AF_INET ? 32 : 128, + -1); + if (prefix == -1) + return FALSE; + } + + NM_SET_OUT (out_addr, g_strdup (inet_ntop (family, &addrbin, addrstr_buf, sizeof (addrstr_buf)))); + NM_SET_OUT (out_prefix, prefix); + return TRUE; +} + +/*****************************************************************************/ + /* _nm_utils_ascii_str_to_int64: * * A wrapper for g_ascii_strtoll, that checks whether the whole string diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h index 968f709ade..dc17fb269f 100644 --- a/shared/nm-utils/nm-shared-utils.h +++ b/shared/nm-utils/nm-shared-utils.h @@ -151,6 +151,15 @@ gboolean nm_utils_ip_is_site_local (int addr_family, /*****************************************************************************/ +gboolean nm_utils_parse_inaddr (const char *text, + int family, + char **out_addr); + +gboolean nm_utils_parse_inaddr_prefix (const char *text, + int family, + char **out_addr, + int *out_prefix); + gint64 _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback); gint _nm_utils_ascii_str_to_bool (const char *str,