Skip to content
Open
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
61 changes: 50 additions & 11 deletions src/aws/flb_aws_credentials_http.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@
#include <fluent-bit/flb_aws_credentials.h>
#include <fluent-bit/flb_aws_util.h>
#include <fluent-bit/flb_utils.h>
#include <fluent-bit/flb_compat.h>

#ifdef FLB_SYSTEM_WINDOWS
#include <ws2tcpip.h>
#endif

#include <fluent-bit/flb_jsmn.h>
#include <stdlib.h>
Expand Down Expand Up @@ -63,22 +68,44 @@ does not satisfy any of the following conditions:
is within the loopback CIDR (IPv4 127.0.0.0/8, IPv6 ::1/128)
is the ECS container host 169.254.170.2
is the EKS container host (IPv4 169.254.170.23, IPv6 fd00:ec2::23)
is localhost with Greengrass credential provider path (/2016-11-01/credentialprovider/)*/
is localhost with Greengrass credential provider path (/2016-11-01/credentialprovider/)
or is an IPv6 link-local address (fe80::/10). */
static int validate_http_credential_uri(flb_sds_t protocol, flb_sds_t host, flb_sds_t path)
{
if (strncmp(protocol, "https", 5) == 0) {
struct in_addr ipv4;
struct in6_addr ipv6;
struct in6_addr eks_ipv6;

if (strcmp(protocol, "https") == 0) {
return 0;
} else if (strncmp(host, "127.", 4) == 0 ||
strncmp(host, ECS_CREDENTIALS_HOST, ECS_CREDENTIALS_HOST_LEN) == 0 ||
strncmp(host, EKS_CREDENTIALS_HOST, EKS_CREDENTIALS_HOST_LEN) == 0 ||
strstr(host, "::1") != NULL ||
strstr(host, "fd00:ec2::23") != NULL ||
strstr(host, "fe80:") != NULL ||
(strcmp(host, GREENGRASS_CREDENTIALS_HOST) == 0 && path != NULL &&
strcmp(path, GREENGRASS_CREDENTIALS_PATH) == 0)) {
}

if (strcmp(protocol, "http") != 0) {
return -1;
}

if (strcmp(host, GREENGRASS_CREDENTIALS_HOST) == 0 && path != NULL &&
strcmp(path, GREENGRASS_CREDENTIALS_PATH) == 0) {
return 0;
}

if (inet_pton(AF_INET, host, &ipv4) == 1) {
if (((unsigned char *) &ipv4.s_addr)[0] == 127 ||
strcmp(host, ECS_CREDENTIALS_HOST) == 0 ||
strcmp(host, EKS_CREDENTIALS_HOST) == 0) {
return 0;
}
}

if (inet_pton(AF_INET6, host, &ipv6) == 1) {
inet_pton(AF_INET6, "fd00:ec2::23", &eks_ipv6);
if (IN6_IS_ADDR_LOOPBACK(&ipv6) ||
memcmp(&ipv6, &eks_ipv6, sizeof(ipv6)) == 0 ||
(ipv6.s6_addr[0] == 0xfe && (ipv6.s6_addr[1] & 0xc0) == 0x80)) {
return 0;
}
}

return -1;
}

Expand Down Expand Up @@ -360,7 +387,7 @@ struct flb_aws_provider *flb_http_provider_create(struct flb_config *config,
return NULL;
}

insecure = strncmp(protocol, "http", 4) == 0 ? FLB_TRUE : FLB_FALSE;
insecure = strcmp(protocol, "http") == 0 ? FLB_TRUE : FLB_FALSE;
ret = validate_http_credential_uri(protocol, host, path);
if (ret < 0) {
flb_error("[aws credentials] %s must be set to an https:// address, a link local IP address, "
Expand All @@ -373,6 +400,18 @@ struct flb_aws_provider *flb_http_provider_create(struct flb_config *config,
flb_sds_destroy(path);
return NULL;
}

/* Use a numeric loopback address so localhost cannot resolve elsewhere. */
if (insecure == FLB_TRUE && strcmp(host, GREENGRASS_CREDENTIALS_HOST) == 0) {
flb_sds_destroy(host);
host = flb_sds_create("127.0.0.1");
if (host == NULL) {
flb_sds_destroy(protocol);
flb_sds_destroy(port_sds);
flb_sds_destroy(path);
return NULL;
}
}
}
else {
flb_debug("[aws_credentials] Not initializing ECS/EKS HTTP Provider because"
Expand Down
41 changes: 38 additions & 3 deletions tests/include/aws_client_mock.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,40 @@
#define AWS_CLIENT_MOCK_H

/* Variadic Argument Counter, Counts up to 64 variadic args */
#ifdef _MSC_VER
#if defined(_MSC_VER) && defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL
/* Detect empty arguments before counting with the traditional preprocessor. */
#define FLB_AWS_CLIENT_MOCK_COUNT_T(args) \
FLB_AWS_CLIENT_MOCK_EVAL(_FLB_AWS_CLIENT_MOCK_COUNT64 args)
#define FLB_AWS_CLIENT_MOCK_HAS_COMMA(...) \
FLB_AWS_CLIENT_MOCK_EVAL(FLB_AWS_CLIENT_MOCK_COUNT_T((dummy, __VA_ARGS__, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)))
#define FLB_AWS_CLIENT_MOCK_TRIGGER(...) ,
#define FLB_AWS_CLIENT_MOCK_JOIN_I(a,b,c,d,e) a##b##c##d##e
#define FLB_AWS_CLIENT_MOCK_JOIN(a,b,c,d,e) \
FLB_AWS_CLIENT_MOCK_EVAL(FLB_AWS_CLIENT_MOCK_JOIN_I(a, b, c, d, e))
#define FLB_AWS_CLIENT_MOCK_EMPTY_CASE_0001 ,
#define FLB_AWS_CLIENT_MOCK_EMPTY_I(a,b,c,d) \
FLB_AWS_CLIENT_MOCK_EVAL(FLB_AWS_CLIENT_MOCK_HAS_COMMA(FLB_AWS_CLIENT_MOCK_JOIN(FLB_AWS_CLIENT_MOCK_EMPTY_CASE_, \
a, b, c, d)))
#define FLB_AWS_CLIENT_MOCK_IS_EMPTY(...) \
FLB_AWS_CLIENT_MOCK_EVAL(FLB_AWS_CLIENT_MOCK_EMPTY_I(FLB_AWS_CLIENT_MOCK_HAS_COMMA(__VA_ARGS__), \
FLB_AWS_CLIENT_MOCK_HAS_COMMA(FLB_AWS_CLIENT_MOCK_TRIGGER __VA_ARGS__), \
FLB_AWS_CLIENT_MOCK_HAS_COMMA(__VA_ARGS__ ()), \
FLB_AWS_CLIENT_MOCK_HAS_COMMA(FLB_AWS_CLIENT_MOCK_TRIGGER __VA_ARGS__ ())))
#define FLB_AWS_CLIENT_MOCK_CAT_I(a,b) a##b
#define FLB_AWS_CLIENT_MOCK_CAT(a,b) FLB_AWS_CLIENT_MOCK_CAT_I(a,b)
#define FLB_AWS_CLIENT_MOCK_COUNT_1(...) 0
#define FLB_AWS_CLIENT_MOCK_COUNT_0(...) \
FLB_AWS_CLIENT_MOCK_COUNT_T((dummy, __VA_ARGS__, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, \
52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \
29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, \
5, 4, 3, 2, 1, 0))
#define FLB_AWS_CLIENT_MOCK_COUNT(...) \
FLB_AWS_CLIENT_MOCK_EVAL(FLB_AWS_CLIENT_MOCK_CAT(FLB_AWS_CLIENT_MOCK_COUNT_, \
FLB_AWS_CLIENT_MOCK_IS_EMPTY(__VA_ARGS__))(__VA_ARGS__))
#define FLB_AWS_CLIENT_MOCK_COUNT64(...) FLB_AWS_CLIENT_MOCK_COUNT(__VA_ARGS__)
#elif defined(_MSC_VER)
#define FLB_AWS_CLIENT_MOCK_COUNT64(...) \
_FLB_AWS_CLIENT_MOCK_COUNT64(dummy __VA_OPT__(,) __VA_ARGS__, 63, 62, 61, 60, 59, \
58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, \
Expand Down Expand Up @@ -97,12 +130,14 @@
/* Make block-scope addressable compound-literal request chain */
#define FLB_AWS_CLIENT_MOCK(...) \
FLB_AWS_CLIENT_MOCK_EVAL(&(struct flb_aws_client_mock_request_chain){ \
FLB_AWS_CLIENT_MOCK_COUNT64(__VA_ARGS__), \
sizeof((struct flb_aws_client_mock_response[]){__VA_ARGS__}) / \
sizeof(struct flb_aws_client_mock_response), \
(struct flb_aws_client_mock_response[]){__VA_ARGS__}})

#define FLB_AWS_CLIENT_MOCK_RESPONSE(...) \
{ \
FLB_AWS_CLIENT_MOCK_COUNT64(__VA_ARGS__), \
sizeof((struct flb_aws_client_mock_response_config[]){__VA_ARGS__}) / \
sizeof(struct flb_aws_client_mock_response_config), \
(struct flb_aws_client_mock_response_config[]) \
{ \
__VA_ARGS__ \
Expand Down
54 changes: 53 additions & 1 deletion tests/integration/src/utils/fluent_bit_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import signal
import shutil
import subprocess
import sys
import tempfile
import time

Expand All @@ -46,6 +47,7 @@
logger = logging.getLogger(__name__)
FLUENT_BIT_VERSION_PATTERN = re.compile(r"(?:Fluent Bit\s+)?v?(\d+)\.(\d+)\.(\d+)")
_BINARY_VERSION_INFO_CACHE = {}
_WINDOWS_ATTACH_CONSOLE_FAILED = 3

class FluentBitStartupError(RuntimeError):
pass
Expand Down Expand Up @@ -234,10 +236,20 @@ def start(self):

output_path = self.leaks_log_file if leaks_enabled() else self.log_file
self.output_handle = open(output_path, "a", encoding="utf-8")
process_options = {}
if os.name == "nt":
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = subprocess.SW_HIDE
process_options = {
"creationflags": subprocess.CREATE_NEW_CONSOLE,
"startupinfo": startupinfo,
}
self.process = subprocess.Popen(
command,
stdout=self.output_handle,
stderr=subprocess.STDOUT,
**process_options,
)

if leaks_enabled():
Expand All @@ -257,10 +269,21 @@ def stop(self):
return

pid = self.target_pid or self.process.pid
shutdown_error = None
return_code = self.process.poll()
supervisor_running = self.process.poll() is None
if supervisor_running or (leaks_enabled() and self.target_pid):
self.send_signal(signal.SIGTERM)
if os.name == "nt":
try:
self._send_windows_shutdown(pid)
except subprocess.TimeoutExpired:
logger.warning("Windows shutdown helper timed out; waiting for Fluent Bit")
except subprocess.CalledProcessError as error:
if (error.returncode != _WINDOWS_ATTACH_CONSOLE_FAILED
or self.process.poll() is None):
shutdown_error = error
else:
self.send_signal(signal.SIGTERM)

if supervisor_running:
try:
Expand All @@ -280,6 +303,9 @@ def stop(self):
self.output_handle.close()
self.output_handle = None

if shutdown_error is not None:
raise shutdown_error

if self.http_monitoring_port:
timeout = 10 if memory_check_enabled() else 5
wait_for_port_to_be_free(int(self.http_monitoring_port), timeout=timeout)
Expand All @@ -292,6 +318,32 @@ def stop(self):

logger.info(f"Fluent Bit stopped (pid: {pid})")

@staticmethod
def _send_windows_shutdown(pid):
# Attach a helper to the child's isolated console and send Ctrl+C.
# CTRL_BREAK triggers Fluent Bit reload; SIGTERM forcibly kills it.
helper = f"""
import ctypes
import sys
import time

k = ctypes.WinDLL('kernel32', use_last_error=True)
k.FreeConsole()
if not k.AttachConsole(int(sys.argv[1])):
print('AttachConsole failed:', ctypes.get_last_error(), file=sys.stderr)
sys.exit({_WINDOWS_ATTACH_CONSOLE_FAILED})
try:
if not k.SetConsoleCtrlHandler(None, True):
raise ctypes.WinError(ctypes.get_last_error())
if not k.GenerateConsoleCtrlEvent(0, 0):
raise ctypes.WinError(ctypes.get_last_error())
time.sleep(0.1)
finally:
k.FreeConsole()
"""
subprocess.run([sys.executable, "-c", helper, str(pid)], check=True,
creationflags=subprocess.CREATE_NO_WINDOW, timeout=5)

def send_signal(self, signal_number):
if not self.process:
raise RuntimeError("Fluent Bit is not running")
Expand Down
Loading
Loading