]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: Added net_str2hostport()
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Fri, 29 Jan 2016 15:32:30 +0000 (17:32 +0200)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Fri, 29 Jan 2016 15:37:25 +0000 (17:37 +0200)
src/lib/net.c
src/lib/net.h
src/lib/test-net.c

index bac51494920bc89eb7360b82d503fc6140274387..5223a54419815d6b6f310687cab80ae4dcd5d201 100644 (file)
@@ -977,6 +977,42 @@ int net_str2port_zero(const char *str, in_port_t *port_r)
        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)
 {
index 8c0b0a6d9915e76427ce6e1720edcdfc9d6c5f21..59d89a6ad7619cd632bed7f1e1529d6a9e006e19 100644 (file)
@@ -152,6 +152,13 @@ int net_addr2ip(const char *addr, struct ip_addr *ip);
 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. */
index c0ea58870b4c885ccb290b1124ad3a07a3b6a9b8..fe545d99e860f1ca947b622ddc5b39e9e8d603e2 100644 (file)
@@ -84,8 +84,57 @@ static void test_net_ip2addr(void)
        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();
 }