Commit 506fca65 authored by Thomas Haller's avatar Thomas Haller

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
parent b434d7d4
......@@ -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);
......
......@@ -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
......
......@@ -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
......
......@@ -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,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment