ctdb-common: Parse IPv4-mapped IPv6 addresses into IPv4 addresses
authorMartin Schwenke <martin@meltin.net>
Wed, 1 Mar 2017 06:22:22 +0000 (17:22 +1100)
committerMartin Schwenke <martins@samba.org>
Fri, 1 Sep 2017 02:06:32 +0000 (04:06 +0200)
Tools like ctdb_killtcp can't route packets to IPv4-mapped IPv6
addresses so this works around that.

Add a test case to confirm that this works.

Signed-off-by: Martin Schwenke <martin@meltin.net>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
Autobuild-User(master): Martin Schwenke <martins@samba.org>
Autobuild-Date(master): Fri Sep  1 04:06:32 CEST 2017 on sn-devel-144

ctdb/common/system_util.c
ctdb/tests/src/protocol_util_test.c

index 57452aa6a1a81854125c42e6527cc961e99efdcd..96ea71dafaf1a72b75dd86b703e435b20081b40f 100644 (file)
@@ -168,12 +168,35 @@ bool parse_ip(const char *addr, const char *ifaces, unsigned port, ctdb_sock_add
 
        ZERO_STRUCTP(saddr); /* valgrind :-) */
 
-       /* now is this a ipv4 or ipv6 address ?*/
-       p = index(addr, ':');
+       /* IPv4 or IPv6 address?
+        *
+        * Use rindex() because we need the right-most ':' below for
+        * IPv4-mapped IPv6 addresses anyway...
+        */
+       p = rindex(addr, ':');
        if (p == NULL) {
                ret = parse_ipv4(addr, port, &saddr->ip);
        } else {
+               uint8_t ipv4_mapped_prefix[12] = {
+                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff
+               };
+
                ret = parse_ipv6(addr, ifaces, port, saddr);
+               if (! ret) {
+                       return ret;
+               }
+
+               /*
+                * Check for IPv4-mapped IPv6 address
+                * (e.g. ::ffff:192.0.2.128) - reparse as IPv4 if
+                * necessary
+                */
+               if (memcmp(&saddr->ip6.sin6_addr.s6_addr[0],
+                          ipv4_mapped_prefix,
+                          sizeof(ipv4_mapped_prefix)) == 0) {
+                       /* Reparse as IPv4 */
+                       ret = parse_ipv4(p+1, port, &saddr->ip);
+               }
        }
 
        return ret;
index 1fcaa62d38937c269664262c23dc47a3a93fafc2..c8bffff8b257fb510c37736f6185278b66d68fb0 100644 (file)
@@ -77,6 +77,7 @@ int main(int argc, char *argv[])
                           "fe80::6af7:28ff:fefa:d137" , -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);
 
        return 0;
 }