blob: 34f5ba9e7ec4203dd95f173f79d4521126d34a4f [file] [edit]
//===----------------------------------------------------------------------===//
//
// 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/__support/libc_errno.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);
}