#include "include/ipaddr.h" #include "common/pick_address.h" #include "gtest/gtest.h" #include "include/stringify.h" #include "common/ceph_context.h" #include #if defined(__FreeBSD__) #include #include #include #endif #include #include #ifdef _WIN32 #include #else #include #endif static void ipv4(struct sockaddr_in *addr, const char *s) { int err; addr->sin_family = AF_INET; err = inet_pton(AF_INET, s, &addr->sin_addr); ASSERT_EQ(1, err); } static void ipv6(struct sockaddr_in6 *addr, const char *s) { int err; addr->sin6_family = AF_INET6; err = inet_pton(AF_INET6, s, &addr->sin6_addr); ASSERT_EQ(1, err); } static char eth0[] = "eth0"; static char eth1[] = "eth1"; TEST(CommonIPAddr, TestNotFound) { struct ifaddrs one, two; struct sockaddr_in a_one; struct sockaddr_in6 a_two; struct sockaddr_in net; memset(&net, 0, sizeof(net)); one.ifa_next = &two; one.ifa_addr = (struct sockaddr*)&a_one; one.ifa_name = eth0; two.ifa_next = NULL; two.ifa_addr = (struct sockaddr*)&a_two; two.ifa_name = eth1; ipv4(&a_one, "10.11.12.13"); ipv6(&a_two, "2001:1234:5678:90ab::cdef"); ipv4(&net, "10.11.234.56"); ASSERT_FALSE(matches_ipv4_in_subnet(one, (struct sockaddr_in*)&net, 24)); ASSERT_FALSE(matches_ipv6_in_subnet(two, (struct sockaddr_in6*)&net, 24)); } TEST(CommonIPAddr, TestV4_Simple) { struct ifaddrs one, two; struct sockaddr_in a_one; struct sockaddr_in6 a_two; struct sockaddr_in net; memset(&net, 0, sizeof(net)); one.ifa_next = &two; one.ifa_addr = (struct sockaddr*)&a_one; one.ifa_name = eth0; two.ifa_next = NULL; two.ifa_addr = (struct sockaddr*)&a_two; two.ifa_name = eth1; ipv4(&a_one, "10.11.12.13"); ipv6(&a_two, "2001:1234:5678:90ab::cdef"); ipv4(&net, "10.11.12.42"); ASSERT_TRUE(matches_ipv4_in_subnet(one, (struct sockaddr_in*)&net, 24)); ASSERT_FALSE(matches_ipv4_in_subnet(two, (struct sockaddr_in*)&net, 24)); } TEST(CommonIPAddr, TestV4_Prefix25) { struct ifaddrs one, two; struct sockaddr_in a_one; struct sockaddr_in a_two; struct sockaddr_in net; memset(&net, 0, sizeof(net)); one.ifa_next = &two; one.ifa_addr = (struct sockaddr*)&a_one; one.ifa_name = eth0; two.ifa_next = NULL; two.ifa_addr = (struct sockaddr*)&a_two; two.ifa_name = eth1; ipv4(&a_one, "10.11.12.13"); ipv4(&a_two, "10.11.12.129"); ipv4(&net, "10.11.12.128"); ASSERT_FALSE(matches_ipv4_in_subnet(one, (struct sockaddr_in*)&net, 25)); ASSERT_TRUE(matches_ipv4_in_subnet(two, (struct sockaddr_in*)&net, 25)); } TEST(CommonIPAddr, TestV4_Prefix16) { struct ifaddrs one, two; struct sockaddr_in a_one; struct sockaddr_in a_two; struct sockaddr_in net; memset(&net, 0, sizeof(net)); one.ifa_next = &two; one.ifa_addr = (struct sockaddr*)&a_one; one.ifa_name = eth0; two.ifa_next = NULL; two.ifa_addr = (struct sockaddr*)&a_two; two.ifa_name = eth1; ipv4(&a_one, "10.1.1.2"); ipv4(&a_two, "10.2.1.123"); ipv4(&net, "10.2.0.0"); ASSERT_FALSE(matches_ipv4_in_subnet(one, (struct sockaddr_in*)&net, 16)); ASSERT_TRUE(matches_ipv4_in_subnet(two, (struct sockaddr_in*)&net, 16)); } TEST(CommonIPAddr, TestV4_PrefixTooLong) { struct ifaddrs one; struct sockaddr_in a_one; struct sockaddr_in net; memset(&net, 0, sizeof(net)); one.ifa_next = NULL; one.ifa_addr = (struct sockaddr*)&a_one; one.ifa_name = eth0; ipv4(&a_one, "10.11.12.13"); ipv4(&net, "10.11.12.12"); ASSERT_FALSE(matches_ipv4_in_subnet(one, (struct sockaddr_in*)&net, 42)); } TEST(CommonIPAddr, TestV4_PrefixZero) { struct ifaddrs one, two; struct sockaddr_in6 a_one; struct sockaddr_in a_two; struct sockaddr_in net; memset(&net, 0, sizeof(net)); one.ifa_next = &two; one.ifa_addr = (struct sockaddr*)&a_one; one.ifa_name = eth0; two.ifa_next = NULL; two.ifa_addr = (struct sockaddr*)&a_two; two.ifa_name = eth1; ipv6(&a_one, "2001:1234:5678:900F::cdef"); ipv4(&a_two, "10.1.2.3"); ipv4(&net, "255.0.1.2"); ASSERT_FALSE(matches_ipv4_in_subnet(one, (struct sockaddr_in*)&net, 0)); ASSERT_TRUE(matches_ipv4_in_subnet(two, (struct sockaddr_in*)&net, 0)); } static char lo[] = "lo"; static char lo0[] = "lo:0"; TEST(CommonIPAddr, TestV4_SkipLoopback) { struct ifaddrs one, two, three; struct sockaddr_in a_one; struct sockaddr_in a_two; struct sockaddr_in a_three; one.ifa_next = &two; one.ifa_addr = (struct sockaddr*)&a_one; one.ifa_name = lo; two.ifa_next = &three; two.ifa_flags = IFF_UP; two.ifa_addr = (struct sockaddr*)&a_two; two.ifa_name = lo0; three.ifa_next = NULL; three.ifa_flags = IFF_UP; three.ifa_addr = (struct sockaddr*)&a_three; three.ifa_name = eth0; ipv4(&a_one, "127.0.0.1"); ipv4(&a_two, "127.0.0.1"); ipv4(&a_three, "10.1.2.3"); const struct sockaddr *result = nullptr; // we prefer the non-loopback address despite the loopback addresses result = find_ip_in_subnet_list(nullptr, (struct ifaddrs*)&one, CEPH_PICK_ADDRESS_IPV4 | CEPH_PICK_ADDRESS_IPV6, "", ""); ASSERT_EQ((struct sockaddr*)&a_three, result); // the subnet criteria leaves us no choice but the UP loopback address result = find_ip_in_subnet_list(nullptr, (struct ifaddrs*)&one, CEPH_PICK_ADDRESS_IPV4 | CEPH_PICK_ADDRESS_IPV6, "127.0.0.0/8", ""); ASSERT_EQ((struct sockaddr*)&a_two, result); } TEST(CommonIPAddr, TestV6_Simple) { struct ifaddrs one, two; struct sockaddr_in a_one; struct sockaddr_in6 a_two; struct sockaddr_in6 net; memset(&net, 0, sizeof(net)); one.ifa_next = &two; one.ifa_addr = (struct sockaddr*)&a_one; one.ifa_name = eth0; two.ifa_next = NULL; two.ifa_addr = (struct sockaddr*)&a_two; two.ifa_name = eth1; ipv4(&a_one, "10.11.12.13"); ipv6(&a_two, "2001:1234:5678:90ab::cdef"); ipv6(&net, "2001:1234:5678:90ab::dead:beef"); ASSERT_FALSE(matches_ipv6_in_subnet(one, (struct sockaddr_in6*)&net, 64)); ASSERT_TRUE(matches_ipv6_in_subnet(two, (struct sockaddr_in6*)&net, 64)); } TEST(CommonIPAddr, TestV6_Prefix57) { struct ifaddrs one, two; struct sockaddr_in6 a_one; struct sockaddr_in6 a_two; struct sockaddr_in6 net; memset(&net, 0, sizeof(net)); one.ifa_next = &two; one.ifa_addr = (struct sockaddr*)&a_one; one.ifa_name = eth0; two.ifa_next = NULL; two.ifa_addr = (struct sockaddr*)&a_two; two.ifa_name = eth1; ipv6(&a_one, "2001:1234:5678:900F::cdef"); ipv6(&a_two, "2001:1234:5678:90ab::cdef"); ipv6(&net, "2001:1234:5678:90ab::dead:beef"); ASSERT_FALSE(matches_ipv6_in_subnet(one, (struct sockaddr_in6*)&net, 57)); ASSERT_TRUE(matches_ipv6_in_subnet(two, (struct sockaddr_in6*)&net, 57)); } TEST(CommonIPAddr, TestV6_PrefixTooLong) { struct ifaddrs one; struct sockaddr_in6 a_one; struct sockaddr_in6 net; memset(&net, 0, sizeof(net)); one.ifa_next = NULL; one.ifa_addr = (struct sockaddr*)&a_one; one.ifa_name = eth0; ipv6(&a_one, "2001:1234:5678:900F::cdef"); ipv6(&net, "2001:1234:5678:900F::cdee"); ASSERT_FALSE(matches_ipv6_in_subnet(one, (struct sockaddr_in6*)&net, 9000)); } TEST(CommonIPAddr, TestV6_PrefixZero) { struct ifaddrs one, two; struct sockaddr_in a_one; struct sockaddr_in6 a_two; struct sockaddr_in6 net; one.ifa_next = &two; one.ifa_addr = (struct sockaddr*)&a_one; one.ifa_name = eth0; two.ifa_next = NULL; two.ifa_addr = (struct sockaddr*)&a_two; two.ifa_name = eth1; ipv4(&a_one, "10.2.3.4"); ipv6(&a_two, "2001:f00b::1"); ipv6(&net, "ff00::1"); ASSERT_FALSE(matches_ipv6_in_subnet(one, (struct sockaddr_in6*)&net, 0)); ASSERT_TRUE(matches_ipv6_in_subnet(two, (struct sockaddr_in6*)&net, 0)); } TEST(CommonIPAddr, TestV6_SkipLoopback) { struct ifaddrs one, two, three; struct sockaddr_in6 a_one; struct sockaddr_in6 a_two; struct sockaddr_in6 a_three; one.ifa_next = &two; ipv6(&a_one, "::1"); one.ifa_addr = (struct sockaddr*)&a_one; one.ifa_name = lo; two.ifa_next = &three; two.ifa_flags = IFF_UP; ipv6(&a_two, "::1"); two.ifa_addr = (struct sockaddr*)&a_two; two.ifa_name = lo0; three.ifa_next = NULL; three.ifa_flags = IFF_UP; ipv6(&a_three, "2001:1234:5678:90ab::beef"); three.ifa_addr = (struct sockaddr*)&a_three; three.ifa_name = eth0; const struct sockaddr *result = nullptr; // we prefer the non-loopback address despite the loopback addresses result = find_ip_in_subnet_list(nullptr, (struct ifaddrs*)&one, CEPH_PICK_ADDRESS_IPV4 | CEPH_PICK_ADDRESS_IPV6, "", ""); ASSERT_EQ((struct sockaddr*)&a_three, result); // the subnet criteria leaves us no choice but the UP loopback address result = find_ip_in_subnet_list(nullptr, (struct ifaddrs*)&one, CEPH_PICK_ADDRESS_IPV4 | CEPH_PICK_ADDRESS_IPV6, "::1/128", ""); ASSERT_EQ((struct sockaddr*)&a_two, result); } TEST(CommonIPAddr, ParseNetwork_Empty) { struct sockaddr_storage network; unsigned int prefix_len; bool ok; ok = parse_network("", &network, &prefix_len); ASSERT_EQ(ok, false); } TEST(CommonIPAddr, ParseNetwork_Bad_Junk) { struct sockaddr_storage network; unsigned int prefix_len; bool ok; ok = parse_network("foo", &network, &prefix_len); ASSERT_EQ(ok, false); } TEST(CommonIPAddr, ParseNetwork_Bad_SlashNum) { struct sockaddr_storage network; unsigned int prefix_len; bool ok; ok = parse_network("/24", &network, &prefix_len); ASSERT_EQ(ok, false); } TEST(CommonIPAddr, ParseNetwork_Bad_Slash) { struct sockaddr_storage network; unsigned int prefix_len; bool ok; ok = parse_network("/", &network, &prefix_len); ASSERT_EQ(ok, false); } TEST(CommonIPAddr, ParseNetwork_Bad_IPv4) { struct sockaddr_storage network; unsigned int prefix_len; bool ok; ok = parse_network("123.123.123.123", &network, &prefix_len); ASSERT_EQ(ok, false); } TEST(CommonIPAddr, ParseNetwork_Bad_IPv4Slash) { struct sockaddr_storage network; unsigned int prefix_len; bool ok; ok = parse_network("123.123.123.123/", &network, &prefix_len); ASSERT_EQ(ok, false); } TEST(CommonIPAddr, ParseNetwork_Bad_IPv4SlashNegative) { struct sockaddr_storage network; unsigned int prefix_len; bool ok; ok = parse_network("123.123.123.123/-3", &network, &prefix_len); ASSERT_EQ(ok, false); } TEST(CommonIPAddr, ParseNetwork_Bad_IPv4SlashJunk) { struct sockaddr_storage network; unsigned int prefix_len; bool ok; ok = parse_network("123.123.123.123/foo", &network, &prefix_len); ASSERT_EQ(ok, false); } TEST(CommonIPAddr, ParseNetwork_Bad_IPv6) { struct sockaddr_storage network; unsigned int prefix_len; bool ok; ok = parse_network("2001:1234:5678:90ab::dead:beef", &network, &prefix_len); ASSERT_EQ(ok, false); } TEST(CommonIPAddr, ParseNetwork_Bad_IPv6Slash) { struct sockaddr_storage network; unsigned int prefix_len; bool ok; ok = parse_network("2001:1234:5678:90ab::dead:beef/", &network, &prefix_len); ASSERT_EQ(ok, false); } TEST(CommonIPAddr, ParseNetwork_Bad_IPv6SlashNegative) { struct sockaddr_storage network; unsigned int prefix_len; bool ok; ok = parse_network("2001:1234:5678:90ab::dead:beef/-3", &network, &prefix_len); ASSERT_EQ(ok, false); } TEST(CommonIPAddr, ParseNetwork_Bad_IPv6SlashJunk) { struct sockaddr_storage network; unsigned int prefix_len; bool ok; ok = parse_network("2001:1234:5678:90ab::dead:beef/foo", &network, &prefix_len); ASSERT_EQ(ok, false); } TEST(CommonIPAddr, ParseNetwork_IPv4_0) { struct sockaddr_in network; struct sockaddr_storage net_storage; unsigned int prefix_len; bool ok; ok = parse_network("123.123.123.123/0", &net_storage, &prefix_len); network = *(struct sockaddr_in *) &net_storage; ASSERT_EQ(ok, true); ASSERT_EQ(0U, prefix_len); ASSERT_EQ(AF_INET, network.sin_family); ASSERT_EQ(0, network.sin_port); struct sockaddr_in want; ipv4(&want, "123.123.123.123"); ASSERT_EQ(want.sin_addr.s_addr, network.sin_addr.s_addr); } TEST(CommonIPAddr, ParseNetwork_IPv4_13) { struct sockaddr_in network; struct sockaddr_storage net_storage; unsigned int prefix_len; bool ok; ok = parse_network("123.123.123.123/13", &net_storage, &prefix_len); network = *(struct sockaddr_in *) &net_storage; ASSERT_EQ(ok, true); ASSERT_EQ(13U, prefix_len); ASSERT_EQ(AF_INET, network.sin_family); ASSERT_EQ(0, network.sin_port); struct sockaddr_in want; ipv4(&want, "123.123.123.123"); ASSERT_EQ(want.sin_addr.s_addr, network.sin_addr.s_addr); } TEST(CommonIPAddr, ParseNetwork_IPv4_32) { struct sockaddr_in network; struct sockaddr_storage net_storage; unsigned int prefix_len; bool ok; ok = parse_network("123.123.123.123/32", &net_storage, &prefix_len); network = *(struct sockaddr_in *) &net_storage; ASSERT_EQ(ok, true); ASSERT_EQ(32U, prefix_len); ASSERT_EQ(AF_INET, network.sin_family); ASSERT_EQ(0, network.sin_port); struct sockaddr_in want; ipv4(&want, "123.123.123.123"); ASSERT_EQ(want.sin_addr.s_addr, network.sin_addr.s_addr); } TEST(CommonIPAddr, ParseNetwork_IPv4_42) { struct sockaddr_in network; struct sockaddr_storage net_storage; unsigned int prefix_len; bool ok; ok = parse_network("123.123.123.123/42", &net_storage, &prefix_len); network = *(struct sockaddr_in *) &net_storage; ASSERT_EQ(ok, true); ASSERT_EQ(42U, prefix_len); ASSERT_EQ(AF_INET, network.sin_family); ASSERT_EQ(0, network.sin_port); struct sockaddr_in want; ipv4(&want, "123.123.123.123"); ASSERT_EQ(want.sin_addr.s_addr, network.sin_addr.s_addr); } TEST(CommonIPAddr, ParseNetwork_IPv6_0) { struct sockaddr_in6 network; struct sockaddr_storage net_storage; unsigned int prefix_len; bool ok; ok = parse_network("2001:1234:5678:90ab::dead:beef/0", &net_storage, &prefix_len); network = *(struct sockaddr_in6 *) &net_storage; ASSERT_EQ(ok, true); ASSERT_EQ(0U, prefix_len); ASSERT_EQ(AF_INET6, network.sin6_family); ASSERT_EQ(0, network.sin6_port); struct sockaddr_in6 want; ipv6(&want, "2001:1234:5678:90ab::dead:beef"); ASSERT_EQ(0, memcmp(want.sin6_addr.s6_addr, network.sin6_addr.s6_addr, sizeof(network.sin6_addr.s6_addr))); } TEST(CommonIPAddr, ParseNetwork_IPv6_67) { struct sockaddr_in6 network; struct sockaddr_storage net_storage; unsigned int prefix_len; bool ok; ok = parse_network("2001:1234:5678:90ab::dead:beef/67", &net_storage, &prefix_len); network = *(struct sockaddr_in6 *) &net_storage; ASSERT_EQ(ok, true); ASSERT_EQ(67U, prefix_len); ASSERT_EQ(AF_INET6, network.sin6_family); ASSERT_EQ(0, network.sin6_port); struct sockaddr_in6 want; ipv6(&want, "2001:1234:5678:90ab::dead:beef"); ASSERT_EQ(0, memcmp(want.sin6_addr.s6_addr, network.sin6_addr.s6_addr, sizeof(network.sin6_addr.s6_addr))); } TEST(CommonIPAddr, ParseNetwork_IPv6_128) { struct sockaddr_in6 network; struct sockaddr_storage net_storage; unsigned int prefix_len; bool ok; ok = parse_network("2001:1234:5678:90ab::dead:beef/128", &net_storage, &prefix_len); network = *(struct sockaddr_in6 *) &net_storage; ASSERT_EQ(ok, true); ASSERT_EQ(128U, prefix_len); ASSERT_EQ(AF_INET6, network.sin6_family); ASSERT_EQ(0, network.sin6_port); struct sockaddr_in6 want; ipv6(&want, "2001:1234:5678:90ab::dead:beef"); ASSERT_EQ(0, memcmp(want.sin6_addr.s6_addr, network.sin6_addr.s6_addr, sizeof(network.sin6_addr.s6_addr))); } TEST(CommonIPAddr, ParseNetwork_IPv6_9000) { struct sockaddr_in6 network; struct sockaddr_storage net_storage; unsigned int prefix_len; bool ok; ok = parse_network("2001:1234:5678:90ab::dead:beef/9000", &net_storage, &prefix_len); network = *(struct sockaddr_in6 *) &net_storage; ASSERT_EQ(ok, true); ASSERT_EQ(9000U, prefix_len); ASSERT_EQ(AF_INET6, network.sin6_family); ASSERT_EQ(0, network.sin6_port); struct sockaddr_in6 want; ipv6(&want, "2001:1234:5678:90ab::dead:beef"); ASSERT_EQ(0, memcmp(want.sin6_addr.s6_addr, network.sin6_addr.s6_addr, sizeof(network.sin6_addr.s6_addr))); } TEST(CommonIPAddr, ambiguous) { entity_addr_t a; bool ok; ok = a.parse("1.2.3.4", nullptr, entity_addr_t::TYPE_ANY); ASSERT_TRUE(ok); ASSERT_EQ(entity_addr_t::TYPE_ANY, a.get_type()); ok = a.parse("any:1.2.3.4", nullptr, entity_addr_t::TYPE_ANY); ASSERT_TRUE(ok); ASSERT_EQ(entity_addr_t::TYPE_ANY, a.get_type()); ok = a.parse("v1:1.2.3.4", nullptr, entity_addr_t::TYPE_ANY); ASSERT_TRUE(ok); ASSERT_EQ(entity_addr_t::TYPE_LEGACY, a.get_type()); ok = a.parse("v2:1.2.3.4", nullptr, entity_addr_t::TYPE_ANY); ASSERT_TRUE(ok); ASSERT_EQ(entity_addr_t::TYPE_MSGR2, a.get_type()); } TEST(CommonIPAddr, network_contains) { entity_addr_t network, addr; unsigned int prefix; bool ok; ok = parse_network("2001:1234:5678:90ab::dead:beef/32", &network, &prefix); ASSERT_TRUE(ok); ASSERT_EQ(32U, prefix); ok = addr.parse("2001:1234:5678:90ab::dead:beef", nullptr); ASSERT_TRUE(ok); ASSERT_TRUE(network_contains(network, prefix, addr)); ok = addr.parse("2001:1334:5678:90ab::dead:beef", nullptr); ASSERT_TRUE(ok); ASSERT_FALSE(network_contains(network, prefix, addr)); ok = addr.parse("127.0.0.1", nullptr); ASSERT_TRUE(ok); ASSERT_FALSE(network_contains(network, prefix, addr)); ok = parse_network("10.1.2.3/16", &network, &prefix); ASSERT_TRUE(ok); ASSERT_EQ(16U, prefix); ok = addr.parse("2001:1234:5678:90ab::dead:beef", nullptr); ASSERT_TRUE(ok); ASSERT_FALSE(network_contains(network, prefix, addr)); ok = addr.parse("1.2.3.4", nullptr); ASSERT_TRUE(ok); ASSERT_FALSE(network_contains(network, prefix, addr)); ok = addr.parse("10.1.22.44", nullptr); ASSERT_TRUE(ok); ASSERT_TRUE(network_contains(network, prefix, addr)); ok = addr.parse("10.2.22.44", nullptr); ASSERT_TRUE(ok); ASSERT_FALSE(network_contains(network, prefix, addr)); } TEST(pick_address, find_ip_in_subnet_list) { struct ifaddrs one, two, three; struct sockaddr_in a_one; struct sockaddr_in a_two; struct sockaddr_in6 a_three; const struct sockaddr *result; one.ifa_next = &two; one.ifa_addr = (struct sockaddr*)&a_one; one.ifa_name = eth0; two.ifa_next = &three; two.ifa_addr = (struct sockaddr*)&a_two; two.ifa_name = eth1; three.ifa_next = NULL; three.ifa_addr = (struct sockaddr*)&a_three; three.ifa_name = eth1; ipv4(&a_one, "10.1.1.2"); ipv4(&a_two, "10.2.1.123"); ipv6(&a_three, "2001:1234:5678:90ab::cdef"); boost::intrusive_ptr cct = new CephContext(CEPH_ENTITY_TYPE_OSD); // match by network result = find_ip_in_subnet_list( cct.get(), &one, CEPH_PICK_ADDRESS_IPV4, "10.1.0.0/16", "eth0"); ASSERT_EQ((struct sockaddr*)&a_one, result); result = find_ip_in_subnet_list( cct.get(), &one, CEPH_PICK_ADDRESS_IPV4, "10.2.0.0/16", "eth1"); ASSERT_EQ((struct sockaddr*)&a_two, result); // match by eth name result = find_ip_in_subnet_list( cct.get(), &one, CEPH_PICK_ADDRESS_IPV4, "10.0.0.0/8", "eth0"); ASSERT_EQ((struct sockaddr*)&a_one, result); result = find_ip_in_subnet_list( cct.get(), &one, CEPH_PICK_ADDRESS_IPV4, "10.0.0.0/8", "eth1"); ASSERT_EQ((struct sockaddr*)&a_two, result); result = find_ip_in_subnet_list( cct.get(), &one, CEPH_PICK_ADDRESS_IPV6, "2001::/16", "eth1"); ASSERT_EQ((struct sockaddr*)&a_three, result); } TEST(pick_address, filtering) { struct ifaddrs one, two, three; struct sockaddr_in a_one; struct sockaddr_in a_two; struct sockaddr_in6 a_three; one.ifa_next = &two; one.ifa_addr = (struct sockaddr*)&a_one; one.ifa_name = eth0; two.ifa_next = &three; two.ifa_addr = (struct sockaddr*)&a_two; two.ifa_name = eth1; three.ifa_next = NULL; three.ifa_addr = (struct sockaddr*)&a_three; three.ifa_name = eth1; ipv4(&a_one, "10.1.1.2"); ipv4(&a_two, "10.2.1.123"); ipv6(&a_three, "2001:1234:5678:90ab::cdef"); boost::intrusive_ptr cct = new CephContext(CEPH_ENTITY_TYPE_MON); cct->_conf._clear_safe_to_start_threads(); // so we can set configs cct->_conf.set_val("public_addr", ""); cct->_conf.set_val("public_network", ""); cct->_conf.set_val("public_network_interface", ""); cct->_conf.set_val("cluster_addr", ""); cct->_conf.set_val("cluster_network", ""); cct->_conf.set_val("cluster_network_interface", ""); entity_addrvec_t av; { int r = pick_addresses(cct.get(), CEPH_PICK_ADDRESS_PUBLIC | CEPH_PICK_ADDRESS_IPV4 | CEPH_PICK_ADDRESS_MSGR1, &one, &av); cout << av << std::endl; ASSERT_EQ(0, r); ASSERT_EQ(1u, av.v.size()); ASSERT_EQ(string("v1:0.0.0.0:0/0"), stringify(av.v[0])); } { int r = pick_addresses(cct.get(), CEPH_PICK_ADDRESS_PUBLIC | CEPH_PICK_ADDRESS_IPV6 | CEPH_PICK_ADDRESS_MSGR1, &one, &av); cout << av << std::endl; ASSERT_EQ(0, r); ASSERT_EQ(1u, av.v.size()); ASSERT_EQ(string("v1:[::]:0/0"), stringify(av.v[0])); } { cct->_conf.set_val("public_network", "10.2.0.0/16"); int r = pick_addresses(cct.get(), CEPH_PICK_ADDRESS_PUBLIC | CEPH_PICK_ADDRESS_IPV4 | CEPH_PICK_ADDRESS_MSGR1, &one, &av); cout << av << std::endl; ASSERT_EQ(0, r); ASSERT_EQ(1u, av.v.size()); ASSERT_EQ(string("v1:10.2.1.123:0/0"), stringify(av.v[0])); cct->_conf.set_val("public_network", ""); } { cct->_conf.set_val("public_network", "10.0.0.0/8"); cct->_conf.set_val("public_network_interface", "eth1"); int r = pick_addresses(cct.get(), CEPH_PICK_ADDRESS_PUBLIC | CEPH_PICK_ADDRESS_IPV4 | CEPH_PICK_ADDRESS_MSGR2, &one, &av); cout << av << std::endl; ASSERT_EQ(0, r); ASSERT_EQ(1u, av.v.size()); ASSERT_EQ(string("v2:10.2.1.123:0/0"), stringify(av.v[0])); cct->_conf.set_val("public_network", ""); cct->_conf.set_val("public_network_interface", ""); } { cct->_conf.set_val("public_network", "10.2.0.0/16"); cct->_conf.set_val("cluster_network", "10.1.0.0/16"); int r = pick_addresses(cct.get(), CEPH_PICK_ADDRESS_PUBLIC | CEPH_PICK_ADDRESS_IPV4 | CEPH_PICK_ADDRESS_MSGR2, &one, &av); cout << av << std::endl; ASSERT_EQ(0, r); ASSERT_EQ(1u, av.v.size()); ASSERT_EQ(string("v2:10.2.1.123:0/0"), stringify(av.v[0])); cct->_conf.set_val("public_network", ""); cct->_conf.set_val("cluster_network", ""); } { cct->_conf.set_val("public_network", "10.2.0.0/16"); cct->_conf.set_val("cluster_network", "10.1.0.0/16"); int r = pick_addresses(cct.get(), CEPH_PICK_ADDRESS_CLUSTER | CEPH_PICK_ADDRESS_IPV4 | CEPH_PICK_ADDRESS_MSGR1, &one, &av); cout << av << std::endl; ASSERT_EQ(0, r); ASSERT_EQ(1u, av.v.size()); ASSERT_EQ(string("v1:10.1.1.2:0/0"), stringify(av.v[0])); cct->_conf.set_val("public_network", ""); cct->_conf.set_val("cluster_network", ""); } { cct->_conf.set_val("public_network", "2001::/16"); int r = pick_addresses(cct.get(), CEPH_PICK_ADDRESS_PUBLIC | CEPH_PICK_ADDRESS_IPV6 | CEPH_PICK_ADDRESS_MSGR2, &one, &av); cout << av << std::endl; ASSERT_EQ(0, r); ASSERT_EQ(1u, av.v.size()); ASSERT_EQ(string("v2:[2001:1234:5678:90ab::cdef]:0/0"), stringify(av.v[0])); cct->_conf.set_val("public_network", ""); } { cct->_conf.set_val("public_network", "2001::/16 10.0.0.0/8"); cct->_conf.set_val("public_network_interface", "eth1"); int r = pick_addresses(cct.get(), CEPH_PICK_ADDRESS_PUBLIC | CEPH_PICK_ADDRESS_IPV4 | CEPH_PICK_ADDRESS_IPV6 | CEPH_PICK_ADDRESS_MSGR2, &one, &av); cout << av << std::endl; ASSERT_EQ(0, r); ASSERT_EQ(2u, av.v.size()); ASSERT_EQ(string("v2:[2001:1234:5678:90ab::cdef]:0/0"), stringify(av.v[0])); ASSERT_EQ(string("v2:10.2.1.123:0/0"), stringify(av.v[1])); cct->_conf.set_val("public_network", ""); cct->_conf.set_val("public_network_interface", ""); } { cct->_conf.set_val("public_network", "2001::/16 10.0.0.0/8"); cct->_conf.set_val("public_network_interface", "eth1"); int r = pick_addresses(cct.get(), CEPH_PICK_ADDRESS_PUBLIC | CEPH_PICK_ADDRESS_IPV4 | CEPH_PICK_ADDRESS_IPV6 | CEPH_PICK_ADDRESS_MSGR1 | CEPH_PICK_ADDRESS_PREFER_IPV4, &one, &av); cout << av << std::endl; ASSERT_EQ(0, r); ASSERT_EQ(2u, av.v.size()); ASSERT_EQ(string("v1:10.2.1.123:0/0"), stringify(av.v[0])); ASSERT_EQ(string("v1:[2001:1234:5678:90ab::cdef]:0/0"), stringify(av.v[1])); cct->_conf.set_val("public_network", ""); cct->_conf.set_val("public_network_interface", ""); } { cct->_conf.set_val("public_network", "2001::/16"); int r = pick_addresses(cct.get(), CEPH_PICK_ADDRESS_PUBLIC | CEPH_PICK_ADDRESS_IPV6 | CEPH_PICK_ADDRESS_MSGR1 | CEPH_PICK_ADDRESS_MSGR2, &one, &av); cout << av << std::endl; ASSERT_EQ(0, r); ASSERT_EQ(2u, av.v.size()); ASSERT_EQ(string("v2:[2001:1234:5678:90ab::cdef]:0/0"), stringify(av.v[0])); ASSERT_EQ(string("v1:[2001:1234:5678:90ab::cdef]:0/0"), stringify(av.v[1])); cct->_conf.set_val("public_network", ""); } { int r = pick_addresses(cct.get(), CEPH_PICK_ADDRESS_PUBLIC | CEPH_PICK_ADDRESS_IPV4 | CEPH_PICK_ADDRESS_MSGR1 | CEPH_PICK_ADDRESS_MSGR2, &one, &av); cout << av << std::endl; ASSERT_EQ(0, r); ASSERT_EQ(2u, av.v.size()); ASSERT_EQ(string("v2:0.0.0.0:0/0"), stringify(av.v[0])); ASSERT_EQ(string("v1:0.0.0.0:0/0"), stringify(av.v[1])); } } TEST(pick_address, ipv4_ipv6_enabled) { struct ifaddrs one; struct sockaddr_in a_one; one.ifa_next = NULL; one.ifa_addr = (struct sockaddr*)&a_one; one.ifa_name = eth0; ipv4(&a_one, "10.1.1.2"); boost::intrusive_ptr cct = new CephContext(CEPH_ENTITY_TYPE_OSD); cct->_conf._clear_safe_to_start_threads(); // so we can set configs cct->_conf.set_val("public_addr", ""); cct->_conf.set_val("public_network", "10.1.1.0/24"); cct->_conf.set_val("public_network_interface", ""); cct->_conf.set_val("cluster_addr", ""); cct->_conf.set_val("cluster_network", ""); cct->_conf.set_val("cluster_network_interface", ""); cct->_conf.set_val("ms_bind_ipv6", "true"); entity_addrvec_t av; { int r = pick_addresses(cct.get(), CEPH_PICK_ADDRESS_PUBLIC | CEPH_PICK_ADDRESS_MSGR1, &one, &av); cout << av << std::endl; ASSERT_EQ(-1, r); } } TEST(pick_address, ipv4_ipv6_enabled2) { struct ifaddrs one; struct sockaddr_in6 a_one; one.ifa_next = NULL; one.ifa_addr = (struct sockaddr*)&a_one; one.ifa_name = eth0; ipv6(&a_one, "2001:1234:5678:90ab::cdef"); boost::intrusive_ptr cct = new CephContext(CEPH_ENTITY_TYPE_OSD); cct->_conf._clear_safe_to_start_threads(); // so we can set configs cct->_conf.set_val("public_addr", ""); cct->_conf.set_val("public_network", "2001::/16"); cct->_conf.set_val("public_network_interface", ""); cct->_conf.set_val("cluster_addr", ""); cct->_conf.set_val("cluster_network", ""); cct->_conf.set_val("cluster_network_interface", ""); cct->_conf.set_val("ms_bind_ipv6", "true"); entity_addrvec_t av; { int r = pick_addresses(cct.get(), CEPH_PICK_ADDRESS_PUBLIC | CEPH_PICK_ADDRESS_MSGR1, &one, &av); cout << av << std::endl; ASSERT_EQ(-1, r); } }