Add netebpfext user mode tests (#2124)
* fix * add more tests, address cr comments * fix cicd * fix cicd * fix analyze build * switch to read / write lock * fix fuzzer * add concurrent test * fix * cr comments * add sock_addr concurrency tests * add tests * add tests * fix, cleanup * cr comments * bugfix
This commit is contained in:
Родитель
87a88593a4
Коммит
30f96a64aa
|
@ -121,6 +121,21 @@ jobs:
|
|||
gather_dumps: true
|
||||
capture_etw: true
|
||||
|
||||
netebpfext_unit_leak_detection:
|
||||
# Always run this job.
|
||||
needs: regular
|
||||
if: github.event_name == 'schedule' || github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'merge_group'
|
||||
uses: ./.github/workflows/reusable-test.yml
|
||||
with:
|
||||
name: netebpfext_unit_leak_detection
|
||||
test_command: .\netebpfext_unit.exe -d yes
|
||||
build_artifact: Build-x64
|
||||
environment: windows-2022
|
||||
code_coverage: true
|
||||
gather_dumps: true
|
||||
capture_etw: true
|
||||
leak_detection: true
|
||||
|
||||
# Run the bpf2c tests in GitHub.
|
||||
bpf2c:
|
||||
# Always run this job.
|
||||
|
|
|
@ -25,6 +25,11 @@ bool _ebpf_platform_code_integrity_enabled = false;
|
|||
// Permit the test to simulate non-preemptible execution.
|
||||
bool _ebpf_platform_is_preemptible = true;
|
||||
|
||||
// Global variable to track the number of times ebpf_platform has been
|
||||
// initialized. In user mode it is possible for ebpf_platform_{initiate|terminate}
|
||||
// to be called multiple times.
|
||||
int32_t _ebpf_platform_initiate_count = 0;
|
||||
|
||||
extern "C" bool ebpf_fuzzing_enabled = false;
|
||||
extern "C" size_t ebpf_fuzzing_memory_limit = MAXSIZE_T;
|
||||
|
||||
|
@ -296,6 +301,11 @@ _get_environment_variable_as_size_t(const std::string& name)
|
|||
_Must_inspect_result_ ebpf_result_t
|
||||
ebpf_platform_initiate()
|
||||
{
|
||||
int32_t count = ebpf_interlocked_increment_int32(&_ebpf_platform_initiate_count);
|
||||
if (count > 1) {
|
||||
// Platform library already initialized, return.
|
||||
return EBPF_SUCCESS;
|
||||
}
|
||||
|
||||
try {
|
||||
_ebpf_platform_maximum_group_count = GetMaximumProcessorGroupCount();
|
||||
|
@ -336,6 +346,11 @@ ebpf_platform_initiate()
|
|||
void
|
||||
ebpf_platform_terminate()
|
||||
{
|
||||
int32_t count = ebpf_interlocked_decrement_int32(&_ebpf_platform_initiate_count);
|
||||
if (count != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
_clean_up_thread_pool();
|
||||
_ebpf_emulated_dpcs.resize(0);
|
||||
if (_ebpf_leak_detector_ptr) {
|
||||
|
|
|
@ -171,11 +171,11 @@ _net_ebpf_extension_detach_client_completion(_In_ DEVICE_OBJECT* device_object,
|
|||
// Wait for any in progress callbacks to complete.
|
||||
_ebpf_ext_attach_wait_for_rundown(&hook_client->rundown);
|
||||
|
||||
IoFreeWorkItem(work_item);
|
||||
|
||||
// Note: This frees the provider binding context (hook_client).
|
||||
NmrProviderDetachClientComplete(hook_client->nmr_binding_handle);
|
||||
|
||||
IoFreeWorkItem(work_item);
|
||||
|
||||
NET_EBPF_EXT_LOG_EXIT();
|
||||
}
|
||||
|
||||
|
|
|
@ -1067,8 +1067,11 @@ net_ebpf_extension_sock_addr_authorize_recv_accept_classify(
|
|||
goto Exit;
|
||||
}
|
||||
|
||||
if (net_ebpf_extension_hook_invoke_program(attached_client, sock_addr_ctx, &result) != EBPF_SUCCESS)
|
||||
if (net_ebpf_extension_hook_invoke_program(attached_client, sock_addr_ctx, &result) != EBPF_SUCCESS) {
|
||||
// Block the request if we failed to invoke the eBPF program.
|
||||
classify_output->actionType = FWP_ACTION_BLOCK;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
classify_output->actionType = (result == BPF_SOCK_ADDR_VERDICT_PROCEED) ? FWP_ACTION_PERMIT : FWP_ACTION_BLOCK;
|
||||
if (classify_output->actionType == FWP_ACTION_BLOCK)
|
||||
|
@ -1304,7 +1307,7 @@ net_ebpf_extension_sock_addr_redirect_connection_classify(
|
|||
net_ebpf_extension_connection_context_t* connection_context_original = NULL;
|
||||
net_ebpf_extension_connection_context_t* connection_context_redirected = NULL;
|
||||
BOOLEAN redirected = FALSE;
|
||||
FWP_ACTION_TYPE action = FWP_ACTION_BLOCK;
|
||||
FWP_ACTION_TYPE action = FWP_ACTION_PERMIT;
|
||||
BOOLEAN classify_handle_acquired = FALSE;
|
||||
BOOLEAN v4_mapped = FALSE;
|
||||
BOOLEAN is_original_connection;
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "net_ebpf_ext_sock_addr.h"
|
||||
#include "netebpfext_platform.h"
|
||||
|
||||
thread_local static FWPS_CONNECT_REQUEST0* _fwp_um_connect_request = nullptr;
|
||||
|
||||
// 98849e12-b07d-11ec-9a30-18602489beee
|
||||
DEFINE_GUID(
|
||||
EBPF_HOOK_CGROUP_CONNECT_V4_SUBLAYER, 0x98849e12, 0xb07d, 0x11ec, 0x9a, 0x30, 0x18, 0x60, 0x24, 0x89, 0xbe, 0xee);
|
||||
|
@ -24,12 +26,12 @@ std::unique_ptr<_fwp_engine> _fwp_engine::_engine;
|
|||
FWP_ACTION_TYPE
|
||||
_fwp_engine::classify_test_packet(_In_ const GUID* layer_guid, NET_IFINDEX if_index)
|
||||
{
|
||||
std::unique_lock l(lock);
|
||||
const GUID* callout_key = get_callout_key_from_layer_guid(layer_guid);
|
||||
shared_lock_t l(lock);
|
||||
const GUID* callout_key = get_callout_key_from_layer_guid_under_lock(layer_guid);
|
||||
if (callout_key == nullptr) {
|
||||
return FWP_ACTION_CALLOUT_UNKNOWN;
|
||||
}
|
||||
const FWPS_CALLOUT3* callout = get_callout_from_key(callout_key);
|
||||
const FWPS_CALLOUT3* callout = get_callout_from_key_under_lock(callout_key);
|
||||
if (callout == nullptr) {
|
||||
return FWP_ACTION_CALLOUT_UNKNOWN;
|
||||
}
|
||||
|
@ -38,7 +40,7 @@ _fwp_engine::classify_test_packet(_In_ const GUID* layer_guid, NET_IFINDEX if_in
|
|||
FWPS_INCOMING_VALUES incoming_fixed_values = {.incomingValue = incoming_value};
|
||||
incoming_fixed_values.incomingValue[FWPS_FIELD_INBOUND_MAC_FRAME_NATIVE_INTERFACE_INDEX].value.uint32 = if_index;
|
||||
FWPS_INCOMING_METADATA_VALUES incoming_metadata_values = {};
|
||||
const FWPM_FILTER* fwpm_filter = get_fwpm_filter_with_context(*layer_guid);
|
||||
const FWPM_FILTER* fwpm_filter = get_fwpm_filter_with_context_under_lock(*layer_guid);
|
||||
if (!fwpm_filter) {
|
||||
return FWP_ACTION_CALLOUT_UNKNOWN;
|
||||
}
|
||||
|
@ -82,32 +84,16 @@ _fwp_engine::classify_test_packet(_In_ const GUID* layer_guid, NET_IFINDEX if_in
|
|||
return result.actionType;
|
||||
}
|
||||
|
||||
constexpr uint32_t _test_destination_ipv4_address = 0x01020304;
|
||||
static FWP_BYTE_ARRAY16 _test_destination_ipv6_address = {1, 2, 3, 4};
|
||||
constexpr uint16_t _test_destination_port = 1234;
|
||||
constexpr uint32_t _test_source_ipv4_address = 0x05060708;
|
||||
static FWP_BYTE_ARRAY16 _test_source_ipv6_address = {5, 6, 7, 8};
|
||||
constexpr uint16_t _test_source_port = 5678;
|
||||
constexpr uint8_t _test_protocol = IPPROTO_TCP;
|
||||
constexpr uint32_t _test_compartment_id = 1;
|
||||
static FWP_BYTE_BLOB _test_app_id = {.size = 2, .data = (uint8_t*)"\\"};
|
||||
static uint64_t _test_interface_luid = 1;
|
||||
static TOKEN_ACCESS_INFORMATION _test_token_access_information = {0};
|
||||
static FWP_BYTE_BLOB _test_user_id = {
|
||||
.size = (sizeof(TOKEN_ACCESS_INFORMATION)), .data = (uint8_t*)&_test_token_access_information};
|
||||
|
||||
// This is used to test the bind hook.
|
||||
FWP_ACTION_TYPE
|
||||
_fwp_engine::test_bind_ipv4()
|
||||
_fwp_engine::test_bind_ipv4(_In_ fwp_classify_parameters_t* parameters)
|
||||
{
|
||||
std::unique_lock l(lock);
|
||||
|
||||
FWPS_INCOMING_VALUE0 incoming_value[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_MAX] = {};
|
||||
incoming_value[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_PORT].value.uint16 = _test_destination_port;
|
||||
incoming_value[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_PORT].value.uint16 = parameters->destination_port;
|
||||
incoming_value[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_ADDRESS].value.uint32 =
|
||||
_test_destination_ipv4_address;
|
||||
incoming_value[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_PROTOCOL].value.uint8 = _test_protocol;
|
||||
incoming_value[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_ALE_APP_ID].value.byteBlob = &_test_app_id;
|
||||
parameters->destination_ipv4_address;
|
||||
incoming_value[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_PROTOCOL].value.uint8 = parameters->protocol;
|
||||
incoming_value[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_ALE_APP_ID].value.byteBlob = ¶meters->app_id;
|
||||
|
||||
return test_callout(
|
||||
FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V4,
|
||||
|
@ -116,8 +102,7 @@ _fwp_engine::test_bind_ipv4()
|
|||
incoming_value);
|
||||
}
|
||||
|
||||
FWP_ACTION_TYPE
|
||||
_fwp_engine::test_callout(
|
||||
_Requires_lock_not_held_(this->lock) FWP_ACTION_TYPE _fwp_engine::test_callout(
|
||||
uint16_t layer_id,
|
||||
_In_ const GUID& layer_guid,
|
||||
_In_ const GUID& sublayer_guid,
|
||||
|
@ -125,20 +110,28 @@ _fwp_engine::test_callout(
|
|||
{
|
||||
FWPS_INCOMING_VALUES incoming_fixed_values = {.layerId = layer_id, .incomingValue = incoming_value};
|
||||
FWPS_INCOMING_METADATA_VALUES incoming_metadata_values = {};
|
||||
const FWPM_FILTER* fwpm_filter = get_fwpm_filter_with_context(layer_guid, sublayer_guid);
|
||||
if (!fwpm_filter) {
|
||||
return FWP_ACTION_CALLOUT_UNKNOWN;
|
||||
}
|
||||
FWPS_FILTER fwps_filter = {.context = fwpm_filter->rawContext};
|
||||
FWPS_FILTER fwps_filter = {};
|
||||
const FWPS_CALLOUT3* callout = nullptr;
|
||||
|
||||
const GUID* callout_key = get_callout_key_from_layer_guid(&layer_guid);
|
||||
if (callout_key == nullptr) {
|
||||
return FWP_ACTION_CALLOUT_UNKNOWN;
|
||||
}
|
||||
{
|
||||
shared_lock_t l(lock);
|
||||
const FWPM_FILTER* fwpm_filter = get_fwpm_filter_with_context_under_lock(layer_guid, sublayer_guid);
|
||||
if (!fwpm_filter) {
|
||||
return FWP_ACTION_CALLOUT_UNKNOWN;
|
||||
}
|
||||
fwps_filter.context = fwpm_filter->rawContext;
|
||||
|
||||
const FWPS_CALLOUT3* callout = get_callout_from_key(callout_key);
|
||||
if (callout == nullptr) {
|
||||
return FWP_ACTION_CALLOUT_UNKNOWN;
|
||||
const GUID* callout_key = get_callout_key_from_layer_guid_under_lock(&layer_guid);
|
||||
if (callout_key == nullptr) {
|
||||
return FWP_ACTION_CALLOUT_UNKNOWN;
|
||||
}
|
||||
|
||||
callout = get_callout_from_key_under_lock(callout_key);
|
||||
if (callout == nullptr) {
|
||||
return FWP_ACTION_CALLOUT_UNKNOWN;
|
||||
}
|
||||
|
||||
incoming_metadata_values.flowHandle = next_flow_id++;
|
||||
}
|
||||
|
||||
FWPS_CLASSIFY_OUT0 result = {};
|
||||
|
@ -155,162 +148,248 @@ _fwp_engine::test_callout(
|
|||
return result.actionType;
|
||||
}
|
||||
|
||||
// This is used to test CGROUP_SOCK_ADDR hooks.
|
||||
// This is used to test the INET4_RECV_ACCEPT hook.
|
||||
FWP_ACTION_TYPE
|
||||
_fwp_engine::test_cgroup_sock_addr(
|
||||
uint16_t layer_id,
|
||||
_In_ const GUID& layer_guid,
|
||||
_In_ const GUID& sublayer_guid,
|
||||
_In_ FWPS_INCOMING_VALUE0* incoming_value)
|
||||
_fwp_engine::test_cgroup_inet4_recv_accept(_In_ fwp_classify_parameters_t* parameters)
|
||||
{
|
||||
GUID filter_key = {};
|
||||
FWPS_FILTER filter = {};
|
||||
net_ebpf_ext_connect_redirect_filter_change_notify(FWPS_CALLOUT_NOTIFY_ADD_FILTER, &filter_key, &filter);
|
||||
|
||||
FWP_ACTION_TYPE action_type = test_callout(layer_id, layer_guid, sublayer_guid, incoming_value);
|
||||
|
||||
net_ebpf_ext_connect_redirect_filter_change_notify(FWPS_CALLOUT_NOTIFY_DELETE_FILTER, &filter_key, &filter);
|
||||
|
||||
return action_type;
|
||||
}
|
||||
|
||||
// This is used to test the INET4_RECV_ADDEPT hook.
|
||||
FWP_ACTION_TYPE
|
||||
_fwp_engine::test_cgroup_inet4_recv_accept()
|
||||
{
|
||||
std::unique_lock l(lock);
|
||||
|
||||
FWPS_INCOMING_VALUE0 incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_MAX] = {};
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_ADDRESS].value.uint32 = _test_destination_ipv4_address;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_PORT].value.uint16 = _test_destination_port;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_ADDRESS].value.uint32 = _test_source_ipv4_address;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_PORT].value.uint16 = _test_source_port;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8 = _test_protocol;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_COMPARTMENT_ID].value.uint32 = _test_compartment_id;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_INTERFACE].value.uint64 = &_test_interface_luid;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_ALE_APP_ID].value.byteBlob = &_test_app_id;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_ALE_USER_ID].value.byteBlob = &_test_user_id;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_ADDRESS].value.uint32 =
|
||||
parameters->destination_ipv4_address;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_PORT].value.uint16 = parameters->destination_port;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_ADDRESS].value.uint32 = parameters->source_ipv4_address;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_PORT].value.uint16 = parameters->source_port;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8 = parameters->protocol;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_COMPARTMENT_ID].value.uint32 = parameters->compartment_id;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_INTERFACE].value.uint64 =
|
||||
const_cast<UINT64*>(¶meters->interface_luid);
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_ALE_APP_ID].value.byteBlob =
|
||||
const_cast<FWP_BYTE_BLOB*>(¶meters->app_id);
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_ALE_USER_ID].value.byteBlob =
|
||||
const_cast<FWP_BYTE_BLOB*>(¶meters->user_id);
|
||||
|
||||
return test_cgroup_sock_addr(
|
||||
return test_callout(
|
||||
FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, EBPF_DEFAULT_SUBLAYER, incoming_value);
|
||||
}
|
||||
|
||||
// This is used to test the INET6_RECV_ADDEPT hook.
|
||||
// This is used to test the INET6_RECV_ACCEPT hook.
|
||||
FWP_ACTION_TYPE
|
||||
_fwp_engine::test_cgroup_inet6_recv_accept()
|
||||
_fwp_engine::test_cgroup_inet6_recv_accept(_In_ fwp_classify_parameters_t* parameters)
|
||||
{
|
||||
std::unique_lock l(lock);
|
||||
|
||||
FWPS_INCOMING_VALUE0 incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_MAX] = {};
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_LOCAL_ADDRESS].value.byteArray16 =
|
||||
&_test_destination_ipv6_address;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_LOCAL_PORT].value.uint16 = _test_destination_port;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_REMOTE_ADDRESS].value.byteArray16 = &_test_source_ipv6_address;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_REMOTE_PORT].value.uint16 = _test_source_port;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_PROTOCOL].value.uint8 = _test_protocol;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_COMPARTMENT_ID].value.uint32 = _test_compartment_id;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_LOCAL_INTERFACE].value.uint64 = &_test_interface_luid;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_ALE_APP_ID].value.byteBlob = &_test_app_id;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_ALE_USER_ID].value.byteBlob = &_test_user_id;
|
||||
¶meters->destination_ipv6_address;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_LOCAL_PORT].value.uint16 = parameters->destination_port;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_REMOTE_ADDRESS].value.byteArray16 =
|
||||
¶meters->source_ipv6_address;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_REMOTE_PORT].value.uint16 = parameters->source_port;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_PROTOCOL].value.uint8 = parameters->protocol;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_COMPARTMENT_ID].value.uint32 = parameters->compartment_id;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_LOCAL_INTERFACE].value.uint64 = ¶meters->interface_luid;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_ALE_APP_ID].value.byteBlob = ¶meters->app_id;
|
||||
incoming_value[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_ALE_USER_ID].value.byteBlob = ¶meters->user_id;
|
||||
|
||||
return test_cgroup_sock_addr(
|
||||
return test_callout(
|
||||
FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, EBPF_DEFAULT_SUBLAYER, incoming_value);
|
||||
}
|
||||
|
||||
bool
|
||||
_is_connection_redirected(
|
||||
_In_ const fwp_classify_parameters_t* parameters,
|
||||
_In_ const FWPS_CONNECT_REQUEST0* request,
|
||||
_Out_ uint16_t* redirected_port,
|
||||
_Out_ uint8_t** redirected_address)
|
||||
{
|
||||
// Test ebpf program modifies both port and IP address. Only check the port
|
||||
// to know if redirection happened.
|
||||
*redirected_port = INETADDR_PORT((PSOCKADDR)&request->remoteAddressAndPort);
|
||||
*redirected_address = INETADDR_ADDRESS((PSOCKADDR)&request->remoteAddressAndPort);
|
||||
|
||||
if (parameters->destination_port == *redirected_port) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (request->remoteAddressAndPort.ss_family == AF_INET) {
|
||||
if (parameters->destination_ipv4_address == *((uint32_t*)*redirected_address)) {
|
||||
return false;
|
||||
}
|
||||
} else if (memcmp(*redirected_address, parameters->destination_ipv6_address.byteArray16, 16) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allocate and initialize FWPS_CONNECT_REQUEST0.
|
||||
void static _allocate_and_initialize_connection_request(
|
||||
ADDRESS_FAMILY family, _In_ const fwp_classify_parameters_t* parameters)
|
||||
{
|
||||
ebpf_assert(_fwp_um_connect_request == nullptr);
|
||||
_fwp_um_connect_request = (FWPS_CONNECT_REQUEST0*)ebpf_allocate(sizeof(FWPS_CONNECT_REQUEST0));
|
||||
if (_fwp_um_connect_request == nullptr) {
|
||||
// Most likely we are under low memory simulation. Return.
|
||||
return;
|
||||
}
|
||||
|
||||
_fwp_um_connect_request->remoteAddressAndPort.ss_family = family;
|
||||
INETADDR_SET_PORT((PSOCKADDR)&_fwp_um_connect_request->remoteAddressAndPort, parameters->destination_port);
|
||||
return;
|
||||
}
|
||||
|
||||
void static _free_connection_request()
|
||||
{
|
||||
ebpf_free(_fwp_um_connect_request);
|
||||
_fwp_um_connect_request = nullptr;
|
||||
}
|
||||
|
||||
// This is used to test the INET4_CONNECT hook.
|
||||
FWP_ACTION_TYPE
|
||||
_fwp_engine::test_cgroup_inet4_connect()
|
||||
_fwp_engine::test_cgroup_inet4_connect(_In_ fwp_classify_parameters_t* parameters)
|
||||
{
|
||||
FWP_ACTION_TYPE action;
|
||||
std::unique_lock l(lock);
|
||||
bool redirected = false;
|
||||
uint16_t redirected_port = 0;
|
||||
uint8_t* redirected_address = nullptr;
|
||||
|
||||
_allocate_and_initialize_connection_request(AF_INET, parameters);
|
||||
|
||||
// For CGROUP_CONNECT* attach type, first CONNECT_REDIRECT callout is invoked, followed by
|
||||
// AUTH_CONNECT.
|
||||
FWPS_INCOMING_VALUE0 incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_MAX] = {};
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_IP_LOCAL_ADDRESS].value.uint32 = _test_source_ipv4_address;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_IP_LOCAL_PORT].value.uint16 = _test_source_port;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_IP_REMOTE_ADDRESS].value.uint32 = _test_destination_ipv4_address;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_IP_REMOTE_PORT].value.uint16 = _test_destination_port;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_IP_PROTOCOL].value.uint8 = _test_protocol;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_COMPARTMENT_ID].value.uint32 = _test_compartment_id;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_ALE_APP_ID].value.byteBlob = &_test_app_id;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_ALE_USER_ID].value.byteBlob = &_test_user_id;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_IP_LOCAL_ADDRESS].value.uint32 = parameters->source_ipv4_address;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_IP_LOCAL_PORT].value.uint16 = parameters->source_port;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_IP_REMOTE_ADDRESS].value.uint32 =
|
||||
parameters->destination_ipv4_address;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_IP_REMOTE_PORT].value.uint16 = parameters->destination_port;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_IP_PROTOCOL].value.uint8 = parameters->protocol;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_COMPARTMENT_ID].value.uint32 = parameters->compartment_id;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_ALE_APP_ID].value.byteBlob = ¶meters->app_id;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_ALE_USER_ID].value.byteBlob = ¶meters->user_id;
|
||||
|
||||
action = test_cgroup_sock_addr(
|
||||
action = test_callout(
|
||||
FWPS_LAYER_ALE_CONNECT_REDIRECT_V4, FWPM_LAYER_ALE_CONNECT_REDIRECT_V4, EBPF_DEFAULT_SUBLAYER, incoming_value);
|
||||
ebpf_assert(action == FWP_ACTION_PERMIT);
|
||||
|
||||
FWPS_INCOMING_VALUE0 incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_MAX] = {};
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS].value.uint32 = _test_source_ipv4_address;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT].value.uint16 = _test_source_port;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS].value.uint32 = _test_destination_ipv4_address;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT].value.uint16 = _test_destination_port;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL].value.uint8 = _test_protocol;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_COMPARTMENT_ID].value.uint32 = _test_compartment_id;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_ALE_APP_ID].value.byteBlob = &_test_app_id;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_ALE_USER_ID].value.byteBlob = &_test_user_id;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_INTERFACE].value.uint64 = &_test_interface_luid;
|
||||
if (_fwp_um_connect_request != nullptr) {
|
||||
redirected =
|
||||
_is_connection_redirected(parameters, _fwp_um_connect_request, &redirected_port, &redirected_address);
|
||||
}
|
||||
|
||||
return test_cgroup_sock_addr(
|
||||
FWPS_INCOMING_VALUE0 incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_MAX] = {};
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS].value.uint32 = parameters->source_ipv4_address;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT].value.uint16 = parameters->source_port;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS].value.uint32 =
|
||||
parameters->destination_ipv4_address;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT].value.uint16 = parameters->destination_port;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL].value.uint8 = parameters->protocol;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_COMPARTMENT_ID].value.uint32 = parameters->compartment_id;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_ALE_APP_ID].value.byteBlob = ¶meters->app_id;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_ALE_USER_ID].value.byteBlob = ¶meters->user_id;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_INTERFACE].value.uint64 = ¶meters->interface_luid;
|
||||
|
||||
action = test_callout(
|
||||
FWPS_LAYER_ALE_AUTH_CONNECT_V4, FWPM_LAYER_ALE_AUTH_CONNECT_V4, EBPF_DEFAULT_SUBLAYER, incoming_value2);
|
||||
|
||||
if (redirected) {
|
||||
// In case the connection is redirected, AUTH_CONNECT callout will be invoked twice.
|
||||
ebpf_assert(action == FWP_ACTION_PERMIT);
|
||||
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT].value.uint16 = ntohs(redirected_port);
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS].value.uint32 =
|
||||
ntohl(*((uint32_t*)redirected_address));
|
||||
|
||||
action = test_callout(
|
||||
FWPS_LAYER_ALE_AUTH_CONNECT_V4, FWPM_LAYER_ALE_AUTH_CONNECT_V4, EBPF_DEFAULT_SUBLAYER, incoming_value2);
|
||||
}
|
||||
|
||||
_free_connection_request();
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
// This is used to test the INET6_CONNECT hook.
|
||||
FWP_ACTION_TYPE
|
||||
_fwp_engine::test_cgroup_inet6_connect()
|
||||
_fwp_engine::test_cgroup_inet6_connect(_In_ fwp_classify_parameters_t* parameters)
|
||||
{
|
||||
FWP_ACTION_TYPE action;
|
||||
std::unique_lock l(lock);
|
||||
bool redirected = false;
|
||||
uint16_t redirected_port = 0;
|
||||
uint8_t* redirected_address = nullptr;
|
||||
|
||||
_allocate_and_initialize_connection_request(AF_INET6, parameters);
|
||||
|
||||
FWPS_INCOMING_VALUE0 incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V6_MAX] = {};
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V6_IP_LOCAL_ADDRESS].value.byteArray16 = &_test_source_ipv6_address;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V6_IP_LOCAL_PORT].value.uint16 = _test_source_port;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V6_IP_LOCAL_ADDRESS].value.byteArray16 =
|
||||
¶meters->source_ipv6_address;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V6_IP_LOCAL_PORT].value.uint16 = parameters->source_port;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V6_IP_REMOTE_ADDRESS].value.byteArray16 =
|
||||
&_test_destination_ipv6_address;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V6_IP_REMOTE_PORT].value.uint16 = _test_destination_port;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V6_IP_PROTOCOL].value.uint8 = _test_protocol;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V6_COMPARTMENT_ID].value.uint32 = _test_compartment_id;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V6_ALE_APP_ID].value.byteBlob = &_test_app_id;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V6_ALE_USER_ID].value.byteBlob = &_test_user_id;
|
||||
¶meters->destination_ipv6_address;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V6_IP_REMOTE_PORT].value.uint16 = parameters->destination_port;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V6_IP_PROTOCOL].value.uint8 = parameters->protocol;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V6_COMPARTMENT_ID].value.uint32 = parameters->compartment_id;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V6_ALE_APP_ID].value.byteBlob = ¶meters->app_id;
|
||||
incoming_value[FWPS_FIELD_ALE_CONNECT_REDIRECT_V6_ALE_USER_ID].value.byteBlob = ¶meters->user_id;
|
||||
|
||||
action = test_cgroup_sock_addr(
|
||||
action = test_callout(
|
||||
FWPS_LAYER_ALE_CONNECT_REDIRECT_V6,
|
||||
FWPM_LAYER_ALE_CONNECT_REDIRECT_V6,
|
||||
EBPF_HOOK_CGROUP_CONNECT_V6_SUBLAYER,
|
||||
incoming_value);
|
||||
ebpf_assert(action == FWP_ACTION_PERMIT);
|
||||
|
||||
FWPS_INCOMING_VALUE0 incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_MAX] = {};
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_LOCAL_ADDRESS].value.byteArray16 = &_test_source_ipv6_address;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_LOCAL_PORT].value.uint16 = _test_source_port;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_REMOTE_ADDRESS].value.byteArray16 =
|
||||
&_test_destination_ipv6_address;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_REMOTE_PORT].value.uint16 = _test_destination_port;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_PROTOCOL].value.uint8 = _test_protocol;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_COMPARTMENT_ID].value.uint32 = _test_compartment_id;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_ALE_APP_ID].value.byteBlob = &_test_app_id;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_ALE_USER_ID].value.byteBlob = &_test_user_id;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_LOCAL_INTERFACE].value.uint64 = &_test_interface_luid;
|
||||
if (_fwp_um_connect_request != nullptr) {
|
||||
redirected =
|
||||
_is_connection_redirected(parameters, _fwp_um_connect_request, &redirected_port, &redirected_address);
|
||||
}
|
||||
|
||||
return test_cgroup_sock_addr(
|
||||
FWPS_INCOMING_VALUE0 incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_MAX] = {};
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_LOCAL_ADDRESS].value.byteArray16 =
|
||||
¶meters->source_ipv6_address;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_LOCAL_PORT].value.uint16 = parameters->source_port;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_REMOTE_ADDRESS].value.byteArray16 =
|
||||
¶meters->destination_ipv6_address;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_REMOTE_PORT].value.uint16 = parameters->destination_port;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_PROTOCOL].value.uint8 = parameters->protocol;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_COMPARTMENT_ID].value.uint32 = parameters->compartment_id;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_ALE_APP_ID].value.byteBlob = ¶meters->app_id;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_ALE_USER_ID].value.byteBlob = ¶meters->user_id;
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_LOCAL_INTERFACE].value.uint64 = ¶meters->interface_luid;
|
||||
|
||||
action = test_callout(
|
||||
FWPS_LAYER_ALE_AUTH_CONNECT_V6, FWPM_LAYER_ALE_AUTH_CONNECT_V6, EBPF_DEFAULT_SUBLAYER, incoming_value2);
|
||||
|
||||
if (redirected) {
|
||||
// In case the connection is redirected, AUTH_CONNECT callout will be invoked twice.
|
||||
ebpf_assert(action == FWP_ACTION_PERMIT);
|
||||
|
||||
FWP_BYTE_ARRAY16 destination_ip = {0};
|
||||
memcpy(destination_ip.byteArray16, redirected_address, 16);
|
||||
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_REMOTE_PORT].value.uint16 = ntohs(redirected_port);
|
||||
incoming_value2[FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_REMOTE_ADDRESS].value.byteArray16 = &destination_ip;
|
||||
|
||||
action = test_callout(
|
||||
FWPS_LAYER_ALE_AUTH_CONNECT_V6, FWPM_LAYER_ALE_AUTH_CONNECT_V6, EBPF_DEFAULT_SUBLAYER, incoming_value2);
|
||||
}
|
||||
|
||||
_free_connection_request();
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
// This is used to test the SOCK_OPS hook for IPv4 traffic.
|
||||
FWP_ACTION_TYPE
|
||||
_fwp_engine::test_sock_ops_v4()
|
||||
_fwp_engine::test_sock_ops_v4(_In_ fwp_classify_parameters_t* parameters)
|
||||
{
|
||||
std::unique_lock l(lock);
|
||||
|
||||
FWPS_INCOMING_VALUE0 incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_MAX] = {};
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_ADDRESS].value.uint32 = _test_destination_ipv4_address;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_PORT].value.uint16 = _test_destination_port;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_ADDRESS].value.uint32 = _test_source_ipv4_address;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_PORT].value.uint16 = _test_source_port;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_PROTOCOL].value.uint8 = _test_protocol;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_COMPARTMENT_ID].value.uint32 = _test_compartment_id;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_INTERFACE].value.uint64 = &_test_interface_luid;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_ALE_APP_ID].value.byteBlob = &_test_app_id;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_ADDRESS].value.uint32 =
|
||||
parameters->destination_ipv4_address;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_PORT].value.uint16 = parameters->destination_port;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_ADDRESS].value.uint32 = parameters->source_ipv4_address;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_PORT].value.uint16 = parameters->source_port;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_PROTOCOL].value.uint8 = parameters->protocol;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_COMPARTMENT_ID].value.uint32 = parameters->compartment_id;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_INTERFACE].value.uint64 = ¶meters->interface_luid;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_ALE_APP_ID].value.byteBlob = ¶meters->app_id;
|
||||
|
||||
return test_callout(
|
||||
FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4, FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4, EBPF_DEFAULT_SUBLAYER, incoming_value);
|
||||
|
@ -318,20 +397,19 @@ _fwp_engine::test_sock_ops_v4()
|
|||
|
||||
// This is used to test the SOCK_OPS hook for IPv6 traffic.
|
||||
FWP_ACTION_TYPE
|
||||
_fwp_engine::test_sock_ops_v6()
|
||||
_fwp_engine::test_sock_ops_v6(_In_ fwp_classify_parameters_t* parameters)
|
||||
{
|
||||
std::unique_lock l(lock);
|
||||
|
||||
FWPS_INCOMING_VALUE0 incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_MAX] = {};
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_LOCAL_ADDRESS].value.byteArray16 =
|
||||
&_test_destination_ipv6_address;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_LOCAL_PORT].value.uint16 = _test_destination_port;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_REMOTE_ADDRESS].value.byteArray16 = &_test_source_ipv6_address;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_REMOTE_PORT].value.uint16 = _test_source_port;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_PROTOCOL].value.uint8 = _test_protocol;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_COMPARTMENT_ID].value.uint32 = _test_compartment_id;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_LOCAL_INTERFACE].value.uint64 = &_test_interface_luid;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_ALE_APP_ID].value.byteBlob = &_test_app_id;
|
||||
¶meters->destination_ipv6_address;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_LOCAL_PORT].value.uint16 = parameters->destination_port;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_REMOTE_ADDRESS].value.byteArray16 =
|
||||
¶meters->source_ipv6_address;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_REMOTE_PORT].value.uint16 = parameters->source_port;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_PROTOCOL].value.uint8 = parameters->protocol;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_COMPARTMENT_ID].value.uint32 = parameters->compartment_id;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_LOCAL_INTERFACE].value.uint64 = ¶meters->interface_luid;
|
||||
incoming_value[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_ALE_APP_ID].value.byteBlob = ¶meters->app_id;
|
||||
|
||||
return test_callout(
|
||||
FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6, FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6, EBPF_DEFAULT_SUBLAYER, incoming_value);
|
||||
|
@ -497,19 +575,20 @@ _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS FwpsInjectionHandleDestroy0(_In_ HAN
|
|||
_IRQL_requires_max_(DISPATCH_LEVEL) NTSTATUS
|
||||
FwpsFlowRemoveContext0(_In_ uint64_t flow_id, _In_ UINT16 layer_id, _In_ uint32_t callout_id)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(flow_id);
|
||||
UNREFERENCED_PARAMETER(layer_id);
|
||||
UNREFERENCED_PARAMETER(callout_id);
|
||||
auto& engine = *_fwp_engine::get()->get();
|
||||
engine.delete_flow_context(flow_id, layer_id, callout_id);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL) NTSTATUS FwpsFlowAssociateContext0(
|
||||
_In_ uint64_t flow_id, _In_ UINT16 layer_id, _In_ uint32_t callout_id, _In_ uint64_t flowContext)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(flow_id);
|
||||
UNREFERENCED_PARAMETER(layer_id);
|
||||
UNREFERENCED_PARAMETER(callout_id);
|
||||
UNREFERENCED_PARAMETER(flowContext);
|
||||
|
||||
auto& engine = *_fwp_engine::get()->get();
|
||||
engine.associate_flow_context(flow_id, callout_id, flowContext);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -651,14 +730,18 @@ _IRQL_requires_max_(DISPATCH_LEVEL) NTSTATUS NTAPI FwpsAcquireWritableLayerDataP
|
|||
_Out_ void** writableLayerData,
|
||||
_Inout_opt_ FWPS_CLASSIFY_OUT0* classifyOut)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
UNREFERENCED_PARAMETER(classifyHandle);
|
||||
UNREFERENCED_PARAMETER(filterId);
|
||||
UNREFERENCED_PARAMETER(flags);
|
||||
UNREFERENCED_PARAMETER(classifyOut);
|
||||
|
||||
*writableLayerData = NULL;
|
||||
*writableLayerData = _fwp_um_connect_request;
|
||||
if (*writableLayerData == nullptr) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
return status;
|
||||
}
|
||||
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL) NTSTATUS NTAPI
|
||||
|
@ -682,8 +765,9 @@ _IRQL_requires_max_(DISPATCH_LEVEL) void NTAPI
|
|||
FwpsApplyModifiedLayerData0(_In_ UINT64 classifyHandle, _In_ void* modifiedLayerData, _In_ UINT32 flags)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(classifyHandle);
|
||||
UNREFERENCED_PARAMETER(modifiedLayerData);
|
||||
UNREFERENCED_PARAMETER(flags);
|
||||
|
||||
ebpf_assert(modifiedLayerData != nullptr);
|
||||
}
|
||||
|
||||
_IRQL_requires_(PASSIVE_LEVEL) NTSTATUS NTAPI
|
||||
|
|
|
@ -4,18 +4,38 @@
|
|||
|
||||
#include "net_ebpf_ext.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
typedef std::unique_lock<std::shared_mutex> exclusive_lock_t;
|
||||
typedef std::shared_lock<std::shared_mutex> shared_lock_t;
|
||||
|
||||
typedef struct _fwp_classify_parameters
|
||||
{
|
||||
ADDRESS_FAMILY family;
|
||||
uint32_t destination_ipv4_address;
|
||||
FWP_BYTE_ARRAY16 destination_ipv6_address;
|
||||
uint16_t destination_port;
|
||||
uint32_t source_ipv4_address;
|
||||
FWP_BYTE_ARRAY16 source_ipv6_address;
|
||||
uint16_t source_port;
|
||||
uint8_t protocol;
|
||||
uint32_t compartment_id;
|
||||
FWP_BYTE_BLOB app_id;
|
||||
uint64_t interface_luid;
|
||||
TOKEN_ACCESS_INFORMATION token_access_information;
|
||||
FWP_BYTE_BLOB user_id;
|
||||
} fwp_classify_parameters_t;
|
||||
|
||||
typedef class _fwp_engine
|
||||
{
|
||||
public:
|
||||
_fwp_engine() = default;
|
||||
|
||||
uint32_t
|
||||
add_fwpm_callout(const FWPM_CALLOUT0* callout)
|
||||
add_fwpm_callout(_In_ const FWPM_CALLOUT0* callout)
|
||||
{
|
||||
std::unique_lock l(lock);
|
||||
exclusive_lock_t l(lock);
|
||||
uint32_t id = next_id++;
|
||||
fwpm_callouts.insert({id, *callout});
|
||||
return id;
|
||||
|
@ -24,55 +44,143 @@ typedef class _fwp_engine
|
|||
bool
|
||||
remove_fwpm_callout(size_t id)
|
||||
{
|
||||
std::unique_lock l(lock);
|
||||
exclusive_lock_t l(lock);
|
||||
return fwpm_callouts.erase(id) == 1;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
register_fwps_callout(const FWPS_CALLOUT3* callout)
|
||||
register_fwps_callout(_In_ const FWPS_CALLOUT3* callout)
|
||||
{
|
||||
std::unique_lock l(lock);
|
||||
exclusive_lock_t l(lock);
|
||||
uint32_t id = next_id++;
|
||||
fwps_callouts.insert({id, *callout});
|
||||
return id;
|
||||
}
|
||||
|
||||
bool
|
||||
remove_fwps_callout(size_t id)
|
||||
_Requires_lock_held_(this->lock) FWPS_CALLOUT3* get_fwps_callout(_In_ const GUID* callout_key)
|
||||
{
|
||||
std::unique_lock l(lock);
|
||||
for (auto& it : fwps_callouts) {
|
||||
if (memcmp(&it.second.calloutKey, callout_key, sizeof(GUID)) == 0) {
|
||||
return &it.second;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_Requires_lock_held_(this->lock) FWPS_CALLOUT3* get_fwps_callout(uint32_t callout_id)
|
||||
{
|
||||
for (auto& it : fwps_callouts) {
|
||||
if (it.first == callout_id) {
|
||||
return &it.second;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_Requires_lock_not_held_(this->lock) bool remove_fwps_callout(size_t id)
|
||||
{
|
||||
exclusive_lock_t l(lock);
|
||||
return fwps_callouts.erase(id) == 1;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
add_fwpm_filter(const FWPM_FILTER0* filter)
|
||||
_Requires_lock_not_held_(this->lock) void associate_flow_context(
|
||||
uint64_t flow_id, uint32_t callout_id, uint64_t flow_context)
|
||||
{
|
||||
std::unique_lock l(lock);
|
||||
uint32_t id = next_id++;
|
||||
fwpm_filters.insert({id, *filter});
|
||||
UNREFERENCED_PARAMETER(callout_id);
|
||||
exclusive_lock_t l(lock);
|
||||
fwpm_flow_contexts.insert({flow_id, flow_context});
|
||||
}
|
||||
|
||||
_Requires_lock_not_held_(this->lock) void delete_flow_context(
|
||||
uint64_t flow_id, uint16_t layer_id, uint32_t callout_id)
|
||||
{
|
||||
FWPS_CALLOUT3* callout = nullptr;
|
||||
FWPS_FILTER fwps_filter = {};
|
||||
uint64_t flow_context = 0;
|
||||
|
||||
{
|
||||
exclusive_lock_t l(lock);
|
||||
for (auto& it : fwpm_flow_contexts) {
|
||||
if (it.first == flow_id) {
|
||||
callout = get_fwps_callout(callout_id);
|
||||
ebpf_assert(callout != nullptr);
|
||||
flow_context = it.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fwpm_flow_contexts.erase(flow_id);
|
||||
}
|
||||
|
||||
ebpf_assert(callout != nullptr);
|
||||
__analysis_assume(callout != nullptr);
|
||||
// Invoke flow delete notification callback.
|
||||
callout->flowDeleteFn(layer_id, callout_id, flow_context);
|
||||
}
|
||||
|
||||
_Requires_lock_not_held_(this->lock) uint32_t add_fwpm_filter(_In_ const FWPM_FILTER0* filter)
|
||||
{
|
||||
FWPS_CALLOUT3* callout = nullptr;
|
||||
FWPS_FILTER fwps_filter = {};
|
||||
uint32_t id;
|
||||
|
||||
{
|
||||
exclusive_lock_t l(lock);
|
||||
id = next_id++;
|
||||
fwpm_filters.insert({id, *filter});
|
||||
|
||||
callout = get_fwps_callout(&filter->action.calloutKey);
|
||||
ebpf_assert(callout != nullptr);
|
||||
fwps_filter.context = filter->rawContext;
|
||||
}
|
||||
|
||||
__analysis_assume(callout != nullptr);
|
||||
// Invoke filter add notification callback.
|
||||
callout->notifyFn(FWPS_CALLOUT_NOTIFY_ADD_FILTER, &filter->action.calloutKey, &fwps_filter);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
bool
|
||||
remove_fwpm_filter(size_t id)
|
||||
_Requires_lock_not_held_(this->lock) bool remove_fwpm_filter(size_t id)
|
||||
{
|
||||
std::unique_lock l(lock);
|
||||
return fwpm_filters.erase(id) == 1;
|
||||
FWPS_CALLOUT3* callout = nullptr;
|
||||
FWPS_FILTER fwps_filter = {};
|
||||
bool return_value = false;
|
||||
{
|
||||
exclusive_lock_t l(lock);
|
||||
for (auto& it : fwpm_filters) {
|
||||
if (it.first == id) {
|
||||
callout = get_fwps_callout(&it.second.action.calloutKey);
|
||||
ebpf_assert(callout != nullptr);
|
||||
fwps_filter.context = it.second.rawContext;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return_value = fwpm_filters.erase(id) == 1;
|
||||
}
|
||||
|
||||
ebpf_assert(callout != nullptr);
|
||||
__analysis_assume(callout != nullptr);
|
||||
// Invoke filter delete notification callback.
|
||||
callout->notifyFn(FWPS_CALLOUT_NOTIFY_DELETE_FILTER, &callout->calloutKey, &fwps_filter);
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
add_fwpm_sub_layer(const FWPM_SUBLAYER0* sub_layer)
|
||||
_Requires_lock_not_held_(this->lock) uint32_t add_fwpm_sub_layer(_In_ const FWPM_SUBLAYER0* sub_layer)
|
||||
{
|
||||
std::unique_lock l(lock);
|
||||
exclusive_lock_t l(lock);
|
||||
uint32_t id = next_id++;
|
||||
fwpm_sub_layers.insert({id, *sub_layer});
|
||||
return id;
|
||||
}
|
||||
|
||||
bool
|
||||
remove_fwpm_sub_layer(size_t id)
|
||||
_Requires_lock_not_held_(this->lock) bool remove_fwpm_sub_layer(size_t id)
|
||||
{
|
||||
std::unique_lock l(lock);
|
||||
exclusive_lock_t l(lock);
|
||||
return fwpm_sub_layers.erase(id) == 1;
|
||||
}
|
||||
|
||||
|
@ -80,25 +188,25 @@ typedef class _fwp_engine
|
|||
classify_test_packet(_In_ const GUID* layer_guid, NET_IFINDEX if_index);
|
||||
|
||||
FWP_ACTION_TYPE
|
||||
test_bind_ipv4();
|
||||
test_bind_ipv4(_In_ fwp_classify_parameters_t* parameters);
|
||||
|
||||
FWP_ACTION_TYPE
|
||||
test_cgroup_inet4_recv_accept();
|
||||
test_cgroup_inet4_recv_accept(_In_ fwp_classify_parameters_t* parameters);
|
||||
|
||||
FWP_ACTION_TYPE
|
||||
test_cgroup_inet6_recv_accept();
|
||||
test_cgroup_inet6_recv_accept(_In_ fwp_classify_parameters_t* parameters);
|
||||
|
||||
FWP_ACTION_TYPE
|
||||
test_cgroup_inet4_connect();
|
||||
test_cgroup_inet4_connect(_In_ fwp_classify_parameters_t* parameters);
|
||||
|
||||
FWP_ACTION_TYPE
|
||||
test_cgroup_inet6_connect();
|
||||
test_cgroup_inet6_connect(_In_ fwp_classify_parameters_t* parameters);
|
||||
|
||||
FWP_ACTION_TYPE
|
||||
test_sock_ops_v4();
|
||||
test_sock_ops_v4(_In_ fwp_classify_parameters_t* parameters);
|
||||
|
||||
FWP_ACTION_TYPE
|
||||
test_sock_ops_v6();
|
||||
test_sock_ops_v6(_In_ fwp_classify_parameters_t* parameters);
|
||||
|
||||
static _fwp_engine*
|
||||
get()
|
||||
|
@ -109,22 +217,14 @@ typedef class _fwp_engine
|
|||
}
|
||||
|
||||
private:
|
||||
FWP_ACTION_TYPE
|
||||
test_cgroup_sock_addr(
|
||||
uint16_t layer_id,
|
||||
_In_ const GUID& layer_guid,
|
||||
_In_ const GUID& sublayer_guid,
|
||||
_In_ FWPS_INCOMING_VALUE0* incomingValue);
|
||||
|
||||
FWP_ACTION_TYPE
|
||||
test_callout(
|
||||
_Requires_lock_not_held_(this->lock) FWP_ACTION_TYPE test_callout(
|
||||
uint16_t layer_id,
|
||||
_In_ const GUID& layer_guid,
|
||||
_In_ const GUID& sublayer_guid,
|
||||
_In_ FWPS_INCOMING_VALUE0* incoming_value);
|
||||
|
||||
_Ret_maybenull_ const FWPM_FILTER*
|
||||
get_fwpm_filter_with_context(_In_ const GUID& layer_guid)
|
||||
get_fwpm_filter_with_context_under_lock(_In_ const GUID& layer_guid)
|
||||
{
|
||||
for (auto& [first, filter] : fwpm_filters) {
|
||||
if (memcmp(&filter.layerKey, &layer_guid, sizeof(GUID)) == 0 && filter.rawContext != 0) {
|
||||
|
@ -135,7 +235,7 @@ typedef class _fwp_engine
|
|||
}
|
||||
|
||||
_Ret_maybenull_ const FWPM_FILTER*
|
||||
get_fwpm_filter_with_context(_In_ const GUID& layer_guid, _In_ const GUID& sublayer_guid)
|
||||
get_fwpm_filter_with_context_under_lock(_In_ const GUID& layer_guid, _In_ const GUID& sublayer_guid)
|
||||
{
|
||||
for (auto& [first, filter] : fwpm_filters) {
|
||||
if (memcmp(&filter.layerKey, &layer_guid, sizeof(GUID)) == 0 &&
|
||||
|
@ -147,7 +247,7 @@ typedef class _fwp_engine
|
|||
}
|
||||
|
||||
_Ret_maybenull_ const GUID*
|
||||
get_callout_key_from_layer_guid(_In_ const GUID* layer_guid)
|
||||
get_callout_key_from_layer_guid_under_lock(_In_ const GUID* layer_guid)
|
||||
{
|
||||
for (auto& [first, callout] : fwpm_callouts) {
|
||||
if (callout.applicableLayer == *layer_guid) {
|
||||
|
@ -158,7 +258,7 @@ typedef class _fwp_engine
|
|||
}
|
||||
|
||||
_Ret_maybenull_ const FWPS_CALLOUT3*
|
||||
get_callout_from_key(_In_ const GUID* callout_key)
|
||||
get_callout_from_key_under_lock(_In_ const GUID* callout_key)
|
||||
{
|
||||
for (auto& [first, callout] : fwps_callouts) {
|
||||
if (callout.calloutKey == *callout_key) {
|
||||
|
@ -170,10 +270,12 @@ typedef class _fwp_engine
|
|||
|
||||
static std::unique_ptr<_fwp_engine> _engine;
|
||||
|
||||
std::mutex lock;
|
||||
std::shared_mutex lock;
|
||||
uint32_t next_id = 1;
|
||||
uint32_t next_flow_id = 1;
|
||||
std::unordered_map<size_t, FWPS_CALLOUT3> fwps_callouts;
|
||||
std::unordered_map<size_t, FWPM_CALLOUT0> fwpm_callouts;
|
||||
std::unordered_map<size_t, FWPM_FILTER0> fwpm_filters;
|
||||
std::unordered_map<size_t, FWPM_SUBLAYER0> fwpm_sub_layers;
|
||||
std::unordered_map<uint64_t, uint64_t> fwpm_flow_contexts;
|
||||
} fwp_engine;
|
||||
|
|
|
@ -103,23 +103,26 @@ FUZZ_EXPORT int __cdecl LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
fwp_classify_parameters_t parameters = {};
|
||||
netebpfext_initialize_fwp_classify_parameters(¶meters);
|
||||
|
||||
client_context.metadata = *metadata;
|
||||
switch (prog_type) {
|
||||
case BPF_PROG_TYPE_XDP:
|
||||
(void)helper.classify_test_packet(&FWPM_LAYER_INBOUND_MAC_FRAME_NATIVE, if_index);
|
||||
break;
|
||||
case BPF_PROG_TYPE_BIND:
|
||||
(void)helper.test_bind_ipv4();
|
||||
(void)helper.test_bind_ipv4(¶meters);
|
||||
break;
|
||||
case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
|
||||
(void)helper.test_cgroup_inet4_recv_accept();
|
||||
(void)helper.test_cgroup_inet6_recv_accept();
|
||||
(void)helper.test_cgroup_inet4_connect();
|
||||
(void)helper.test_cgroup_inet6_connect();
|
||||
(void)helper.test_cgroup_inet4_recv_accept(¶meters);
|
||||
(void)helper.test_cgroup_inet6_recv_accept(¶meters);
|
||||
(void)helper.test_cgroup_inet4_connect(¶meters);
|
||||
(void)helper.test_cgroup_inet6_connect(¶meters);
|
||||
break;
|
||||
case BPF_PROG_TYPE_SOCK_OPS:
|
||||
(void)helper.test_sock_ops_v4();
|
||||
(void)helper.test_sock_ops_v6();
|
||||
(void)helper.test_sock_ops_v4(¶meters);
|
||||
(void)helper.test_sock_ops_v6(¶meters);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,37 @@
|
|||
ebpf_registry_key_t ebpf_root_registry_key = HKEY_CURRENT_USER;
|
||||
DEVICE_OBJECT* _net_ebpf_ext_driver_device_object;
|
||||
|
||||
constexpr uint32_t _test_destination_ipv4_address = 0x01020304;
|
||||
static FWP_BYTE_ARRAY16 _test_destination_ipv6_address = {1, 2, 3, 4};
|
||||
constexpr uint16_t _test_destination_port = 1234;
|
||||
constexpr uint32_t _test_source_ipv4_address = 0x05060708;
|
||||
static FWP_BYTE_ARRAY16 _test_source_ipv6_address = {5, 6, 7, 8};
|
||||
constexpr uint16_t _test_source_port = 5678;
|
||||
constexpr uint8_t _test_protocol = IPPROTO_TCP;
|
||||
constexpr uint32_t _test_compartment_id = 1;
|
||||
static FWP_BYTE_BLOB _test_app_id = {.size = 2, .data = (uint8_t*)"\\"};
|
||||
static uint64_t _test_interface_luid = 1;
|
||||
static TOKEN_ACCESS_INFORMATION _test_token_access_information = {0};
|
||||
static FWP_BYTE_BLOB _test_user_id = {
|
||||
.size = (sizeof(TOKEN_ACCESS_INFORMATION)), .data = (uint8_t*)&_test_token_access_information};
|
||||
|
||||
void
|
||||
netebpfext_initialize_fwp_classify_parameters(_Out_ fwp_classify_parameters_t* parameters)
|
||||
{
|
||||
parameters->destination_ipv4_address = _test_destination_ipv4_address;
|
||||
parameters->destination_ipv6_address = _test_destination_ipv6_address;
|
||||
parameters->source_ipv4_address = _test_source_ipv4_address;
|
||||
parameters->source_ipv6_address = _test_source_ipv6_address;
|
||||
parameters->source_port = _test_source_port;
|
||||
parameters->destination_port = _test_destination_port;
|
||||
parameters->protocol = _test_protocol;
|
||||
parameters->compartment_id = _test_compartment_id;
|
||||
parameters->app_id = _test_app_id;
|
||||
parameters->interface_luid = _test_interface_luid;
|
||||
parameters->token_access_information = _test_token_access_information;
|
||||
parameters->user_id = _test_user_id;
|
||||
}
|
||||
|
||||
_netebpf_ext_helper::_netebpf_ext_helper(
|
||||
_In_opt_ const void* npi_specific_characteristics,
|
||||
_In_opt_ _ebpf_extension_dispatch_function dispatch_function,
|
||||
|
@ -16,6 +47,9 @@ _netebpf_ext_helper::_netebpf_ext_helper(
|
|||
REQUIRE(NT_SUCCESS(status));
|
||||
trace_initiated = true;
|
||||
|
||||
REQUIRE(ebpf_platform_initiate() == EBPF_SUCCESS);
|
||||
platform_initialized = true;
|
||||
|
||||
status = net_ebpf_ext_initialize_ndis_handles(driver_object);
|
||||
REQUIRE(NT_SUCCESS(status));
|
||||
|
||||
|
@ -71,6 +105,10 @@ _netebpf_ext_helper::~_netebpf_ext_helper()
|
|||
net_ebpf_ext_uninitialize_ndis_handles();
|
||||
}
|
||||
|
||||
if (platform_initialized) {
|
||||
ebpf_platform_terminate();
|
||||
}
|
||||
|
||||
if (trace_initiated) {
|
||||
net_ebpf_ext_trace_terminate();
|
||||
}
|
||||
|
|
|
@ -49,31 +49,53 @@ typedef class _netebpf_ext_helper
|
|||
}
|
||||
|
||||
FWP_ACTION_TYPE
|
||||
test_bind_ipv4() { return _fwp_engine::get()->test_bind_ipv4(); }
|
||||
test_bind_ipv4(_In_ fwp_classify_parameters_t* parameters)
|
||||
{
|
||||
return _fwp_engine::get()->test_bind_ipv4(parameters);
|
||||
}
|
||||
|
||||
FWP_ACTION_TYPE
|
||||
test_cgroup_inet4_recv_accept() { return _fwp_engine::get()->test_cgroup_inet4_recv_accept(); }
|
||||
test_cgroup_inet4_recv_accept(_In_ fwp_classify_parameters_t* parameters)
|
||||
{
|
||||
return _fwp_engine::get()->test_cgroup_inet4_recv_accept(parameters);
|
||||
}
|
||||
|
||||
FWP_ACTION_TYPE
|
||||
test_cgroup_inet6_recv_accept() { return _fwp_engine::get()->test_cgroup_inet6_recv_accept(); }
|
||||
test_cgroup_inet6_recv_accept(_In_ fwp_classify_parameters_t* parameters)
|
||||
{
|
||||
return _fwp_engine::get()->test_cgroup_inet6_recv_accept(parameters);
|
||||
}
|
||||
|
||||
FWP_ACTION_TYPE
|
||||
test_cgroup_inet4_connect() { return _fwp_engine::get()->test_cgroup_inet4_connect(); }
|
||||
test_cgroup_inet4_connect(_In_ fwp_classify_parameters_t* parameters)
|
||||
{
|
||||
return _fwp_engine::get()->test_cgroup_inet4_connect(parameters);
|
||||
}
|
||||
|
||||
FWP_ACTION_TYPE
|
||||
test_cgroup_inet6_connect() { return _fwp_engine::get()->test_cgroup_inet6_connect(); }
|
||||
test_cgroup_inet6_connect(_In_ fwp_classify_parameters_t* parameters)
|
||||
{
|
||||
return _fwp_engine::get()->test_cgroup_inet6_connect(parameters);
|
||||
}
|
||||
|
||||
FWP_ACTION_TYPE
|
||||
test_sock_ops_v4() { return _fwp_engine::get()->test_sock_ops_v4(); }
|
||||
test_sock_ops_v4(_In_ fwp_classify_parameters_t* parameters)
|
||||
{
|
||||
return _fwp_engine::get()->test_sock_ops_v4(parameters);
|
||||
}
|
||||
|
||||
FWP_ACTION_TYPE
|
||||
test_sock_ops_v6() { return _fwp_engine::get()->test_sock_ops_v6(); }
|
||||
test_sock_ops_v6(_In_ fwp_classify_parameters_t* parameters)
|
||||
{
|
||||
return _fwp_engine::get()->test_sock_ops_v6(parameters);
|
||||
}
|
||||
|
||||
private:
|
||||
bool trace_initiated = false;
|
||||
bool ndis_handle_initialized = false;
|
||||
bool provider_registered = false;
|
||||
bool wfp_initialized = false;
|
||||
bool platform_initialized = false;
|
||||
DRIVER_OBJECT* driver_object = reinterpret_cast<DRIVER_OBJECT*>(this);
|
||||
DEVICE_OBJECT* device_object = reinterpret_cast<DEVICE_OBJECT*>(this);
|
||||
|
||||
|
@ -165,3 +187,6 @@ typedef class _netebpf_ext_helper
|
|||
HANDLE nmr_hook_client_handle;
|
||||
|
||||
} netebpf_ext_helper_t;
|
||||
|
||||
void
|
||||
netebpfext_initialize_fwp_classify_parameters(_Out_ fwp_classify_parameters_t* parameters);
|
|
@ -7,6 +7,31 @@
|
|||
|
||||
#include <map>
|
||||
|
||||
#define CONCURRENT_THREAD_RUN_TIME_IN_SECONDS 10
|
||||
|
||||
typedef enum _sock_addr_test_type
|
||||
{
|
||||
SOCK_ADDR_TEST_TYPE_CONNECT,
|
||||
SOCK_ADDR_TEST_TYPE_RECV_ACCEPT
|
||||
} sock_addr_test_type_t;
|
||||
|
||||
typedef enum _sock_addr_test_action
|
||||
{
|
||||
SOCK_ADDR_TEST_ACTION_PERMIT,
|
||||
SOCK_ADDR_TEST_ACTION_BLOCK,
|
||||
SOCK_ADDR_TEST_ACTION_REDIRECT,
|
||||
SOCK_ADDR_TEST_ACTION_FAILURE,
|
||||
SOCK_ADDR_TEST_ACTION_ROUND_ROBIN
|
||||
} sock_addr_test_action_t;
|
||||
|
||||
typedef enum _xdp_test_action
|
||||
{
|
||||
XDP_TEST_ACTION_PASS, ///< Allow the packet to pass.
|
||||
XDP_TEST_ACTION_DROP, ///< Drop the packet.
|
||||
XDP_TEST_ACTION_TX, ///< Bounce the received packet back out the same NIC it arrived on.
|
||||
XDP_TEST_ACTION_FAILURE ///< Failed to invoke the eBPF program.
|
||||
} xdp_test_action_t;
|
||||
|
||||
TEST_CASE("query program info", "[netebpfext]")
|
||||
{
|
||||
netebpf_ext_helper_t helper;
|
||||
|
@ -44,7 +69,7 @@ typedef struct _test_xdp_client_context
|
|||
{
|
||||
netebpfext_helper_base_client_context_t base;
|
||||
void* provider_binding_context;
|
||||
xdp_action_t xdp_action;
|
||||
xdp_test_action_t xdp_action;
|
||||
} test_xdp_client_context_t;
|
||||
|
||||
// This callback occurs when netebpfext gets a packet and submits it to our dummy
|
||||
|
@ -53,10 +78,29 @@ _Must_inspect_result_ ebpf_result_t
|
|||
netebpfext_unit_invoke_xdp_program(
|
||||
_In_ const void* client_binding_context, _In_ const void* context, _Out_ uint32_t* result)
|
||||
{
|
||||
ebpf_result_t return_result = EBPF_SUCCESS;
|
||||
auto client_context = (test_xdp_client_context_t*)client_binding_context;
|
||||
UNREFERENCED_PARAMETER(context);
|
||||
*result = client_context->xdp_action;
|
||||
return EBPF_SUCCESS;
|
||||
|
||||
switch (client_context->xdp_action) {
|
||||
case XDP_TEST_ACTION_PASS:
|
||||
*result = XDP_PASS;
|
||||
break;
|
||||
case XDP_TEST_ACTION_DROP:
|
||||
*result = XDP_DROP;
|
||||
break;
|
||||
case XDP_TEST_ACTION_TX:
|
||||
*result = XDP_TX;
|
||||
break;
|
||||
case XDP_TEST_ACTION_FAILURE:
|
||||
return_result = EBPF_FAILED;
|
||||
break;
|
||||
default:
|
||||
*result = XDP_DROP;
|
||||
break;
|
||||
}
|
||||
|
||||
return return_result;
|
||||
}
|
||||
|
||||
TEST_CASE("classify_packet", "[netebpfext]")
|
||||
|
@ -72,17 +116,22 @@ TEST_CASE("classify_packet", "[netebpfext]")
|
|||
(netebpfext_helper_base_client_context_t*)&client_context);
|
||||
|
||||
// Classify an inbound packet that should pass.
|
||||
client_context.xdp_action = XDP_PASS;
|
||||
client_context.xdp_action = XDP_TEST_ACTION_PASS;
|
||||
FWP_ACTION_TYPE result = helper.classify_test_packet(&FWPM_LAYER_INBOUND_MAC_FRAME_NATIVE, if_index);
|
||||
REQUIRE(result == FWP_ACTION_PERMIT);
|
||||
|
||||
// Classify an inbound packet that should be hairpinned.
|
||||
client_context.xdp_action = XDP_TX;
|
||||
client_context.xdp_action = XDP_TEST_ACTION_TX;
|
||||
result = helper.classify_test_packet(&FWPM_LAYER_INBOUND_MAC_FRAME_NATIVE, if_index);
|
||||
REQUIRE(result == FWP_ACTION_BLOCK);
|
||||
|
||||
// Classify an inbound packet that should be dropped.
|
||||
client_context.xdp_action = XDP_DROP;
|
||||
client_context.xdp_action = XDP_TEST_ACTION_DROP;
|
||||
result = helper.classify_test_packet(&FWPM_LAYER_INBOUND_MAC_FRAME_NATIVE, if_index);
|
||||
REQUIRE(result == FWP_ACTION_BLOCK);
|
||||
|
||||
// Classify an inbound packet when eBPF program invocation failed.
|
||||
client_context.xdp_action = XDP_TEST_ACTION_FAILURE;
|
||||
result = helper.classify_test_packet(&FWPM_LAYER_INBOUND_MAC_FRAME_NATIVE, if_index);
|
||||
REQUIRE(result == FWP_ACTION_BLOCK);
|
||||
}
|
||||
|
@ -168,25 +217,28 @@ TEST_CASE("bind_invoke", "[netebpfext]")
|
|||
{
|
||||
ebpf_extension_data_t npi_specific_characteristics = {};
|
||||
test_bind_client_context_t client_context = {};
|
||||
fwp_classify_parameters_t parameters = {};
|
||||
|
||||
netebpf_ext_helper_t helper(
|
||||
&npi_specific_characteristics,
|
||||
(_ebpf_extension_dispatch_function)netebpfext_unit_invoke_bind_program,
|
||||
(netebpfext_helper_base_client_context_t*)&client_context);
|
||||
|
||||
netebpfext_initialize_fwp_classify_parameters(¶meters);
|
||||
|
||||
// Classify a bind that should be allowed.
|
||||
client_context.bind_action = BIND_PERMIT;
|
||||
FWP_ACTION_TYPE result = helper.test_bind_ipv4(); // TODO(issue #526): support IPv6.
|
||||
FWP_ACTION_TYPE result = helper.test_bind_ipv4(¶meters); // TODO(issue #526): support IPv6.
|
||||
REQUIRE(result == FWP_ACTION_PERMIT);
|
||||
|
||||
// Classify a bind that should be redirected.
|
||||
client_context.bind_action = BIND_REDIRECT;
|
||||
result = helper.test_bind_ipv4();
|
||||
result = helper.test_bind_ipv4(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_PERMIT);
|
||||
|
||||
// Classify a bind that should be blocked.
|
||||
client_context.bind_action = BIND_DENY;
|
||||
result = helper.test_bind_ipv4();
|
||||
result = helper.test_bind_ipv4(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_BLOCK);
|
||||
}
|
||||
|
||||
|
@ -271,69 +323,324 @@ typedef struct test_sock_addr_client_context_t
|
|||
{
|
||||
netebpfext_helper_base_client_context_t base;
|
||||
int sock_addr_action;
|
||||
bool validate_sock_addr_entries = true;
|
||||
} test_sock_addr_client_context_t;
|
||||
|
||||
static inline sock_addr_test_action_t
|
||||
_get_sock_addr_action(uint16_t destination_port)
|
||||
{
|
||||
return (sock_addr_test_action_t)(destination_port % SOCK_ADDR_TEST_ACTION_ROUND_ROBIN);
|
||||
}
|
||||
|
||||
static inline FWP_ACTION_TYPE
|
||||
_get_fwp_sock_addr_action(uint16_t destination_port)
|
||||
{
|
||||
sock_addr_test_action_t action = _get_sock_addr_action(destination_port);
|
||||
if (action == SOCK_ADDR_TEST_ACTION_PERMIT || action == SOCK_ADDR_TEST_ACTION_REDIRECT) {
|
||||
return FWP_ACTION_PERMIT;
|
||||
}
|
||||
|
||||
return FWP_ACTION_BLOCK;
|
||||
}
|
||||
|
||||
_Must_inspect_result_ ebpf_result_t
|
||||
netebpfext_unit_invoke_sock_addr_program(
|
||||
_In_ const void* client_binding_context, _In_ const void* context, _Out_ uint32_t* result)
|
||||
{
|
||||
ebpf_result_t return_result = EBPF_SUCCESS;
|
||||
auto client_context = (test_sock_addr_client_context_t*)client_binding_context;
|
||||
auto sock_addr_context = (bpf_sock_addr_t*)context;
|
||||
int action;
|
||||
|
||||
// Verify context fields match what the netebpfext helper set.
|
||||
// Note that the helper sets the first four bytes of the address to the
|
||||
// same value regardless of whether it is IPv4 or IPv6, so we just look
|
||||
// at the first four bytes as if it were an IPv4 address.
|
||||
REQUIRE((sock_addr_context->family == AF_INET || sock_addr_context->family == AF_INET6));
|
||||
REQUIRE(sock_addr_context->user_ip4 == htonl(0x01020304));
|
||||
REQUIRE(sock_addr_context->msg_src_ip4 == htonl(0x05060708));
|
||||
REQUIRE(sock_addr_context->protocol == IPPROTO_TCP);
|
||||
REQUIRE(sock_addr_context->user_port == htons(1234));
|
||||
REQUIRE(sock_addr_context->msg_src_port == htons(5678));
|
||||
if (client_context->validate_sock_addr_entries) {
|
||||
REQUIRE((sock_addr_context->family == AF_INET || sock_addr_context->family == AF_INET6));
|
||||
REQUIRE(sock_addr_context->user_ip4 == htonl(0x01020304));
|
||||
REQUIRE(sock_addr_context->msg_src_ip4 == htonl(0x05060708));
|
||||
REQUIRE(sock_addr_context->protocol == IPPROTO_TCP);
|
||||
REQUIRE(sock_addr_context->user_port == htons(1234));
|
||||
REQUIRE(sock_addr_context->msg_src_port == htons(5678));
|
||||
}
|
||||
|
||||
*result = client_context->sock_addr_action;
|
||||
return EBPF_SUCCESS;
|
||||
// If the action is round robin, decide the action based on the port number.
|
||||
if (client_context->sock_addr_action == SOCK_ADDR_TEST_ACTION_ROUND_ROBIN) {
|
||||
action = _get_sock_addr_action(sock_addr_context->user_port);
|
||||
} else {
|
||||
action = client_context->sock_addr_action;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case SOCK_ADDR_TEST_ACTION_PERMIT:
|
||||
*result = BPF_SOCK_ADDR_VERDICT_PROCEED;
|
||||
break;
|
||||
case SOCK_ADDR_TEST_ACTION_BLOCK:
|
||||
*result = BPF_SOCK_ADDR_VERDICT_REJECT;
|
||||
break;
|
||||
case SOCK_ADDR_TEST_ACTION_REDIRECT:
|
||||
sock_addr_context->user_port++;
|
||||
if (sock_addr_context->family == AF_INET) {
|
||||
sock_addr_context->user_ip4++;
|
||||
} else {
|
||||
auto first_octet = &sock_addr_context->user_ip6[0];
|
||||
(*first_octet)++;
|
||||
}
|
||||
*result = BPF_SOCK_ADDR_VERDICT_PROCEED;
|
||||
break;
|
||||
case SOCK_ADDR_TEST_ACTION_FAILURE:
|
||||
return_result = EBPF_FAILED;
|
||||
break;
|
||||
default:
|
||||
*result = BPF_SOCK_ADDR_VERDICT_REJECT;
|
||||
}
|
||||
|
||||
return return_result;
|
||||
}
|
||||
|
||||
TEST_CASE("sock_addr_invoke", "[netebpfext]")
|
||||
{
|
||||
ebpf_extension_data_t npi_specific_characteristics = {};
|
||||
test_sock_addr_client_context_t client_context = {};
|
||||
fwp_classify_parameters_t parameters = {};
|
||||
|
||||
netebpf_ext_helper_t helper(
|
||||
&npi_specific_characteristics,
|
||||
(_ebpf_extension_dispatch_function)netebpfext_unit_invoke_sock_addr_program,
|
||||
(netebpfext_helper_base_client_context_t*)&client_context);
|
||||
|
||||
netebpfext_initialize_fwp_classify_parameters(¶meters);
|
||||
|
||||
// Classify operations that should be allowed.
|
||||
client_context.sock_addr_action = BPF_SOCK_ADDR_VERDICT_PROCEED;
|
||||
client_context.sock_addr_action = SOCK_ADDR_TEST_ACTION_PERMIT;
|
||||
client_context.validate_sock_addr_entries = true;
|
||||
|
||||
FWP_ACTION_TYPE result = helper.test_cgroup_inet4_recv_accept();
|
||||
FWP_ACTION_TYPE result = helper.test_cgroup_inet4_recv_accept(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_PERMIT);
|
||||
|
||||
result = helper.test_cgroup_inet6_recv_accept();
|
||||
result = helper.test_cgroup_inet6_recv_accept(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_PERMIT);
|
||||
|
||||
result = helper.test_cgroup_inet4_connect();
|
||||
result = helper.test_cgroup_inet4_connect(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_PERMIT);
|
||||
|
||||
result = helper.test_cgroup_inet6_connect();
|
||||
result = helper.test_cgroup_inet6_connect(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_PERMIT);
|
||||
|
||||
// Classify operations that should be blocked.
|
||||
client_context.sock_addr_action = BPF_SOCK_ADDR_VERDICT_REJECT;
|
||||
client_context.sock_addr_action = SOCK_ADDR_TEST_ACTION_BLOCK;
|
||||
|
||||
result = helper.test_cgroup_inet4_recv_accept();
|
||||
result = helper.test_cgroup_inet4_recv_accept(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_BLOCK);
|
||||
|
||||
result = helper.test_cgroup_inet6_recv_accept();
|
||||
result = helper.test_cgroup_inet6_recv_accept(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_BLOCK);
|
||||
|
||||
result = helper.test_cgroup_inet4_connect();
|
||||
result = helper.test_cgroup_inet4_connect(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_BLOCK);
|
||||
|
||||
result = helper.test_cgroup_inet6_connect();
|
||||
result = helper.test_cgroup_inet6_connect(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_BLOCK);
|
||||
|
||||
// Classify operations for redirect.
|
||||
client_context.sock_addr_action = SOCK_ADDR_TEST_ACTION_REDIRECT;
|
||||
|
||||
result = helper.test_cgroup_inet4_connect(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_PERMIT);
|
||||
|
||||
result = helper.test_cgroup_inet6_connect(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_PERMIT);
|
||||
|
||||
// Test eBPF program invocation failure.
|
||||
client_context.sock_addr_action = SOCK_ADDR_TEST_ACTION_FAILURE;
|
||||
|
||||
result = helper.test_cgroup_inet4_recv_accept(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_BLOCK);
|
||||
|
||||
result = helper.test_cgroup_inet6_recv_accept(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_BLOCK);
|
||||
|
||||
result = helper.test_cgroup_inet4_connect(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_BLOCK);
|
||||
|
||||
result = helper.test_cgroup_inet6_connect(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_BLOCK);
|
||||
}
|
||||
|
||||
void
|
||||
sock_addr_thread_function(
|
||||
std::stop_token token,
|
||||
_In_ netebpf_ext_helper_t* helper,
|
||||
_In_ fwp_classify_parameters_t* parameters,
|
||||
sock_addr_test_type_t type,
|
||||
uint16_t start_port,
|
||||
uint16_t end_port)
|
||||
{
|
||||
FWP_ACTION_TYPE result;
|
||||
uint16_t port_number;
|
||||
|
||||
if (start_port != end_port) {
|
||||
port_number = start_port - 1;
|
||||
} else {
|
||||
port_number = htons(parameters->destination_port);
|
||||
}
|
||||
|
||||
while (!token.stop_requested()) {
|
||||
// If start_port and end_port are same, then the port number for each
|
||||
// invocation will remain the same.
|
||||
if (start_port != end_port) {
|
||||
port_number++;
|
||||
if (port_number > end_port) {
|
||||
port_number = start_port;
|
||||
}
|
||||
parameters->destination_port = htons(port_number);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case SOCK_ADDR_TEST_TYPE_RECV_ACCEPT:
|
||||
result = helper->test_cgroup_inet4_recv_accept(parameters);
|
||||
break;
|
||||
case SOCK_ADDR_TEST_TYPE_CONNECT:
|
||||
default:
|
||||
result = helper->test_cgroup_inet4_connect(parameters);
|
||||
break;
|
||||
}
|
||||
|
||||
REQUIRE(result == _get_fwp_sock_addr_action(port_number));
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke SOCK_ADDR_CONNECT concurrently with same classify parameters.
|
||||
TEST_CASE("sock_addr_invoke_concurrent1", "[netebpfext_concurrent]")
|
||||
{
|
||||
ebpf_extension_data_t npi_specific_characteristics = {};
|
||||
test_sock_addr_client_context_t client_context = {};
|
||||
fwp_classify_parameters_t parameters = {};
|
||||
std::vector<std::jthread> threads;
|
||||
|
||||
netebpf_ext_helper_t helper(
|
||||
&npi_specific_characteristics,
|
||||
(_ebpf_extension_dispatch_function)netebpfext_unit_invoke_sock_addr_program,
|
||||
(netebpfext_helper_base_client_context_t*)&client_context);
|
||||
|
||||
netebpfext_initialize_fwp_classify_parameters(¶meters);
|
||||
client_context.validate_sock_addr_entries = true;
|
||||
|
||||
// Classify operations that should be allowed.
|
||||
client_context.sock_addr_action = SOCK_ADDR_TEST_ACTION_PERMIT;
|
||||
|
||||
uint32_t thread_count = 2 * ebpf_get_cpu_count();
|
||||
for (uint32_t i = 0; i < thread_count; i++) {
|
||||
threads.emplace_back(
|
||||
sock_addr_thread_function,
|
||||
&helper,
|
||||
¶meters,
|
||||
SOCK_ADDR_TEST_TYPE_CONNECT,
|
||||
parameters.destination_port,
|
||||
parameters.destination_port);
|
||||
}
|
||||
|
||||
// Wait for 10 seconds.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(CONCURRENT_THREAD_RUN_TIME_IN_SECONDS));
|
||||
|
||||
// Stop all threads.
|
||||
for (auto& thread : threads) {
|
||||
thread.request_stop();
|
||||
}
|
||||
|
||||
// Wait for all threads to stop.
|
||||
for (auto& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke SOCK_ADDR_CONNECT concurrently with different classify parameters.
|
||||
TEST_CASE("sock_addr_invoke_concurrent2", "[netebpfext_concurrent]")
|
||||
{
|
||||
ebpf_extension_data_t npi_specific_characteristics = {};
|
||||
test_sock_addr_client_context_t client_context = {};
|
||||
std::vector<std::jthread> threads;
|
||||
std::vector<fwp_classify_parameters_t> parameters;
|
||||
|
||||
netebpf_ext_helper_t helper(
|
||||
&npi_specific_characteristics,
|
||||
(_ebpf_extension_dispatch_function)netebpfext_unit_invoke_sock_addr_program,
|
||||
(netebpfext_helper_base_client_context_t*)&client_context);
|
||||
|
||||
client_context.sock_addr_action = SOCK_ADDR_TEST_ACTION_ROUND_ROBIN;
|
||||
client_context.validate_sock_addr_entries = false;
|
||||
|
||||
uint32_t thread_count = 2 * ebpf_get_cpu_count();
|
||||
parameters.resize(thread_count);
|
||||
|
||||
for (uint32_t i = 0; i < thread_count; i++) {
|
||||
netebpfext_initialize_fwp_classify_parameters(¶meters[i]);
|
||||
threads.emplace_back(
|
||||
sock_addr_thread_function,
|
||||
&helper,
|
||||
¶meters[i],
|
||||
SOCK_ADDR_TEST_TYPE_CONNECT,
|
||||
(uint16_t)(i * 1000),
|
||||
(uint16_t)(i * 1000 + 1000));
|
||||
}
|
||||
|
||||
// Wait for 10 seconds.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(CONCURRENT_THREAD_RUN_TIME_IN_SECONDS));
|
||||
|
||||
// Stop all threads.
|
||||
for (auto& thread : threads) {
|
||||
thread.request_stop();
|
||||
}
|
||||
|
||||
// Wait for all threads to stop.
|
||||
for (auto& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke SOCK_ADDR_RECV_ACCEPT concurrently with different classify parameters.
|
||||
TEST_CASE("sock_addr_invoke_concurrent3", "[netebpfext_concurrent]")
|
||||
{
|
||||
ebpf_extension_data_t npi_specific_characteristics = {};
|
||||
test_sock_addr_client_context_t client_context = {};
|
||||
std::vector<std::jthread> threads;
|
||||
std::vector<fwp_classify_parameters_t> parameters;
|
||||
|
||||
netebpf_ext_helper_t helper(
|
||||
&npi_specific_characteristics,
|
||||
(_ebpf_extension_dispatch_function)netebpfext_unit_invoke_sock_addr_program,
|
||||
(netebpfext_helper_base_client_context_t*)&client_context);
|
||||
|
||||
client_context.sock_addr_action = SOCK_ADDR_TEST_ACTION_ROUND_ROBIN;
|
||||
client_context.validate_sock_addr_entries = false;
|
||||
|
||||
uint32_t thread_count = 2 * ebpf_get_cpu_count();
|
||||
parameters.resize(thread_count);
|
||||
|
||||
for (uint32_t i = 0; i < thread_count; i++) {
|
||||
netebpfext_initialize_fwp_classify_parameters(¶meters[i]);
|
||||
threads.emplace_back(
|
||||
sock_addr_thread_function,
|
||||
&helper,
|
||||
¶meters[i],
|
||||
SOCK_ADDR_TEST_TYPE_RECV_ACCEPT,
|
||||
(uint16_t)(i * 1000),
|
||||
(uint16_t)(i * 1000 + 1000));
|
||||
}
|
||||
|
||||
// Wait for 10 seconds.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(CONCURRENT_THREAD_RUN_TIME_IN_SECONDS));
|
||||
|
||||
// Stop all threads.
|
||||
for (auto& thread : threads) {
|
||||
thread.request_stop();
|
||||
}
|
||||
|
||||
// Wait for all threads to stop.
|
||||
for (auto& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("sock_addr_context", "[netebpfext]")
|
||||
|
@ -426,28 +733,31 @@ TEST_CASE("sock_ops_invoke", "[netebpfext]")
|
|||
{
|
||||
ebpf_extension_data_t npi_specific_characteristics = {};
|
||||
test_sock_ops_client_context_t client_context = {};
|
||||
fwp_classify_parameters_t parameters = {};
|
||||
|
||||
netebpf_ext_helper_t helper(
|
||||
&npi_specific_characteristics,
|
||||
(_ebpf_extension_dispatch_function)netebpfext_unit_invoke_sock_ops_program,
|
||||
(netebpfext_helper_base_client_context_t*)&client_context);
|
||||
|
||||
netebpfext_initialize_fwp_classify_parameters(¶meters);
|
||||
|
||||
// Do some operations that return success.
|
||||
client_context.sock_ops_action = 0;
|
||||
|
||||
FWP_ACTION_TYPE result = helper.test_sock_ops_v4();
|
||||
FWP_ACTION_TYPE result = helper.test_sock_ops_v4(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_PERMIT);
|
||||
|
||||
result = helper.test_sock_ops_v6();
|
||||
result = helper.test_sock_ops_v6(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_PERMIT);
|
||||
|
||||
// Do some operations that return failure.
|
||||
client_context.sock_ops_action = -1;
|
||||
|
||||
result = helper.test_sock_ops_v4();
|
||||
result = helper.test_sock_ops_v4(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_BLOCK);
|
||||
|
||||
result = helper.test_sock_ops_v6();
|
||||
result = helper.test_sock_ops_v6(¶meters);
|
||||
REQUIRE(result == FWP_ACTION_BLOCK);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче