summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Schwenke <martin@meltin.net>2017-09-11 16:39:38 +1000
committerMartin Schwenke <martins@samba.org>2017-09-19 13:30:26 +0200
commit6f1b1a05fb821d49c44195c6ff91fbe21b1b10ef (patch)
tree4a0a48f003211b0aadddb3dcc1dba86fa895d90f
parent93668f50266ce43e591f0708bc0dcd557719e2dc (diff)
downloadsamba-6f1b1a05fb821d49c44195c6ff91fbe21b1b10ef.tar.gz
ctdb-protocol: Add ctdb_sock_addr_from_string()
This and the supporting functions duplicate functionality (parse_ip() and parse_ip_port()) from common/system_util.c. The old functions will be removed at a later time. Signed-off-by: Martin Schwenke <martin@meltin.net> Reviewed-by: Amitay Isaacs <amitay@gmail.com>
-rw-r--r--ctdb/protocol/protocol_util.c126
-rw-r--r--ctdb/protocol/protocol_util.h2
-rw-r--r--ctdb/tests/src/protocol_util_test.c64
3 files changed, 169 insertions, 23 deletions
diff --git a/ctdb/protocol/protocol_util.c b/ctdb/protocol/protocol_util.c
index 26425d97a56..3c8c21a472a 100644
--- a/ctdb/protocol/protocol_util.c
+++ b/ctdb/protocol/protocol_util.c
@@ -174,6 +174,132 @@ const char *ctdb_sock_addr_to_string(TALLOC_CTX *mem_ctx,
return cip;
}
+static int ipv4_from_string(const char *str, struct sockaddr_in *ip)
+{
+ int ret;
+
+ *ip = (struct sockaddr_in) {
+ .sin_family = AF_INET,
+ };
+
+ ret = inet_pton(AF_INET, str, &ip->sin_addr);
+ if (ret != 1) {
+ return EINVAL;
+ }
+
+#ifdef HAVE_SOCK_SIN_LEN
+ ip->sin_len = sizeof(*ip);
+#endif
+ return 0;
+}
+
+static int ipv6_from_string(const char *str, struct sockaddr_in6 *ip6)
+{
+ int ret;
+
+ *ip6 = (struct sockaddr_in6) {
+ .sin6_family = AF_INET6,
+ };
+
+ ret = inet_pton(AF_INET6, str, &ip6->sin6_addr);
+ if (ret != 1) {
+ return EINVAL;
+ }
+
+#ifdef HAVE_SOCK_SIN_LEN
+ ip6->sin6_len = sizeof(*ip6);
+#endif
+ return 0;
+}
+
+static int ip_from_string(const char *str, ctdb_sock_addr *addr)
+{
+ char *p;
+ int ret;
+
+ if (addr == NULL) {
+ return EINVAL;
+ }
+
+ ZERO_STRUCTP(addr); /* valgrind :-) */
+
+ /* IPv4 or IPv6 address?
+ *
+ * Use rindex() because we need the right-most ':' below for
+ * IPv4-mapped IPv6 addresses anyway...
+ */
+ p = rindex(str, ':');
+ if (p == NULL) {
+ ret = ipv4_from_string(str, &addr->ip);
+ } else {
+ uint8_t ipv4_mapped_prefix[12] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff
+ };
+
+ ret = ipv6_from_string(str, &addr->ip6);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /*
+ * Check for IPv4-mapped IPv6 address
+ * (e.g. ::ffff:192.0.2.128) - reparse as IPv4 if
+ * necessary
+ */
+ if (memcmp(&addr->ip6.sin6_addr.s6_addr[0],
+ ipv4_mapped_prefix,
+ sizeof(ipv4_mapped_prefix)) == 0) {
+ /* Reparse as IPv4 */
+ ret = ipv4_from_string(p+1, &addr->ip);
+ }
+ }
+
+ return ret;
+}
+
+int ctdb_sock_addr_from_string(const char *str,
+ ctdb_sock_addr *addr, bool with_port)
+{
+ char *p;
+ char s[64]; /* Much longer than INET6_ADDRSTRLEN */
+ unsigned port;
+ char *endp = NULL;
+ size_t len;
+ bool ret;
+
+ if (! with_port) {
+ ret = ip_from_string(str, addr);
+ return ret;
+ }
+
+ /* Parse out port number and then IP address */
+
+ len = strlen(str);
+ if (len >= sizeof(s)) {
+ return EINVAL;
+ }
+
+ strncpy(s, str, len+1);
+
+ p = rindex(s, ':');
+ if (p == NULL) {
+ return EINVAL;
+ }
+
+ port = strtoul(p+1, &endp, 10);
+ if (endp == p+1 || *endp != '\0') {
+ /* Empty string or trailing garbage */
+ return EINVAL;
+ }
+
+ *p = '\0';
+ ret = ip_from_string(s, addr);
+
+ ctdb_sock_addr_set_port(addr, port);
+
+ return ret;
+}
+
unsigned int ctdb_sock_addr_port(ctdb_sock_addr *addr)
{
switch (addr->sa.sa_family) {
diff --git a/ctdb/protocol/protocol_util.h b/ctdb/protocol/protocol_util.h
index b8c4f0aae42..88819366e5d 100644
--- a/ctdb/protocol/protocol_util.h
+++ b/ctdb/protocol/protocol_util.h
@@ -39,6 +39,8 @@ int ctdb_sock_addr_to_buf(char *buf, socklen_t buflen,
ctdb_sock_addr *addr, bool with_port);
const char *ctdb_sock_addr_to_string(TALLOC_CTX *mem_ctx,
ctdb_sock_addr *addr, bool with_port);
+int ctdb_sock_addr_from_string(const char *str,
+ ctdb_sock_addr *addr, bool with_port);
unsigned int ctdb_sock_addr_port(ctdb_sock_addr *addr);
void ctdb_sock_addr_set_port(ctdb_sock_addr *addr, unsigned int port);
int ctdb_sock_addr_cmp_ip(const ctdb_sock_addr *addr1,
diff --git a/ctdb/tests/src/protocol_util_test.c b/ctdb/tests/src/protocol_util_test.c
index 1fcf1a0648d..8926de0197b 100644
--- a/ctdb/tests/src/protocol_util_test.c
+++ b/ctdb/tests/src/protocol_util_test.c
@@ -26,33 +26,42 @@
#include "protocol/protocol_types.c"
#include "protocol/protocol_util.c"
-#include "common/system_util.c"
+/*
+ * Test parsing of IPs, conversion to string
+ */
-/* Test parsing of IPs, conversion to string */
static void test_sock_addr_to_string(const char *ip, bool with_port)
{
ctdb_sock_addr sa;
const char *s;
- bool status;
+ int ret;
- if (with_port) {
- status = parse_ip_port(ip, &sa);
- } else {
- status = parse_ip(ip, NULL, 0, &sa);
- }
- assert(status);
+ ret = ctdb_sock_addr_from_string(ip, &sa, with_port);
+ assert(ret == 0);
s = ctdb_sock_addr_to_string(NULL, &sa, with_port);
assert(strcmp(ip, s) == 0);
talloc_free(discard_const(s));
}
-static void test_sock_addr_cmp(const char *ip1, const char *ip2, int res)
+static void test_sock_addr_from_string_bad(const char *ip, bool with_port)
+{
+ ctdb_sock_addr sa;
+ int ret;
+
+ ret = ctdb_sock_addr_from_string(ip, &sa, with_port);
+ assert(ret != 0);
+}
+
+static void test_sock_addr_cmp(const char *ip1, const char *ip2,
+ bool with_port, int res)
{
ctdb_sock_addr sa1, sa2;
int ret;
- assert(parse_ip(ip1, NULL, 0, &sa1));
- assert(parse_ip(ip2, NULL, 0, &sa2));
+ ret = ctdb_sock_addr_from_string(ip1, &sa1, with_port);
+ assert(ret == 0);
+ ret = ctdb_sock_addr_from_string(ip2, &sa2, with_port);
+ assert(ret == 0);
ret = ctdb_sock_addr_cmp(&sa1, &sa2);
if (ret < 0) {
ret = -1;
@@ -77,20 +86,29 @@ int main(int argc, char *argv[])
test_sock_addr_to_string("192.168.2.1:123", true);
test_sock_addr_to_string("fe80::6af7:28ff:fefa:d136:234", true);
-
- test_sock_addr_cmp("127.0.0.1", "127.0.0.1" , 0);
- test_sock_addr_cmp("127.0.0.1", "127.0.0.2" , -1);
- test_sock_addr_cmp("127.0.0.2", "127.0.0.1" , 1);
- test_sock_addr_cmp("127.0.1.2", "127.0.2.1" , -1);
- test_sock_addr_cmp("127.0.2.1", "127.0.1.2" , 1);
- test_sock_addr_cmp("fe80::6af7:28ff:fefa:d136", "127.0.1.2" , 1);
+ test_sock_addr_from_string_bad("0.0.0", false);
+ test_sock_addr_from_string_bad("0.0.0:0", true);
+ test_sock_addr_from_string_bad("fe80::6af7:28ff:fefa:d136", true);
+ test_sock_addr_from_string_bad("junk", false);
+ test_sock_addr_from_string_bad("0.0.0.0:0 trailing junk", true);
+
+ test_sock_addr_cmp("127.0.0.1", "127.0.0.1" , false, 0);
+ test_sock_addr_cmp("127.0.0.1", "127.0.0.2" , false, -1);
+ test_sock_addr_cmp("127.0.0.2", "127.0.0.1" , false, 1);
+ test_sock_addr_cmp("127.0.1.2", "127.0.2.1" , false, -1);
+ test_sock_addr_cmp("127.0.2.1", "127.0.1.2" , false, 1);
+ test_sock_addr_cmp("fe80::6af7:28ff:fefa:d136", "127.0.1.2" , false, 1);
test_sock_addr_cmp("fe80::6af7:28ff:fefa:d136",
- "fe80::6af7:28ff:fefa:d136" , 0);
+ "fe80::6af7:28ff:fefa:d136" , false, 0);
test_sock_addr_cmp("fe80::6af7:28ff:fefa:d136",
- "fe80::6af7:28ff:fefa:d137" , -1);
+ "fe80::6af7:28ff:fefa:d137" , false, -1);
test_sock_addr_cmp("fe80::6af7:28ff:fefa:d136",
- "fe80:0000:0000:0000:6af7:28ff:fefa:d136" , 0);
- test_sock_addr_cmp("::ffff:192.0.2.128", "192.0.2.128", 0);
+ "fe80:0000:0000:0000:6af7:28ff:fefa:d136" ,
+ false, 0);
+ test_sock_addr_cmp("::ffff:192.0.2.128", "192.0.2.128", false, 0);
+ test_sock_addr_cmp("127.0.0.1:123", "127.0.0.1:124" , true, -1);
+ test_sock_addr_cmp("fe80::6af7:28ff:fefa:d136:123",
+ "fe80::6af7:28ff:fefa:d136:122" , true, 1);
return 0;
}