Родитель
f661e74d82
Коммит
4d4c5b5cc7
|
@ -17,149 +17,30 @@ Environment:
|
|||
Kernel mode
|
||||
|
||||
--*/
|
||||
#define INITGUID
|
||||
|
||||
#include "net_ebpf_ext.h"
|
||||
#include "net_ebpf_ext_bind.h"
|
||||
#include "net_ebpf_ext_xdp.h"
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4201) // unnamed struct/union
|
||||
#include <fwpsk.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
#include <fwpmk.h>
|
||||
#include <guiddef.h>
|
||||
#include <netiodef.h>
|
||||
#include <ntddk.h>
|
||||
|
||||
#include "ebpf_ext_attach_provider.h"
|
||||
// ebpf_bind_program_data.h and ebpf_xdp_program_data.h are generated
|
||||
// headers. encode_program_info generates them from the structs
|
||||
// in ebpf_nethooks.h. This workaround exists due to the inability
|
||||
// to call RPC serialization services from kernel mode. Once we switch
|
||||
// to a different serializer, we can get rid of this workaround.
|
||||
#include "ebpf_bind_program_data.h"
|
||||
#include "ebpf_nethooks.h"
|
||||
#include "ebpf_platform.h"
|
||||
#include "ebpf_program_types.h"
|
||||
#include "ebpf_windows.h"
|
||||
#include "ebpf_xdp_program_data.h"
|
||||
|
||||
static HANDLE _net_ebpf_ext_l2_injection_handle = NULL;
|
||||
|
||||
static ebpf_ext_attach_hook_provider_registration_t* _ebpf_xdp_hook_provider_registration = NULL;
|
||||
static ebpf_ext_attach_hook_provider_registration_t* _ebpf_bind_hook_provider_registration = NULL;
|
||||
static ebpf_extension_provider_t* _ebpf_xdp_program_info_provider = NULL;
|
||||
static ebpf_extension_provider_t* _ebpf_bind_program_info_provider = NULL;
|
||||
|
||||
#define RTL_COUNT_OF(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||
|
||||
#define NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION 0
|
||||
|
||||
static ebpf_context_descriptor_t _ebpf_xdp_context_descriptor = {
|
||||
sizeof(xdp_md_t),
|
||||
EBPF_OFFSET_OF(xdp_md_t, data),
|
||||
EBPF_OFFSET_OF(xdp_md_t, data_end),
|
||||
EBPF_OFFSET_OF(xdp_md_t, data_meta)};
|
||||
static ebpf_program_info_t _ebpf_xdp_program_info = {{"xdp", &_ebpf_xdp_context_descriptor, {0}}, 0, NULL};
|
||||
|
||||
static ebpf_program_data_t _ebpf_xdp_program_data = {&_ebpf_xdp_program_info, NULL};
|
||||
|
||||
static ebpf_extension_data_t _ebpf_xdp_program_info_provider_data = {
|
||||
NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION, sizeof(_ebpf_xdp_program_data), &_ebpf_xdp_program_data};
|
||||
|
||||
static ebpf_context_descriptor_t _ebpf_bind_context_descriptor = {
|
||||
sizeof(bind_md_t), EBPF_OFFSET_OF(bind_md_t, app_id_start), EBPF_OFFSET_OF(bind_md_t, app_id_end), -1};
|
||||
static ebpf_program_info_t _ebpf_bind_program_info = {{"bind", &_ebpf_bind_context_descriptor, {0}}, 0, NULL};
|
||||
|
||||
static ebpf_program_data_t _ebpf_bind_program_data = {&_ebpf_bind_program_info, NULL};
|
||||
|
||||
static ebpf_extension_data_t _ebpf_bind_program_info_provider_data = {
|
||||
NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION, sizeof(_ebpf_bind_program_data), &_ebpf_bind_program_data};
|
||||
// Callout and sublayer GUIDs
|
||||
// Sublayer GUID.
|
||||
|
||||
// 7c7b3fb9-3331-436a-98e1-b901df457fff
|
||||
DEFINE_GUID(EBPF_HOOK_SUBLAYER, 0x7c7b3fb9, 0x3331, 0x436a, 0x98, 0xe1, 0xb9, 0x01, 0xdf, 0x45, 0x7f, 0xff);
|
||||
|
||||
// 5a5614e5-6b64-4738-8367-33c6ca07bf8f
|
||||
DEFINE_GUID(EBPF_HOOK_L2_CALLOUT, 0x5a5614e5, 0x6b64, 0x4738, 0x83, 0x67, 0x33, 0xc6, 0xca, 0x07, 0xbf, 0x8f);
|
||||
|
||||
// c69f4de0-3d80-457d-9aea-75faef42ec12
|
||||
DEFINE_GUID(
|
||||
EBPF_HOOK_ALE_BIND_REDIRECT_CALLOUT, 0xc69f4de0, 0x3d80, 0x457d, 0x9a, 0xea, 0x75, 0xfa, 0xef, 0x42, 0xec, 0x12);
|
||||
|
||||
// 732acf94-7319-4fed-97d0-41d3a18f3fa1
|
||||
DEFINE_GUID(
|
||||
EBPF_HOOK_ALE_RESOURCE_ALLOCATION_CALLOUT,
|
||||
0x732acf94,
|
||||
0x7319,
|
||||
0x4fed,
|
||||
0x97,
|
||||
0xd0,
|
||||
0x41,
|
||||
0xd3,
|
||||
0xa1,
|
||||
0x8f,
|
||||
0x3f,
|
||||
0xa1);
|
||||
|
||||
// d5792949-2d91-4023-9993-3f3dd9d54b2b
|
||||
DEFINE_GUID(
|
||||
EBPF_HOOK_ALE_RESOURCE_RELEASE_CALLOUT, 0xd5792949, 0x2d91, 0x4023, 0x99, 0x93, 0x3f, 0x3d, 0xd9, 0xd5, 0x4b, 0x2b);
|
||||
|
||||
// 85e0d8ef-579e-4931-b072-8ee226bb2e9d
|
||||
DEFINE_GUID(EBPF_ATTACH_TYPE_XDP, 0x85e0d8ef, 0x579e, 0x4931, 0xb0, 0x72, 0x8e, 0xe2, 0x26, 0xbb, 0x2e, 0x9d);
|
||||
|
||||
// b9707e04-8127-4c72-833e-05b1fb439496
|
||||
DEFINE_GUID(EBPF_ATTACH_TYPE_BIND, 0xb9707e04, 0x8127, 0x4c72, 0x83, 0x3e, 0x05, 0xb1, 0xfb, 0x43, 0x94, 0x96);
|
||||
|
||||
DEFINE_GUID(EBPF_PROGRAM_TYPE_XDP, 0xf1832a85, 0x85d5, 0x45b0, 0x98, 0xa0, 0x70, 0x69, 0xd6, 0x30, 0x13, 0xb0);
|
||||
|
||||
DEFINE_GUID(EBPF_PROGRAM_TYPE_BIND, 0x608c517c, 0x6c52, 0x4a26, 0xb6, 0x77, 0xbb, 0x1c, 0x34, 0x42, 0x5a, 0xdf);
|
||||
|
||||
static void
|
||||
_net_ebpf_ext_layer_2_classify(
|
||||
_In_ const FWPS_INCOMING_VALUES* incoming_fixed_values,
|
||||
_In_ const FWPS_INCOMING_METADATA_VALUES* incoming_metadata_values,
|
||||
_Inout_opt_ void* layer_data,
|
||||
_In_opt_ const void* classify_context,
|
||||
_In_ const FWPS_FILTER* filter,
|
||||
uint64_t flow_context,
|
||||
_Inout_ FWPS_CLASSIFY_OUT* classify_output);
|
||||
|
||||
static void
|
||||
_net_ebpf_ext_resource_allocation_classify(
|
||||
_In_ const FWPS_INCOMING_VALUES* incoming_fixed_values,
|
||||
_In_ const FWPS_INCOMING_METADATA_VALUES* incoming_metadata_values,
|
||||
_Inout_opt_ void* layer_data,
|
||||
_In_opt_ const void* classify_context,
|
||||
_In_ const FWPS_FILTER* filter,
|
||||
uint64_t flow_context,
|
||||
_Inout_ FWPS_CLASSIFY_OUT* classify_output);
|
||||
|
||||
static void
|
||||
_net_ebpf_ext_resource_release_classify(
|
||||
_In_ const FWPS_INCOMING_VALUES* incoming_fixed_values,
|
||||
_In_ const FWPS_INCOMING_METADATA_VALUES* incoming_metadata_values,
|
||||
_Inout_opt_ void* layer_data,
|
||||
_In_opt_ const void* classify_context,
|
||||
_In_ const FWPS_FILTER* filter,
|
||||
uint64_t flow_context,
|
||||
_Inout_ FWPS_CLASSIFY_OUT* classify_output);
|
||||
|
||||
static void
|
||||
_net_ebpf_ext_no_op_flow_delete(uint16_t layer_id, uint32_t fwpm_callout_id, uint64_t flow_context);
|
||||
_net_ebpf_ext_flow_delete(uint16_t layer_id, uint32_t fwpm_callout_id, uint64_t flow_context);
|
||||
|
||||
static NTSTATUS
|
||||
_net_ebpf_ext_no_op_notify(
|
||||
_net_ebpf_ext_filter_change_notify(
|
||||
FWPS_CALLOUT_NOTIFY_TYPE callout_notification_type, _In_ const GUID* filter_key, _Inout_ const FWPS_FILTER* filter);
|
||||
|
||||
typedef struct _net_ebpf_ext_wfp_callout_state
|
||||
{
|
||||
const GUID* callout_guid;
|
||||
const GUID* layer_guid;
|
||||
FWPS_CALLOUT_CLASSIFY_FN3 classify_fn;
|
||||
FWPS_CALLOUT_NOTIFY_FN3 notify_fn;
|
||||
FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN0 delete_fn;
|
||||
FWPS_CALLOUT_CLASSIFY_FN classify_fn;
|
||||
FWPS_CALLOUT_NOTIFY_FN notify_fn;
|
||||
FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN delete_fn;
|
||||
wchar_t* name;
|
||||
wchar_t* description;
|
||||
FWP_ACTION_TYPE filter_action_type;
|
||||
|
@ -170,19 +51,19 @@ static net_ebpf_ext_wfp_callout_state_t _net_ebpf_ext_wfp_callout_state[] = {
|
|||
{
|
||||
&EBPF_HOOK_L2_CALLOUT,
|
||||
&FWPM_LAYER_INBOUND_MAC_FRAME_NATIVE,
|
||||
_net_ebpf_ext_layer_2_classify,
|
||||
_net_ebpf_ext_no_op_notify,
|
||||
_net_ebpf_ext_no_op_flow_delete,
|
||||
net_ebpf_ext_layer_2_classify,
|
||||
_net_ebpf_ext_filter_change_notify,
|
||||
_net_ebpf_ext_flow_delete,
|
||||
L"L2 XDP Callout",
|
||||
L"L2 callout driver for eBPF at XDP-like layer",
|
||||
FWP_ACTION_CALLOUT_TERMINATING,
|
||||
},
|
||||
{
|
||||
&EBPF_HOOK_ALE_RESOURCE_ALLOCATION_CALLOUT,
|
||||
&EBPF_HOOK_ALE_RESOURCE_ALLOC_CALLOUT,
|
||||
&FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4,
|
||||
_net_ebpf_ext_resource_allocation_classify,
|
||||
_net_ebpf_ext_no_op_notify,
|
||||
_net_ebpf_ext_no_op_flow_delete,
|
||||
net_ebpf_ext_resource_allocation_classify,
|
||||
_net_ebpf_ext_filter_change_notify,
|
||||
_net_ebpf_ext_flow_delete,
|
||||
L"Resource Allocation eBPF Callout",
|
||||
L"Resource Allocation callout driver for eBPF",
|
||||
FWP_ACTION_CALLOUT_TERMINATING,
|
||||
|
@ -190,9 +71,9 @@ static net_ebpf_ext_wfp_callout_state_t _net_ebpf_ext_wfp_callout_state[] = {
|
|||
{
|
||||
&EBPF_HOOK_ALE_RESOURCE_RELEASE_CALLOUT,
|
||||
&FWPM_LAYER_ALE_RESOURCE_RELEASE_V4,
|
||||
_net_ebpf_ext_resource_release_classify,
|
||||
_net_ebpf_ext_no_op_notify,
|
||||
_net_ebpf_ext_no_op_flow_delete,
|
||||
net_ebpf_ext_resource_release_classify,
|
||||
_net_ebpf_ext_filter_change_notify,
|
||||
_net_ebpf_ext_flow_delete,
|
||||
L"Resource Release eBPF Callout",
|
||||
L"Resource Release callout driver for eBPF",
|
||||
FWP_ACTION_CALLOUT_TERMINATING,
|
||||
|
@ -352,7 +233,7 @@ net_ebpf_ext_register_callouts(_Inout_ void* device_object)
|
|||
goto Exit;
|
||||
}
|
||||
|
||||
for (index = 0; index < RTL_COUNT_OF(_net_ebpf_ext_wfp_callout_state); index++) {
|
||||
for (index = 0; index < EBPF_COUNT_OF(_net_ebpf_ext_wfp_callout_state); index++) {
|
||||
status = _net_ebpf_ext_register_wfp_callout(&_net_ebpf_ext_wfp_callout_state[index], device_object);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
KdPrintEx(
|
||||
|
@ -406,7 +287,7 @@ net_ebpf_ext_unregister_callouts(void)
|
|||
FwpmEngineClose(_fwp_engine_handle);
|
||||
_fwp_engine_handle = NULL;
|
||||
|
||||
for (index = 0; index < RTL_COUNT_OF(_net_ebpf_ext_wfp_callout_state); index++) {
|
||||
for (index = 0; index < EBPF_COUNT_OF(_net_ebpf_ext_wfp_callout_state); index++) {
|
||||
FwpsCalloutUnregisterById(_net_ebpf_ext_wfp_callout_state[index].assigned_callout_id);
|
||||
}
|
||||
}
|
||||
|
@ -414,249 +295,8 @@ net_ebpf_ext_unregister_callouts(void)
|
|||
FwpsInjectionHandleDestroy(_net_ebpf_ext_l2_injection_handle);
|
||||
}
|
||||
|
||||
static void
|
||||
_net_ebpf_ext_l2_inject_complete(
|
||||
_In_ const void* context, _Inout_ NET_BUFFER_LIST* packet_clone, BOOLEAN dispatch_level)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(context);
|
||||
FwpsFreeCloneNetBufferList(packet_clone, dispatch_level);
|
||||
}
|
||||
|
||||
static void
|
||||
_net_ebpf_ext_handle_xdp_tx(_Inout_ NET_BUFFER_LIST* packet, _In_ const FWPS_INCOMING_VALUES* incoming_fixed_values)
|
||||
{
|
||||
NET_BUFFER_LIST* packet_clone = NULL;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
uint32_t interface_index =
|
||||
incoming_fixed_values->incomingValue[FWPS_FIELD_INBOUND_MAC_FRAME_NATIVE_INTERFACE_INDEX].value.uint32;
|
||||
uint32_t ndis_port =
|
||||
incoming_fixed_values->incomingValue[FWPS_FIELD_INBOUND_MAC_FRAME_NATIVE_NDIS_PORT].value.uint32;
|
||||
|
||||
status = FwpsAllocateCloneNetBufferList(packet, NULL, NULL, 0, &packet_clone);
|
||||
if (status != STATUS_SUCCESS)
|
||||
goto Exit;
|
||||
|
||||
status = FwpsInjectMacSendAsync(
|
||||
_net_ebpf_ext_l2_injection_handle,
|
||||
NULL,
|
||||
0,
|
||||
FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE,
|
||||
interface_index,
|
||||
ndis_port,
|
||||
packet_clone,
|
||||
_net_ebpf_ext_l2_inject_complete,
|
||||
NULL);
|
||||
|
||||
if (status != STATUS_SUCCESS)
|
||||
goto Exit;
|
||||
Exit:
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
_net_ebpf_ext_layer_2_classify(
|
||||
_In_ const FWPS_INCOMING_VALUES* incoming_fixed_values,
|
||||
_In_ const FWPS_INCOMING_METADATA_VALUES* incoming_metadata_values,
|
||||
_Inout_opt_ void* layer_data,
|
||||
_In_opt_ const void* classify_context,
|
||||
_In_ const FWPS_FILTER* filter,
|
||||
uint64_t flow_context,
|
||||
_Inout_ FWPS_CLASSIFY_OUT* classify_output)
|
||||
/* ++
|
||||
|
||||
A simple classify function at the WFP L2 MAC layer.
|
||||
|
||||
-- */
|
||||
{
|
||||
FWP_ACTION_TYPE action = FWP_ACTION_PERMIT;
|
||||
|
||||
UNREFERENCED_PARAMETER(incoming_metadata_values);
|
||||
UNREFERENCED_PARAMETER(classify_context);
|
||||
UNREFERENCED_PARAMETER(filter);
|
||||
UNREFERENCED_PARAMETER(flow_context);
|
||||
NET_BUFFER_LIST* nbl = (NET_BUFFER_LIST*)layer_data;
|
||||
NET_BUFFER* net_buffer = NULL;
|
||||
uint8_t* packet_buffer;
|
||||
uint32_t result = 0;
|
||||
|
||||
if (!ebpf_ext_attach_enter_rundown(_ebpf_xdp_hook_provider_registration))
|
||||
goto done;
|
||||
|
||||
if (nbl == NULL) {
|
||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Null nbl \n"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
net_buffer = NET_BUFFER_LIST_FIRST_NB(nbl);
|
||||
if (net_buffer == NULL) {
|
||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "net_buffer not present\n"));
|
||||
// nothing to do
|
||||
goto done;
|
||||
}
|
||||
|
||||
packet_buffer = NdisGetDataBuffer(net_buffer, net_buffer->DataLength, NULL, sizeof(uint16_t), 0);
|
||||
if (!packet_buffer) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
xdp_md_t ctx = {packet_buffer, packet_buffer + net_buffer->DataLength};
|
||||
|
||||
if (ebpf_ext_attach_invoke_hook(_ebpf_xdp_hook_provider_registration, &ctx, &result) == EBPF_SUCCESS) {
|
||||
switch (result) {
|
||||
case XDP_PASS:
|
||||
action = FWP_ACTION_PERMIT;
|
||||
break;
|
||||
case XDP_TX:
|
||||
_net_ebpf_ext_handle_xdp_tx(nbl, incoming_fixed_values);
|
||||
// Fall through.
|
||||
case XDP_DROP:
|
||||
action = FWP_ACTION_BLOCK;
|
||||
classify_output->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
|
||||
break;
|
||||
}
|
||||
}
|
||||
done:
|
||||
classify_output->actionType = action;
|
||||
|
||||
ebpf_ext_attach_leave_rundown(_ebpf_xdp_hook_provider_registration);
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
_net_ebpf_ext_resource_truncate_appid(bind_md_t* ctx)
|
||||
{
|
||||
wchar_t* last_separator = (wchar_t*)ctx->app_id_start;
|
||||
for (wchar_t* position = (wchar_t*)ctx->app_id_start; position < (wchar_t*)ctx->app_id_end; position++) {
|
||||
if (*position == '\\') {
|
||||
last_separator = position;
|
||||
}
|
||||
}
|
||||
if (*last_separator == '\\') {
|
||||
last_separator++;
|
||||
}
|
||||
ctx->app_id_start = (uint8_t*)last_separator;
|
||||
}
|
||||
|
||||
static void
|
||||
_net_ebpf_ext_resource_allocation_classify(
|
||||
_In_ const FWPS_INCOMING_VALUES* incoming_fixed_values,
|
||||
_In_ const FWPS_INCOMING_METADATA_VALUES* incoming_metadata_values,
|
||||
_Inout_opt_ void* layer_data,
|
||||
_In_opt_ const void* classify_context,
|
||||
_In_ const FWPS_FILTER* filter,
|
||||
uint64_t flow_context,
|
||||
_Inout_ FWPS_CLASSIFY_OUT* classify_output)
|
||||
/* ++
|
||||
|
||||
A simple classify function at the WFP Resource Allocation layer.
|
||||
|
||||
-- */
|
||||
{
|
||||
SOCKADDR_IN addr = {AF_INET};
|
||||
uint32_t result;
|
||||
bind_md_t ctx;
|
||||
|
||||
UNREFERENCED_PARAMETER(layer_data);
|
||||
UNREFERENCED_PARAMETER(classify_context);
|
||||
UNREFERENCED_PARAMETER(filter);
|
||||
UNREFERENCED_PARAMETER(flow_context);
|
||||
|
||||
if (!ebpf_ext_attach_enter_rundown(_ebpf_bind_hook_provider_registration)) {
|
||||
classify_output->actionType = FWP_ACTION_PERMIT;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
addr.sin_port =
|
||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_PORT].value.uint16;
|
||||
addr.sin_addr.S_un.S_addr =
|
||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_ADDRESS].value.uint32;
|
||||
|
||||
ctx.process_id = incoming_metadata_values->processId;
|
||||
memcpy(&ctx.socket_address, &addr, sizeof(addr));
|
||||
ctx.operation = BIND_OPERATION_BIND;
|
||||
ctx.protocol = incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_PROTOCOL].value.uint8;
|
||||
|
||||
ctx.app_id_start =
|
||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_ALE_APP_ID].value.byteBlob->data;
|
||||
ctx.app_id_end =
|
||||
ctx.app_id_start +
|
||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_ALE_APP_ID].value.byteBlob->size;
|
||||
|
||||
_net_ebpf_ext_resource_truncate_appid(&ctx);
|
||||
if (ebpf_ext_attach_invoke_hook(_ebpf_bind_hook_provider_registration, &ctx, &result) == EBPF_SUCCESS) {
|
||||
switch (result) {
|
||||
case BIND_PERMIT:
|
||||
case BIND_REDIRECT:
|
||||
classify_output->actionType = FWP_ACTION_PERMIT;
|
||||
break;
|
||||
case BIND_DENY:
|
||||
classify_output->actionType = FWP_ACTION_BLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
Exit:
|
||||
ebpf_ext_attach_leave_rundown(_ebpf_bind_hook_provider_registration);
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
_net_ebpf_ext_resource_release_classify(
|
||||
_In_ const FWPS_INCOMING_VALUES* incoming_fixed_values,
|
||||
_In_ const FWPS_INCOMING_METADATA_VALUES* incoming_metadata_values,
|
||||
_Inout_opt_ void* layer_data,
|
||||
_In_opt_ const void* classify_context,
|
||||
_In_ const FWPS_FILTER* filter,
|
||||
uint64_t flow_context,
|
||||
_Inout_ FWPS_CLASSIFY_OUT* classify_output)
|
||||
/* ++
|
||||
|
||||
A simple classify function at the WFP Resource Release layer.
|
||||
|
||||
-- */
|
||||
{
|
||||
SOCKADDR_IN addr = {AF_INET};
|
||||
uint32_t result;
|
||||
bind_md_t ctx;
|
||||
|
||||
UNREFERENCED_PARAMETER(layer_data);
|
||||
UNREFERENCED_PARAMETER(classify_context);
|
||||
UNREFERENCED_PARAMETER(filter);
|
||||
UNREFERENCED_PARAMETER(flow_context);
|
||||
|
||||
if (!ebpf_ext_attach_enter_rundown(_ebpf_bind_hook_provider_registration)) {
|
||||
classify_output->actionType = FWP_ACTION_PERMIT;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
addr.sin_port = incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_IP_LOCAL_PORT].value.uint16;
|
||||
addr.sin_addr.S_un.S_addr =
|
||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_IP_LOCAL_ADDRESS].value.uint32;
|
||||
|
||||
ctx.process_id = incoming_metadata_values->processId;
|
||||
memcpy(&ctx.socket_address, &addr, sizeof(addr));
|
||||
ctx.operation = BIND_OPERATION_UNBIND;
|
||||
ctx.protocol = incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_IP_PROTOCOL].value.uint8;
|
||||
|
||||
ctx.app_id_start =
|
||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_ALE_APP_ID].value.byteBlob->data;
|
||||
ctx.app_id_end =
|
||||
ctx.app_id_start +
|
||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_ALE_APP_ID].value.byteBlob->size;
|
||||
|
||||
_net_ebpf_ext_resource_truncate_appid(&ctx);
|
||||
|
||||
ebpf_ext_attach_invoke_hook(_ebpf_bind_hook_provider_registration, &ctx, &result);
|
||||
|
||||
classify_output->actionType = FWP_ACTION_PERMIT;
|
||||
|
||||
Exit:
|
||||
ebpf_ext_attach_leave_rundown(_ebpf_bind_hook_provider_registration);
|
||||
return;
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
_net_ebpf_ext_no_op_notify(
|
||||
_net_ebpf_ext_filter_change_notify(
|
||||
FWPS_CALLOUT_NOTIFY_TYPE callout_notification_type, _In_ const GUID* filter_key, _Inout_ const FWPS_FILTER* filter)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(callout_notification_type);
|
||||
|
@ -667,7 +307,7 @@ _net_ebpf_ext_no_op_notify(
|
|||
}
|
||||
|
||||
static void
|
||||
_net_ebpf_ext_no_op_flow_delete(uint16_t layer_id, uint32_t fwpm_callout_id, uint64_t flow_context)
|
||||
_net_ebpf_ext_flow_delete(uint16_t layer_id, uint32_t fwpm_callout_id, uint64_t flow_context)
|
||||
/* ++
|
||||
|
||||
This is the flowDeleteFn function of the L2 callout.
|
||||
|
@ -683,90 +323,23 @@ _net_ebpf_ext_no_op_flow_delete(uint16_t layer_id, uint32_t fwpm_callout_id, uin
|
|||
NTSTATUS
|
||||
net_ebpf_ext_register_providers()
|
||||
{
|
||||
ebpf_result_t return_value;
|
||||
return_value = ebpf_ext_attach_register_provider(
|
||||
&EBPF_PROGRAM_TYPE_XDP,
|
||||
&EBPF_ATTACH_TYPE_XDP,
|
||||
EBPF_EXT_HOOK_EXECUTION_DISPATCH,
|
||||
&_ebpf_xdp_hook_provider_registration);
|
||||
if (return_value != EBPF_SUCCESS) {
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
return_value = ebpf_ext_attach_register_provider(
|
||||
&EBPF_PROGRAM_TYPE_BIND,
|
||||
&EBPF_ATTACH_TYPE_BIND,
|
||||
EBPF_EXT_HOOK_EXECUTION_PASSIVE,
|
||||
&_ebpf_bind_hook_provider_registration);
|
||||
status = net_ebpf_ext_xdp_register_providers();
|
||||
if (status != STATUS_SUCCESS)
|
||||
goto Exit;
|
||||
|
||||
if (return_value != EBPF_SUCCESS) {
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
status = net_ebpf_ext_bind_register_providers();
|
||||
if (status != STATUS_SUCCESS)
|
||||
goto Exit;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
Exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
void
|
||||
net_ebpf_ext_unregister_providers()
|
||||
{
|
||||
ebpf_ext_attach_unregister_provider(_ebpf_xdp_hook_provider_registration);
|
||||
ebpf_ext_attach_unregister_provider(_ebpf_bind_hook_provider_registration);
|
||||
}
|
||||
|
||||
void
|
||||
net_ebpf_ext_program_info_provider_unregister()
|
||||
{
|
||||
ebpf_provider_unload(_ebpf_xdp_program_info_provider);
|
||||
ebpf_provider_unload(_ebpf_bind_program_info_provider);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
net_ebpf_ext_program_info_provider_register()
|
||||
{
|
||||
ebpf_result_t return_value;
|
||||
ebpf_extension_data_t* provider_data;
|
||||
ebpf_program_data_t* program_data;
|
||||
|
||||
provider_data = &_ebpf_xdp_program_info_provider_data;
|
||||
program_data = (ebpf_program_data_t*)provider_data->data;
|
||||
program_data->program_info->program_type_descriptor.program_type = EBPF_PROGRAM_TYPE_XDP;
|
||||
|
||||
return_value = ebpf_provider_load(
|
||||
&_ebpf_xdp_program_info_provider,
|
||||
&EBPF_PROGRAM_TYPE_XDP,
|
||||
NULL,
|
||||
&_ebpf_xdp_program_info_provider_data,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (return_value != EBPF_SUCCESS) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
provider_data = &_ebpf_bind_program_info_provider_data;
|
||||
program_data = (ebpf_program_data_t*)provider_data->data;
|
||||
program_data->program_info->program_type_descriptor.program_type = EBPF_PROGRAM_TYPE_BIND;
|
||||
|
||||
return_value = ebpf_provider_load(
|
||||
&_ebpf_bind_program_info_provider,
|
||||
&EBPF_PROGRAM_TYPE_BIND,
|
||||
NULL,
|
||||
&_ebpf_bind_program_info_provider_data,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (return_value != EBPF_SUCCESS) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
Done:
|
||||
if (return_value != EBPF_SUCCESS) {
|
||||
net_ebpf_ext_program_info_provider_unregister();
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
} else
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
net_ebpf_ext_xdp_unregister_providers();
|
||||
net_ebpf_ext_bind_unregister_providers();
|
||||
}
|
|
@ -18,8 +18,29 @@ Environment:
|
|||
|
||||
#include <ntddk.h>
|
||||
|
||||
#define INITGUID
|
||||
|
||||
#include <fwpmk.h>
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4201) // unnamed struct/union
|
||||
#include <fwpsk.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
#include <guiddef.h>
|
||||
#include <netiodef.h>
|
||||
#include <ntddk.h>
|
||||
|
||||
#include "ebpf_ext_attach_provider.h"
|
||||
#include "ebpf_nethooks.h"
|
||||
#include "ebpf_platform.h"
|
||||
#include "ebpf_program_types.h"
|
||||
#include "ebpf_windows.h"
|
||||
|
||||
#define NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION 0
|
||||
|
||||
//
|
||||
// Shared function prototypes
|
||||
// Shared function prototypes.
|
||||
//
|
||||
|
||||
/**
|
||||
|
@ -40,7 +61,7 @@ void
|
|||
net_ebpf_ext_unregister_callouts(void);
|
||||
|
||||
/**
|
||||
* @brief Register hook providers with eBPF core.
|
||||
* @brief Register network extension NPI providers with eBPF core.
|
||||
*
|
||||
* @retval STATUS_SUCCESS Operation succeeded.
|
||||
* @retval STATUS_UNSUCCESSFUL Operation failed.
|
||||
|
@ -49,24 +70,8 @@ NTSTATUS
|
|||
net_ebpf_ext_register_providers();
|
||||
|
||||
/**
|
||||
* @brief Unregister hook providers from eBPF core.
|
||||
* @brief Unregister network extension NPI providers from eBPF core.
|
||||
*
|
||||
*/
|
||||
void
|
||||
net_ebpf_ext_unregister_providers();
|
||||
|
||||
/**
|
||||
* @brief Register program info providers with eBPF core.
|
||||
*
|
||||
* @retval STATUS_SUCCESS Operation succeeded.
|
||||
* @retval STATUS_UNSUCCESSFUL Operation failed.
|
||||
*/
|
||||
NTSTATUS
|
||||
net_ebpf_ext_program_info_provider_register();
|
||||
|
||||
/**
|
||||
* @brief Unregister program info providers from eBPF core.
|
||||
*
|
||||
*/
|
||||
void
|
||||
net_ebpf_ext_program_info_provider_unregister();
|
||||
net_ebpf_ext_unregister_providers();
|
|
@ -0,0 +1,250 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file This file implements the BIND program type hook on eBPF for Windows.
|
||||
*
|
||||
*/
|
||||
|
||||
#define INITGUID
|
||||
|
||||
// ebpf_bind_program_data.h has generated
|
||||
// headers. encode_program_info generates them from the structs
|
||||
// in ebpf_nethooks.h. This workaround exists due to the inability
|
||||
// to call RPC serialization services from kernel mode. Once we switch
|
||||
// to a different serializer, we can get rid of this workaround.
|
||||
#include "ebpf_bind_program_data.h"
|
||||
|
||||
#include "net_ebpf_ext.h"
|
||||
|
||||
static ebpf_ext_attach_hook_provider_registration_t* _ebpf_bind_hook_provider_registration = NULL;
|
||||
static ebpf_extension_provider_t* _ebpf_bind_program_info_provider = NULL;
|
||||
|
||||
static ebpf_context_descriptor_t _ebpf_bind_context_descriptor = {
|
||||
sizeof(bind_md_t), EBPF_OFFSET_OF(bind_md_t, app_id_start), EBPF_OFFSET_OF(bind_md_t, app_id_end), -1};
|
||||
static ebpf_program_info_t _ebpf_bind_program_info = {{"bind", &_ebpf_bind_context_descriptor, {0}}, 0, NULL};
|
||||
|
||||
static ebpf_program_data_t _ebpf_bind_program_data = {&_ebpf_bind_program_info, NULL};
|
||||
|
||||
static ebpf_extension_data_t _ebpf_bind_program_info_provider_data = {
|
||||
NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION, sizeof(_ebpf_bind_program_data), &_ebpf_bind_program_data};
|
||||
|
||||
// b9707e04-8127-4c72-833e-05b1fb439496
|
||||
DEFINE_GUID(EBPF_ATTACH_TYPE_BIND, 0xb9707e04, 0x8127, 0x4c72, 0x83, 0x3e, 0x05, 0xb1, 0xfb, 0x43, 0x94, 0x96);
|
||||
|
||||
// 608c517c-6c52-0x4a26-b677-bb01c34425adf
|
||||
DEFINE_GUID(EBPF_PROGRAM_TYPE_BIND, 0x608c517c, 0x6c52, 0x4a26, 0xb6, 0x77, 0xbb, 0x1c, 0x34, 0x42, 0x5a, 0xdf);
|
||||
|
||||
static void
|
||||
_net_ebpf_ext_resource_truncate_appid(bind_md_t* ctx)
|
||||
{
|
||||
wchar_t* last_separator = (wchar_t*)ctx->app_id_start;
|
||||
for (wchar_t* position = (wchar_t*)ctx->app_id_start; position < (wchar_t*)ctx->app_id_end; position++) {
|
||||
if (*position == '\\') {
|
||||
last_separator = position;
|
||||
}
|
||||
}
|
||||
if (*last_separator == '\\') {
|
||||
last_separator++;
|
||||
}
|
||||
ctx->app_id_start = (uint8_t*)last_separator;
|
||||
}
|
||||
|
||||
void
|
||||
net_ebpf_ext_resource_allocation_classify(
|
||||
_In_ const FWPS_INCOMING_VALUES* incoming_fixed_values,
|
||||
_In_ const FWPS_INCOMING_METADATA_VALUES* incoming_metadata_values,
|
||||
_Inout_opt_ void* layer_data,
|
||||
_In_opt_ const void* classify_context,
|
||||
_In_ const FWPS_FILTER* filter,
|
||||
uint64_t flow_context,
|
||||
_Inout_ FWPS_CLASSIFY_OUT* classify_output)
|
||||
{
|
||||
SOCKADDR_IN addr = {AF_INET};
|
||||
uint32_t result;
|
||||
bind_md_t ctx;
|
||||
|
||||
UNREFERENCED_PARAMETER(layer_data);
|
||||
UNREFERENCED_PARAMETER(classify_context);
|
||||
UNREFERENCED_PARAMETER(filter);
|
||||
UNREFERENCED_PARAMETER(flow_context);
|
||||
|
||||
if (!ebpf_ext_attach_enter_rundown(_ebpf_bind_hook_provider_registration)) {
|
||||
classify_output->actionType = FWP_ACTION_PERMIT;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
addr.sin_port =
|
||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_PORT].value.uint16;
|
||||
addr.sin_addr.S_un.S_addr =
|
||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_ADDRESS].value.uint32;
|
||||
|
||||
ctx.process_id = incoming_metadata_values->processId;
|
||||
memcpy(&ctx.socket_address, &addr, sizeof(addr));
|
||||
ctx.operation = BIND_OPERATION_BIND;
|
||||
ctx.protocol = incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_PROTOCOL].value.uint8;
|
||||
|
||||
ctx.app_id_start =
|
||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_ALE_APP_ID].value.byteBlob->data;
|
||||
ctx.app_id_end =
|
||||
ctx.app_id_start +
|
||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_ALE_APP_ID].value.byteBlob->size;
|
||||
|
||||
_net_ebpf_ext_resource_truncate_appid(&ctx);
|
||||
if (ebpf_ext_attach_invoke_hook(_ebpf_bind_hook_provider_registration, &ctx, &result) == EBPF_SUCCESS) {
|
||||
switch (result) {
|
||||
case BIND_PERMIT:
|
||||
case BIND_REDIRECT:
|
||||
classify_output->actionType = FWP_ACTION_PERMIT;
|
||||
break;
|
||||
case BIND_DENY:
|
||||
classify_output->actionType = FWP_ACTION_BLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
Exit:
|
||||
ebpf_ext_attach_leave_rundown(_ebpf_bind_hook_provider_registration);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
net_ebpf_ext_resource_release_classify(
|
||||
_In_ const FWPS_INCOMING_VALUES* incoming_fixed_values,
|
||||
_In_ const FWPS_INCOMING_METADATA_VALUES* incoming_metadata_values,
|
||||
_Inout_opt_ void* layer_data,
|
||||
_In_opt_ const void* classify_context,
|
||||
_In_ const FWPS_FILTER* filter,
|
||||
uint64_t flow_context,
|
||||
_Inout_ FWPS_CLASSIFY_OUT* classify_output)
|
||||
{
|
||||
SOCKADDR_IN addr = {AF_INET};
|
||||
uint32_t result;
|
||||
bind_md_t ctx;
|
||||
|
||||
UNREFERENCED_PARAMETER(layer_data);
|
||||
UNREFERENCED_PARAMETER(classify_context);
|
||||
UNREFERENCED_PARAMETER(filter);
|
||||
UNREFERENCED_PARAMETER(flow_context);
|
||||
|
||||
if (!ebpf_ext_attach_enter_rundown(_ebpf_bind_hook_provider_registration)) {
|
||||
classify_output->actionType = FWP_ACTION_PERMIT;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
addr.sin_port = incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_IP_LOCAL_PORT].value.uint16;
|
||||
addr.sin_addr.S_un.S_addr =
|
||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_IP_LOCAL_ADDRESS].value.uint32;
|
||||
|
||||
ctx.process_id = incoming_metadata_values->processId;
|
||||
memcpy(&ctx.socket_address, &addr, sizeof(addr));
|
||||
ctx.operation = BIND_OPERATION_UNBIND;
|
||||
ctx.protocol = incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_IP_PROTOCOL].value.uint8;
|
||||
|
||||
ctx.app_id_start =
|
||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_ALE_APP_ID].value.byteBlob->data;
|
||||
ctx.app_id_end =
|
||||
ctx.app_id_start +
|
||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_ALE_APP_ID].value.byteBlob->size;
|
||||
|
||||
_net_ebpf_ext_resource_truncate_appid(&ctx);
|
||||
|
||||
ebpf_ext_attach_invoke_hook(_ebpf_bind_hook_provider_registration, &ctx, &result);
|
||||
|
||||
classify_output->actionType = FWP_ACTION_PERMIT;
|
||||
|
||||
Exit:
|
||||
ebpf_ext_attach_leave_rundown(_ebpf_bind_hook_provider_registration);
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
_net_ebpf_ext_bind_hook_provider_unregister()
|
||||
{
|
||||
ebpf_ext_attach_unregister_provider(_ebpf_bind_hook_provider_registration);
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
_net_ebpf_ext_bind_hook_provider_register()
|
||||
{
|
||||
ebpf_result_t return_value;
|
||||
|
||||
return_value = ebpf_ext_attach_register_provider(
|
||||
&EBPF_PROGRAM_TYPE_BIND,
|
||||
&EBPF_ATTACH_TYPE_BIND,
|
||||
EBPF_EXT_HOOK_EXECUTION_PASSIVE,
|
||||
&_ebpf_bind_hook_provider_registration);
|
||||
|
||||
if (return_value != EBPF_SUCCESS) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
Done:
|
||||
if (return_value != EBPF_SUCCESS) {
|
||||
_net_ebpf_ext_bind_hook_provider_unregister();
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
} else
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_net_ebpf_ext_bind_program_info_provider_unregister()
|
||||
{
|
||||
ebpf_provider_unload(_ebpf_bind_program_info_provider);
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
_net_ebpf_ext_bind_program_info_provider_register()
|
||||
{
|
||||
ebpf_result_t return_value;
|
||||
ebpf_extension_data_t* provider_data;
|
||||
ebpf_program_data_t* program_data;
|
||||
|
||||
provider_data = &_ebpf_bind_program_info_provider_data;
|
||||
program_data = (ebpf_program_data_t*)provider_data->data;
|
||||
program_data->program_info->program_type_descriptor.program_type = EBPF_PROGRAM_TYPE_BIND;
|
||||
|
||||
return_value = ebpf_provider_load(
|
||||
&_ebpf_bind_program_info_provider,
|
||||
&EBPF_PROGRAM_TYPE_BIND,
|
||||
NULL,
|
||||
&_ebpf_bind_program_info_provider_data,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (return_value != EBPF_SUCCESS) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
Done:
|
||||
if (return_value != EBPF_SUCCESS) {
|
||||
_net_ebpf_ext_bind_program_info_provider_unregister();
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
} else
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
net_ebpf_ext_bind_register_providers()
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
status = _net_ebpf_ext_bind_program_info_provider_register();
|
||||
if (status != STATUS_SUCCESS)
|
||||
goto Exit;
|
||||
|
||||
status = _net_ebpf_ext_bind_hook_provider_register();
|
||||
if (status != STATUS_SUCCESS)
|
||||
goto Exit;
|
||||
|
||||
Exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
void
|
||||
net_ebpf_ext_bind_unregister_providers()
|
||||
{
|
||||
_net_ebpf_ext_bind_hook_provider_unregister();
|
||||
_net_ebpf_ext_bind_program_info_provider_unregister();
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "net_ebpf_ext.h"
|
||||
|
||||
// Callout and sublayer GUIDs
|
||||
|
||||
// 732acf94-7319-4fed-97d0-41d3a18f3fa1
|
||||
DEFINE_GUID(
|
||||
EBPF_HOOK_ALE_RESOURCE_ALLOC_CALLOUT, 0x732acf94, 0x7319, 0x4fed, 0x97, 0xd0, 0x41, 0xd3, 0xa1, 0x8f, 0x3f, 0xa1);
|
||||
|
||||
// d5792949-2d91-4023-9993-3f3dd9d54b2b
|
||||
DEFINE_GUID(
|
||||
EBPF_HOOK_ALE_RESOURCE_RELEASE_CALLOUT, 0xd5792949, 0x2d91, 0x4023, 0x99, 0x93, 0x3f, 0x3d, 0xd9, 0xd5, 0x4b, 0x2b);
|
||||
|
||||
/**
|
||||
* @brief WFP classifyFn callback for EBPF_HOOK_ALE_RESOURCE_ALLOC_CALLOUT.
|
||||
*
|
||||
*/
|
||||
void
|
||||
net_ebpf_ext_resource_allocation_classify(
|
||||
_In_ const FWPS_INCOMING_VALUES* incoming_fixed_values,
|
||||
_In_ const FWPS_INCOMING_METADATA_VALUES* incoming_metadata_values,
|
||||
_Inout_opt_ void* layer_data,
|
||||
_In_opt_ const void* classify_context,
|
||||
_In_ const FWPS_FILTER* filter,
|
||||
uint64_t flow_context,
|
||||
_Inout_ FWPS_CLASSIFY_OUT* classify_output);
|
||||
|
||||
/**
|
||||
* @brief WFP classifyFn callback for EBPF_HOOK_ALE_RESOURCE_RELEASE_CALLOUT.
|
||||
*
|
||||
*/
|
||||
void
|
||||
net_ebpf_ext_resource_release_classify(
|
||||
_In_ const FWPS_INCOMING_VALUES* incoming_fixed_values,
|
||||
_In_ const FWPS_INCOMING_METADATA_VALUES* incoming_metadata_values,
|
||||
_Inout_opt_ void* layer_data,
|
||||
_In_opt_ const void* classify_context,
|
||||
_In_ const FWPS_FILTER* filter,
|
||||
uint64_t flow_context,
|
||||
_Inout_ FWPS_CLASSIFY_OUT* classify_output);
|
||||
|
||||
/**
|
||||
* @brief Unregister BIND NPI providers.
|
||||
*
|
||||
*/
|
||||
void
|
||||
net_ebpf_ext_bind_unregister_providers();
|
||||
|
||||
/**
|
||||
* @brief Register BIND NPI providers.
|
||||
*
|
||||
* @retval STATUS_SUCCESS Operation succeeded.
|
||||
* @retval STATUS_UNSUCCESSFUL Operation failed.
|
||||
*/
|
||||
NTSTATUS
|
||||
net_ebpf_ext_bind_register_providers();
|
|
@ -32,7 +32,8 @@ Environment:
|
|||
#define NET_EBPF_EXT_DEVICE_NAME L"\\Device\\NetEbpfExt"
|
||||
|
||||
// Driver global variables
|
||||
static DEVICE_OBJECT* _net_ebpf_ext_driver_device_object;
|
||||
static WDFDEVICE _net_ebpf_ext_device = NULL;
|
||||
static DEVICE_OBJECT* _net_ebpf_ext_driver_device_object = NULL;
|
||||
static BOOLEAN _net_ebpf_ext_driver_unloading_flag = FALSE;
|
||||
|
||||
//
|
||||
|
@ -40,50 +41,52 @@ static BOOLEAN _net_ebpf_ext_driver_unloading_flag = FALSE;
|
|||
//
|
||||
DRIVER_INITIALIZE DriverEntry;
|
||||
|
||||
static _Function_class_(EVT_WDF_DRIVER_UNLOAD) _IRQL_requires_same_
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL) void __net_ebpf_ext_driver_unload(_In_ WDFDRIVER driver_object)
|
||||
static void
|
||||
_net_ebpf_ext_driver_uninitialize_objects()
|
||||
{
|
||||
UNREFERENCED_PARAMETER(driver_object);
|
||||
|
||||
_net_ebpf_ext_driver_unloading_flag = TRUE;
|
||||
|
||||
net_ebpf_ext_program_info_provider_unregister();
|
||||
|
||||
net_ebpf_ext_unregister_providers();
|
||||
|
||||
net_ebpf_ext_unregister_callouts();
|
||||
|
||||
if (_net_ebpf_ext_device != NULL)
|
||||
WdfObjectDelete(_net_ebpf_ext_device);
|
||||
}
|
||||
|
||||
static _Function_class_(EVT_WDF_DRIVER_UNLOAD) _IRQL_requires_same_
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL) void _net_ebpf_ext_driver_unload(_In_ WDFDRIVER driver_object)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(driver_object);
|
||||
_net_ebpf_ext_driver_uninitialize_objects();
|
||||
}
|
||||
|
||||
//
|
||||
// Create a basic WDF driver, set up the device object
|
||||
// for a callout driver and register with NMR.
|
||||
// Create and initialize WDF driver, device object,
|
||||
// WFP callouts and NPI providers.
|
||||
//
|
||||
static NTSTATUS
|
||||
__net_ebpf_ext_driver_initialize_objects(
|
||||
_Inout_ DRIVER_OBJECT* driver_object,
|
||||
_In_ const UNICODE_STRING* registry_path,
|
||||
_Out_ WDFDRIVER* driver,
|
||||
_Out_ WDFDEVICE* device)
|
||||
_net_ebpf_ext_driver_initialize_objects(_Inout_ DRIVER_OBJECT* driver_object, _In_ const UNICODE_STRING* registry_path)
|
||||
{
|
||||
NTSTATUS status;
|
||||
WDF_DRIVER_CONFIG driver_configuration;
|
||||
PWDFDEVICE_INIT device_initialize = NULL;
|
||||
UNICODE_STRING ebpf_device_name;
|
||||
BOOLEAN device_create_flag = FALSE;
|
||||
WDFDRIVER driver;
|
||||
|
||||
WDF_DRIVER_CONFIG_INIT(&driver_configuration, WDF_NO_EVENT_CALLBACK);
|
||||
|
||||
driver_configuration.DriverInitFlags |= WdfDriverInitNonPnpDriver;
|
||||
driver_configuration.EvtDriverUnload = __net_ebpf_ext_driver_unload;
|
||||
driver_configuration.EvtDriverUnload = _net_ebpf_ext_driver_unload;
|
||||
|
||||
status = WdfDriverCreate(driver_object, registry_path, WDF_NO_OBJECT_ATTRIBUTES, &driver_configuration, driver);
|
||||
status = WdfDriverCreate(driver_object, registry_path, WDF_NO_OBJECT_ATTRIBUTES, &driver_configuration, &driver);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
device_initialize = WdfControlDeviceInitAllocate(
|
||||
*driver,
|
||||
driver,
|
||||
&SDDL_DEVOBJ_SYS_ALL_ADM_ALL // only kernel/system and administrators.
|
||||
);
|
||||
if (!device_initialize) {
|
||||
|
@ -103,7 +106,7 @@ __net_ebpf_ext_driver_initialize_objects(
|
|||
goto Exit;
|
||||
}
|
||||
|
||||
status = WdfDeviceCreate(&device_initialize, WDF_NO_OBJECT_ATTRIBUTES, device);
|
||||
status = WdfDeviceCreate(&device_initialize, WDF_NO_OBJECT_ATTRIBUTES, &_net_ebpf_ext_device);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
// do not free if any other call
|
||||
|
@ -113,30 +116,19 @@ __net_ebpf_ext_driver_initialize_objects(
|
|||
goto Exit;
|
||||
}
|
||||
|
||||
device_create_flag = TRUE;
|
||||
_net_ebpf_ext_driver_device_object = WdfDeviceWdmGetDeviceObject(_net_ebpf_ext_device);
|
||||
|
||||
status = net_ebpf_ext_register_providers();
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
status = net_ebpf_ext_program_info_provider_register();
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Exit;
|
||||
}
|
||||
// TODO: https://github.com/microsoft/ebpf-for-windows/issues/521
|
||||
(void)net_ebpf_ext_register_callouts(_net_ebpf_ext_driver_device_object);
|
||||
|
||||
WdfControlFinishInitializing(*device);
|
||||
WdfControlFinishInitializing(_net_ebpf_ext_device);
|
||||
|
||||
Exit:
|
||||
if (!NT_SUCCESS(status)) {
|
||||
if (device_create_flag && device != NULL) {
|
||||
//
|
||||
// Release the reference on the newly created object, since
|
||||
// we couldn't initialize it.
|
||||
//
|
||||
WdfObjectDelete(*device);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -144,30 +136,22 @@ NTSTATUS
|
|||
DriverEntry(_In_ DRIVER_OBJECT* driver_object, _In_ UNICODE_STRING* registry_path)
|
||||
{
|
||||
NTSTATUS status;
|
||||
WDFDRIVER driver;
|
||||
WDFDEVICE device;
|
||||
|
||||
// Request NX Non-Paged Pool when available
|
||||
ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
|
||||
|
||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "NetEbpfExt: DriverEntry\n"));
|
||||
|
||||
status = __net_ebpf_ext_driver_initialize_objects(driver_object, registry_path, &driver, &device);
|
||||
status = _net_ebpf_ext_driver_initialize_objects(driver_object, registry_path);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
_net_ebpf_ext_driver_device_object = WdfDeviceWdmGetDeviceObject(device);
|
||||
|
||||
net_ebpf_ext_register_callouts(_net_ebpf_ext_driver_device_object);
|
||||
// ignore status. at boot, registration can fail.
|
||||
// we will try to re-register during program load.
|
||||
|
||||
Exit:
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
net_ebpf_ext_unregister_callouts();
|
||||
_net_ebpf_ext_driver_uninitialize_objects();
|
||||
}
|
||||
|
||||
return status;
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file This file implements the XDP program type hook and helper functions on eBPF for Windows.
|
||||
*
|
||||
*/
|
||||
|
||||
#define INITGUID
|
||||
|
||||
// ebpf_xdp_program_data.h has generated
|
||||
// headers. encode_program_info generates them from the structs
|
||||
// in ebpf_nethooks.h. This workaround exists due to the inability
|
||||
// to call RPC serialization services from kernel mode. Once we switch
|
||||
// to a different serializer, we can get rid of this workaround.
|
||||
#include "ebpf_xdp_program_data.h"
|
||||
|
||||
#include "net_ebpf_ext.h"
|
||||
|
||||
HANDLE _net_ebpf_ext_l2_injection_handle = NULL;
|
||||
static ebpf_ext_attach_hook_provider_registration_t* _ebpf_xdp_hook_provider_registration = NULL;
|
||||
static ebpf_extension_provider_t* _ebpf_xdp_program_info_provider = NULL;
|
||||
|
||||
static ebpf_context_descriptor_t _ebpf_xdp_context_descriptor = {
|
||||
sizeof(xdp_md_t),
|
||||
EBPF_OFFSET_OF(xdp_md_t, data),
|
||||
EBPF_OFFSET_OF(xdp_md_t, data_end),
|
||||
EBPF_OFFSET_OF(xdp_md_t, data_meta)};
|
||||
static ebpf_program_info_t _ebpf_xdp_program_info = {{"xdp", &_ebpf_xdp_context_descriptor, {0}}, 0, NULL};
|
||||
|
||||
static ebpf_program_data_t _ebpf_xdp_program_data = {&_ebpf_xdp_program_info, NULL};
|
||||
|
||||
static ebpf_extension_data_t _ebpf_xdp_program_info_provider_data = {
|
||||
NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION, sizeof(_ebpf_xdp_program_data), &_ebpf_xdp_program_data};
|
||||
|
||||
// 85e0d8ef-579e-4931-b072-8ee226bb2e9d
|
||||
DEFINE_GUID(EBPF_ATTACH_TYPE_XDP, 0x85e0d8ef, 0x579e, 0x4931, 0xb0, 0x72, 0x8e, 0xe2, 0x26, 0xbb, 0x2e, 0x9d);
|
||||
|
||||
// f1832a85-85d5-45b0-98a0-7069d63013b0
|
||||
DEFINE_GUID(EBPF_PROGRAM_TYPE_XDP, 0xf1832a85, 0x85d5, 0x45b0, 0x98, 0xa0, 0x70, 0x69, 0xd6, 0x30, 0x13, 0xb0);
|
||||
|
||||
static void
|
||||
_net_ebpf_ext_l2_inject_complete(
|
||||
_In_ const void* context, _Inout_ NET_BUFFER_LIST* packet_clone, BOOLEAN dispatch_level)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(context);
|
||||
FwpsFreeCloneNetBufferList(packet_clone, dispatch_level);
|
||||
}
|
||||
|
||||
static void
|
||||
_net_ebpf_ext_handle_xdp_tx(_Inout_ NET_BUFFER_LIST* packet, _In_ const FWPS_INCOMING_VALUES* incoming_fixed_values)
|
||||
{
|
||||
NET_BUFFER_LIST* packet_clone = NULL;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
uint32_t interface_index =
|
||||
incoming_fixed_values->incomingValue[FWPS_FIELD_INBOUND_MAC_FRAME_NATIVE_INTERFACE_INDEX].value.uint32;
|
||||
uint32_t ndis_port =
|
||||
incoming_fixed_values->incomingValue[FWPS_FIELD_INBOUND_MAC_FRAME_NATIVE_NDIS_PORT].value.uint32;
|
||||
|
||||
status = FwpsAllocateCloneNetBufferList(packet, NULL, NULL, 0, &packet_clone);
|
||||
if (status != STATUS_SUCCESS)
|
||||
goto Exit;
|
||||
|
||||
status = FwpsInjectMacSendAsync(
|
||||
_net_ebpf_ext_l2_injection_handle,
|
||||
NULL,
|
||||
0,
|
||||
FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE,
|
||||
interface_index,
|
||||
ndis_port,
|
||||
packet_clone,
|
||||
_net_ebpf_ext_l2_inject_complete,
|
||||
NULL);
|
||||
|
||||
if (status != STATUS_SUCCESS)
|
||||
goto Exit;
|
||||
Exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
net_ebpf_ext_layer_2_classify(
|
||||
_In_ const FWPS_INCOMING_VALUES* incoming_fixed_values,
|
||||
_In_ const FWPS_INCOMING_METADATA_VALUES* incoming_metadata_values,
|
||||
_Inout_opt_ void* layer_data,
|
||||
_In_opt_ const void* classify_context,
|
||||
_In_ const FWPS_FILTER* filter,
|
||||
uint64_t flow_context,
|
||||
_Inout_ FWPS_CLASSIFY_OUT* classify_output)
|
||||
{
|
||||
FWP_ACTION_TYPE action = FWP_ACTION_PERMIT;
|
||||
|
||||
UNREFERENCED_PARAMETER(incoming_metadata_values);
|
||||
UNREFERENCED_PARAMETER(classify_context);
|
||||
UNREFERENCED_PARAMETER(filter);
|
||||
UNREFERENCED_PARAMETER(flow_context);
|
||||
NET_BUFFER_LIST* nbl = (NET_BUFFER_LIST*)layer_data;
|
||||
NET_BUFFER* net_buffer = NULL;
|
||||
uint8_t* packet_buffer;
|
||||
uint32_t result = 0;
|
||||
|
||||
if (!ebpf_ext_attach_enter_rundown(_ebpf_xdp_hook_provider_registration))
|
||||
goto done;
|
||||
|
||||
if (nbl == NULL) {
|
||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Null NBL \n"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
net_buffer = NET_BUFFER_LIST_FIRST_NB(nbl);
|
||||
if (net_buffer == NULL) {
|
||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "net_buffer not present\n"));
|
||||
// nothing to do
|
||||
goto done;
|
||||
}
|
||||
|
||||
packet_buffer = NdisGetDataBuffer(net_buffer, net_buffer->DataLength, NULL, sizeof(uint16_t), 0);
|
||||
if (!packet_buffer) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
xdp_md_t ctx = {packet_buffer, packet_buffer + net_buffer->DataLength};
|
||||
|
||||
if (ebpf_ext_attach_invoke_hook(_ebpf_xdp_hook_provider_registration, &ctx, &result) == EBPF_SUCCESS) {
|
||||
switch (result) {
|
||||
case XDP_PASS:
|
||||
action = FWP_ACTION_PERMIT;
|
||||
break;
|
||||
case XDP_TX:
|
||||
_net_ebpf_ext_handle_xdp_tx(nbl, incoming_fixed_values);
|
||||
// Fall through.
|
||||
case XDP_DROP:
|
||||
action = FWP_ACTION_BLOCK;
|
||||
classify_output->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
|
||||
break;
|
||||
}
|
||||
}
|
||||
done:
|
||||
classify_output->actionType = action;
|
||||
|
||||
ebpf_ext_attach_leave_rundown(_ebpf_xdp_hook_provider_registration);
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
_net_ebpf_ext_xdp_hook_provider_unregister()
|
||||
{
|
||||
ebpf_ext_attach_unregister_provider(_ebpf_xdp_hook_provider_registration);
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
_net_ebpf_ext_xdp_hook_provider_register()
|
||||
{
|
||||
ebpf_result_t return_value;
|
||||
return_value = ebpf_ext_attach_register_provider(
|
||||
&EBPF_PROGRAM_TYPE_XDP,
|
||||
&EBPF_ATTACH_TYPE_XDP,
|
||||
EBPF_EXT_HOOK_EXECUTION_DISPATCH,
|
||||
&_ebpf_xdp_hook_provider_registration);
|
||||
|
||||
if (return_value != EBPF_SUCCESS) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
Done:
|
||||
if (return_value != EBPF_SUCCESS) {
|
||||
_net_ebpf_ext_xdp_hook_provider_unregister();
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
} else
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_net_ebpf_ext_xdp_program_info_provider_unregister()
|
||||
{
|
||||
ebpf_provider_unload(_ebpf_xdp_program_info_provider);
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
_net_ebpf_ext_xdp_program_info_provider_register()
|
||||
{
|
||||
ebpf_result_t return_value;
|
||||
ebpf_extension_data_t* provider_data;
|
||||
ebpf_program_data_t* program_data;
|
||||
|
||||
provider_data = &_ebpf_xdp_program_info_provider_data;
|
||||
program_data = (ebpf_program_data_t*)provider_data->data;
|
||||
program_data->program_info->program_type_descriptor.program_type = EBPF_PROGRAM_TYPE_XDP;
|
||||
|
||||
return_value = ebpf_provider_load(
|
||||
&_ebpf_xdp_program_info_provider,
|
||||
&EBPF_PROGRAM_TYPE_XDP,
|
||||
NULL,
|
||||
&_ebpf_xdp_program_info_provider_data,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (return_value != EBPF_SUCCESS) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
Done:
|
||||
if (return_value != EBPF_SUCCESS) {
|
||||
_net_ebpf_ext_xdp_program_info_provider_unregister();
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
} else
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
net_ebpf_ext_xdp_register_providers()
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
status = _net_ebpf_ext_xdp_program_info_provider_register();
|
||||
if (status != STATUS_SUCCESS)
|
||||
goto Exit;
|
||||
|
||||
status = _net_ebpf_ext_xdp_hook_provider_register();
|
||||
if (status != STATUS_SUCCESS)
|
||||
goto Exit;
|
||||
|
||||
Exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
void
|
||||
net_ebpf_ext_xdp_unregister_providers()
|
||||
{
|
||||
_net_ebpf_ext_xdp_hook_provider_unregister();
|
||||
_net_ebpf_ext_xdp_program_info_provider_unregister();
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "net_ebpf_ext.h"
|
||||
|
||||
extern HANDLE _net_ebpf_ext_l2_injection_handle;
|
||||
|
||||
// Callout GUIDs
|
||||
|
||||
// 5a5614e5-6b64-4738-8367-33c6ca07bf8f
|
||||
DEFINE_GUID(EBPF_HOOK_L2_CALLOUT, 0x5a5614e5, 0x6b64, 0x4738, 0x83, 0x67, 0x33, 0xc6, 0xca, 0x07, 0xbf, 0x8f);
|
||||
|
||||
/**
|
||||
* @brief WFP classifyFn callback for EBPF_HOOK_L2_CALLOUT.
|
||||
*
|
||||
*/
|
||||
void
|
||||
net_ebpf_ext_layer_2_classify(
|
||||
_In_ const FWPS_INCOMING_VALUES* incoming_fixed_values,
|
||||
_In_ const FWPS_INCOMING_METADATA_VALUES* incoming_metadata_values,
|
||||
_Inout_opt_ void* layer_data,
|
||||
_In_opt_ const void* classify_context,
|
||||
_In_ const FWPS_FILTER* filter,
|
||||
uint64_t flow_context,
|
||||
_Inout_ FWPS_CLASSIFY_OUT* classify_output);
|
||||
|
||||
/**
|
||||
* @brief Unregister XDP NPI providers.
|
||||
*
|
||||
*/
|
||||
void
|
||||
net_ebpf_ext_xdp_unregister_providers();
|
||||
|
||||
/**
|
||||
* @brief Register XDP NPI providers.
|
||||
*
|
||||
* @retval STATUS_SUCCESS Operation succeeded.
|
||||
* @retval STATUS_UNSUCCESSFUL Operation failed.
|
||||
*/
|
||||
NTSTATUS
|
||||
net_ebpf_ext_xdp_register_providers();
|
|
@ -124,6 +124,8 @@
|
|||
<ItemGroup>
|
||||
<ClCompile Include="net_ebpf_ext_drv.c" />
|
||||
<ClCompile Include="net_ebpf_ext.c" />
|
||||
<ClCompile Include="net_ebpf_ext_bind.c" />
|
||||
<ClCompile Include="net_ebpf_ext_xdp.c" />
|
||||
<ClCompile Include="ebpf_ext_attach_provider.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -134,6 +136,8 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="net_ebpf_ext.h" />
|
||||
<ClInclude Include="net_ebpf_ext_bind.h" />
|
||||
<ClInclude Include="net_ebpf_ext_xdp.h" />
|
||||
<ClInclude Include="ebpf_ext_attach_provider.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -29,6 +29,12 @@
|
|||
<ClCompile Include="net_ebpf_ext.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="net_ebpf_ext_bind.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="net_ebpf_ext_xdp.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ebpf_ext_attach_provider.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -40,6 +46,12 @@
|
|||
<ClInclude Include="ebpf_ext_attach_provider.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="net_ebpf_ext_bind.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="net_ebpf_ext_xdp.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
|
Загрузка…
Ссылка в новой задаче