[v2,9/9] ui/ncurses: Allow IPv6 addresses in address fields

Message ID 20180524044742.25889-10-sam@mendozajonas.com
State New
Headers show
Series
  • IPv6 Support
Related show

Commit Message

Samuel Mendoza-Jonas May 24, 2018, 4:47 a.m.
Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
 ui/ncurses/nc-config.c  |   8 +--
 ui/ncurses/nc-widgets.c | 115 +++++++++++++++++++++++++++-------------
 ui/ncurses/nc-widgets.h |   4 +-
 3 files changed, 84 insertions(+), 43 deletions(-)

Patch

diff --git a/ui/ncurses/nc-config.c b/ui/ncurses/nc-config.c
index 5c0f23b..5186176 100644
--- a/ui/ncurses/nc-config.c
+++ b/ui/ncurses/nc-config.c
@@ -1029,8 +1029,8 @@  static void config_screen_setup_widgets(struct config_screen *screen,
 
 	widget_textbox_set_fixed_size(screen->widgets.ip_addr_f);
 	widget_textbox_set_fixed_size(screen->widgets.ip_mask_f);
-	widget_textbox_set_validator_ipv4(screen->widgets.ip_addr_f);
-	widget_textbox_set_validator_integer(screen->widgets.ip_mask_f, 1, 31);
+	widget_textbox_set_validator_ip(screen->widgets.ip_addr_f);
+	widget_textbox_set_validator_integer(screen->widgets.ip_mask_f, 1, 127);
 
 	screen->widgets.gateway_l = widget_new_label(set, 0, 0, _("Gateway:"));
 	screen->widgets.gateway_f = widget_new_textbox(set, 0, 0, 16, gw);
@@ -1038,7 +1038,7 @@  static void config_screen_setup_widgets(struct config_screen *screen,
 		widget_new_label(set, 0, 0, _("(eg. 192.168.0.1)"));
 
 	widget_textbox_set_fixed_size(screen->widgets.gateway_f);
-	widget_textbox_set_validator_ipv4(screen->widgets.gateway_f);
+	widget_textbox_set_validator_ip(screen->widgets.gateway_f);
 
 	screen->widgets.url_l = widget_new_label(set, 0, 0, _("URL:"));
 	screen->widgets.url_f = widget_new_textbox(set, 0, 0, 32, url);
@@ -1059,7 +1059,7 @@  static void config_screen_setup_widgets(struct config_screen *screen,
 	screen->widgets.dns_help_l =
 		widget_new_label(set, 0, 0, _("(eg. 192.168.0.2)"));
 
-	widget_textbox_set_validator_ipv4_multi(screen->widgets.dns_f);
+	widget_textbox_set_validator_ip_multi(screen->widgets.dns_f);
 
 	screen->widgets.dns_dhcp_help_l = widget_new_label(set, 0, 0,
 			_("(if not provided by DHCP server)"));
diff --git a/ui/ncurses/nc-widgets.c b/ui/ncurses/nc-widgets.c
index 93c882b..30915a9 100644
--- a/ui/ncurses/nc-widgets.c
+++ b/ui/ncurses/nc-widgets.c
@@ -44,8 +44,10 @@ 
 #  error "Curses form.h not found."
 #endif
 
-#include <string.h>
+#include <arpa/inet.h>
 #include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
 
 #include <talloc/talloc.h>
 #include <types/types.h>
@@ -83,7 +85,8 @@  struct nc_widgetset {
 	FIELD	*cur_field;
 
 	/* custom validators */
-	FIELDTYPE *ipv4_multi_type;
+	FIELDTYPE *ip_multi_type;
+	FIELDTYPE *ip_type;
 	FIELDTYPE *url_type;
 };
 
@@ -415,54 +418,88 @@  void widget_textbox_set_validator_url(struct nc_widget_textbox *textbox)
 	set_field_type(textbox->widget.field, textbox->set->url_type);
 }
 
-void widget_textbox_set_validator_ipv4(struct nc_widget_textbox *textbox)
+static bool check_ip_field(FIELD *field,
+		const void *arg __attribute__((unused)))
+{
+	char *str;
+	int rc;
+
+	str = strip_string(field_buffer(field, 0));
+
+	rc = addr_scheme(str);
+
+	return (rc == AF_INET || rc == AF_INET6);
+}
+
+
+static bool check_ipv6_multi_char(int c)
 {
-	set_field_type(textbox->widget.field, TYPE_IPV4);
+	return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ||
+	       c == ':' || c == ' ';
 }
 
-static bool check_ipv4_multi_char(int c,
-		const void *arg __attribute__((unused)))
+static bool check_ipv4_multi_char(int c)
 {
 	return isdigit(c) || c == '.' || c == ' ';
 }
 
-static bool check_ipv4_multi_field(FIELD *field,
+static bool check_ip_multi_field(FIELD *field,
 		const void *arg __attribute__((unused)))
 {
-	char *buf = field_buffer(field, 0);
-	unsigned int ip[4];
-	int n, len;
-
-	while (*buf != '\0') {
-		n = sscanf(buf, "%u.%u.%u.%u%n",
-				&ip[0], &ip[1], &ip[2], &ip[3], &len);
-		if (n != 4)
-			return false;
-
-		if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255)
-			return false;
-
-		for (buf += len; *buf != '\0'; buf++) {
-			if (isspace(*buf))
-				continue;
-			else if (isdigit(*buf))
-				break;
-			else
-				return false;
-		}
+	char *buf, *tok, *saveptr;
+	bool result;
+	int type;
+
+	/* Use strdup directly since we can't easily reach a talloc parent */
+	buf = strdup(strip_string(field_buffer(field, 0)));
+	if (!buf)
+		/* We tried */
+		return true;
+
+	result = false;
+	tok = strtok_r(buf, " ", &saveptr);
+	if (!tok || *tok == '\0')
+		goto err;
+
+	while (tok) {
+		type = addr_scheme(tok);
+		if (!(type == AF_INET || type == AF_INET6))
+			goto err;
+
+		tok = strtok_r(NULL, " ", &saveptr);
 	}
+	result = true;
 
-	return true;
+err:
+	free(buf);
+	return result;
+}
+
+static bool check_ip_multi_char(int c, const void *arg __attribute__((unused)))
+{
+	return (check_ipv4_multi_char(c) || check_ipv6_multi_char(c));
 }
 
-void widget_textbox_set_validator_ipv4_multi(struct nc_widget_textbox *textbox)
+void widget_textbox_set_validator_ip(struct nc_widget_textbox *textbox)
+{
+	if (!textbox->set->ip_type) {
+		textbox->set->ip_type = new_fieldtype(check_ip_field, NULL);
+	}
+	set_field_type(textbox->widget.field, textbox->set->ip_type);
+}
+
+/*
+ * In a perfect world we would use link_fieldtype() but segfaults do not
+ * enhance the user experience.
+ */
+void widget_textbox_set_validator_ip_multi(struct nc_widget_textbox *textbox)
 {
-	if (!textbox->set->ipv4_multi_type) {
-		textbox->set->ipv4_multi_type = new_fieldtype(
-				check_ipv4_multi_field,
-				check_ipv4_multi_char);
+	if (!textbox->set->ip_multi_type) {
+		textbox->set->ip_multi_type = new_fieldtype(
+						check_ip_multi_field,
+						check_ip_multi_char);
 	}
-	set_field_type(textbox->widget.field, textbox->set->ipv4_multi_type);
+	set_field_type(textbox->widget.field, textbox->set->ip_multi_type);
 }
 
 static void subset_update_order(struct nc_widget_subset *subset)
@@ -1201,8 +1238,12 @@  static int widgetset_destructor(void *ptr)
 {
 	struct nc_widgetset *set = ptr;
 	free_form(set->form);
-	if (set->ipv4_multi_type)
-		free_fieldtype(set->ipv4_multi_type);
+	if (set->ip_type)
+		free_fieldtype(set->ip_type);
+	if (set->ip_multi_type)
+		free_fieldtype(set->ip_multi_type);
+	if (set->url_type)
+		free_fieldtype(set->url_type);
 	return 0;
 }
 
diff --git a/ui/ncurses/nc-widgets.h b/ui/ncurses/nc-widgets.h
index aa9263f..a946c4f 100644
--- a/ui/ncurses/nc-widgets.h
+++ b/ui/ncurses/nc-widgets.h
@@ -40,8 +40,8 @@  struct nc_widget_button *widget_new_button(struct nc_widgetset *set,
 void widget_textbox_set_fixed_size(struct nc_widget_textbox *textbox);
 void widget_textbox_set_validator_integer(struct nc_widget_textbox *textbox,
 		long min, long max);
-void widget_textbox_set_validator_ipv4(struct nc_widget_textbox *textbox);
-void widget_textbox_set_validator_ipv4_multi(struct nc_widget_textbox *textbox);
+void widget_textbox_set_validator_ip(struct nc_widget_textbox *textbox);
+void widget_textbox_set_validator_ip_multi(struct nc_widget_textbox *textbox);
 void widget_textbox_set_validator_url(struct nc_widget_textbox *textbox);
 
 void widget_subset_add_option(struct nc_widget_subset *subset, const char *text);