- Wrap the sublayer/filter/callout setup in transactions. This appears to

make it less likely to break networking if something goes wrong.  It may
  also solve issue #15.
- Fix bug in last commit.
This commit is contained in:
basil00
2014-03-23 22:33:46 +08:00
parent 7f0e697092
commit 4b708f0c16
+78 -31
View File
@@ -679,11 +679,18 @@ extern NTSTATUS DriverEntry(IN PDRIVER_OBJECT driver_obj,
}
// Register WFP sub-layers:
status = FwpmTransactionBegin0(engine_handle, 0);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to begin WFP transaction", status);
goto driver_entry_exit;
}
status = windivert_install_sublayer(layer_inbound_network_ipv4);
if (!NT_SUCCESS(status))
{
driver_entry_sublayer_error:
DEBUG_ERROR("failed to install WFP sub-layer", status);
FwpmTransactionAbort0(engine_handle);
goto driver_entry_exit;
}
status = windivert_install_sublayer(layer_outbound_network_ipv4);
@@ -711,6 +718,12 @@ driver_entry_sublayer_error:
{
goto driver_entry_sublayer_error;
}
status = FwpmTransactionCommit0(engine_handle);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to commit WFP transaction", status);
goto driver_entry_exit;
}
driver_entry_exit:
@@ -735,6 +748,8 @@ extern VOID windivert_unload(IN WDFDRIVER Driver)
*/
static void windivert_driver_unload(void)
{
NTSTATUS status;
DEBUG("UNLOAD: unloading the WinDivert driver");
if (inject_handle != NULL)
@@ -751,6 +766,13 @@ static void windivert_driver_unload(void)
}
if (engine_handle != NULL)
{
status = FwpmTransactionBegin0(engine_handle, 0);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to begin WFP transaction", status);
FwpmEngineClose0(engine_handle);
return;
}
FwpmSubLayerDeleteByKey0(engine_handle,
&layer_inbound_network_ipv4->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
@@ -763,6 +785,11 @@ static void windivert_driver_unload(void)
&layer_forward_network_ipv4->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
&layer_forward_network_ipv6->sublayer_guid);
status = FwpmTransactionCommit0(engine_handle);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to commit WFP transaction", status);
}
FwpmEngineClose0(engine_handle);
}
}
@@ -1059,23 +1086,40 @@ static NTSTATUS windivert_install_callout(context_t context, UINT idx,
DEBUG_ERROR("failed to install WFP callout", status);
return status;
}
status = FwpmTransactionBegin0(context->engine_handle, 0);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to begin WFP transaction", status);
FwpsCalloutUnregisterByKey0(&context->callout_guid[idx]);
return status;
}
status = FwpmCalloutAdd0(context->engine_handle, &mcallout, NULL, NULL);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to add WFP callout", status);
FwpsCalloutUnregisterByKey0(&context->callout_guid[idx]);
return status;
goto windivert_install_callout_error;
}
status = FwpmFilterAdd0(context->engine_handle, &filter, NULL, NULL);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to add WFP filter", status);
goto windivert_install_callout_error;
}
status = FwpmTransactionCommit0(context->engine_handle);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to commit WFP transaction", status);
FwpsCalloutUnregisterByKey0(&context->callout_guid[idx]);
return status;
}
context->installed[idx] = TRUE;
context->installed[idx] = TRUE;
return STATUS_SUCCESS;
windivert_install_callout_error:
FwpmTransactionAbort0(context->engine_handle);
FwpsCalloutUnregisterByKey0(&context->callout_guid[idx]);
return status;
}
/*
@@ -1083,14 +1127,15 @@ static NTSTATUS windivert_install_callout(context_t context, UINT idx,
*/
static void windivert_uninstall_callouts(context_t context)
{
LARGE_INTEGER timeout;
int retries;
UINT i;
NTSTATUS status;
timeout.HighPart = 0;
timeout.LowPart = -640; // 64ms
status = FwpmTransactionBegin0(context->engine_handle, 0);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to begin WFP transaction", status);
return;
}
for (i = 0; i < WINDIVERT_CONTEXT_MAXLAYERS; i++)
{
if (!context->installed[i])
@@ -1098,34 +1143,36 @@ static void windivert_uninstall_callouts(context_t context)
continue;
}
// It is essential that the filter/callout be deleted, otherwise
// networking will break. Sometimes these calls fail with generic
// RPC errors (e.g. RPC_NT_CALL_FAILED), so we retry until they work.
// There should be a better solution?
for (retries = 8; retries > 0; retries--)
status = FwpmFilterDeleteByKey0(context->engine_handle,
&context->filter_guid[i]);
if (!NT_SUCCESS(status))
{
status = FwpmFilterDeleteByKey0(context->engine_handle,
&context->filter_guid[i]);
if (NT_SUCCESS(status))
{
break;
}
retries--;
KeDelayExecutionThread(KernelMode, FALSE, &timeout);
DEBUG_ERROR("failed to delete filter", status);
break;
}
for (retries = 8; retries > 0; retries--)
status = FwpmCalloutDeleteByKey0(context->engine_handle,
&context->callout_guid[i]);
if (!NT_SUCCESS(status))
{
status = FwpmCalloutDeleteByKey0(context->engine_handle,
&context->callout_guid[i]);
if (NT_SUCCESS(status))
{
break;
}
retries--;
KeDelayExecutionThread(KernelMode, FALSE, &timeout);
DEBUG_ERROR("failed to delete callout", status);
break;
}
}
if (!NT_SUCCESS(status))
{
FwpmTransactionAbort0(context->engine_handle);
return;
}
status = FwpmTransactionCommit0(context->engine_handle);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to commit WFP transaction", status);
return;
}
for (i = 0; i < WINDIVERT_CONTEXT_MAXLAYERS; i++)
{
FwpsCalloutUnregisterByKey0(&context->callout_guid[i]);
context->installed[i] = FALSE;
}
@@ -2421,7 +2468,7 @@ windivert_reinject_packet_exit:
}
}
return status;
return NT_SUCCESS(status);
}
/*