| //===----------------------------------------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| /// | |
| /// \file | |
| /// Unittests for inet_pton. | |
| /// | |
| //===----------------------------------------------------------------------===// | |
| #include "hdr/errno_macros.h" | |
| #include "hdr/sys_socket_macros.h" | |
| #include "hdr/types/struct_in6_addr.h" | |
| #include "hdr/types/struct_in_addr.h" | |
| #include "src/__support/endian_internal.h" | |
| #include "src/arpa/inet/inet_pton.h" | |
| #include "src/string/memory_utils/inline_memcmp.h" | |
| #include "test/UnitTest/ErrnoCheckingTest.h" | |
| #include "test/UnitTest/Test.h" | |
| using LlvmLibcInetPtonTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; | |
| static uint32_t ipv4_bits(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { | |
| return LIBC_NAMESPACE::Endian::to_big_endian( | |
| static_cast<uint32_t>(a) << 24 | static_cast<uint32_t>(b) << 16 | | |
| static_cast<uint32_t>(c) << 8 | static_cast<uint32_t>(d)); | |
| } | |
| TEST_F(LlvmLibcInetPtonTest, ValidIPv4Addresses) { | |
| struct in_addr addr; | |
| EXPECT_EQ(1, LIBC_NAMESPACE::inet_pton(AF_INET, "127.0.0.1", &addr)); | |
| EXPECT_EQ(addr.s_addr, ipv4_bits(127, 0, 0, 1)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| EXPECT_EQ(1, LIBC_NAMESPACE::inet_pton(AF_INET, "192.168.1.254", &addr)); | |
| EXPECT_EQ(addr.s_addr, ipv4_bits(192, 168, 1, 254)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| EXPECT_EQ(1, LIBC_NAMESPACE::inet_pton(AF_INET, "0.0.0.0", &addr)); | |
| EXPECT_EQ(addr.s_addr, ipv4_bits(0, 0, 0, 0)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| EXPECT_EQ(1, LIBC_NAMESPACE::inet_pton(AF_INET, "255.255.255.255", &addr)); | |
| EXPECT_EQ(addr.s_addr, ipv4_bits(255, 255, 255, 255)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| } | |
| TEST_F(LlvmLibcInetPtonTest, InvalidOctetValues) { | |
| struct in_addr addr; | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "256.0.0.1", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "192.168.1.300", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "192.168.-1.1", &addr)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| } | |
| TEST_F(LlvmLibcInetPtonTest, InvalidFormats) { | |
| struct in_addr addr; | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "127.0.0", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "10.0.0.0.1", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, ".1.2.3.4", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "1.2.3.4.", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "192..168.1.1", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "192.168.1.1a", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "abc.def.ghi.jkl", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "127.0.0.1 ", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, ".", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "0", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "1", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, ".1", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "1.1", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "1.1.", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "1.1.1", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "1.1.1.", &addr)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| } | |
| TEST_F(LlvmLibcInetPtonTest, StrictPosixLeadingZeros) { | |
| struct in_addr addr; | |
| // inet_pton must reject octal-style leading zeros | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "192.168.01.1", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "010.0.0.1", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "00.0.0.0", &addr)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| } | |
| static bool check_ipv6(const struct in6_addr &addr, uint16_t a, uint16_t b, | |
| uint16_t c, uint16_t d, uint16_t e, uint16_t f, | |
| uint16_t g, uint16_t h) { | |
| uint16_t words[8] = {a, b, c, d, e, f, g, h}; | |
| struct in6_addr expected; | |
| for (size_t i = 0; i < 8; ++i) | |
| expected.s6_addr16[i] = LIBC_NAMESPACE::Endian::to_big_endian(words[i]); | |
| return LIBC_NAMESPACE::inline_memcmp(&addr, &expected, | |
| sizeof(struct in6_addr)) == 0; | |
| } | |
| TEST_F(LlvmLibcInetPtonTest, ValidIPv6Addresses) { | |
| struct in6_addr addr; | |
| // Unspecified address | |
| EXPECT_EQ(1, LIBC_NAMESPACE::inet_pton(AF_INET6, "::", &addr)); | |
| EXPECT_TRUE(check_ipv6(addr, 0, 0, 0, 0, 0, 0, 0, 0)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| // Loopback address | |
| EXPECT_EQ(1, LIBC_NAMESPACE::inet_pton(AF_INET6, "::1", &addr)); | |
| EXPECT_TRUE(check_ipv6(addr, 0, 0, 0, 0, 0, 0, 0, 1)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| // Full 8 groups without compression | |
| EXPECT_EQ(1, LIBC_NAMESPACE::inet_pton( | |
| AF_INET6, "2001:0db8:85a3:0000:0000:8a2e:0370:7334", &addr)); | |
| EXPECT_TRUE( | |
| check_ipv6(addr, 0x2001, 0x0db8, 0x85a3, 0, 0, 0x8a2e, 0x0370, 0x7334)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| // Full 8 groups with varying digit lengths | |
| EXPECT_EQ(1, LIBC_NAMESPACE::inet_pton( | |
| AF_INET6, "2001:db8:85a3:0:0:8a2e:370:7334", &addr)); | |
| EXPECT_TRUE( | |
| check_ipv6(addr, 0x2001, 0x0db8, 0x85a3, 0, 0, 0x8a2e, 0x0370, 0x7334)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| // Compression at beginning | |
| EXPECT_EQ(1, LIBC_NAMESPACE::inet_pton(AF_INET6, "::1234", &addr)); | |
| EXPECT_TRUE(check_ipv6(addr, 0, 0, 0, 0, 0, 0, 0, 0x1234)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| // Compression at end | |
| EXPECT_EQ(1, LIBC_NAMESPACE::inet_pton(AF_INET6, "fe80::", &addr)); | |
| EXPECT_TRUE(check_ipv6(addr, 0xfe80, 0, 0, 0, 0, 0, 0, 0)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| // Compression in middle | |
| EXPECT_EQ(1, LIBC_NAMESPACE::inet_pton(AF_INET6, "2001:db8::1", &addr)); | |
| EXPECT_TRUE(check_ipv6(addr, 0x2001, 0x0db8, 0, 0, 0, 0, 0, 1)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| // Multiple words before and after compression | |
| EXPECT_EQ(1, LIBC_NAMESPACE::inet_pton( | |
| AF_INET6, "2001:db8:85a3::8a2e:370:7334", &addr)); | |
| EXPECT_TRUE( | |
| check_ipv6(addr, 0x2001, 0x0db8, 0x85a3, 0, 0, 0x8a2e, 0x0370, 0x7334)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| // Case insensitivity | |
| EXPECT_EQ(1, LIBC_NAMESPACE::inet_pton(AF_INET6, "2001:Db8::AbCd", &addr)); | |
| EXPECT_TRUE(check_ipv6(addr, 0x2001, 0x0db8, 0, 0, 0, 0, 0, 0xabcd)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| } | |
| TEST_F(LlvmLibcInetPtonTest, ValidIPv4MappedIPv6Addresses) { | |
| struct in6_addr addr; | |
| // Standard IPv4-mapped address ::ffff:192.168.1.1 | |
| EXPECT_EQ(1, | |
| LIBC_NAMESPACE::inet_pton(AF_INET6, "::ffff:192.168.1.1", &addr)); | |
| EXPECT_TRUE(check_ipv6(addr, 0, 0, 0, 0, 0, 0xffff, 0xc0a8, 0x0101)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| // IPv4-compatible address ::192.168.1.1 | |
| EXPECT_EQ(1, LIBC_NAMESPACE::inet_pton(AF_INET6, "::192.168.1.1", &addr)); | |
| EXPECT_TRUE(check_ipv6(addr, 0, 0, 0, 0, 0, 0, 0xc0a8, 0x0101)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| // Mixed prefix with compression: 2001:db8::192.168.1.1 | |
| EXPECT_EQ( | |
| 1, LIBC_NAMESPACE::inet_pton(AF_INET6, "2001:db8::192.168.1.1", &addr)); | |
| EXPECT_TRUE(check_ipv6(addr, 0x2001, 0x0db8, 0, 0, 0, 0, 0xc0a8, 0x0101)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| // Full 6 words without compression followed by IPv4 | |
| EXPECT_EQ( | |
| 1, LIBC_NAMESPACE::inet_pton(AF_INET6, "0:0:0:0:0:0:192.168.1.1", &addr)); | |
| EXPECT_TRUE(check_ipv6(addr, 0, 0, 0, 0, 0, 0, 0xc0a8, 0x0101)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| } | |
| TEST_F(LlvmLibcInetPtonTest, InvalidIPv6Formats) { | |
| struct in6_addr addr; | |
| // Empty string | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "", &addr)); | |
| // Colon misuse | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, ":", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, ":::", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, ":1:2:3:4:5:6:7:8", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "1:2:3:4:5:6:7:8:", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "1::2:", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "1::2::3", &addr)); | |
| // Word count errors | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "1:2:3:4:5:6:7:8:9", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "1:2:3:4::5:6:7:8", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "1:2:3:4:5:6:7", &addr)); | |
| // Field overflow (> 4 hex digits) | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "12345::1", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "00000::1", &addr)); | |
| // Non-hex characters | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "2001:xyz::1", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "fe80::1%eth0", &addr)); | |
| // Plain IPv4 without :: | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "192.168.1.1", &addr)); | |
| // Embedded IPv4 errors | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "::ffff:192.168.1", &addr)); | |
| EXPECT_EQ(0, | |
| LIBC_NAMESPACE::inet_pton(AF_INET6, "::ffff:192.168.1.256", &addr)); | |
| EXPECT_EQ(0, | |
| LIBC_NAMESPACE::inet_pton(AF_INET6, "::ffff:192.168.1.1:", &addr)); | |
| EXPECT_EQ(0, | |
| LIBC_NAMESPACE::inet_pton(AF_INET6, "::ffff:192.168.01.1", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "1:2:3:4:5:6:7:192.168.1.1", | |
| &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "1:2:3:4:5:6::192.168.1.1", | |
| &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "1::2.3.4.5:6", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "1:2.3.4.5:6", &addr)); | |
| // Hex prefixes and signs | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "0x1234::", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "+1234::", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "-1234::", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "1234g::", &addr)); | |
| // Whitespace | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, " ::1", &addr)); | |
| EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET6, "::1 ", &addr)); | |
| ASSERT_ERRNO_SUCCESS(); | |
| } | |
| TEST_F(LlvmLibcInetPtonTest, InvalidAddressFamily) { | |
| struct in_addr addr; | |
| EXPECT_EQ(-1, LIBC_NAMESPACE::inet_pton(AF_INET + AF_INET6 + 1, "127.0.0.1", | |
| &addr)); | |
| ASSERT_ERRNO_EQ(EAFNOSUPPORT); | |
| EXPECT_EQ(-1, LIBC_NAMESPACE::inet_pton(12345, "127.0.0.1", &addr)); | |
| ASSERT_ERRNO_EQ(EAFNOSUPPORT); | |
| } |