changeset 19680:55831f9d2e66

lib: Added net_str2hostport()
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Fri, 29 Jan 2016 17:32:30 +0200
parents 74f8b5be8f59
children 5a3aac8f8ee1
files src/lib/net.c src/lib/net.h src/lib/test-net.c
diffstat 3 files changed, 92 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib/net.c	Fri Jan 29 16:23:57 2016 +0200
+++ b/src/lib/net.c	Fri Jan 29 17:32:30 2016 +0200
@@ -977,6 +977,42 @@
 	return 0;
 }
 
+int net_str2hostport(const char *str, in_port_t default_port,
+		     const char **host_r, in_port_t *port_r)
+{
+	const char *p, *host;
+	in_port_t port;
+
+	if (str[0] == '[') {
+		/* [IPv6] address, possibly followed by :port */
+		p = strchr(str, ']');
+		if (p == NULL)
+			return -1;
+		host = t_strdup_until(str+1, p++);
+	} else {
+		p = strchr(str, ':');
+		if (p == NULL || strchr(p+1, ':') != NULL) {
+			/* host or IPv6 address */
+			*host_r = str;
+			*port_r = default_port;
+			return 0;
+		}
+		host = t_strdup_until(str, p);
+	}
+	if (p[0] == '\0') {
+		*host_r = host;
+		*port_r = default_port;
+		return 0;
+	}
+	if (p[0] != ':')
+		return -1;
+	if (net_str2port(p+1, &port) < 0)
+		return -1;
+	*host_r = host;
+	*port_r = port;
+	return 0;
+}
+
 int net_ipv6_mapped_ipv4_convert(const struct ip_addr *src,
 				 struct ip_addr *dest)
 {
--- a/src/lib/net.h	Fri Jan 29 16:23:57 2016 +0200
+++ b/src/lib/net.h	Fri Jan 29 17:32:30 2016 +0200
@@ -152,6 +152,13 @@
 int net_str2port(const char *str, in_port_t *port_r);
 /* char* -> net_port_t translation (allows port zero) */
 int net_str2port_zero(const char *str, in_port_t *port_r);
+/* Parse "host", "host:port", "IPv4", "IPv4:port", "IPv6", "[IPv6]" or
+   "[IPv6]:port" to its host and port components. [IPv6] address is returned
+   without []. If no port is given, return default_port. The :port in the
+   parsed string isn't allowed to be zero, but default_port=0 is passed
+   through. */
+int net_str2hostport(const char *str, in_port_t default_port,
+		     const char **host_r, in_port_t *port_r);
 
 /* Convert IPv6 mapped IPv4 address to an actual IPv4 address. Returns 0 if
    successful, -1 if the source address isn't IPv6 mapped IPv4 address. */
--- a/src/lib/test-net.c	Fri Jan 29 16:23:57 2016 +0200
+++ b/src/lib/test-net.c	Fri Jan 29 17:32:30 2016 +0200
@@ -84,8 +84,57 @@
 	test_end();
 }
 
+static void test_net_str2hostport(void)
+{
+	const char *host;
+	in_port_t port;
+
+	test_begin("net_str2hostport()");
+	/* [IPv6] */
+	test_assert(net_str2hostport("[1::4]", 0, &host, &port) == 0 &&
+		    strcmp(host, "1::4") == 0 && port == 0);
+	test_assert(net_str2hostport("[1::4]", 1234, &host, &port) == 0 &&
+		    strcmp(host, "1::4") == 0 && port == 1234);
+	test_assert(net_str2hostport("[1::4]:78", 1234, &host, &port) == 0 &&
+		    strcmp(host, "1::4") == 0 && port == 78);
+	host = NULL;
+	test_assert(net_str2hostport("[1::4]:", 1234, &host, &port) < 0 && host == NULL);
+	test_assert(net_str2hostport("[1::4]:0", 1234, &host, &port) < 0 && host == NULL);
+	test_assert(net_str2hostport("[1::4]:x", 1234, &host, &port) < 0 && host == NULL);
+	/* IPv6 */
+	test_assert(net_str2hostport("1::4", 0, &host, &port) == 0 &&
+		    strcmp(host, "1::4") == 0 && port == 0);
+	test_assert(net_str2hostport("1::4", 1234, &host, &port) == 0 &&
+		    strcmp(host, "1::4") == 0 && port == 1234);
+	/* host */
+	test_assert(net_str2hostport("foo", 0, &host, &port) == 0 &&
+		    strcmp(host, "foo") == 0 && port == 0);
+	test_assert(net_str2hostport("foo", 1234, &host, &port) == 0 &&
+		    strcmp(host, "foo") == 0 && port == 1234);
+	test_assert(net_str2hostport("foo:78", 1234, &host, &port) == 0 &&
+		    strcmp(host, "foo") == 0 && port == 78);
+	host = NULL;
+	test_assert(net_str2hostport("foo:", 1234, &host, &port) < 0 && host == NULL);
+	test_assert(net_str2hostport("foo:0", 1234, &host, &port) < 0 && host == NULL);
+	test_assert(net_str2hostport("foo:x", 1234, &host, &port) < 0 && host == NULL);
+	/* edge cases with multiple ':' - currently these don't return errors,
+	   but perhaps they should. */
+	test_assert(net_str2hostport("foo::78", 1234, &host, &port) == 0 &&
+		    strcmp(host, "foo::78") == 0 && port == 1234);
+	test_assert(net_str2hostport("::foo:78", 1234, &host, &port) == 0 &&
+		    strcmp(host, "::foo:78") == 0 && port == 1234);
+	test_assert(net_str2hostport("[::foo]:78", 1234, &host, &port) == 0 &&
+		    strcmp(host, "::foo") == 0 && port == 78);
+	test_assert(net_str2hostport("[::::]", 1234, &host, &port) == 0 &&
+		    strcmp(host, "::::") == 0 && port == 1234);
+	test_assert(net_str2hostport("[::::]:78", 1234, &host, &port) == 0 &&
+		    strcmp(host, "::::") == 0 && port == 78);
+	test_end();
+}
+
 void test_net(void)
 {
 	test_net_is_in_network();
 	test_net_ip2addr();
+	test_net_str2hostport();
 }