Skip to content

Commit 567628b

Browse files
author
Michael Agun
committed
Add sockops listen callout with tests.
1 parent ee7491e commit 567628b

File tree

10 files changed

+641
-6
lines changed

10 files changed

+641
-6
lines changed

include/ebpf_nethooks.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,9 @@ typedef enum _bpf_sock_op_type
149149
/** @brief Indicates when a passive (inbound) connection is established. **/
150150
BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB,
151151
/** @brief Indicates when a connection is deleted. **/
152-
BPF_SOCK_OPS_CONNECTION_DELETED_CB
152+
BPF_SOCK_OPS_CONNECTION_DELETED_CB,
153+
/** @brief Indicates when a connection transitions to the listening state. **/
154+
BPF_SOCK_OPS_LISTEN_CB,
153155
} bpf_sock_op_type_t;
154156

155157
typedef struct _bpf_sock_ops

netebpfext/net_ebpf_ext.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
#include "net_ebpf_ext_sock_ops.h"
2424
#include "net_ebpf_ext_xdp.h"
2525

26-
#define SECONDSTO100NS(x) ((x)*10000000)
26+
#define SECONDSTO100NS(x) ((x) * 10000000)
2727
#define SUBLAYER_WEIGHT_MAXIMUM 0xFFFF
2828

2929
// Globals.
@@ -223,9 +223,31 @@ static net_ebpf_ext_wfp_callout_state_t _net_ebpf_ext_wfp_callout_states[] = {
223223
net_ebpf_extension_sock_ops_flow_established_classify,
224224
net_ebpf_ext_filter_change_notify,
225225
net_ebpf_extension_sock_ops_flow_delete,
226-
L"ALE Flow Established Callout v4",
226+
L"ALE Flow Established Callout v6",
227227
L"ALE Flow Established callout for eBPF",
228228
FWP_ACTION_CALLOUT_TERMINATING,
229+
},
230+
// EBPF_HOOK_ALE_AUTH_LISTEN_V4
231+
{
232+
&EBPF_HOOK_ALE_AUTH_LISTEN_V4_CALLOUT,
233+
&FWPM_LAYER_ALE_AUTH_LISTEN_V4,
234+
net_ebpf_extension_sock_ops_listen_classify,
235+
net_ebpf_ext_filter_change_notify,
236+
NULL, // No flow delete callback for listen
237+
L"ALE Auth Listen Callout v4",
238+
L"ALE Auth Listen callout for eBPF",
239+
FWP_ACTION_CALLOUT_TERMINATING,
240+
},
241+
// EBPF_HOOK_ALE_AUTH_LISTEN_V6
242+
{
243+
&EBPF_HOOK_ALE_AUTH_LISTEN_V6_CALLOUT,
244+
&FWPM_LAYER_ALE_AUTH_LISTEN_V6,
245+
net_ebpf_extension_sock_ops_listen_classify,
246+
net_ebpf_ext_filter_change_notify,
247+
NULL, // No flow delete callback for listen
248+
L"ALE Auth Listen Callout v6",
249+
L"ALE Auth Listen callout for eBPF",
250+
FWP_ACTION_CALLOUT_TERMINATING,
229251
}};
230252

231253
// WFP globals
@@ -365,6 +387,12 @@ net_ebpf_extension_get_hook_id_from_wfp_layer_id(uint16_t wfp_layer_id)
365387
case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6:
366388
hook_id = EBPF_HOOK_ALE_FLOW_ESTABLISHED_V6;
367389
break;
390+
case FWPS_LAYER_ALE_AUTH_LISTEN_V4:
391+
hook_id = EBPF_HOOK_ALE_AUTH_LISTEN_V4;
392+
break;
393+
case FWPS_LAYER_ALE_AUTH_LISTEN_V6:
394+
hook_id = EBPF_HOOK_ALE_AUTH_LISTEN_V6;
395+
break;
368396
case FWPS_LAYER_ALE_CONNECT_REDIRECT_V4:
369397
hook_id = EBPF_HOOK_ALE_CONNECT_REDIRECT_V4;
370398
break;

netebpfext/net_ebpf_ext.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,9 @@ typedef enum _net_ebpf_extension_hook_id
249249
EBPF_HOOK_ALE_AUTH_RECV_ACCEPT_V4, // 10
250250
EBPF_HOOK_ALE_AUTH_RECV_ACCEPT_V6,
251251
EBPF_HOOK_ALE_FLOW_ESTABLISHED_V4,
252-
EBPF_HOOK_ALE_FLOW_ESTABLISHED_V6
252+
EBPF_HOOK_ALE_FLOW_ESTABLISHED_V6,
253+
EBPF_HOOK_ALE_AUTH_LISTEN_V4,
254+
EBPF_HOOK_ALE_AUTH_LISTEN_V6
253255
} net_ebpf_extension_hook_id_t;
254256

255257
/**

netebpfext/net_ebpf_ext_sock_ops.c

Lines changed: 173 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,17 @@ const net_ebpf_extension_wfp_filter_parameters_t _net_ebpf_extension_sock_ops_wf
5252
NULL, // Default sublayer.
5353
&EBPF_HOOK_ALE_FLOW_ESTABLISHED_V6_CALLOUT,
5454
L"net eBPF sock_ops hook",
55-
L"net eBPF sock_ops hook WFP filter"}};
55+
L"net eBPF sock_ops hook WFP filter"},
56+
{&FWPM_LAYER_ALE_AUTH_LISTEN_V4,
57+
NULL, // Default sublayer.
58+
&EBPF_HOOK_ALE_AUTH_LISTEN_V4_CALLOUT,
59+
L"net eBPF sock_ops listen hook",
60+
L"net eBPF sock_ops listen hook WFP filter"},
61+
{&FWPM_LAYER_ALE_AUTH_LISTEN_V6,
62+
NULL, // Default sublayer.
63+
&EBPF_HOOK_ALE_AUTH_LISTEN_V6_CALLOUT,
64+
L"net eBPF sock_ops listen hook",
65+
L"net eBPF sock_ops listen hook WFP filter"}};
5666

5767
#define NET_EBPF_SOCK_OPS_FILTER_COUNT EBPF_COUNT_OF(_net_ebpf_extension_sock_ops_wfp_filter_parameters)
5868

@@ -386,6 +396,27 @@ wfp_ale_layer_fields_t wfp_flow_established_fields[] = {
386396
FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_COMPARTMENT_ID,
387397
FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_LOCAL_INTERFACE}};
388398

399+
// WFP layer fields for listen hooks
400+
wfp_ale_layer_fields_t wfp_auth_listen_fields[] = {
401+
// EBPF_HOOK_ALE_AUTH_LISTEN_V4
402+
{FWPS_FIELD_ALE_AUTH_LISTEN_V4_IP_LOCAL_ADDRESS,
403+
FWPS_FIELD_ALE_AUTH_LISTEN_V4_IP_LOCAL_PORT,
404+
0, // No remote address for listen
405+
0, // No remote port for listen
406+
0, // No protocol field for listen layer
407+
0, // No direction field for listen (always inbound)
408+
FWPS_FIELD_ALE_AUTH_LISTEN_V4_COMPARTMENT_ID,
409+
FWPS_FIELD_ALE_AUTH_LISTEN_V4_IP_LOCAL_INTERFACE},
410+
// EBPF_HOOK_ALE_AUTH_LISTEN_V6
411+
{FWPS_FIELD_ALE_AUTH_LISTEN_V6_IP_LOCAL_ADDRESS,
412+
FWPS_FIELD_ALE_AUTH_LISTEN_V6_IP_LOCAL_PORT,
413+
0, // No remote address for listen
414+
0, // No remote port for listen
415+
0, // No protocol field for listen layer
416+
0, // No direction field for listen (always inbound)
417+
FWPS_FIELD_ALE_AUTH_LISTEN_V6_COMPARTMENT_ID,
418+
FWPS_FIELD_ALE_AUTH_LISTEN_V6_IP_LOCAL_INTERFACE}};
419+
389420
static void
390421
_net_ebpf_extension_sock_ops_copy_wfp_connection_fields(
391422
_In_ const FWPS_INCOMING_VALUES* incoming_fixed_values,
@@ -437,6 +468,53 @@ _net_ebpf_extension_sock_ops_copy_wfp_connection_fields(
437468
}
438469
}
439470

471+
static void
472+
_net_ebpf_extension_sock_ops_copy_wfp_listen_fields(
473+
_In_ const FWPS_INCOMING_VALUES* incoming_fixed_values,
474+
_In_ const FWPS_INCOMING_METADATA_VALUES* incoming_metadata_values,
475+
_Out_ net_ebpf_sock_ops_t* sock_ops_context)
476+
{
477+
uint16_t wfp_layer_id = incoming_fixed_values->layerId;
478+
net_ebpf_extension_hook_id_t hook_id = net_ebpf_extension_get_hook_id_from_wfp_layer_id(wfp_layer_id);
479+
wfp_ale_layer_fields_t* fields = &wfp_auth_listen_fields[hook_id - EBPF_HOOK_ALE_AUTH_LISTEN_V4];
480+
bpf_sock_ops_t* sock_ops = &sock_ops_context->context;
481+
482+
FWPS_INCOMING_VALUE0* incoming_values = incoming_fixed_values->incomingValue;
483+
484+
// Listen operations are always of type BPF_SOCK_OPS_LISTEN_CB
485+
sock_ops->op = BPF_SOCK_OPS_LISTEN_CB;
486+
487+
// Copy IP address fields.
488+
if (hook_id == EBPF_HOOK_ALE_AUTH_LISTEN_V4) {
489+
sock_ops->family = AF_INET;
490+
sock_ops->local_ip4 = htonl(incoming_values[fields->local_ip_address_field].value.uint32);
491+
sock_ops->remote_ip4 = 0; // No remote address for listen
492+
} else {
493+
sock_ops->family = AF_INET6;
494+
RtlCopyMemory(
495+
sock_ops->local_ip6,
496+
incoming_values[fields->local_ip_address_field].value.byteArray16,
497+
sizeof(FWP_BYTE_ARRAY16));
498+
memset(sock_ops->remote_ip6, 0, sizeof(sock_ops->remote_ip6)); // No remote address for listen
499+
}
500+
sock_ops->local_port = htons(incoming_values[fields->local_port_field].value.uint16);
501+
sock_ops->remote_port = 0; // No remote port for listen
502+
sock_ops->protocol = IPPROTO_TCP; // Listen operations are typically TCP
503+
sock_ops->compartment_id = incoming_values[fields->compartment_id_field].value.uint32;
504+
sock_ops->interface_luid = *incoming_values[fields->interface_luid_field].value.uint64;
505+
if (incoming_metadata_values->currentMetadataValues & FWPS_METADATA_FIELD_PROCESS_ID) {
506+
sock_ops_context->process_id = incoming_metadata_values->processId;
507+
} else {
508+
NET_EBPF_EXT_LOG_MESSAGE_UINT64(
509+
NET_EBPF_EXT_TRACELOG_LEVEL_VERBOSE,
510+
NET_EBPF_EXT_TRACELOG_KEYWORD_SOCK_OPS,
511+
"FWPS_METADATA_FIELD_PROCESS_ID not present",
512+
hook_id);
513+
514+
sock_ops_context->process_id = 0;
515+
}
516+
}
517+
440518
//
441519
// WFP callout callback function.
442520
//
@@ -624,6 +702,100 @@ net_ebpf_extension_sock_ops_flow_delete(uint16_t layer_id, uint32_t callout_id,
624702
}
625703
}
626704

705+
//
706+
// WFP classifyFn callback function for listen operations.
707+
//
708+
void
709+
net_ebpf_extension_sock_ops_listen_classify(
710+
_In_ const FWPS_INCOMING_VALUES* incoming_fixed_values,
711+
_In_ const FWPS_INCOMING_METADATA_VALUES* incoming_metadata_values,
712+
_Inout_opt_ void* layer_data,
713+
_In_opt_ const void* classify_context,
714+
_In_ const FWPS_FILTER* filter,
715+
uint64_t flow_context,
716+
_Inout_ FWPS_CLASSIFY_OUT* classify_output)
717+
{
718+
uint32_t result;
719+
net_ebpf_extension_sock_ops_wfp_filter_context_t* filter_context = NULL;
720+
net_ebpf_sock_ops_t sock_ops_context = {0};
721+
uint32_t client_compartment_id = UNSPECIFIED_COMPARTMENT_ID;
722+
ebpf_result_t program_result;
723+
724+
UNREFERENCED_PARAMETER(layer_data);
725+
UNREFERENCED_PARAMETER(classify_context);
726+
UNREFERENCED_PARAMETER(flow_context);
727+
728+
NET_EBPF_EXT_LOG_ENTRY();
729+
730+
classify_output->actionType = FWP_ACTION_PERMIT;
731+
732+
filter_context = (net_ebpf_extension_sock_ops_wfp_filter_context_t*)filter->context;
733+
ASSERT(filter_context != NULL);
734+
if (filter_context == NULL) {
735+
goto Exit;
736+
}
737+
738+
if (filter_context->base.context_deleting) {
739+
NET_EBPF_EXT_LOG_MESSAGE_NTSTATUS(
740+
NET_EBPF_EXT_TRACELOG_LEVEL_VERBOSE,
741+
NET_EBPF_EXT_TRACELOG_KEYWORD_SOCK_OPS,
742+
"net_ebpf_extension_sock_ops_listen_classify - Client detach detected.",
743+
STATUS_INVALID_PARAMETER);
744+
goto Exit;
745+
}
746+
747+
// Copy WFP fields for listen operation
748+
_net_ebpf_extension_sock_ops_copy_wfp_listen_fields(
749+
incoming_fixed_values, incoming_metadata_values, &sock_ops_context);
750+
751+
client_compartment_id = filter_context->compartment_id;
752+
ASSERT(
753+
(client_compartment_id == UNSPECIFIED_COMPARTMENT_ID) ||
754+
(client_compartment_id == sock_ops_context.context.compartment_id));
755+
if (client_compartment_id != UNSPECIFIED_COMPARTMENT_ID &&
756+
client_compartment_id != sock_ops_context.context.compartment_id) {
757+
// The client is not interested in this compartment Id.
758+
NET_EBPF_EXT_LOG_MESSAGE_UINT32(
759+
NET_EBPF_EXT_TRACELOG_LEVEL_VERBOSE,
760+
NET_EBPF_EXT_TRACELOG_KEYWORD_SOCK_OPS,
761+
"The sock_ops eBPF program is not interested in this compartmentId",
762+
sock_ops_context.context.compartment_id);
763+
goto Exit;
764+
}
765+
766+
program_result = net_ebpf_extension_hook_invoke_programs(&sock_ops_context.context, &filter_context->base, &result);
767+
if (program_result == EBPF_OBJECT_NOT_FOUND) {
768+
// No program is attached to this hook.
769+
NET_EBPF_EXT_LOG_MESSAGE(
770+
NET_EBPF_EXT_TRACELOG_LEVEL_WARNING,
771+
NET_EBPF_EXT_TRACELOG_KEYWORD_SOCK_OPS,
772+
"net_ebpf_extension_sock_ops_listen_classify - No attached client.");
773+
goto Exit;
774+
} else if (program_result != EBPF_SUCCESS) {
775+
NET_EBPF_EXT_LOG_MESSAGE_UINT32(
776+
NET_EBPF_EXT_TRACELOG_LEVEL_ERROR,
777+
NET_EBPF_EXT_TRACELOG_KEYWORD_SOCK_OPS,
778+
"net_ebpf_extension_sock_ops_listen_classify - Program invocation failed.",
779+
program_result);
780+
goto Exit;
781+
}
782+
783+
// For listen operations, the result determines whether to allow or block the listen operation
784+
classify_output->actionType = (result == 0) ? FWP_ACTION_PERMIT : FWP_ACTION_BLOCK;
785+
if (classify_output->actionType == FWP_ACTION_BLOCK) {
786+
classify_output->rights &= ~FWPS_RIGHT_ACTION_WRITE;
787+
}
788+
789+
NET_EBPF_EXT_LOG_MESSAGE_UINT32(
790+
NET_EBPF_EXT_TRACELOG_LEVEL_VERBOSE,
791+
NET_EBPF_EXT_TRACELOG_KEYWORD_SOCK_OPS,
792+
"Listen operation processed, port:",
793+
sock_ops_context.context.local_port);
794+
795+
Exit:
796+
NET_EBPF_EXT_LOG_EXIT();
797+
}
798+
627799
static ebpf_result_t
628800
_ebpf_sock_ops_context_create(
629801
_In_reads_bytes_opt_(data_size_in) const uint8_t* data_in,

netebpfext/net_ebpf_ext_sock_ops.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
// Callout GUIDs
99

10+
// clang-format off
1011
// f53b4577-bc47-11ec-9a30-18602489beee
1112
DEFINE_GUID(
1213
EBPF_HOOK_ALE_FLOW_ESTABLISHED_V4_CALLOUT,
@@ -37,6 +38,37 @@ DEFINE_GUID(
3738
0xbe,
3839
0xee);
3940

41+
// f53b4579-bc47-11ec-9a30-18602489beee
42+
DEFINE_GUID(
43+
EBPF_HOOK_ALE_AUTH_LISTEN_V4_CALLOUT,
44+
0xf53b4579,
45+
0xbc47,
46+
0x11ec,
47+
0x9a,
48+
0x30,
49+
0x18,
50+
0x60,
51+
0x24,
52+
0x89,
53+
0xbe,
54+
0xee);
55+
56+
// f53b457a-bc47-11ec-9a30-18602489beee
57+
DEFINE_GUID(
58+
EBPF_HOOK_ALE_AUTH_LISTEN_V6_CALLOUT,
59+
0xf53b457a,
60+
0xbc47,
61+
0x11ec,
62+
0x9a,
63+
0x30,
64+
0x18,
65+
0x60,
66+
0x24,
67+
0x89,
68+
0xbe,
69+
0xee);
70+
// clang-format on
71+
4072
/**
4173
* @brief WFP classifyFn callback for EBPF_HOOK_ALE_FLOW_ESTABLISHED_V4/6_CALLOUT.
4274
*/
@@ -56,6 +88,19 @@ net_ebpf_extension_sock_ops_flow_established_classify(
5688
void
5789
net_ebpf_extension_sock_ops_flow_delete(uint16_t layer_id, uint32_t callout_id, uint64_t flow_context);
5890

91+
/**
92+
* @brief WFP classifyFn callback for EBPF_HOOK_ALE_AUTH_LISTEN_V4/6.
93+
*/
94+
void
95+
net_ebpf_extension_sock_ops_listen_classify(
96+
_In_ const FWPS_INCOMING_VALUES* incoming_fixed_values,
97+
_In_ const FWPS_INCOMING_METADATA_VALUES* incoming_metadata_values,
98+
_Inout_opt_ void* layer_data,
99+
_In_opt_ const void* classify_context,
100+
_In_ const FWPS_FILTER* filter,
101+
uint64_t flow_context,
102+
_Inout_ FWPS_CLASSIFY_OUT* classify_output);
103+
59104
/**
60105
* @brief Unregister SOCK_OPS NPI providers.
61106
*

tests/netebpfext_unit/netebpf_ext_helper.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,18 @@ typedef class _netebpf_ext_helper
9898
usersim_fwp_sock_ops_v4_remove_flow_context(flow_id);
9999
}
100100

101+
FWP_ACTION_TYPE
102+
test_sock_ops_listen_v4(_In_ fwp_classify_parameters_t* parameters)
103+
{
104+
return usersim_fwp_sock_ops_listen_v4(parameters);
105+
}
106+
107+
FWP_ACTION_TYPE
108+
test_sock_ops_listen_v6(_In_ fwp_classify_parameters_t* parameters)
109+
{
110+
return usersim_fwp_sock_ops_listen_v6(parameters);
111+
}
112+
101113
private:
102114
bool trace_initiated = false;
103115
bool ndis_handle_initialized = false;

0 commit comments

Comments
 (0)