Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move is ipv4/ipv6 functions from Aws-c-sdkutils to Aws-c-common #1105

Merged
merged 11 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions include/aws/common/host_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef AWS_COMMON_HOST_UTILS_H
#define AWS_COMMON_HOST_UTILS_H
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/common/common.h>

struct aws_byte_cursor;

AWS_PUSH_SANE_WARNING_LEVEL
AWS_EXTERN_C_BEGIN

/*
* Determine whether host cursor is IPv4 string.
*/
AWS_COMMON_API bool aws_host_utils_is_ipv4(struct aws_byte_cursor host);

/*
* Determine whether host cursor is IPv6 string.
* Supports checking for uri encoded strings and scoped literals.
*/
AWS_COMMON_API bool aws_host_utils_is_ipv6(struct aws_byte_cursor host, bool is_uri_encoded);

AWS_EXTERN_C_END
AWS_POP_SANE_WARNING_LEVEL

#endif /* AWS_COMMON_HOST_UTILS_H */
127 changes: 127 additions & 0 deletions source/host_utils.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/common/host_utils.h>
#include <aws/common/string.h>
#include <inttypes.h>

#ifdef _MSC_VER /* Disable sscanf warnings on windows. */
# pragma warning(disable : 4204)
# pragma warning(disable : 4706)
# pragma warning(disable : 4996)
#endif

/* 4 octets of 3 chars max + 3 separators + null terminator */
#define AWS_IPV4_STR_LEN 16
#define IP_CHAR_FMT "%03" SCNu16

static bool s_is_ipv6_char(uint8_t value) {
return aws_isxdigit(value) || value == ':';
}

static bool s_starts_with(struct aws_byte_cursor cur, uint8_t ch) {
return cur.len > 0 && cur.ptr[0] == ch;
}

static bool s_ends_with(struct aws_byte_cursor cur, uint8_t ch) {
return cur.len > 0 && cur.ptr[cur.len - 1] == ch;
}

bool aws_host_utils_is_ipv4(struct aws_byte_cursor host) {
if (host.len > AWS_IPV4_STR_LEN - 1) {
return false;
}

char copy[AWS_IPV4_STR_LEN] = {0};
memcpy(copy, host.ptr, host.len);

uint16_t octet[4] = {0};
char remainder[2] = {0};
if (4 != sscanf(
copy,
IP_CHAR_FMT "." IP_CHAR_FMT "." IP_CHAR_FMT "." IP_CHAR_FMT "%1s",
&octet[0],
&octet[1],
&octet[2],
&octet[3],
remainder)) {
return false;
}

for (size_t i = 0; i < 4; ++i) {
if (octet[i] > 255) {
return false;
}
}

return true;
}

/* actual encoding is %25, but % is omitted for simplicity, since split removes it */
static struct aws_byte_cursor s_percent_uri_enc = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("25");
/*
* IPv6 format:
* 8 groups of 4 hex chars separated by colons (:)
* leading 0s in each group can be skipped
* 2 or more consecutive zero groups can be replaced by double colon (::),
* but only once.
* ipv6 literal can be scoped by to zone by appending % followed by zone name
* ( does not look like there is length reqs on zone name length. this
* implementation enforces that its > 1 )
* ipv6 can be embedded in url, in which case it must be wrapped inside []
* and % be uri encoded as %25.
* Implementation is fairly trivial and just iterates through the string
* keeping track of the spec above.
*/
bool aws_host_utils_is_ipv6(struct aws_byte_cursor host, bool is_uri_encoded) {
if (host.len == 0) {
return false;
}

if (is_uri_encoded) {
if (!s_starts_with(host, '[') || !s_ends_with(host, ']')) {
return false;
}
aws_byte_cursor_advance(&host, 1);
--host.len;
}

struct aws_byte_cursor substr = {0};
/* first split is required ipv6 part */
bool is_split = aws_byte_cursor_next_split(&host, '%', &substr);
AWS_ASSERT(is_split); /* function is guaranteed to return at least one split */

if (!is_split || substr.len == 0 || s_ends_with(substr, ':') ||
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To fix the ::1 case:
Changes made:
removed _starts_with(substr,':') condition here.

!aws_byte_cursor_satisfies_pred(&substr, s_is_ipv6_char)) {
return false;
}

uint8_t group_count = 0;
bool has_double_colon = false;
struct aws_byte_cursor group = {0};
while (aws_byte_cursor_next_split(&substr, ':', &group)) {
++group_count;

if (group_count > 8 || /* too many groups */
group.len > 4 || /* too many chars in group */
(has_double_colon && group.len == 0 && group_count > 2)) { /* only one double colon allowed */
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To fix the ::1 case:
Changes made:
Added the group_count>2 condition here.

return false;
}

has_double_colon = has_double_colon || group.len == 0;
}

/* second split is optional zone part */
if (aws_byte_cursor_next_split(&host, '%', &substr)) {
if ((is_uri_encoded &&
(substr.len < 3 ||
!aws_byte_cursor_starts_with(&substr, &s_percent_uri_enc))) || /* encoding for % + 1 extra char */
(!is_uri_encoded && substr.len == 0) || /* at least 1 char */
!aws_byte_cursor_satisfies_pred(&substr, aws_isalnum)) {
return false;
}
}

return has_double_colon ? group_count < 7 : group_count == 8;
}
2 changes: 2 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,8 @@ add_test_case(test_cross_process_lock_works_cross_proc)
add_test_case(cross_process_lock_mp_test_runner)
add_test_case(test_cross_process_lock_invalid_nonce_fails)

add_test_case(host_util_is_ipv4)
add_test_case(host_util_is_ipv6)

generate_test_driver(${PROJECT_NAME}-tests)

Expand Down
74 changes: 74 additions & 0 deletions tests/host_util_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/

#include <aws/common/byte_buf.h>
#include <aws/common/host_utils.h>
#include <aws/testing/aws_test_harness.h>

AWS_TEST_CASE(host_util_is_ipv4, s_test_is_ipv4)
static int s_test_is_ipv4(struct aws_allocator *allocator, void *ctx) {
(void)allocator;
(void)ctx;

ASSERT_TRUE(aws_host_utils_is_ipv4(aws_byte_cursor_from_c_str("0.0.0.0")));
ASSERT_TRUE(aws_host_utils_is_ipv4(aws_byte_cursor_from_c_str("127.0.0.1")));
ASSERT_TRUE(aws_host_utils_is_ipv4(aws_byte_cursor_from_c_str("255.255.255.255")));
ASSERT_TRUE(aws_host_utils_is_ipv4(aws_byte_cursor_from_c_str("192.168.1.1")));

ASSERT_FALSE(aws_host_utils_is_ipv4(aws_byte_cursor_from_c_str("256.0.0.1")));
ASSERT_FALSE(aws_host_utils_is_ipv4(aws_byte_cursor_from_c_str("127.0.0")));
ASSERT_FALSE(aws_host_utils_is_ipv4(aws_byte_cursor_from_c_str("127.0")));
ASSERT_FALSE(aws_host_utils_is_ipv4(aws_byte_cursor_from_c_str("127")));
ASSERT_FALSE(aws_host_utils_is_ipv4(aws_byte_cursor_from_c_str("")));

ASSERT_FALSE(aws_host_utils_is_ipv4(aws_byte_cursor_from_c_str("foo.com")));
ASSERT_FALSE(aws_host_utils_is_ipv4(aws_byte_cursor_from_c_str("a.b.c.d")));
ASSERT_FALSE(aws_host_utils_is_ipv4(aws_byte_cursor_from_c_str("a127.0.0.1")));
ASSERT_FALSE(aws_host_utils_is_ipv4(aws_byte_cursor_from_c_str("127.0.0.1a")));
ASSERT_FALSE(aws_host_utils_is_ipv4(aws_byte_cursor_from_c_str("127.0.0.1011")));

return AWS_OP_SUCCESS;
}

AWS_TEST_CASE(host_util_is_ipv6, s_test_is_ipv6)
static int s_test_is_ipv6(struct aws_allocator *allocator, void *ctx) {
(void)allocator;
(void)ctx;

ASSERT_TRUE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("0:0:0000:0000:0000:0:0:0"), false));
ASSERT_TRUE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("2001:0db8:0000:0000:0000:8a2e:0370:7334"), false));
ASSERT_TRUE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("2001:0DB8:0000:0000:0000:8a2e:0370:7334"), false));
ASSERT_TRUE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("fe80::1"), false));
ASSERT_TRUE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("fe80::1%en0"), false));
ASSERT_TRUE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("::1"), false));
ASSERT_TRUE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("0:0:0:0:0:0:0:1"), false));
ASSERT_TRUE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("fd00:ec2::23"), false));
ASSERT_TRUE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("fd00:ec2:0:0:0:0:0:23"), false));
ASSERT_TRUE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("[2001:0db8:0000:0000:0000:8a2e:0370:7334]"), true));
ASSERT_TRUE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("[fe80::1]"), true));
ASSERT_TRUE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("[fe80::1%25en0]"), true));
ASSERT_TRUE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("[2001:db8:85a3:8d3:1319:8a2e:370:7348]"), true));

ASSERT_FALSE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("2001:0db8:0000:0000:0000:8a2e:0370"), false));
ASSERT_FALSE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("2001:0db8:0000:0000:0000:8a2e:0370:"), false));
ASSERT_FALSE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("2001::"), false));
ASSERT_FALSE(
aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("2001:0db8:0000:0000:0000:8a2e:0370:7334:8745"), false));
ASSERT_FALSE(
aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str(":2001:0db8:0000:0000:0000:8a2e:0370:7334:8745"), false));
ASSERT_FALSE(
aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("z001:0db8:0000:0000:0000:8a2e:0370:7334:8745"), false));
ASSERT_FALSE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("z001::8a2e::8745"), false));
ASSERT_FALSE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("::2001:0db8:0000:0000:8a2e:0370:7334"), false));

ASSERT_FALSE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("fe80::1%25en0"), true));
ASSERT_FALSE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("[fe80::1%en0]"), true));
ASSERT_FALSE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("[fe80::1%24en0]"), true));
ASSERT_FALSE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("[fe80::1%25en0"), true));
ASSERT_FALSE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("fe80::1%25en0]"), true));
ASSERT_FALSE(aws_host_utils_is_ipv6(aws_byte_cursor_from_c_str("[fe80::1%25]"), true));

return AWS_OP_SUCCESS;
}
Loading