Skip to content
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
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
11.7.0
11.8.0
7 changes: 6 additions & 1 deletion agent/fw_magento2.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "nr_txn.h"
#include "util_logging.h"

#define PHP_PACKAGE_NAME "magento/magento2-base"

/*
* Magento 2 adds (depending on how you count)
* either three or four completely separate routing paths in the Community
Expand Down Expand Up @@ -540,7 +542,10 @@ void nr_magento2_enable(TSRMLS_D) {
nr_magento2_ui_controller_execute TSRMLS_CC);

if (NRINI(vulnerability_management_package_detection_enabled)) {
nr_txn_add_php_package(NRPRG(txn), "magento",
nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME,
PHP_PACKAGE_VERSION_UNKNOWN);
}

nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME,
PHP_PACKAGE_VERSION_UNKNOWN);
}
231 changes: 199 additions & 32 deletions agent/lib_aws_sdk_php.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,16 @@
#include "fw_hooks.h"
#include "fw_support.h"
#include "util_logging.h"
#include "nr_segment_message.h"
#include "nr_segment_external.h"
#include "lib_aws_sdk_php.h"

#define PHP_PACKAGE_NAME "aws/aws-sdk-php"
#define AWS_LAMBDA_ARN_REGEX "(arn:(aws[a-zA-Z-]*)?:lambda:)?" \
"((?<region>[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}):)?" \
"((?<accountId>\\d{12}):)?" \
"(function:)?" \
"(?<functionName>[a-zA-Z0-9-\\.]+)" \
"(:(?<qualifier>\\$LATEST|[a-zA-Z0-9-]+))?"
#define AWS_LAMBDA_ARN_REGEX \
"(arn:(aws[a-zA-Z-]*)?:lambda:)?" \
"((?<region>[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}):)?" \
"((?<accountId>\\d{12}):)?" \
"(function:)?" \
"(?<functionName>[a-zA-Z0-9-\\.]+)" \
"(:(?<qualifier>\\$LATEST|[a-zA-Z0-9-]+))?"

#if ZEND_MODULE_API_NO >= ZEND_8_1_X_API_NO /* PHP8.1+ */
/* Service instrumentation only supported above PHP 8.1+*/
Expand Down Expand Up @@ -309,9 +308,7 @@ void nr_lib_aws_sdk_php_lambda_handle(nr_segment_t* auto_segment,
nr_segment_t* external_segment = NULL;
zval** retval_ptr = NR_GET_RETURN_VALUE_PTR;

nr_segment_cloud_attrs_t cloud_attrs = {
.cloud_platform = "aws_lambda"
};
nr_segment_cloud_attrs_t cloud_attrs = {.cloud_platform = "aws_lambda"};

if (NULL == auto_segment) {
return;
Expand All @@ -332,7 +329,8 @@ void nr_lib_aws_sdk_php_lambda_handle(nr_segment_t* auto_segment,
/* Determine if we instrument this command. */
if (AWS_COMMAND_IS("invoke")) {
/* reconstruct the ARN */
nr_aws_sdk_lambda_client_invoke_parse_args(NR_EXECUTE_ORIG_ARGS, &cloud_attrs);
nr_aws_sdk_lambda_client_invoke_parse_args(NR_EXECUTE_ORIG_ARGS,
&cloud_attrs);
} else {
return;
}
Expand Down Expand Up @@ -362,7 +360,7 @@ void nr_lib_aws_sdk_php_lambda_handle(nr_segment_t* auto_segment,
external_params.status = Z_LVAL_P(status_code);
}
zval* metadata = nr_php_zend_hash_find(Z_ARRVAL_P(data), "@metadata");
if (NULL != metadata && IS_REFERENCE == Z_TYPE_P(metadata)) {
if (NULL != metadata && IS_REFERENCE == Z_TYPE_P(metadata)) {
metadata = Z_REFVAL_P(metadata);
}
if (nr_php_is_zval_valid_array(metadata)) {
Expand All @@ -371,14 +369,13 @@ void nr_lib_aws_sdk_php_lambda_handle(nr_segment_t* auto_segment,
external_params.uri = Z_STRVAL_P(uri);
}
}

}
nr_segment_external_end(&external_segment, &external_params);
nr_free(cloud_attrs.cloud_resource_id);
}

/* This stores the compiled regex to parse AWS ARNs. The compilation happens when
* it is first needed and is destroyed in mshutdown
/* This stores the compiled regex to parse AWS ARNs. The compilation happens
* when it is first needed and is destroyed in mshutdown
*/
static nr_regex_t* aws_arn_regex;

Expand All @@ -390,7 +387,9 @@ void nr_aws_sdk_mshutdown(void) {
nr_regex_destroy(&aws_arn_regex);
}

void nr_aws_sdk_lambda_client_invoke_parse_args(NR_EXECUTE_PROTO, nr_segment_cloud_attrs_t* cloud_attrs) {
void nr_aws_sdk_lambda_client_invoke_parse_args(
NR_EXECUTE_PROTO,
nr_segment_cloud_attrs_t* cloud_attrs) {
zval* call_args = nr_php_get_user_func_arg(2, NR_EXECUTE_ORIG_ARGS);
zval* this_obj = NR_PHP_USER_FN_THIS();
char* arn = NULL;
Expand All @@ -409,7 +408,8 @@ void nr_aws_sdk_lambda_client_invoke_parse_args(NR_EXECUTE_PROTO, nr_segment_clo
if (!nr_php_is_zval_valid_array(lambda_args)) {
return;
}
zval* lambda_name = nr_php_zend_hash_find(Z_ARRVAL_P(lambda_args), "FunctionName");
zval* lambda_name
= nr_php_zend_hash_find(Z_ARRVAL_P(lambda_args), "FunctionName");
if (!nr_php_is_zval_non_empty_string(lambda_name)) {
return;
}
Expand All @@ -420,10 +420,8 @@ void nr_aws_sdk_lambda_client_invoke_parse_args(NR_EXECUTE_PROTO, nr_segment_clo
}

/* Extract all information possible from the passed lambda name via regex */
nr_regex_substrings_t* matches =
nr_regex_match_capture(aws_arn_regex,
Z_STRVAL_P(lambda_name),
Z_STRLEN_P(lambda_name));
nr_regex_substrings_t* matches = nr_regex_match_capture(
aws_arn_regex, Z_STRVAL_P(lambda_name), Z_STRLEN_P(lambda_name));
function_name = nr_regex_substrings_get_named(matches, "functionName");
accountID = nr_regex_substrings_get_named(matches, "accountId");
region = nr_regex_substrings_get_named(matches, "region");
Expand All @@ -449,11 +447,12 @@ void nr_aws_sdk_lambda_client_invoke_parse_args(NR_EXECUTE_PROTO, nr_segment_clo
}
if (nr_strempty(region)) {
zend_class_entry* base_class = NULL;
if (NULL != execute_data->func && NULL!= execute_data->func->common.scope) {
base_class = execute_data->func->common.scope;
if (NULL != execute_data->func
&& NULL != execute_data->func->common.scope) {
base_class = execute_data->func->common.scope;
}
region_zval
= nr_php_get_zval_object_property_with_class(this_obj, base_class, "region");
region_zval = nr_php_get_zval_object_property_with_class(
this_obj, base_class, "region");
if (nr_php_is_zval_valid_string(region_zval)) {
/*
* In this case, region is likely to be NULL, but could be an empty
Expand All @@ -467,11 +466,11 @@ void nr_aws_sdk_lambda_client_invoke_parse_args(NR_EXECUTE_PROTO, nr_segment_clo
if (!nr_strempty(accountID) && !nr_strempty(region)) {
/* construct the ARN */
if (!nr_strempty(qualifier)) {
arn = nr_formatf("arn:aws:lambda:%s:%s:function:%s:%s",
region, accountID, function_name, qualifier);
arn = nr_formatf("arn:aws:lambda:%s:%s:function:%s:%s", region, accountID,
function_name, qualifier);
} else {
arn = nr_formatf("arn:aws:lambda:%s:%s:function:%s",
region, accountID, function_name);
arn = nr_formatf("arn:aws:lambda:%s:%s:function:%s", region, accountID,
function_name);
}

/* Attach the ARN */
Expand Down Expand Up @@ -519,6 +518,170 @@ char* nr_lib_aws_sdk_php_get_command_arg_value(char* command_arg_name,
return command_arg_value;
}

void nr_lib_aws_sdk_php_dynamodb_set_params(
nr_segment_datastore_params_t* datastore_params,
nr_segment_cloud_attrs_t* cloud_attrs,
NR_EXECUTE_PROTO) {
zval* endpoint_zval = NULL;
zval* region_zval = NULL;
zval* host_zval = NULL;
zval* port_zval = NULL;
zval* this_obj = NULL;
zend_function* func = NULL;
zend_class_entry* base_class = NULL;
char* table_name = NULL;
char* account_id = NULL;

if (NULL == datastore_params || NULL == cloud_attrs) {
return;
}

this_obj = NR_PHP_USER_FN_THIS();
func = nr_php_execute_function(NR_EXECUTE_ORIG_ARGS);

if (NULL == this_obj || NULL == func) {
return;
}

if (NULL != func->common.scope) {
base_class = func->common.scope;

region_zval = nr_php_get_zval_object_property_with_class(
this_obj, base_class, "region");
if (nr_php_is_zval_non_empty_string(region_zval)) {
cloud_attrs->cloud_region = Z_STRVAL_P(region_zval);
}

endpoint_zval = nr_php_get_zval_object_property_with_class(
this_obj, base_class, "endpoint");
if (nr_php_is_zval_valid_object(endpoint_zval)) {
host_zval = nr_php_get_zval_object_property(endpoint_zval, "host");
if (nr_php_is_zval_non_empty_string(host_zval)) {
datastore_params->instance->host = Z_STRVAL_P(host_zval);

/* Only try to get a port if we have a valid host. */
port_zval = nr_php_get_zval_object_property(endpoint_zval, "port");
if (nr_php_is_zval_valid_integer(port_zval)) {
/* Must be freed by caller */
datastore_params->instance->port_path_or_id
= nr_formatf(NR_INT64_FMT, Z_LVAL_P(port_zval));
} else {
/* In case where host was found but port was not, spec says return
* unknown for port. */
datastore_params->instance->port_path_or_id = nr_strdup("unknown");
}
}
}
}
if (NULL == datastore_params->instance->host) {
/* Unable to retrieve the endpoint, go with AWS defaults. */
datastore_params->instance->host = AWS_SDK_PHP_DYNAMODBCLIENT_DEFAULT_HOST;
/* Need to strdup because the calling function will free it. */
datastore_params->instance->port_path_or_id
= nr_strdup(AWS_SDK_PHP_DYNAMODBCLIENT_DEFAULT_PORT);
}

table_name = nr_lib_aws_sdk_php_get_command_arg_value(
AWS_SDK_PHP_DYNAMODBCLIENT_TABLENAME_ARG, NR_EXECUTE_ORIG_ARGS);
if (!nr_strempty(table_name)) {
/* Must be freed by caller */
datastore_params->collection = table_name;
}
if (!nr_strempty(NRINI(aws_account_id))) {
account_id = NRINI(aws_account_id);
}

if (NULL != datastore_params->collection && NULL != account_id
&& NULL != cloud_attrs->cloud_region) {
/* Must be freed by caller */
cloud_attrs->cloud_resource_id = nr_formatf(
"arn:aws:dynamodb:%s:%s:table/%s", cloud_attrs->cloud_region,
account_id, datastore_params->collection);
}
}

void nr_lib_aws_sdk_php_dynamodb_handle(nr_segment_t* auto_segment,
char* command_name_string,
size_t command_name_len,
NR_EXECUTE_PROTO) {
nr_segment_t* datastore_segment = NULL;
nr_segment_cloud_attrs_t cloud_attrs = {0};
nr_datastore_instance_t instance = {0};
nr_segment_datastore_params_t datastore_params = {
.db_system = AWS_SDK_PHP_DYNAMODBCLIENT_DATASTORE_SYSTEM,
.datastore = {
.type = NR_DATASTORE_DYNAMODB,
},
.instance = &instance,
.callbacks = {
.backtrace = nr_php_backtrace_callback,
},
};
if (NULL == auto_segment) {
return;
}

if (NULL == command_name_string || 0 == command_name_len) {
return;
}

#define AWS_COMMAND_IS(CMD) \
(command_name_len == (sizeof(CMD) - 1) && nr_streq(CMD, command_name_string))

/* Determine if we instrument this command. */
if (AWS_COMMAND_IS("createTable")) {
datastore_params.operation = AWS_SDK_PHP_DYNAMODBCLIENT_CREATE_TABLE;
} else if (AWS_COMMAND_IS("deleteItem")) {
datastore_params.operation = AWS_SDK_PHP_DYNAMODBCLIENT_DELETE_ITEM;
} else if (AWS_COMMAND_IS("deleteTable")) {
datastore_params.operation = AWS_SDK_PHP_DYNAMODBCLIENT_DELETE_TABLE;
} else if (AWS_COMMAND_IS("getItem")) {
datastore_params.operation = AWS_SDK_PHP_DYNAMODBCLIENT_GET_ITEM;
} else if (AWS_COMMAND_IS("putItem")) {
datastore_params.operation = AWS_SDK_PHP_DYNAMODBCLIENT_PUT_ITEM;
} else if (AWS_COMMAND_IS("query")) {
datastore_params.operation = AWS_SDK_PHP_DYNAMODBCLIENT_QUERY;
} else if (AWS_COMMAND_IS("scan")) {
datastore_params.operation = AWS_SDK_PHP_DYNAMODBCLIENT_SCAN;
} else if (AWS_COMMAND_IS("updateItem")) {
datastore_params.operation = AWS_SDK_PHP_DYNAMODBCLIENT_UPDATE_ITEM;
} else {
/* Nothing to do here so exit. */
return;
}
#undef AWS_COMMAND_IS

/*
* nr_lib_aws_sdk_php_dynamodb_set_params sets:
* the cloud_attrs->region and cloud_resource_id(needs to be freed)
* datastore->instance host and port_path_or_id(needs to be freed)
* datastore->collection (needs to be freed)
*/
nr_lib_aws_sdk_php_dynamodb_set_params(&datastore_params, &cloud_attrs,
NR_EXECUTE_ORIG_ARGS);

/*
* By this point, the datastore params are decoded, grab the parent segment
* start time, add the special segment attributes/metrics then close the newly
* created segment.
*/
datastore_segment = nr_segment_start(NRPRG(txn), NULL, NULL);
if (NULL != datastore_segment) {
/* re-use start time from auto_segment started in func_begin */
datastore_segment->start_time = auto_segment->start_time;
cloud_attrs.aws_operation = command_name_string;

/* Add cloud attributes, if available. */
nr_segment_traces_add_cloud_attributes(datastore_segment, &cloud_attrs);

/* Now end the instrumented segment as a message segment. */
nr_segment_datastore_end(&datastore_segment, &datastore_params);
}
nr_free(datastore_params.collection);
nr_free(cloud_attrs.cloud_resource_id);
nr_free(instance.port_path_or_id);
}

/*
* For Aws/AwsClient::__call see
* https://github.com/aws/aws-sdk-php/blob/master/src/AwsClientInterface.php
Expand Down Expand Up @@ -580,8 +743,12 @@ NR_PHP_WRAPPER(nr_aws_client_call) {
NR_EXECUTE_ORIG_ARGS);
} else if (AWS_CLASS_IS("Aws\\Lambda\\LambdaClient", "LambdaClient")) {
nr_lib_aws_sdk_php_lambda_handle(auto_segment, command_name_string,
Z_STRLEN_P(command_name),
NR_EXECUTE_ORIG_ARGS);
Z_STRLEN_P(command_name),
NR_EXECUTE_ORIG_ARGS);
} else if (AWS_CLASS_IS("Aws\\DynamoDb\\DynamoDbClient", "DynamoDbClient")) {
nr_lib_aws_sdk_php_dynamodb_handle(auto_segment, command_name_string,
Z_STRLEN_P(command_name),
NR_EXECUTE_ORIG_ARGS);
}

#undef AWS_CLASS_IS
Expand Down
Loading
Loading