11 Commits

Author SHA1 Message Date
basil00 97101072db Fix previous commit 8bda0af
Fix #294

Previous commit was incomplete.
2022-04-10 06:51:38 +08:00
basil00 8bda0aff7b Fix handling of FwpmTransaction*() errors.
Fixes #294
2022-04-09 09:49:45 +08:00
basil00 34b565de65 Merge pull request #296 from StalkR/patch-1
windivert.html: fix 6.11 title: format not parse
2022-02-23 11:24:31 +08:00
StalkR 90396ffa2b windivert.html: fix 6.11 title: format not parse 2022-02-15 19:35:18 +01:00
basil00 8cdddce6ac Send an ICMP(V6) message if the packet is too big
Fix #278

The Miniport driver will reject any outbound
packet that is larger than the MTU.  However the
error flows back to the sending application as
an error code/condition, which is disrupted by
WinDivert, meaning the error is lost.

This change translates the error code into an
ICMP(V6) "packet too big" message, allowing for
the error to flow back to the origin in some
form.

This change required some refactoring.
2021-10-22 07:34:23 +08:00
basil00 c26ec39465 Fix filter compiler test simplification logic
Fix #285
2021-09-25 07:23:08 +08:00
basil00 227a6b1e78 Fix #283 2021-09-11 07:09:51 +08:00
basil00 134dd37bd0 Insert all WinDivert sublayers at the max weight. 2020-09-03 08:12:39 +08:00
basil00 97056af256 Cleanup the provider code. 2020-06-26 08:53:18 +08:00
basil00 db674a6696 Merge pull request #241 from ruilisi/add_provider
Install provider to pass HLK test
2020-06-24 08:35:31 +08:00
Zhou Yicheng 32af280add Install provider to pass HLK test 2020-06-22 11:08:51 +08:00
4 changed files with 501 additions and 279 deletions
+134 -53
View File
@@ -1,6 +1,6 @@
/*
* windivert_helper.c
* (C) 2019, all rights reserved,
* (C) 2021, all rights reserved,
*
* This file is part of WinDivert.
*
@@ -1061,7 +1061,10 @@ static PEXPR WinDivertMakeVar(KIND kind, PERROR error)
}
return (PEXPR)(vars + mid);
}
*error = MAKE_ERROR(WINDIVERT_ERROR_ASSERTION_FAILED, 0);
if (error != NULL)
{
*error = MAKE_ERROR(WINDIVERT_ERROR_ASSERTION_FAILED, 0);
}
return NULL;
}
@@ -1091,6 +1094,15 @@ static PEXPR WinDivertMakeZero(void)
return (PEXPR)&zero;
}
/*
* Construct one.
*/
static PEXPR WinDivertMakeOne(void)
{
static const EXPR one = {{{1, 0, 0, 0}}, TOKEN_NUMBER};
return (PEXPR)&one;
}
/*
* Construct a number.
*/
@@ -1480,16 +1492,17 @@ static PEXPR WinDivertParseFilter(HANDLE pool, TOKEN *toks, UINT *i, INT depth,
}
/*
* Statically evaluate a test if possible.
* Simplify a test if possible.
*/
static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
static void WinDivertSimplifyTest(PEXPR test)
{
PEXPR var = test->arg[0];
PEXPR val = test->arg[1];
BOOL neg_lb = FALSE, neg_ub = FALSE, neg;
UINT32 lb[4] = {0}, ub[4] = {0};
int result_lb, result_ub;
BOOL eq = FALSE;
BOOL eq = FALSE, result = FALSE;
KIND type = TOKEN_TRUE;
switch (var->kind)
{
@@ -1512,6 +1525,20 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
case TOKEN_EVENT:
lb[0] = 0; ub[0] = WINDIVERT_EVENT_MAX;
break;
case TOKEN_IP_DF:
case TOKEN_IP_MF:
type = TOKEN_IP;
lb[0] = 0; ub[0] = 1;
break;
case TOKEN_TCP_URG:
case TOKEN_TCP_ACK:
case TOKEN_TCP_PSH:
case TOKEN_TCP_RST:
case TOKEN_TCP_SYN:
case TOKEN_TCP_FIN:
type = TOKEN_TCP;
lb[0] = 0; ub[0] = 1;
break;
case TOKEN_INBOUND:
case TOKEN_OUTBOUND:
case TOKEN_FRAGMENT:
@@ -1521,62 +1548,95 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
case TOKEN_ICMPV6:
case TOKEN_TCP:
case TOKEN_UDP:
case TOKEN_IP_DF:
case TOKEN_IP_MF:
case TOKEN_TCP_URG:
case TOKEN_TCP_ACK:
case TOKEN_TCP_PSH:
case TOKEN_TCP_RST:
case TOKEN_TCP_SYN:
case TOKEN_TCP_FIN:
lb[0] = 0; ub[0] = 1;
break;
case TOKEN_IP_HDR_LENGTH:
type = TOKEN_IP;
lb[0] = 0; ub[0] = 0x0F;
break;
case TOKEN_TCP_HDR_LENGTH:
type = TOKEN_TCP;
lb[0] = 0; ub[0] = 0x0F;
break;
case TOKEN_IP_TTL:
case TOKEN_IP_PROTOCOL:
type = TOKEN_IP;
lb[0] = 0; ub[0] = 0xFF;
break;
case TOKEN_IPV6_TRAFFIC_CLASS:
case TOKEN_IPV6_NEXT_HDR:
case TOKEN_IPV6_HOP_LIMIT:
type = TOKEN_IPV6;
lb[0] = 0; ub[0] = 0xFF;
break;
case TOKEN_ICMP_TYPE:
case TOKEN_ICMP_CODE:
type = TOKEN_ICMP;
lb[0] = 0; ub[0] = 0xFF;
break;
case TOKEN_ICMPV6_TYPE:
case TOKEN_ICMPV6_CODE:
type = TOKEN_ICMPV6;
lb[0] = 0; ub[0] = 0xFF;
break;
case TOKEN_TCP_PAYLOAD:
type = TOKEN_TCP;
lb[0] = 0; ub[0] = 0xFF;
break;
case TOKEN_UDP_PAYLOAD:
type = TOKEN_UDP;
lb[0] = 0; ub[0] = 0xFF;
break;
case TOKEN_PROTOCOL:
case TOKEN_PACKET:
case TOKEN_TCP_PAYLOAD:
case TOKEN_UDP_PAYLOAD:
case TOKEN_RANDOM8:
lb[0] = 0; ub[0] = 0xFF;
break;
case TOKEN_IP_FRAG_OFF:
type = TOKEN_IP;
lb[0] = 0; ub[0] = 0x1FFF;
break;
case TOKEN_IP_TOS:
case TOKEN_IP_LENGTH:
case TOKEN_IP_ID:
case TOKEN_IP_CHECKSUM:
type = TOKEN_IP;
lb[0] = 0; ub[0] = 0xFFFF;
break;
case TOKEN_IPV6_LENGTH:
type = TOKEN_IPV6;
lb[0] = 0; ub[0] = 0xFFFF;
break;
case TOKEN_ICMP_CHECKSUM:
type = TOKEN_ICMP;
lb[0] = 0; ub[0] = 0xFFFF;
break;
case TOKEN_ICMPV6_CHECKSUM:
type = TOKEN_ICMPV6;
lb[0] = 0; ub[0] = 0xFFFF;
break;
case TOKEN_TCP_SRC_PORT:
case TOKEN_TCP_DST_PORT:
case TOKEN_TCP_WINDOW:
case TOKEN_TCP_CHECKSUM:
case TOKEN_TCP_URG_PTR:
case TOKEN_TCP_PAYLOAD_LENGTH:
case TOKEN_TCP_PAYLOAD16:
type = TOKEN_TCP;
lb[0] = 0; ub[0] = 0xFFFF;
break;
case TOKEN_UDP_SRC_PORT:
case TOKEN_UDP_DST_PORT:
case TOKEN_UDP_LENGTH:
case TOKEN_UDP_CHECKSUM:
case TOKEN_UDP_PAYLOAD_LENGTH:
case TOKEN_UDP_PAYLOAD16:
type = TOKEN_UDP;
lb[0] = 0; ub[0] = 0xFFFF;
break;
case TOKEN_LOCAL_PORT:
case TOKEN_REMOTE_PORT:
case TOKEN_PACKET16:
case TOKEN_TCP_PAYLOAD16:
case TOKEN_UDP_PAYLOAD16:
case TOKEN_RANDOM16:
lb[0] = 0; ub[0] = 0xFFFF;
break;
@@ -1584,10 +1644,12 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
lb[0] = sizeof(WINDIVERT_IPHDR); ub[0] = WINDIVERT_MTU_MAX;
break;
case TOKEN_IPV6_FLOW_LABEL:
type = TOKEN_IPV6;
lb[0] = 0; ub[0] = 0x000FFFFF;
break;
case TOKEN_IP_SRC_ADDR:
case TOKEN_IP_DST_ADDR:
type = TOKEN_IP;
lb[0] = 0;
lb[1] = 0xFFFF;
ub[0] = 0xFFFFFFFF;
@@ -1595,6 +1657,8 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
break;
case TOKEN_IPV6_SRC_ADDR:
case TOKEN_IPV6_DST_ADDR:
type = TOKEN_IPV6;
// Fallthrough
case TOKEN_LOCAL_ADDR:
case TOKEN_REMOTE_ADDR:
lb[0] = lb[1] = lb[2] = lb[3] = 0;
@@ -1607,14 +1671,27 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
ub[1] = 0x7FFFFFFF;
neg_lb = TRUE;
break;
case TOKEN_TCP_PAYLOAD32:
type = TOKEN_TCP;
lb[0] = 0; ub[0] = 0xFFFFFFFF;
break;
case TOKEN_UDP_PAYLOAD32:
type = TOKEN_UDP;
lb[0] = 0; ub[0] = 0xFFFFFFFF;
break;
case TOKEN_IF_IDX:
case TOKEN_SUB_IF_IDX:
case TOKEN_RANDOM32:
case TOKEN_PROCESS_ID:
lb[0] = 0; ub[0] = 0xFFFFFFFF;
break;
case TOKEN_ENDPOINT_ID:
case TOKEN_PARENT_ENDPOINT_ID:
lb[0] = lb[1] = 0;
ub[0] = ub[1] = 0xFFFFFFFF;
break;
default:
lb[0] = 0; ub[0] = 0xFFFFFFFF;
break;
return;
}
neg = (val->neg? TRUE: FALSE);
result_lb = WinDivertCompare128(neg, val->val, neg_lb, lb, /*big=*/TRUE);
@@ -1624,78 +1701,81 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
case TOKEN_EQ:
if (result_lb < 0 || result_ub > 0)
{
*res = FALSE;
return TRUE;
result = FALSE;
break;
}
if (eq && result_lb == 0)
{
*res = TRUE;
return TRUE;
result = TRUE;
break;
}
return FALSE;
return;
case TOKEN_NEQ:
if (result_lb < 0 || result_ub > 0)
{
*res = TRUE;
return TRUE;
result = TRUE;
break;
}
if (eq && result_lb == 0)
{
*res = FALSE;
return TRUE;
result = FALSE;
break;
}
return FALSE;
return;
case TOKEN_LT:
if (result_ub > 0)
{
*res = TRUE;
return TRUE;
result = TRUE;
break;
}
if (result_lb <= 0)
{
*res = FALSE;
return TRUE;
result = FALSE;
break;
}
return FALSE;
return;
case TOKEN_LEQ:
if (result_ub >= 0)
{
*res = TRUE;
return TRUE;
result = TRUE;
break;
}
if (result_lb < 0)
{
*res = FALSE;
return TRUE;
result = FALSE;
break;
}
return FALSE;
return;
case TOKEN_GT:
if (result_ub >= 0)
{
*res = FALSE;
return TRUE;
result = FALSE;
break;
}
if (result_lb < 0)
{
*res = TRUE;
return TRUE;
result = TRUE;
break;
}
return FALSE;
return;
case TOKEN_GEQ:
if (result_ub > 0)
{
*res = FALSE;
return TRUE;
result = FALSE;
break;
}
if (result_lb <= 0)
{
*res = TRUE;
return TRUE;
result = TRUE;
break;
}
return FALSE;
return;
default:
return FALSE;
return;
}
test->arg[0] = WinDivertMakeVar(type, NULL);
test->arg[1] = (result? WinDivertMakeOne(): WinDivertMakeZero());
test->kind = TOKEN_EQ;
}
/*
@@ -1705,7 +1785,6 @@ static INT16 WinDivertFlattenExpr(PEXPR expr, INT16 *label, INT16 succ,
INT16 fail, PEXPR *stack)
{
INT16 succ1, fail1;
BOOL res;
if (succ < 0 || fail < 0)
{
return -1;
@@ -1729,9 +1808,11 @@ static INT16 WinDivertFlattenExpr(PEXPR expr, INT16 *label, INT16 succ,
stack);
return succ;
default:
if (WinDivertEvalTest(expr, &res))
WinDivertSimplifyTest(expr);
if (expr->kind == TOKEN_EQ &&
expr->arg[0]->kind == TOKEN_TRUE)
{
return (res? succ: fail);
return (expr->arg[1]->val[0] != 0? succ: fail);
}
if (*label >= WINDIVERT_FILTER_MAXLEN)
{
+1 -1
View File
@@ -2317,7 +2317,7 @@ to convert the result into network-byte-order.
</p>
</dd></dl>
<a name="divert_helper_format_ipv4_address"><h3>6.11 WinDivertHelperParseIPv4Address</h3></a>
<a name="divert_helper_format_ipv4_address"><h3>6.11 WinDivertHelperFormatIPv4Address</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
BOOL <b>WinDivertHelperFormatIPv4Address</b>(
+363 -224
View File
@@ -1,6 +1,6 @@
/*
* windivert.c
* (C) 2019, all rights reserved,
* (C) 2022, all rights reserved,
*
* This file is part of WinDivert.
*
@@ -123,7 +123,6 @@ typedef enum
WINDIVERT_CONTEXT_STATE_OPEN = 0xB1, // Context is open.
WINDIVERT_CONTEXT_STATE_CLOSING = 0xC2, // Context is closing.
WINDIVERT_CONTEXT_STATE_CLOSED = 0xD3, // Context is closed.
WINDIVERT_CONTEXT_STATE_INVALID = 0xE4 // Context is invalid.
} context_state_t;
struct context_s
{
@@ -243,8 +242,9 @@ struct packet_s
UINT32 ip_checksum:1; // Packet has IPv4 checksum?
UINT32 tcp_checksum:1; // Packet has TCP checksum?
UINT32 udp_checksum:1; // Packet has UDP checksum?
UINT32 icmp_checksum:1; // Packet has ICMP(V6) checksum?
UINT32 match:1; // Packet matches filter?
UINT32 padding:7; // Padding for alignment.
UINT32 padding:6; // Padding for alignment.
UINT32 packet_size; // Packet total size.
PVOID object; // Object associated with packet.
UINT32 priority; // Packet priority.
@@ -333,6 +333,7 @@ extern VOID windivert_worker(IN WDFWORKITEM item);
static void windivert_read_service(context_t context);
extern VOID windivert_create(IN WDFDEVICE device, IN WDFREQUEST request,
IN WDFFILEOBJECT object);
static NTSTATUS windivert_install_provider(void);
static NTSTATUS windivert_install_sublayer(layer_t layer);
static NTSTATUS windivert_install_callouts(context_t context, UINT8 layer,
UINT64 flags);
@@ -347,8 +348,7 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
req_context_t req_context);
static void NTAPI windivert_inject_complete(VOID *context,
NET_BUFFER_LIST *packets, BOOLEAN dispatch_level);
static void NTAPI windivert_reinject_complete(VOID *context,
NET_BUFFER_LIST *packets, BOOLEAN dispatch_level);
static void windivert_inject_packet_too_big(packet_t packet);
static NTSTATUS windivert_notify(IN FWPS_CALLOUT_NOTIFY_TYPE type,
IN const GUID *filter_key, IN const FWPS_FILTER0 *filter);
static void windivert_outbound_network_v4_classify(
@@ -469,7 +469,7 @@ static BOOL windivert_queue_work(context_t context, PVOID packet,
UINT64 flags, UINT32 priority, BOOL ipv4, BOOL outbound, BOOL loopback,
BOOL impostor, BOOL match, LONGLONG timestamp);
static void windivert_queue_packet(context_t context, packet_t packet);
static void windivert_reinject_packet(packet_t packet);
static NTSTATUS windivert_inject_packet(packet_t packet);
static void windivert_free_packet(packet_t packet);
static BOOL windivert_copy_data(PNET_BUFFER buffer, PVOID data, UINT size);
static BOOL windivert_get_data(PNET_BUFFER buffer, UINT length, INT min,
@@ -499,6 +499,15 @@ extern void windivert_reflect_worker(IN WDFWORKITEM item);
static void windivert_log_event(PEPROCESS process, PDRIVER_OBJECT driver,
const wchar_t *msg_str);
/*
* WinDivert provider GUIDs
*/
DEFINE_GUID(WINDIVERT_PROVIDER_GUID,
0x450EC398, 0x1EAF, 0x49F5,
0x85, 0xE0, 0x22, 0x8F, 0x0D, 0x29, 0x39, 0x21);
#define WINDIVERT_PROVIDER_NAME WINDIVERT_DEVICE_NAME
#define WINDIVERT_PROVIDER_DESC WINDIVERT_DEVICE_NAME L" provider"
/*
* WinDivert sublayer GUIDs
*/
@@ -680,7 +689,7 @@ static const struct layer_s windivert_layer_resource_assignment_ipv4 =
&WINDIVERT_SUBLAYER_RESOURCE_ASSIGNMENT_IPV4_GUID,
windivert_resource_assignment_v4_classify,
NULL,
0
UINT16_MAX
};
#define WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV4 \
(&windivert_layer_resource_assignment_ipv4)
@@ -697,7 +706,7 @@ static const struct layer_s windivert_layer_resource_assignment_ipv6 =
&WINDIVERT_SUBLAYER_RESOURCE_ASSIGNMENT_IPV6_GUID,
windivert_resource_assignment_v6_classify,
NULL,
0
UINT16_MAX
};
#define WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV6 \
(&windivert_layer_resource_assignment_ipv6)
@@ -714,7 +723,7 @@ static const struct layer_s windivert_layer_resource_release_ipv4 =
&WINDIVERT_SUBLAYER_RESOURCE_RELEASE_IPV4_GUID,
windivert_resource_release_v4_classify,
NULL,
0
UINT16_MAX
};
#define WINDIVERT_LAYER_RESOURCE_RELEASE_IPV4 \
(&windivert_layer_resource_release_ipv4)
@@ -731,7 +740,7 @@ static const struct layer_s windivert_layer_resource_release_ipv6 =
&WINDIVERT_SUBLAYER_RESOURCE_RELEASE_IPV6_GUID,
windivert_resource_release_v6_classify,
NULL,
0
UINT16_MAX
};
#define WINDIVERT_LAYER_RESOURCE_RELEASE_IPV6 \
(&windivert_layer_resource_release_ipv6)
@@ -748,7 +757,7 @@ static const struct layer_s windivert_layer_auth_connect_ipv4 =
&WINDIVERT_SUBLAYER_AUTH_CONNECT_IPV4_GUID,
windivert_auth_connect_v4_classify,
NULL,
0
UINT16_MAX
};
#define WINDIVERT_LAYER_AUTH_CONNECT_IPV4 \
(&windivert_layer_auth_connect_ipv4)
@@ -765,7 +774,7 @@ static const struct layer_s windivert_layer_auth_connect_ipv6 =
&WINDIVERT_SUBLAYER_AUTH_CONNECT_IPV6_GUID,
windivert_auth_connect_v6_classify,
NULL,
0
UINT16_MAX
};
#define WINDIVERT_LAYER_AUTH_CONNECT_IPV6 \
(&windivert_layer_auth_connect_ipv6)
@@ -782,7 +791,7 @@ static const struct layer_s windivert_layer_endpoint_closure_ipv4 =
&WINDIVERT_SUBLAYER_ENDPOINT_CLOSURE_IPV4_GUID,
windivert_endpoint_closure_v4_classify,
NULL,
0
UINT16_MAX
};
#define WINDIVERT_LAYER_ENDPOINT_CLOSURE_IPV4 \
(&windivert_layer_endpoint_closure_ipv4)
@@ -799,7 +808,7 @@ static const struct layer_s windivert_layer_endpoint_closure_ipv6 =
&WINDIVERT_SUBLAYER_ENDPOINT_CLOSURE_IPV6_GUID,
windivert_endpoint_closure_v6_classify,
NULL,
0
UINT16_MAX
};
#define WINDIVERT_LAYER_ENDPOINT_CLOSURE_IPV6 \
(&windivert_layer_endpoint_closure_ipv6)
@@ -816,7 +825,7 @@ static const struct layer_s windivert_layer_auth_listen_ipv4 =
&WINDIVERT_SUBLAYER_AUTH_LISTEN_IPV4_GUID,
windivert_auth_listen_v4_classify,
NULL,
0
UINT16_MAX
};
#define WINDIVERT_LAYER_AUTH_LISTEN_IPV4 \
(&windivert_layer_auth_listen_ipv4)
@@ -833,7 +842,7 @@ static const struct layer_s windivert_layer_auth_listen_ipv6 =
&WINDIVERT_SUBLAYER_AUTH_LISTEN_IPV6_GUID,
windivert_auth_listen_v6_classify,
NULL,
0
UINT16_MAX
};
#define WINDIVERT_LAYER_AUTH_LISTEN_IPV6 \
(&windivert_layer_auth_listen_ipv6)
@@ -850,7 +859,7 @@ static const struct layer_s windivert_layer_auth_recv_accept_ipv4 =
&WINDIVERT_SUBLAYER_AUTH_RECV_ACCEPT_IPV4_GUID,
windivert_auth_recv_accept_v4_classify,
NULL,
0
UINT16_MAX
};
#define WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV4 \
(&windivert_layer_auth_recv_accept_ipv4)
@@ -867,7 +876,7 @@ static const struct layer_s windivert_layer_auth_recv_accept_ipv6 =
&WINDIVERT_SUBLAYER_AUTH_RECV_ACCEPT_IPV6_GUID,
windivert_auth_recv_accept_v6_classify,
NULL,
0
UINT16_MAX
};
#define WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV6 \
(&windivert_layer_auth_recv_accept_ipv6)
@@ -884,7 +893,7 @@ static const struct layer_s windivert_layer_flow_established_ipv4 =
&WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV4_GUID,
windivert_flow_established_v4_classify,
windivert_flow_delete_notify,
0
UINT16_MAX
};
#define WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV4 \
(&windivert_layer_flow_established_ipv4)
@@ -901,7 +910,7 @@ static const struct layer_s windivert_layer_flow_established_ipv6 =
&WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV6_GUID,
windivert_flow_established_v6_classify,
windivert_flow_delete_notify,
0
UINT16_MAX
};
#define WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV6 \
(&windivert_layer_flow_established_ipv6)
@@ -1156,6 +1165,14 @@ extern NTSTATUS DriverEntry(IN PDRIVER_OBJECT driver_obj,
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to begin WFP transaction", status);
FwpmTransactionAbort0(engine_handle);
goto driver_entry_exit;
}
status = windivert_install_provider();
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to install provider", status);
FwpmTransactionAbort0(engine_handle);
goto driver_entry_exit;
}
status = windivert_install_sublayer(WINDIVERT_LAYER_INBOUND_NETWORK_IPV4);
@@ -1267,6 +1284,7 @@ driver_entry_sublayer_error:
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to commit WFP transaction", status);
FwpmTransactionAbort0(engine_handle);
goto driver_entry_exit;
}
@@ -1343,6 +1361,7 @@ static void windivert_driver_unload(void)
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to begin WFP transaction", status);
FwpmTransactionAbort0(engine_handle);
FwpmEngineClose0(engine_handle);
return;
}
@@ -1386,15 +1405,39 @@ static void windivert_driver_unload(void)
WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV4->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV6->sublayer_guid);
FwpmProviderDeleteByKey0(engine_handle,
&WINDIVERT_PROVIDER_GUID);
status = FwpmTransactionCommit0(engine_handle);
if (!NT_SUCCESS(status))
{
FwpmTransactionAbort0(engine_handle);
DEBUG_ERROR("failed to commit WFP transaction", status);
}
FwpmEngineClose0(engine_handle);
}
}
/*
* Register provider.
*/
static NTSTATUS windivert_install_provider()
{
FWPM_PROVIDER0 provider;
NTSTATUS status;
RtlZeroMemory(&provider, sizeof(provider));
provider.providerKey = WINDIVERT_PROVIDER_GUID;
provider.displayData.name = WINDIVERT_PROVIDER_NAME;
provider.displayData.description = WINDIVERT_PROVIDER_DESC;
// We don't care about the install result as this provider
// is only for passing HLK test.
FwpmProviderAdd0(engine_handle, &provider, NULL);
return STATUS_SUCCESS;
}
/*
* Register a sub-layer.
*/
@@ -1529,7 +1572,7 @@ windivert_create_exit:
// Clean-up on error:
if (!NT_SUCCESS(status))
{
context->state = WINDIVERT_CONTEXT_STATE_INVALID;
context->state = WINDIVERT_CONTEXT_STATE_CLOSED;
if (context->read_queue != NULL)
{
WdfObjectDelete(context->read_queue);
@@ -1538,14 +1581,7 @@ windivert_create_exit:
{
WdfObjectDelete(context->worker);
}
if (context->process != NULL)
{
ObDereferenceObject(context->process);
}
if (context->engine_handle != NULL)
{
FwpmEngineClose0(context->engine_handle);
}
// process/engine_handle handled by windivert_destroy()
}
WdfRequestComplete(request, status);
@@ -1564,15 +1600,15 @@ static NTSTATUS windivert_install_callouts(context_t context, UINT8 layer,
accept, close;
NTSTATUS status = STATUS_SUCCESS;
inbound = ((flags & WINDIVERT_FILTER_FLAG_INBOUND) != 0);
outbound = ((flags & WINDIVERT_FILTER_FLAG_OUTBOUND) != 0);
ipv4 = ((flags & WINDIVERT_FILTER_FLAG_IP) != 0);
ipv6 = ((flags & WINDIVERT_FILTER_FLAG_IPV6) != 0);
bind = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_BIND) != 0);
connect = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CONNECT) != 0);
listen = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_LISTEN) != 0);
accept = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_ACCEPT) != 0);
close = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CLOSE) != 0);
inbound = ((flags & WINDIVERT_FILTER_FLAG_INBOUND) != 0);
outbound = ((flags & WINDIVERT_FILTER_FLAG_OUTBOUND) != 0);
ipv4 = ((flags & WINDIVERT_FILTER_FLAG_IP) != 0);
ipv6 = ((flags & WINDIVERT_FILTER_FLAG_IPV6) != 0);
bind = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_BIND) != 0);
connect = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CONNECT) != 0);
listen = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_LISTEN) != 0);
accept = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_ACCEPT) != 0);
close = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CLOSE) != 0);
i = 0;
switch (layer)
@@ -1764,8 +1800,7 @@ static NTSTATUS windivert_install_callout(context_t context, UINT idx,
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to begin WFP transaction", status);
FwpsCalloutUnregisterByKey0(&callout_guid);
return status;
goto windivert_install_callout_error;
}
status = FwpmCalloutAdd0(engine, &mcallout, NULL, NULL);
if (!NT_SUCCESS(status))
@@ -1783,8 +1818,7 @@ static NTSTATUS windivert_install_callout(context_t context, UINT idx,
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to commit WFP transaction", status);
FwpsCalloutUnregisterByKey0(&callout_guid);
return status;
goto windivert_install_callout_error;
}
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
@@ -1839,6 +1873,7 @@ windivert_uninstall_callouts_error:
// RPC handle was closed first. So, this path is "normal" if
// the user's app crashed or never closed the WinDivert handle.
DEBUG_ERROR("failed to begin WFP transaction", status);
FwpmTransactionAbort0(engine);
goto windivert_uninstall_callouts_unregister;
}
for (i = 0; i < WINDIVERT_CONTEXT_MAXLAYERS; i++)
@@ -1883,6 +1918,7 @@ windivert_uninstall_callouts_error:
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to commit WFP transaction", status);
FwpmTransactionAbort0(engine);
// continue
}
@@ -1969,7 +2005,7 @@ windivert_cleanup_error:
timeout = WINDIVERT_TIMEOUT(context, packet->timestamp, timestamp);
if (!sniff_mode && !timeout)
{
windivert_reinject_packet(packet);
windivert_inject_packet(packet);
}
else
{
@@ -1991,7 +2027,7 @@ windivert_cleanup_error:
timeout = WINDIVERT_TIMEOUT(context, work->timestamp, timestamp);
if (!sniff_mode && !timeout)
{
windivert_reinject_packet(work);
windivert_inject_packet(work);
}
else
{
@@ -2065,9 +2101,15 @@ extern VOID windivert_destroy(IN WDFOBJECT object)
filter = context->filter;
KeReleaseInStackQueuedSpinLock(&lock_handle);
windivert_uninstall_callouts(context, WINDIVERT_CONTEXT_STATE_CLOSED);
FwpmEngineClose0(context->engine_handle);
if (context->engine_handle != NULL)
{
FwpmEngineClose0(context->engine_handle);
}
windivert_free((PVOID)filter);
ObDereferenceObject(context->process);
if (context->process != NULL)
{
ObDereferenceObject(context->process);
}
}
/*
@@ -2548,19 +2590,20 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
req_context_t req_context)
{
KLOCK_QUEUE_HANDLE lock_handle;
PMDL mdl = NULL, mdl_copy = NULL;
PVOID data, data_copy = NULL;
UINT data_len, packet_len, inject_len;
PMDL mdl = NULL;
PVOID data, data_copy;
packet_t packet;
UINT data_len, packet_len, packet_size, inject_len;
PWINDIVERT_DATA_NETWORK network_data;
PWINDIVERT_IPHDR ip_header;
PWINDIVERT_IPV6HDR ipv6_header;
BOOL ipv4;
UINT8 layer;
UINT32 priority;
UINT64 flags, checksums;
HANDLE handle;
PNET_BUFFER_LIST buffers = NULL;
PWINDIVERT_ADDRESS addr;
UINT i, addr_len, addr_len_max;
UINT i, addr_len, addr_len_max, version;
NTSTATUS status = STATUS_SUCCESS, status_soft_error = STATUS_SUCCESS;
DEBUG("WRITE: writing/injecting a packet (context=%p, request=%p)",
@@ -2629,10 +2672,6 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
i < WINDIVERT_BATCH_MAX;
i++, addr_len += sizeof(WINDIVERT_ADDRESS))
{
buffers = NULL;
mdl_copy = NULL;
data_copy = NULL;
// Get the packet length:
if (data_len < sizeof(WINDIVERT_IPHDR))
{
@@ -2642,11 +2681,15 @@ windivert_write_too_small_packet:
goto windivert_write_hard_error;
}
ip_header = (PWINDIVERT_IPHDR)data;
switch (ip_header->Version)
version = ip_header->Version;
switch (version)
{
case 4:
packet_len = RtlUshortByteSwap(ip_header->Length);
ipv4 = TRUE;
if (packet_len < sizeof(WINDIVERT_IPHDR))
{
goto windivert_write_invalid_packet;
}
break;
case 6:
if (data_len < sizeof(WINDIVERT_IPV6HDR))
@@ -2656,11 +2699,11 @@ windivert_write_too_small_packet:
ipv6_header = (PWINDIVERT_IPV6HDR)data;
packet_len = RtlUshortByteSwap(ipv6_header->Length) +
sizeof(WINDIVERT_IPV6HDR);
ipv4 = FALSE;
break;
default:
windivert_write_invalid_packet:
status = STATUS_INVALID_PARAMETER;
DEBUG_ERROR("failed to inject non-IP packet", status);
DEBUG_ERROR("failed to inject invalid packet", status);
goto windivert_write_hard_error;
}
if (data_len < packet_len)
@@ -2668,100 +2711,77 @@ windivert_write_too_small_packet:
goto windivert_write_too_small_packet;
}
// Copy packet data:
data_copy = windivert_malloc(packet_len, FALSE);
if (data_copy == NULL)
// Copy packet & data:
packet_size = WINDIVERT_PACKET_SIZE(WINDIVERT_DATA_NETWORK,
packet_len);
packet = (packet_t)windivert_malloc(packet_size, FALSE);
if (packet == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
DEBUG_ERROR("failed to allocate memory for injected packet data",
DEBUG_ERROR("failed to allocate memory for injected packet",
status);
goto windivert_write_hard_error;
}
packet->layer = layer;
packet->event = WINDIVERT_EVENT_NETWORK_PACKET;
packet->sniffed = 0; // Unused
packet->outbound = addr[i].Outbound;
packet->loopback = 0; // Unused
packet->impostor = addr[i].Impostor;
packet->ipv6 = (version == 6? 1: 0);
packet->ip_checksum = addr[i].IPChecksum;
packet->tcp_checksum = addr[i].TCPChecksum;
packet->udp_checksum = addr[i].UDPChecksum;
packet->icmp_checksum = 1; // Assumed valid
packet->match = 0; // Unused
packet->packet_size = packet_size;
packet->packet_len = packet_len;
packet->priority = priority;
packet->timestamp = 0; // Unused
packet->object = NULL;
network_data =
(PWINDIVERT_DATA_NETWORK)WINDIVERT_LAYER_DATA_PTR(packet);
RtlCopyMemory(network_data, &addr[i].Network, sizeof(network_data));
data_copy = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_DATA_NETWORK, packet);
RtlCopyMemory(data_copy, data, packet_len);
switch (version)
{
case 4:
ip_header = (PWINDIVERT_IPHDR)data_copy;
if (ip_header->Version != 4 ||
packet_len != RtlUshortByteSwap(ip_header->Length))
{
windivert_free(packet);
goto windivert_write_invalid_packet;
}
break;
case 6:
ipv6_header = (PWINDIVERT_IPV6HDR)data_copy;
if (ipv6_header->Version != 6 ||
packet_len != RtlUshortByteSwap(ipv6_header->Length) +
sizeof(WINDIVERT_IPV6HDR))
{
windivert_free(packet);
goto windivert_write_invalid_packet;
}
break;
}
// Check bounds:
DEBUG_BOUNDS_CHECK((PVOID)addr, (UINT8 *)addr + addr_len_max,
(PVOID)&addr[i], (PVOID)&addr[i+1]);
// Fix checksums:
if (addr[i].IPChecksum == 0 || addr[i].TCPChecksum == 0 ||
addr[i].UDPChecksum == 0)
{
checksums =
(addr[i].IPChecksum == 0? 0:
WINDIVERT_HELPER_NO_IP_CHECKSUM) |
(addr[i].TCPChecksum == 0? 0:
WINDIVERT_HELPER_NO_TCP_CHECKSUM) |
(addr[i].UDPChecksum == 0? 0:
WINDIVERT_HELPER_NO_UDP_CHECKSUM) |
WINDIVERT_HELPER_NO_ICMP_CHECKSUM |
WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM;
WinDivertHelperCalcChecksums(data_copy, packet_len, NULL,
checksums);
}
// Decrement TTL for impostor packets:
if (addr[i].Impostor &&
!WinDivertHelperDecrementTTL(data_copy, packet_len))
{
status_soft_error = STATUS_HOPLIMIT_EXCEEDED;
windivert_free(data_copy);
goto windivert_write_loop;
}
// Allocate packet:
mdl_copy = IoAllocateMdl(data_copy, packet_len, FALSE, FALSE, NULL);
if (mdl_copy == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
DEBUG_ERROR("failed to allocate MDL for injected packet", status);
goto windivert_write_hard_error;
}
MmBuildMdlForNonPagedPool(mdl_copy);
status = FwpsAllocateNetBufferAndNetBufferList0(nbl_pool_handle, 0, 0,
mdl_copy, 0, packet_len, &buffers);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to create NET_BUFFER_LIST for injected packet",
status);
goto windivert_write_hard_error;
}
// Inject packet:
if (layer == WINDIVERT_LAYER_NETWORK_FORWARD)
{
handle = (ipv4? inject_handle_forward: injectv6_handle_forward);
status = FwpsInjectForwardAsync0(handle, (HANDLE)priority, 0,
(ipv4? AF_INET: AF_INET6), UNSPECIFIED_COMPARTMENT_ID,
addr[i].Network.IfIdx, buffers, windivert_inject_complete,
data_copy);
}
else if (addr[i].Outbound != 0)
{
handle = (ipv4? inject_handle_out: injectv6_handle_out);
status = FwpsInjectNetworkSendAsync0(handle, (HANDLE)priority, 0,
UNSPECIFIED_COMPARTMENT_ID, buffers, windivert_inject_complete,
data_copy);
}
else
{
handle = (ipv4? inject_handle_in: injectv6_handle_in);
status = FwpsInjectNetworkReceiveAsync0(handle, (HANDLE)priority, 0,
UNSPECIFIED_COMPARTMENT_ID, addr[i].Network.IfIdx,
addr[i].Network.SubIfIdx, buffers, windivert_inject_complete,
data_copy);
}
status = windivert_inject_packet(packet);
if (!NT_SUCCESS(status))
{
if (status == STATUS_INSUFFICIENT_RESOURCES)
{
goto windivert_write_hard_error;
}
status_soft_error = status;
FwpsFreeNetBufferList0(buffers);
IoFreeMdl(mdl_copy);
windivert_free(data_copy);
}
windivert_write_loop:
// Reset state:
inject_len += packet_len;
data = (PVOID)((UINT8 *)data + packet_len);
@@ -2776,54 +2796,9 @@ windivert_write_loop:
windivert_write_hard_error:
// Request to be completed in windivert_ioctl()
if (buffers != NULL)
{
FwpsFreeNetBufferList0(buffers);
}
if (mdl_copy != NULL)
{
IoFreeMdl(mdl_copy);
}
windivert_free(data_copy);
return status;
}
/*
* WinDivert inject complete routine.
*/
static void NTAPI windivert_inject_complete(VOID *data,
NET_BUFFER_LIST *buffers, BOOLEAN dispatch_level)
{
PMDL mdl;
PNET_BUFFER buffer;
UNREFERENCED_PARAMETER(dispatch_level);
buffer = NET_BUFFER_LIST_FIRST_NB(buffers);
mdl = NET_BUFFER_FIRST_MDL(buffer);
windivert_free(data);
IoFreeMdl(mdl);
FwpsFreeNetBufferList0(buffers);
}
/*
* WinDivert reinject complete routine.
*/
static void NTAPI windivert_reinject_complete(VOID *context,
NET_BUFFER_LIST *buffers, BOOLEAN dispatch_level)
{
PMDL mdl;
PNET_BUFFER buffer;
packet_t packet;
UNREFERENCED_PARAMETER(dispatch_level);
buffer = NET_BUFFER_LIST_FIRST_NB(buffers);
packet = (packet_t)context;
mdl = NET_BUFFER_FIRST_MDL(buffer);
windivert_free_packet(packet);
IoFreeMdl(mdl);
FwpsFreeNetBufferList0(buffers);
}
/*
* WinDivert caller context preprocessing.
@@ -4022,7 +3997,7 @@ static void windivert_flow_established_v6_classify(
UNREFERENCED_PARAMETER(data);
UNREFERENCED_PARAMETER(flow_context);
flow_data.ProcessId = (UINT32)meta_vals->processId;
flow_data.EndpointId = meta_vals->transportEndpointHandle;
flow_data.ParentEndpointId = meta_vals->parentEndpointHandle;
flow_data.ProcessId = (UINT32)meta_vals->processId;
windivert_get_ipv6_addr(fixed_vals,
@@ -4869,7 +4844,7 @@ VOID windivert_worker(IN WDFWORKITEM item)
}
else
{
windivert_reinject_packet(work);
windivert_inject_packet(work);
}
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
@@ -5030,21 +5005,22 @@ static BOOL windivert_queue_work(context_t context, PVOID packet,
return TRUE;
}
work->layer = layer;
work->event = event;
work->sniffed = (sniffed? 1: 0);
work->outbound = (outbound? 1: 0);
work->loopback = (loopback? 1: 0);
work->impostor = (impostor? 1: 0);
work->ipv6 = (!ipv4? 1: 0);
work->ip_checksum = (ip_checksum? 1: 0);
work->tcp_checksum = (tcp_checksum? 1: 0);
work->udp_checksum = (udp_checksum? 1: 0);
work->match = match;
work->packet_size = packet_size;
work->priority = priority;
work->timestamp = timestamp;
work->object = object;
work->layer = layer;
work->event = event;
work->sniffed = (sniffed? 1: 0);
work->outbound = (outbound? 1: 0);
work->loopback = (loopback? 1: 0);
work->impostor = (impostor? 1: 0);
work->ipv6 = (!ipv4? 1: 0);
work->ip_checksum = (ip_checksum? 1: 0);
work->tcp_checksum = (tcp_checksum? 1: 0);
work->udp_checksum = (udp_checksum? 1: 0);
work->icmp_checksum = 1;
work->match = match;
work->packet_size = packet_size;
work->priority = priority;
work->timestamp = timestamp;
work->object = object;
if (object != NULL)
{
ObfReferenceObject(object);
@@ -5106,7 +5082,7 @@ static void windivert_queue_packet(context_t context, packet_t packet)
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
windivert_reinject_packet(packet);
windivert_inject_packet(packet);
return;
}
if (packet->packet_size > context->packet_queue_maxsize)
@@ -5158,9 +5134,9 @@ static void windivert_queue_packet(context_t context, packet_t packet)
}
/*
* Re-inject a packet.
* Inject a packet.
*/
static void windivert_reinject_packet(packet_t packet)
static NTSTATUS windivert_inject_packet(packet_t packet)
{
UINT8 *packet_data;
UINT32 packet_len;
@@ -5176,7 +5152,7 @@ static void windivert_reinject_packet(packet_t packet)
packet->layer != WINDIVERT_LAYER_NETWORK_FORWARD)
{
windivert_free_packet(packet);
return;
return STATUS_INVALID_PARAMETER;
}
network_data = (PWINDIVERT_DATA_NETWORK)WINDIVERT_LAYER_DATA_PTR(packet);
@@ -5184,47 +5160,43 @@ static void windivert_reinject_packet(packet_t packet)
packet_len = packet->packet_len;
// Fix checksums:
if (packet->ip_checksum == 0 || packet->tcp_checksum == 0 ||
packet->udp_checksum == 0)
{
checksums =
(packet->ip_checksum == 0? 0: WINDIVERT_HELPER_NO_IP_CHECKSUM) |
(packet->tcp_checksum == 0? 0: WINDIVERT_HELPER_NO_TCP_CHECKSUM) |
(packet->udp_checksum == 0? 0: WINDIVERT_HELPER_NO_UDP_CHECKSUM) |
WINDIVERT_HELPER_NO_ICMP_CHECKSUM |
WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM;
WinDivertHelperCalcChecksums(packet_data, packet_len, NULL, checksums);
}
checksums =
(packet->ip_checksum == 0? 0: WINDIVERT_HELPER_NO_IP_CHECKSUM) |
(packet->tcp_checksum == 0? 0: WINDIVERT_HELPER_NO_TCP_CHECKSUM) |
(packet->udp_checksum == 0? 0: WINDIVERT_HELPER_NO_UDP_CHECKSUM) |
(packet->icmp_checksum == 0? 0: WINDIVERT_HELPER_NO_ICMP_CHECKSUM |
WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM);
WinDivertHelperCalcChecksums(packet_data, packet_len, NULL, checksums);
// Decrement TTL for impostor packets:
if (packet->impostor != 0 &&
!WinDivertHelperDecrementTTL(packet_data, packet_len))
{
status = STATUS_HOPLIMIT_EXCEEDED;
DEBUG_ERROR("failed to reinject ttl-exceeded impostor packet", status);
DEBUG_ERROR("failed to inject ttl-exceeded impostor packet", status);
windivert_free_packet(packet);
return;
return status;
}
// Reinject packet:
// Inject packet:
mdl = IoAllocateMdl(packet_data, packet_len, FALSE, FALSE, NULL);
if (mdl == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
DEBUG_ERROR("failed to allocate MDL for reinjected packet", status);
DEBUG_ERROR("failed to allocate MDL for injected packet", status);
windivert_free_packet(packet);
return;
return status;
}
MmBuildMdlForNonPagedPool(mdl);
status = FwpsAllocateNetBufferAndNetBufferList0(nbl_pool_handle, 0, 0,
mdl, 0, packet_len, &buffers);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to create NET_BUFFER_LIST for reinjected packet",
DEBUG_ERROR("failed to create NET_BUFFER_LIST for injected packet",
status);
IoFreeMdl(mdl);
windivert_free_packet(packet);
return;
return status;
}
priority = packet->priority;
if (packet->layer == WINDIVERT_LAYER_NETWORK_FORWARD)
@@ -5232,14 +5204,14 @@ static void windivert_reinject_packet(packet_t packet)
handle = (packet->ipv6? injectv6_handle_forward: inject_handle_forward);
status = FwpsInjectForwardAsync0(handle, (HANDLE)priority, 0,
(packet->ipv6? AF_INET6: AF_INET), UNSPECIFIED_COMPARTMENT_ID,
network_data->IfIdx, buffers, windivert_reinject_complete,
network_data->IfIdx, buffers, windivert_inject_complete,
(HANDLE)packet);
}
else if (packet->outbound)
{
handle = (packet->ipv6? injectv6_handle_out: inject_handle_out);
status = FwpsInjectNetworkSendAsync0(handle, (HANDLE)priority, 0,
UNSPECIFIED_COMPARTMENT_ID, buffers, windivert_reinject_complete,
UNSPECIFIED_COMPARTMENT_ID, buffers, windivert_inject_complete,
(HANDLE)packet);
}
else
@@ -5247,17 +5219,18 @@ static void windivert_reinject_packet(packet_t packet)
handle = (packet->ipv6? injectv6_handle_in: inject_handle_in);
status = FwpsInjectNetworkReceiveAsync0(handle, (HANDLE)priority, 0,
UNSPECIFIED_COMPARTMENT_ID, network_data->IfIdx,
network_data->SubIfIdx, buffers, windivert_reinject_complete,
network_data->SubIfIdx, buffers, windivert_inject_complete,
(HANDLE)packet);
}
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to reinject (packet=%p)", status, packet);
DEBUG_ERROR("failed to inject (packet=%p)", status, packet);
FwpsFreeNetBufferList0(buffers);
IoFreeMdl(mdl);
windivert_free_packet(packet);
}
return status;
}
/*
@@ -5272,6 +5245,172 @@ static void windivert_free_packet(packet_t packet)
windivert_free(packet);
}
/*
* WinDivert inject complete routine.
*/
static void NTAPI windivert_inject_complete(VOID *context,
NET_BUFFER_LIST *buffers, BOOLEAN dispatch_level)
{
PMDL mdl;
PNET_BUFFER buffer;
packet_t packet;
UNREFERENCED_PARAMETER(dispatch_level);
packet = (packet_t)context;
if (buffers->Status == STATUS_INVALID_BUFFER_SIZE)
{
// STATUS_INVALID_BUFFER_SIZE indicates that the send failed because
// the packet was larger than the MTU. We generate an ICMP
// Fragmentation Needed (for IPv4) or an ICMPV6 Packet Too Big (for
// IPv6) message to allow for PMTU discovery.
windivert_inject_packet_too_big(packet);
}
buffer = NET_BUFFER_LIST_FIRST_NB(buffers);
mdl = NET_BUFFER_FIRST_MDL(buffer);
IoFreeMdl(mdl);
FwpsFreeNetBufferList0(buffers);
windivert_free_packet(packet);
}
/*
* WinDivert inject an ICMP(V6) Packet Too Big message.
*/
static void windivert_inject_packet_too_big(packet_t packet)
{
const UINT mtus[] =
{
568, 768, 1024, 1192, 1280, 1372, 1452, 1500, 4096, UINT16_MAX,
UINT32_MAX
};
PWINDIVERT_IPHDR ip_header, ip_header_2;
PWINDIVERT_IPV6HDR ipv6_header, ipv6_header_2;
PWINDIVERT_ICMPHDR icmp_header;
PWINDIVERT_ICMPV6HDR icmpv6_header;
packet_t icmp;
UINT version, packet_len, copy_len, icmp_len;
UINT icmp_size;
UINT i, min_mtu = /*ipv4 min MTU=*/568, mtu;
UINT32 flowlabel;
UINT8 *data;
if (packet->layer != WINDIVERT_LAYER_NETWORK || !packet->outbound ||
packet->loopback)
{
return;
}
ip_header = (PWINDIVERT_IPHDR)WINDIVERT_PACKET_DATA_PTR(
WINDIVERT_DATA_NETWORK, packet);
version = ip_header->Version;
switch (version)
{
case 4:
packet_len = RtlUshortByteSwap(ip_header->Length);
copy_len = ip_header->HdrLength * sizeof(UINT32) + 8;
copy_len = (packet_len < copy_len? packet_len: copy_len);
icmp_len = sizeof(WINDIVERT_IPHDR) + sizeof(WINDIVERT_ICMPHDR) +
copy_len;
break;
case 6:
ipv6_header = (PWINDIVERT_IPV6HDR)ip_header;
packet_len = RtlUshortByteSwap(ipv6_header->Length) +
sizeof(WINDIVERT_IPV6HDR);
min_mtu = /*ipv6 min MTU=*/1280;
copy_len = min_mtu - sizeof(WINDIVERT_IPV6HDR) -
sizeof(WINDIVERT_ICMPV6HDR);
copy_len = (packet_len < copy_len? packet_len: copy_len);
icmp_len = sizeof(WINDIVERT_IPV6HDR) +
sizeof(WINDIVERT_ICMPV6HDR) + copy_len;
break;
default:
return;
}
if (packet_len <= min_mtu)
{
return;
}
// We do not actually know the MTU value, so we make an educated guess.
for (i = 0; packet_len > mtus[i]; i++)
;
mtu = (i == 0? min_mtu: mtus[i-1]);
mtu = (mtu < min_mtu? min_mtu: mtu);
icmp_size = WINDIVERT_PACKET_SIZE(WINDIVERT_DATA_NETWORK, icmp_len);
icmp = (packet_t)windivert_malloc(icmp_size, FALSE);
if (icmp == NULL)
{
return;
}
icmp->layer = WINDIVERT_LAYER_NETWORK;
icmp->event = WINDIVERT_EVENT_NETWORK_PACKET;
icmp->sniffed = 0; // Unused
icmp->outbound = 0; // Inbound
icmp->loopback = 0; // Unused
icmp->impostor = 0; // Treat as non-impostor
icmp->ipv6 = (version == 6? 1: 0);
icmp->ip_checksum = 0; // IP checksum valid
icmp->tcp_checksum = 0; // Unused
icmp->udp_checksum = 0; // Unused
icmp->icmp_checksum = 0; // ICMP(V6) checksum invalid
icmp->match = 0; // Unused
icmp->packet_size = icmp_size;
icmp->packet_len = icmp_len;
icmp->priority = packet->priority;
icmp->timestamp = 0; // Unused
icmp->object = NULL;
RtlCopyMemory(WINDIVERT_LAYER_DATA_PTR(icmp),
WINDIVERT_LAYER_DATA_PTR(packet), sizeof(WINDIVERT_DATA_NETWORK));
data = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_DATA_NETWORK, icmp);
switch (version)
{
case 4:
ip_header_2 = (PWINDIVERT_IPHDR)data;
ip_header_2->Version = 4;
ip_header_2->HdrLength = sizeof(WINDIVERT_IPHDR) / sizeof(UINT32);
ip_header_2->TOS = 0x0;
ip_header_2->Length = RtlUshortByteSwap(icmp_len);
ip_header_2->Id = 0x0;
ip_header_2->TTL = 64;
ip_header_2->Protocol = IPPROTO_ICMP;
ip_header_2->SrcAddr = ip_header->DstAddr;
ip_header_2->DstAddr = ip_header->SrcAddr;
WINDIVERT_IPHDR_SET_FRAGOFF(ip_header_2, 0x0);
WINDIVERT_IPHDR_SET_MF(ip_header_2, 0);
WINDIVERT_IPHDR_SET_DF(ip_header_2, 1);
WINDIVERT_IPHDR_SET_RESERVED(ip_header_2, 0x0);
icmp_header = (PWINDIVERT_ICMPHDR)(ip_header_2 + 1);
icmp_header->Type = /*Destination Unreachable=*/3;
icmp_header->Code = /*Fragmentation required=*/4;
icmp_header->Body = ((UINT32)RtlUshortByteSwap(mtu)) << 16;
data = (UINT8 *)(icmp_header + 1);
RtlCopyMemory(data, ip_header, copy_len);
break;
case 6:
icmp_len -= sizeof(WINDIVERT_IPV6HDR);
ipv6_header_2 = (PWINDIVERT_IPV6HDR)data;
ipv6_header_2->Version = 6;
ipv6_header_2->Length = RtlUshortByteSwap(icmp_len);
ipv6_header_2->NextHdr = IPPROTO_ICMPV6;
ipv6_header_2->HopLimit = 64;
RtlCopyMemory(ipv6_header_2->SrcAddr, ipv6_header->DstAddr,
sizeof(ipv6_header_2->SrcAddr));
RtlCopyMemory(ipv6_header_2->DstAddr, ipv6_header->SrcAddr,
sizeof(ipv6_header_2->DstAddr));
WINDIVERT_IPV6HDR_SET_TRAFFICCLASS(ipv6_header_2, 0x0);
flowlabel = WINDIVERT_IPV6HDR_GET_FLOWLABEL(ipv6_header);
WINDIVERT_IPV6HDR_SET_FLOWLABEL(ipv6_header_2, flowlabel);
icmpv6_header = (PWINDIVERT_ICMPV6HDR)(ipv6_header_2 + 1);
icmpv6_header->Type = /*Packet Too Big=*/2;
icmpv6_header->Code = 0;
icmpv6_header->Body = RtlUlongByteSwap(mtu);
data = (UINT8 *)(icmpv6_header + 1);
RtlCopyMemory(data, ipv6_header, copy_len);
break;
}
windivert_inject_packet(icmp);
}
/*
* Copy data from a NET_BUFFER.
*/
+3 -1
View File
@@ -1,6 +1,6 @@
/*
* test.c
* (C) 2019, all rights reserved,
* (C) 2021, all rights reserved,
*
* This file is part of WinDivert.
*
@@ -632,6 +632,7 @@ static const struct test tests[] =
{"localAddr == 10.0.0.1 && remoteAddr == 8.8.4.4 && "
"localPort == 57413 && remotePort == 53 && protocol == 17",
&pkt_dns_request, TRUE},
{"ipv6.DstAddr >= ::", &pkt_dns_request, FALSE},
{"ipv6", &pkt_ipv6_tcp_syn, TRUE},
{"ip", &pkt_ipv6_tcp_syn, FALSE},
{"tcp.Syn", &pkt_ipv6_tcp_syn, TRUE},
@@ -815,6 +816,7 @@ static const struct test tests[] =
{"ipv6.SrcAddr != abcd::1", &pkt_ipv6_exthdrs_udp, TRUE},
{"ipv6.SrcAddr >= abcd::1", &pkt_ipv6_exthdrs_udp, FALSE},
{"ipv6.SrcAddr > abcd::1", &pkt_ipv6_exthdrs_udp, FALSE},
{"ipv6.DstAddr >= ::", &pkt_ipv6_exthdrs_udp, TRUE},
{"timestamp > -1", &pkt_ipv6_exthdrs_udp, TRUE},
{"udp.SrcPort == 4660 and udp.DstPort == 43690",
&pkt_ipv6_exthdrs_udp, TRUE},