Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package aws-c-auth for openSUSE:Factory checked in at 2026-03-20 21:20:16 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/aws-c-auth (Old) and /work/SRC/openSUSE:Factory/.aws-c-auth.new.8177 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "aws-c-auth" Fri Mar 20 21:20:16 2026 rev:26 rq:1341437 version:0.10.1 Changes: -------- --- /work/SRC/openSUSE:Factory/aws-c-auth/aws-c-auth.changes 2026-02-23 16:14:57.263283371 +0100 +++ /work/SRC/openSUSE:Factory/.aws-c-auth.new.8177/aws-c-auth.changes 2026-03-20 21:20:51.012105076 +0100 @@ -1,0 +2,8 @@ +Tue Mar 17 14:21:16 UTC 2026 - John Paul Adrian Glaubitz <[email protected]> + +- Update to version 0.10.1 + * Fix byo crypto by @TingDaoK in (#290) +- from version 0.10.0 + * Support imds endpoint override by @TingDaoK in (#286) + +------------------------------------------------------------------- Old: ---- v0.9.6.tar.gz New: ---- v0.10.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ aws-c-auth.spec ++++++ --- /var/tmp/diff_new_pack.ew5FWH/_old 2026-03-20 21:20:52.708175737 +0100 +++ /var/tmp/diff_new_pack.ew5FWH/_new 2026-03-20 21:20:52.724176404 +0100 @@ -20,7 +20,7 @@ %define library_pkg 1_0_0 %define library_soversion 1 Name: aws-c-auth -Version: 0.9.6 +Version: 0.10.1 Release: 0 Summary: AWS C99 library implementation of AWS client-side authentication License: Apache-2.0 ++++++ v0.9.6.tar.gz -> v0.10.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-auth-0.9.6/include/aws/auth/aws_imds_client.h new/aws-c-auth-0.10.1/include/aws/auth/aws_imds_client.h --- old/aws-c-auth-0.9.6/include/aws/auth/aws_imds_client.h 2026-02-17 20:01:58.000000000 +0100 +++ new/aws-c-auth-0.10.1/include/aws/auth/aws_imds_client.h 2026-03-05 05:18:17.000000000 +0100 @@ -62,6 +62,32 @@ bool ec2_metadata_v1_disabled; /* + * (Optional) Override the default IMDS endpoint. + * If this cursor is empty (ptr == NULL or len == 0), the endpoint will be determined by: + * 1. AWS_EC2_METADATA_SERVICE_ENDPOINT environment variable (if set) + * 2. Default endpoint based on imds_endpoint_mode (IPv4: "http://169.254.169.254", IPv6: "http://[fd00:ec2::254]") + * + * Should be a valid URI string. Supports both HTTP and HTTPS schemes: + * - HTTP: Uses default port 80 if not specified + * - HTTPS: Uses default port 443 if not specified, with automatic TLS configuration + * HTTPS connections use default client TLS settings with SNI hostname set automatically. + * Example: aws_byte_cursor_from_c_str("http://127.0.0.1:8080") + */ + struct aws_byte_cursor imds_endpoint; + + /* + * (Optional) IP address mode for IMDS connections. + * If set to AWS_IMDS_ENDPOINT_MODE_DEFAULT (0), the mode will be determined by: + * 1. AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE environment variable (if set to "IPv4" or "IPv6") + * 2. Default mode (IPv4) + * + * AWS_IMDS_ENDPOINT_MODE_DEFAULT (0) - Use environment variable or default to IPv4 + * AWS_IMDS_ENDPOINT_MODE_IPV4 - Explicitly use IPv4 + * AWS_IMDS_ENDPOINT_MODE_IPV6 - Explicitly use IPv6 + */ + enum aws_imds_endpoint_mode imds_endpoint_mode; + + /* * Table holding all cross-system functional dependencies for an imds client. * * For mocking the http layer in tests, leave NULL otherwise diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-auth-0.9.6/include/aws/auth/credentials.h new/aws-c-auth-0.10.1/include/aws/auth/credentials.h --- old/aws-c-auth-0.9.6/include/aws/auth/credentials.h 2026-02-17 20:01:58.000000000 +0100 +++ new/aws-c-auth-0.10.1/include/aws/auth/credentials.h 2026-03-05 05:18:17.000000000 +0100 @@ -206,6 +206,18 @@ }; /** + * IP address mode for IMDS connections + */ +enum aws_imds_endpoint_mode { + /* Use default behavior (IPv4), or check environment variable if not explicitly set */ + AWS_IMDS_ENDPOINT_MODE_DEFAULT = 0, + /* Explicitly use IPv4 */ + AWS_IMDS_ENDPOINT_MODE_IPV4, + /* Explicitly use IPv6 */ + AWS_IMDS_ENDPOINT_MODE_IPV6, +}; + +/** * Configuration options for the provider that sources credentials from ec2 instance metadata */ struct aws_credentials_provider_imds_options { @@ -234,6 +246,32 @@ * aws_http_credentials_provider.h for more information. */ const struct proxy_env_var_settings *proxy_ev_settings; + + /* + * (Optional) Override the default IMDS endpoint. + * If this cursor is empty (ptr == NULL or len == 0), the endpoint will be determined by: + * 1. AWS_EC2_METADATA_SERVICE_ENDPOINT environment variable (if set) + * 2. Default endpoint based on imds_endpoint_mode (IPv4: "http://169.254.169.254", IPv6: "http://[fd00:ec2::254]") + * + * Should be a valid URI string. Supports both HTTP and HTTPS schemes: + * - HTTP: Uses default port 80 if not specified + * - HTTPS: Uses default port 443 if not specified, with automatic TLS configuration + * HTTPS connections use default client TLS settings with SNI hostname set automatically. + * Example: aws_byte_cursor_from_c_str("http://127.0.0.1:8080") + */ + struct aws_byte_cursor imds_endpoint; + + /* + * (Optional) IP address mode for IMDS connections. + * If set to AWS_IMDS_ENDPOINT_MODE_DEFAULT (0), the mode will be determined by: + * 1. AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE environment variable (if set to "IPv4" or "IPv6") + * 2. Default mode (IPv4) + * + * AWS_IMDS_ENDPOINT_MODE_DEFAULT (0) - Use environment variable or default to IPv4 + * AWS_IMDS_ENDPOINT_MODE_IPV4 - Explicitly use IPv4 + * AWS_IMDS_ENDPOINT_MODE_IPV6 - Explicitly use IPv6 + */ + enum aws_imds_endpoint_mode imds_endpoint_mode; }; /* diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-auth-0.9.6/source/aws_imds_client.c new/aws-c-auth-0.10.1/source/aws_imds_client.c --- old/aws-c-auth-0.9.6/source/aws_imds_client.c 2026-02-17 20:01:58.000000000 +0100 +++ new/aws-c-auth-0.10.1/source/aws_imds_client.c 2026-03-05 05:18:17.000000000 +0100 @@ -7,13 +7,16 @@ #include <aws/auth/private/credentials_utils.h> #include <aws/common/clock.h> #include <aws/common/condition_variable.h> +#include <aws/common/environment.h> #include <aws/common/mutex.h> #include <aws/common/string.h> +#include <aws/common/uri.h> #include <aws/http/connection.h> #include <aws/http/request_response.h> #include <aws/http/status_code.h> #include <aws/io/channel_bootstrap.h> #include <aws/io/socket.h> +#include <aws/io/tls_channel_handler.h> #include <ctype.h> #include <aws/common/json.h> @@ -31,6 +34,11 @@ #define IMDS_DEFAULT_RETRIES 1 AWS_STATIC_STRING_FROM_LITERAL(s_imds_host, "169.254.169.254"); +AWS_STATIC_STRING_FROM_LITERAL(s_imds_host_ipv6, "fd00:ec2::254"); +AWS_STATIC_STRING_FROM_LITERAL(s_ec2_metadata_service_endpoint_env, "AWS_EC2_METADATA_SERVICE_ENDPOINT"); +AWS_STATIC_STRING_FROM_LITERAL(s_ec2_metadata_service_endpoint_mode_env, "AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE"); +static struct aws_byte_cursor s_ec2_metadata_service_endpoint_mode_ipv4 = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("IPv4"); +static struct aws_byte_cursor s_ec2_metadata_service_endpoint_mode_ipv6 = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("IPv6"); enum imds_token_state { AWS_IMDS_TS_INVALID, @@ -69,9 +77,103 @@ struct aws_condition_variable token_signal; bool ec2_metadata_v1_disabled; + /* endpoint configuration - extracted from URI if override was provided */ + struct aws_string *endpoint_host; + uint32_t endpoint_port; + bool endpoint_uses_tls; + struct aws_atomic_var ref_count; }; +/** + * Resolve the IMDS endpoint configuration from options and environment variables for the client. + */ +static void s_resolve_imds_endpoint( + struct aws_imds_client *client, + const struct aws_imds_client_options *options, + enum aws_socket_domain *out_socket_domain) { + + struct aws_allocator *allocator = client->allocator; + enum aws_imds_endpoint_mode endpoint_mode = options->imds_endpoint_mode; + struct aws_uri env_endpoint; + AWS_ZERO_STRUCT(env_endpoint); + bool env_endpoint_initialized = false; + + /* Check environment variables if not explicitly provided in options */ + if (options->imds_endpoint.ptr == NULL || options->imds_endpoint.len == 0) { + struct aws_string *endpoint_env = + aws_get_env_nonempty(allocator, aws_string_c_str(s_ec2_metadata_service_endpoint_env)); + if (endpoint_env) { + /* Parse the endpoint from environment variable */ + struct aws_byte_cursor endpoint_cursor = aws_byte_cursor_from_string(endpoint_env); + if (aws_uri_init_parse(&env_endpoint, allocator, &endpoint_cursor) == AWS_OP_SUCCESS) { + env_endpoint_initialized = true; + } + aws_string_destroy(endpoint_env); + } + } else { + /* Parse the endpoint from options */ + if (aws_uri_init_parse(&env_endpoint, allocator, &options->imds_endpoint) == AWS_OP_SUCCESS) { + env_endpoint_initialized = true; + } + } + + /* Only check environment variable if mode is DEFAULT */ + if (endpoint_mode == AWS_IMDS_ENDPOINT_MODE_DEFAULT) { + struct aws_string *mode_env = + aws_get_env_nonempty(allocator, aws_string_c_str(s_ec2_metadata_service_endpoint_mode_env)); + if (mode_env) { + struct aws_byte_cursor mode_cursor = aws_byte_cursor_from_string(mode_env); + if (aws_byte_cursor_eq_ignore_case(&mode_cursor, &s_ec2_metadata_service_endpoint_mode_ipv6)) { + endpoint_mode = AWS_IMDS_ENDPOINT_MODE_IPV6; + } else if (aws_byte_cursor_eq_ignore_case(&mode_cursor, &s_ec2_metadata_service_endpoint_mode_ipv4)) { + endpoint_mode = AWS_IMDS_ENDPOINT_MODE_IPV4; + } + /* If environment variable is set but not valid, keep DEFAULT (which becomes IPv4) */ + aws_string_destroy(mode_env); + } + } + + /* Map endpoint mode to socket domain - DEFAULT and IPV4 both use IPv4 */ + *out_socket_domain = (endpoint_mode == AWS_IMDS_ENDPOINT_MODE_IPV6) ? AWS_SOCKET_IPV6 : AWS_SOCKET_IPV4; + + /* Determine the host cursor based on whether custom endpoint is provided */ + struct aws_byte_cursor host_cursor_from_source; + if (env_endpoint_initialized) { + /* Extract host, port, and scheme from provided URI */ + host_cursor_from_source = *aws_uri_host_name(&env_endpoint); + client->endpoint_port = aws_uri_port(&env_endpoint); + + /* Check the scheme to determine if TLS should be used */ + struct aws_byte_cursor scheme_cursor = *aws_uri_scheme(&env_endpoint); + if (aws_byte_cursor_eq_c_str_ignore_case(&scheme_cursor, "https")) { + client->endpoint_uses_tls = true; + if (client->endpoint_port == 0) { + client->endpoint_port = 443; /* Default HTTPS port */ + } + } else { + client->endpoint_uses_tls = false; + if (client->endpoint_port == 0) { + client->endpoint_port = 80; /* Default HTTP port */ + } + } + client->endpoint_host = aws_string_new_from_cursor(allocator, &host_cursor_from_source); + } else { + /* Use default endpoint (HTTP) - IPv4 or IPv6 based on endpoint mode */ + if (endpoint_mode == AWS_IMDS_ENDPOINT_MODE_IPV6) { + client->endpoint_host = aws_string_clone_or_reuse(allocator, s_imds_host_ipv6); + } else { + client->endpoint_host = aws_string_clone_or_reuse(allocator, s_imds_host); + } + client->endpoint_port = 80; + client->endpoint_uses_tls = false; + } + /* Clean up environment endpoint if it was initialized */ + if (env_endpoint_initialized) { + aws_uri_clean_up(&env_endpoint); + } +} + static void s_aws_imds_client_destroy(struct aws_imds_client *client) { if (!client) { return; @@ -84,6 +186,10 @@ aws_condition_variable_clean_up(&client->token_signal); aws_mutex_clean_up(&client->token_lock); aws_byte_buf_clean_up(&client->cached_token); + + /* Clean up endpoint host if we allocated it */ + aws_string_destroy(client->endpoint_host); + client->function_table->aws_http_connection_manager_release(client->connection_manager); /* freeing the client takes place in the shutdown callback below */ } @@ -128,6 +234,8 @@ return NULL; } + struct aws_tls_connection_options tls_connection_options; + AWS_ZERO_STRUCT(tls_connection_options); if (aws_mutex_init(&client->token_lock)) { goto on_error; } @@ -150,10 +258,15 @@ client->ec2_metadata_v1_disabled = options->ec2_metadata_v1_disabled; client->shutdown_options = options->shutdown_options; + /* Resolve endpoint configuration using helper function */ + enum aws_socket_domain socket_domain; + + s_resolve_imds_endpoint(client, options, &socket_domain); + struct aws_socket_options socket_options; AWS_ZERO_STRUCT(socket_options); socket_options.type = AWS_SOCKET_STREAM; - socket_options.domain = AWS_SOCKET_IPV4; + socket_options.domain = socket_domain; socket_options.connect_timeout_ms = (uint32_t)aws_timestamp_convert( IMDS_CONNECT_TIMEOUT_DEFAULT_IN_SECONDS, AWS_TIMESTAMP_SECS, AWS_TIMESTAMP_MILLIS, NULL); @@ -163,13 +276,43 @@ manager_options.initial_window_size = IMDS_RESPONSE_SIZE_LIMIT; manager_options.socket_options = &socket_options; manager_options.tls_connection_options = NULL; - manager_options.host = aws_byte_cursor_from_string(s_imds_host); - manager_options.port = 80; + manager_options.host = aws_byte_cursor_from_string(client->endpoint_host); + manager_options.port = client->endpoint_port; manager_options.max_connections = 10; manager_options.shutdown_complete_callback = s_on_connection_manager_shutdown; manager_options.shutdown_complete_user_data = client; manager_options.proxy_ev_settings = options->proxy_ev_settings; + /* Initialize TLS if HTTPS is being used */ + if (client->endpoint_uses_tls) { +#ifdef BYO_CRYPTO + aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); + AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "TLS IMDS endpoint is not supported."); + goto on_error; +#else + struct aws_tls_ctx_options tls_ctx_options; + aws_tls_ctx_options_init_default_client(&tls_ctx_options, allocator); + + struct aws_tls_ctx *tls_ctx = aws_tls_client_ctx_new(allocator, &tls_ctx_options); + aws_tls_ctx_options_clean_up(&tls_ctx_options); + + if (!tls_ctx) { + AWS_LOGF_ERROR(AWS_LS_IMDS_CLIENT, "Failed to create TLS context for HTTPS endpoint"); + goto on_error; + } + + aws_tls_connection_options_init_from_ctx(&tls_connection_options, tls_ctx); + aws_tls_ctx_release(tls_ctx); + + /* Set hostname for TLS */ + struct aws_byte_cursor server_name = aws_byte_cursor_from_string(client->endpoint_host); + if (aws_tls_connection_options_set_server_name(&tls_connection_options, allocator, &server_name)) { + AWS_LOGF_ERROR(AWS_LS_IMDS_CLIENT, "Failed to set SNI hostname for TLS connection"); + goto on_error; + } +#endif /* BYO_CRYPTO */ + } + client->connection_manager = client->function_table->aws_http_connection_manager_new(allocator, &manager_options); if (!client->connection_manager) { goto on_error; @@ -191,9 +334,11 @@ goto on_error; } + aws_tls_connection_options_clean_up(&tls_connection_options); return client; on_error: + aws_tls_connection_options_clean_up(&tls_connection_options); s_aws_imds_client_destroy(client); return NULL; } @@ -428,9 +573,10 @@ goto on_error; } + /* Use the endpoint host stored in the client (source of truth) */ struct aws_http_header host_header = { .name = aws_byte_cursor_from_string(s_imds_host_header), - .value = aws_byte_cursor_from_string(s_imds_host), + .value = aws_byte_cursor_from_string(client->endpoint_host), }; if (aws_http_message_add_header(request, host_header)) { goto on_error; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-auth-0.9.6/source/credentials_provider_imds.c new/aws-c-auth-0.10.1/source/credentials_provider_imds.c --- old/aws-c-auth-0.9.6/source/credentials_provider_imds.c 2026-02-17 20:01:58.000000000 +0100 +++ new/aws-c-auth-0.10.1/source/credentials_provider_imds.c 2026-03-05 05:18:17.000000000 +0100 @@ -91,6 +91,8 @@ .shutdown_user_data = provider, }, .proxy_ev_settings = options->proxy_ev_settings, + .imds_endpoint = options->imds_endpoint, + .imds_endpoint_mode = options->imds_endpoint_mode, }; impl->client = aws_imds_client_new(allocator, &client_options); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-auth-0.9.6/tests/CMakeLists.txt new/aws-c-auth-0.10.1/tests/CMakeLists.txt --- old/aws-c-auth-0.9.6/tests/CMakeLists.txt 2026-02-17 20:01:58.000000000 +0100 +++ new/aws-c-auth-0.10.1/tests/CMakeLists.txt 2026-03-05 05:18:17.000000000 +0100 @@ -42,6 +42,8 @@ add_test_case(credentials_provider_imds_success_multi_part_doc) add_test_case(credentials_provider_imds_real_new_destroy) add_net_test_case(credentials_provider_imds_proxy_routing_enabled_test) +add_test_case(credentials_provider_imds_ipv6_endpoint_mode) +add_test_case(credentials_provider_imds_custom_endpoint) if(AWS_BUILDING_ON_EC2) add_test_case(credentials_provider_imds_real_success) @@ -206,6 +208,9 @@ add_test_case(imds_client_get_instance_info_success) add_test_case(imds_client_get_credentials_success) add_test_case(imds_client_cache_token_refresh) +add_test_case(imds_client_ipv4_endpoint_mode) +add_test_case(imds_client_ipv6_endpoint_mode) +add_test_case(imds_client_custom_endpoint) if(AWS_BUILDING_ON_EC2) add_test_case(imds_client_real_success) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-auth-0.9.6/tests/aws_imds_client_test.c new/aws-c-auth-0.10.1/tests/aws_imds_client_test.c --- old/aws-c-auth-0.9.6/tests/aws_imds_client_test.c 2026-02-17 20:01:58.000000000 +0100 +++ new/aws-c-auth-0.10.1/tests/aws_imds_client_test.c 2026-03-05 05:18:17.000000000 +0100 @@ -52,6 +52,11 @@ struct aws_byte_buf resource; int successful_requests; + + /* Endpoint verification fields */ + struct aws_byte_buf expected_host; + uint16_t expected_port; + bool verify_endpoint_host; }; static struct aws_mock_imds_client_tester s_tester; @@ -83,7 +88,26 @@ const struct aws_http_connection_manager_options *options) { (void)allocator; - (void)options; + + /* Verify endpoint configuration if verification is enabled */ + if (s_tester.verify_endpoint_host) { + struct aws_byte_cursor expected_host_cursor = aws_byte_cursor_from_buf(&s_tester.expected_host); + if (!aws_byte_cursor_eq(&options->host, &expected_host_cursor)) { + AWS_LOGF_ERROR( + AWS_LS_IMDS_CLIENT, + "Host mismatch: expected '" PRInSTR "' but got '" PRInSTR "'", + AWS_BYTE_CURSOR_PRI(expected_host_cursor), + AWS_BYTE_CURSOR_PRI(options->host)); + /* Fail the test */ + AWS_FATAL_ASSERT(false); + } + if (options->port != s_tester.expected_port) { + AWS_LOGF_ERROR( + AWS_LS_IMDS_CLIENT, "Port mismatch: expected %d but got %d", s_tester.expected_port, options->port); + /* Fail the test */ + AWS_FATAL_ASSERT(false); + } + } return (struct aws_http_connection_manager *)1; } @@ -295,6 +319,11 @@ aws_event_loop_group_release(s_tester.el_group); aws_byte_buf_clean_up(&s_tester.resource); + /* Clean up endpoint verification buffer if it was used */ + if (s_tester.expected_host.buffer) { + aws_byte_buf_clean_up(&s_tester.expected_host); + } + aws_auth_library_clean_up(); return AWS_OP_SUCCESS; @@ -1021,7 +1050,7 @@ struct aws_client_bootstrap *bootstrap = aws_client_bootstrap_new(allocator, &bootstrap_options); struct aws_imds_client_options options = { - .bootstrap = s_tester.bootstrap, + .bootstrap = bootstrap, .shutdown_options = { .shutdown_callback = s_on_shutdown_complete, @@ -1551,3 +1580,156 @@ return 0; } AWS_TEST_CASE(imds_client_cache_token_refresh, s_imds_client_cache_token_refresh); + +static int s_imds_client_ipv4_endpoint_mode(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + + s_aws_imds_tester_init(allocator); + + struct aws_byte_cursor test_token_cursor = aws_byte_cursor_from_string(s_test_imds_token); + aws_array_list_push_back(&s_tester.response_data_callbacks[0], &test_token_cursor); + + struct aws_byte_cursor good_response_cursor = aws_byte_cursor_from_string(s_good_response); + aws_array_list_push_back(&s_tester.response_data_callbacks[1], &good_response_cursor); + + /* Enable endpoint verification for IPv4 default endpoint */ + s_tester.verify_endpoint_host = true; + aws_byte_buf_init(&s_tester.expected_host, allocator, 20); + struct aws_byte_cursor host_cursor = aws_byte_cursor_from_c_str("169.254.169.254"); + aws_byte_buf_append_dynamic(&s_tester.expected_host, &host_cursor); + s_tester.expected_port = 80; + + struct aws_imds_client_options options = { + .bootstrap = s_tester.bootstrap, + .function_table = &s_mock_function_table, + .imds_endpoint_mode = AWS_IMDS_ENDPOINT_MODE_IPV4, + .shutdown_options = + { + .shutdown_callback = s_on_shutdown_complete, + .shutdown_user_data = NULL, + }, + }; + + struct aws_imds_client *client = aws_imds_client_new(allocator, &options); + ASSERT_NOT_NULL(client); + + aws_imds_client_get_resource_async( + client, aws_byte_cursor_from_string(s_expected_imds_resource_uri), s_get_resource_callback, NULL); + + s_aws_wait_for_resource_result(); + + ASSERT_TRUE(s_validate_uri_path_and_resource(2, true /*got resource*/) == 0); + ASSERT_CURSOR_VALUE_STRING_EQUALS(aws_byte_cursor_from_buf(&s_tester.resource), s_good_response); + + aws_imds_client_release(client); + s_aws_wait_for_imds_client_shutdown_callback(); + aws_mem_release(allocator, client); + + ASSERT_SUCCESS(s_aws_imds_tester_cleanup()); + + return 0; +} + +AWS_TEST_CASE(imds_client_ipv4_endpoint_mode, s_imds_client_ipv4_endpoint_mode); + +static int s_imds_client_ipv6_endpoint_mode(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + + s_aws_imds_tester_init(allocator); + + struct aws_byte_cursor test_token_cursor = aws_byte_cursor_from_string(s_test_imds_token); + aws_array_list_push_back(&s_tester.response_data_callbacks[0], &test_token_cursor); + + struct aws_byte_cursor good_response_cursor = aws_byte_cursor_from_string(s_good_response); + aws_array_list_push_back(&s_tester.response_data_callbacks[1], &good_response_cursor); + + /* Enable endpoint verification for IPv6 default endpoint */ + s_tester.verify_endpoint_host = true; + aws_byte_buf_init(&s_tester.expected_host, allocator, 20); + struct aws_byte_cursor host_cursor = aws_byte_cursor_from_c_str("fd00:ec2::254"); + aws_byte_buf_append_dynamic(&s_tester.expected_host, &host_cursor); + s_tester.expected_port = 80; + + struct aws_imds_client_options options = { + .bootstrap = s_tester.bootstrap, + .function_table = &s_mock_function_table, + .imds_endpoint_mode = AWS_IMDS_ENDPOINT_MODE_IPV6, + .shutdown_options = + { + .shutdown_callback = s_on_shutdown_complete, + .shutdown_user_data = NULL, + }, + }; + + struct aws_imds_client *client = aws_imds_client_new(allocator, &options); + ASSERT_NOT_NULL(client); + + aws_imds_client_get_resource_async( + client, aws_byte_cursor_from_string(s_expected_imds_resource_uri), s_get_resource_callback, NULL); + + s_aws_wait_for_resource_result(); + + ASSERT_TRUE(s_validate_uri_path_and_resource(2, true /*got resource*/) == 0); + ASSERT_CURSOR_VALUE_STRING_EQUALS(aws_byte_cursor_from_buf(&s_tester.resource), s_good_response); + + aws_imds_client_release(client); + s_aws_wait_for_imds_client_shutdown_callback(); + aws_mem_release(allocator, client); + + ASSERT_SUCCESS(s_aws_imds_tester_cleanup()); + + return 0; +} + +AWS_TEST_CASE(imds_client_ipv6_endpoint_mode, s_imds_client_ipv6_endpoint_mode); + +static int s_imds_client_custom_endpoint(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + + s_aws_imds_tester_init(allocator); + + struct aws_byte_cursor test_token_cursor = aws_byte_cursor_from_string(s_test_imds_token); + aws_array_list_push_back(&s_tester.response_data_callbacks[0], &test_token_cursor); + + struct aws_byte_cursor good_response_cursor = aws_byte_cursor_from_string(s_good_response); + aws_array_list_push_back(&s_tester.response_data_callbacks[1], &good_response_cursor); + + /* Enable endpoint verification */ + s_tester.verify_endpoint_host = true; + aws_byte_buf_init(&s_tester.expected_host, allocator, 20); + struct aws_byte_cursor host_cursor = aws_byte_cursor_from_c_str("127.0.0.1"); + aws_byte_buf_append_dynamic(&s_tester.expected_host, &host_cursor); + s_tester.expected_port = 8080; + + struct aws_imds_client_options options = { + .bootstrap = s_tester.bootstrap, + .function_table = &s_mock_function_table, + .imds_endpoint = aws_byte_cursor_from_c_str("http://127.0.0.1:8080"), + .shutdown_options = + { + .shutdown_callback = s_on_shutdown_complete, + .shutdown_user_data = NULL, + }, + }; + + struct aws_imds_client *client = aws_imds_client_new(allocator, &options); + ASSERT_NOT_NULL(client); + + aws_imds_client_get_resource_async( + client, aws_byte_cursor_from_string(s_expected_imds_resource_uri), s_get_resource_callback, NULL); + + s_aws_wait_for_resource_result(); + + ASSERT_TRUE(s_validate_uri_path_and_resource(2, true /*got resource*/) == 0); + ASSERT_CURSOR_VALUE_STRING_EQUALS(aws_byte_cursor_from_buf(&s_tester.resource), s_good_response); + + aws_imds_client_release(client); + s_aws_wait_for_imds_client_shutdown_callback(); + aws_mem_release(allocator, client); + + ASSERT_SUCCESS(s_aws_imds_tester_cleanup()); + + return 0; +} + +AWS_TEST_CASE(imds_client_custom_endpoint, s_imds_client_custom_endpoint); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-auth-0.9.6/tests/credentials_provider_imds_tests.c new/aws-c-auth-0.10.1/tests/credentials_provider_imds_tests.c --- old/aws-c-auth-0.9.6/tests/credentials_provider_imds_tests.c 2026-02-17 20:01:58.000000000 +0100 +++ new/aws-c-auth-0.10.1/tests/credentials_provider_imds_tests.c 2026-03-05 05:18:17.000000000 +0100 @@ -65,6 +65,11 @@ bool alternate_closed_connections; struct proxy_env_var_settings *proxy_config; + + /* Endpoint verification fields */ + struct aws_byte_buf expected_host; + uint16_t expected_port; + bool verify_endpoint_host; }; static struct aws_mock_imds_tester s_tester; @@ -100,7 +105,26 @@ const struct aws_http_connection_manager_options *options) { (void)allocator; - (void)options; + + /* Verify endpoint configuration if verification is enabled */ + if (s_tester.verify_endpoint_host) { + struct aws_byte_cursor expected_host_cursor = aws_byte_cursor_from_buf(&s_tester.expected_host); + if (!aws_byte_cursor_eq(&options->host, &expected_host_cursor)) { + AWS_LOGF_ERROR( + AWS_LS_IMDS_CLIENT, + "Host mismatch: expected '" PRInSTR "' but got '" PRInSTR "'", + AWS_BYTE_CURSOR_PRI(expected_host_cursor), + AWS_BYTE_CURSOR_PRI(options->host)); + /* Fail the test */ + AWS_FATAL_ASSERT(false); + } + if (options->port != s_tester.expected_port) { + AWS_LOGF_ERROR( + AWS_LS_IMDS_CLIENT, "Port mismatch: expected %d but got %d", s_tester.expected_port, options->port); + /* Fail the test */ + AWS_FATAL_ASSERT(false); + } + } if (s_tester.proxy_config != NULL) { AWS_FATAL_ASSERT(options->proxy_ev_settings->env_var_type == s_tester.proxy_config->env_var_type); @@ -313,6 +337,11 @@ aws_client_bootstrap_release(s_tester.bootstrap); aws_event_loop_group_release(s_tester.el_group); + /* Clean up endpoint verification buffer if it was used */ + if (s_tester.expected_host.buffer) { + aws_byte_buf_clean_up(&s_tester.expected_host); + } + aws_auth_library_clean_up(); return AWS_OP_SUCCESS; @@ -1244,3 +1273,119 @@ AWS_TEST_CASE( credentials_provider_imds_proxy_routing_enabled_test, s_credentials_provider_imds_proxy_routing_enabled_test); + +static int s_credentials_provider_imds_ipv6_endpoint_mode(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + + s_aws_imds_tester_init(allocator); + + struct aws_byte_cursor test_token_cursor = aws_byte_cursor_from_string(s_test_imds_token); + aws_array_list_push_back(&s_tester.response_data_callbacks[0], &test_token_cursor); + + struct aws_byte_cursor test_role_cursor = aws_byte_cursor_from_string(s_test_role_response); + aws_array_list_push_back(&s_tester.response_data_callbacks[1], &test_role_cursor); + + struct aws_byte_cursor good_response_cursor = aws_byte_cursor_from_string(s_good_response); + aws_array_list_push_back(&s_tester.response_data_callbacks[2], &good_response_cursor); + + /* Enable endpoint verification for IPv4 default endpoint */ + s_tester.verify_endpoint_host = true; + aws_byte_buf_init(&s_tester.expected_host, allocator, 20); + struct aws_byte_cursor host_cursor = aws_byte_cursor_from_c_str("fd00:ec2::254"); + aws_byte_buf_append_dynamic(&s_tester.expected_host, &host_cursor); + s_tester.expected_port = 80; + + struct aws_credentials_provider_imds_options options = { + .bootstrap = s_tester.bootstrap, + .function_table = &s_mock_function_table, + .imds_endpoint_mode = AWS_IMDS_ENDPOINT_MODE_IPV6, + .shutdown_options = + { + .shutdown_callback = s_on_shutdown_complete, + .shutdown_user_data = NULL, + }, + }; + + struct aws_credentials_provider *provider = aws_credentials_provider_new_imds(allocator, &options); + ASSERT_NOT_NULL(provider); + + aws_credentials_provider_get_credentials(provider, s_get_credentials_callback, NULL); + + s_aws_wait_for_credentials_result(); + + ASSERT_TRUE(s_validate_uri_path_and_creds(3, true /*got creds*/) == 0); + ASSERT_SUCCESS(s_verify_credentials(s_tester.credentials)); + + aws_credentials_provider_release(provider); + + s_aws_wait_for_provider_shutdown_callback(); + + /* Because we mock the http connection manager, we never get a callback back from it */ + struct aws_credentials_provider_imds_impl *impl = provider->impl; + aws_mem_release(provider->allocator, impl->client); + aws_mem_release(provider->allocator, provider); + + ASSERT_SUCCESS(s_aws_imds_tester_cleanup()); + + return 0; +} + +AWS_TEST_CASE(credentials_provider_imds_ipv6_endpoint_mode, s_credentials_provider_imds_ipv6_endpoint_mode); + +static int s_credentials_provider_imds_custom_endpoint(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + + s_aws_imds_tester_init(allocator); + + struct aws_byte_cursor test_token_cursor = aws_byte_cursor_from_string(s_test_imds_token); + aws_array_list_push_back(&s_tester.response_data_callbacks[0], &test_token_cursor); + + struct aws_byte_cursor test_role_cursor = aws_byte_cursor_from_string(s_test_role_response); + aws_array_list_push_back(&s_tester.response_data_callbacks[1], &test_role_cursor); + + struct aws_byte_cursor good_response_cursor = aws_byte_cursor_from_string(s_good_response); + aws_array_list_push_back(&s_tester.response_data_callbacks[2], &good_response_cursor); + + /* Enable endpoint verification */ + s_tester.verify_endpoint_host = true; + aws_byte_buf_init(&s_tester.expected_host, allocator, 20); + struct aws_byte_cursor host_cursor = aws_byte_cursor_from_c_str("127.0.0.1"); + aws_byte_buf_append_dynamic(&s_tester.expected_host, &host_cursor); + s_tester.expected_port = 8080; + + struct aws_credentials_provider_imds_options options = { + .bootstrap = s_tester.bootstrap, + .function_table = &s_mock_function_table, + .imds_endpoint = aws_byte_cursor_from_c_str("http://127.0.0.1:8080"), + .shutdown_options = + { + .shutdown_callback = s_on_shutdown_complete, + .shutdown_user_data = NULL, + }, + }; + + struct aws_credentials_provider *provider = aws_credentials_provider_new_imds(allocator, &options); + ASSERT_NOT_NULL(provider); + + aws_credentials_provider_get_credentials(provider, s_get_credentials_callback, NULL); + + s_aws_wait_for_credentials_result(); + + ASSERT_TRUE(s_validate_uri_path_and_creds(3, true /*got creds*/) == 0); + ASSERT_SUCCESS(s_verify_credentials(s_tester.credentials)); + + aws_credentials_provider_release(provider); + + s_aws_wait_for_provider_shutdown_callback(); + + /* Because we mock the http connection manager, we never get a callback back from it */ + struct aws_credentials_provider_imds_impl *impl = provider->impl; + aws_mem_release(provider->allocator, impl->client); + aws_mem_release(provider->allocator, provider); + + ASSERT_SUCCESS(s_aws_imds_tester_cleanup()); + + return 0; +} + +AWS_TEST_CASE(credentials_provider_imds_custom_endpoint, s_credentials_provider_imds_custom_endpoint);
