diff --git a/CHANGELOG b/CHANGELOG index 8f6adc4..375aa37 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -87,4 +87,7 @@ WinDivert 1.3.0 WinDivert 1.4.0-rc - Add a new WINDIVERT_PARAM_QUEUE_SIZE parameter that can be used to control the maximum number of bytes used by the packet queue. + - Add a new WINDIVERT_FLAG_DEBUG flag that causes WinDivertSend() to + block until the packet exits the Windows TCP/IP stack. This is slower + but provides better error messages, so is useful for debugging. - Internally queued packets are now reinjected on WinDivertClose(). diff --git a/doc/windivert.html b/doc/windivert.html index b8eeb1e..e1d7110 100644 --- a/doc/windivert.html +++ b/doc/windivert.html @@ -548,6 +548,20 @@ This is useful for implementing simple packet filters using the WinDivert filter language. + + +WINDIVERT_FLAG_DEBUG + + +This flag causes WinDivertRecv() to block +until the injected packet exits the Windows TCP/IP stack. +By default, WinDivertRecv() does not +block and returns immediately after the packet enters the +TCP/IP stack. +The default mode is faster, but will not return an error code if the +packet is lost or rejected for any reason; making debugging difficult. + + Note that only one of WINDIVERT_FLAG_SNIFF or @@ -584,6 +598,7 @@ BOOL WinDivertRecv( TRUE if a packet was successfully received, or FALSE if an error occurred. Use GetLastError() to get the reason for the error. +

Remarks
Receives a diverted packet that matched the filter passed to @@ -701,6 +716,12 @@ BOOL WinDivertSend( an error occurred. Use GetLastError() to get the reason for the error.

+Note that a return value of TRUE does not necessarily mean the +packet was accepted by the Windows TCP/IP stack. +For better error messages (at the cost of performance), pass the +WINDIVERT_FLAG_DEBUG flag to WinDivertOpen(). +

Remarks
Injects a packet into the network stack. The injected packet may be one received from @@ -1577,7 +1598,7 @@ The sample programs are: The basic idea is to divert outbound TCP connections to a local proxy server which can capture or manipulate the stream. The streamdump sample program also demonstrates usage of the - WinDivertRecvEx() and + WinDivertRecvEx() and WinDivertSendEx() functions.

diff --git a/include/windivert.h b/include/windivert.h index 7788a2b..543a591 100644 --- a/include/windivert.h +++ b/include/windivert.h @@ -79,6 +79,7 @@ typedef enum */ #define WINDIVERT_FLAG_SNIFF 1 #define WINDIVERT_FLAG_DROP 2 +#define WINDIVERT_FLAG_DEBUG 4 /* * Divert parameters. diff --git a/include/windivert_device.h b/include/windivert_device.h index 616f01c..3892326 100644 --- a/include/windivert_device.h +++ b/include/windivert_device.h @@ -131,7 +131,7 @@ * WinDivert flags. */ #define WINDIVERT_FLAGS_ALL \ - (WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_DROP) + (WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_DROP | WINDIVERT_FLAG_DEBUG) #define WINDIVERT_FLAGS_EXCLUDE(flags, flag1, flag2) \ (((flags) & ((flag1) | (flag2))) != ((flag1) | (flag2))) #define WINDIVERT_FLAGS_VALID(flags) \ diff --git a/sys/windivert.c b/sys/windivert.c index 76c5e62..3c986a0 100644 --- a/sys/windivert.c +++ b/sys/windivert.c @@ -1623,7 +1623,8 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request, BOOL isipv4; UINT8 layer; UINT32 priority; - HANDLE handle; + UINT64 flags; + HANDLE handle, compl_handle; PNET_BUFFER_LIST buffers = NULL; NTSTATUS status = STATUS_SUCCESS; @@ -1726,33 +1727,38 @@ windivert_write_bad_packet: } layer = context->layer; priority = context->priority; + flags = context->flags; KeReleaseInStackQueuedSpinLock(&lock_handle); handle = (isipv4? inject_handle: injectv6_handle); + compl_handle = ((flags & WINDIVERT_FLAG_DEBUG) != 0? (HANDLE)request: NULL); if (layer == WINDIVERT_LAYER_NETWORK_FORWARD) { status = FwpsInjectForwardAsync0(handle, (HANDLE)priority, 0, (isipv4? AF_INET: AF_INET6), UNSPECIFIED_COMPARTMENT_ID, - addr->IfIdx, buffers, windivert_inject_complete, NULL); + addr->IfIdx, buffers, windivert_inject_complete, compl_handle); } else if (addr->Direction == WINDIVERT_DIRECTION_OUTBOUND) { status = FwpsInjectNetworkSendAsync0(handle, (HANDLE)priority, 0, UNSPECIFIED_COMPARTMENT_ID, buffers, windivert_inject_complete, - NULL); + compl_handle); } else { status = FwpsInjectNetworkReceiveAsync0(handle, (HANDLE)priority, 0, UNSPECIFIED_COMPARTMENT_ID, addr->IfIdx, addr->SubIfIdx, buffers, - windivert_inject_complete, NULL); + windivert_inject_complete, compl_handle); } windivert_write_exit: if (NT_SUCCESS(status)) { - WdfRequestCompleteWithInformation(request, status, data_len); + if ((flags & WINDIVERT_FLAG_DEBUG) == 0) + { + WdfRequestCompleteWithInformation(request, status, data_len); + } } else { @@ -1780,10 +1786,23 @@ static void NTAPI windivert_inject_complete(VOID *context, PMDL mdl; PVOID data; PNET_BUFFER buffer; - UNREFERENCED_PARAMETER(context); + size_t length; + WDFREQUEST request; + NTSTATUS status; UNREFERENCED_PARAMETER(dispatch_level); buffer = NET_BUFFER_LIST_FIRST_NB(buffers); + request = (WDFREQUEST)context; + if (request != NULL) + { + status = NET_BUFFER_LIST_STATUS(buffers); + length = 0; + if (NT_SUCCESS(status)) + { + length = NET_BUFFER_DATA_LENGTH(buffer); + } + WdfRequestCompleteWithInformation(request, status, length); + } mdl = NET_BUFFER_FIRST_MDL(buffer); data = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority); windivert_free(data); @@ -2834,7 +2853,7 @@ static BOOL windivert_reinject_packet(BOOL sniff_mode, BOOL forward, PMDL mdl = NULL; PVOID data = NULL; FWPS_INJECT_COMPLETE0 completion; - HANDLE comp_handle, handle; + HANDLE compl_handle, handle; NTSTATUS status; if (buffer != NULL) @@ -2863,7 +2882,7 @@ static BOOL windivert_reinject_packet(BOOL sniff_mode, BOOL forward, } clone = FALSE; completion = windivert_reinject_complete; - comp_handle = (HANDLE)buffers; + compl_handle = (HANDLE)buffers; FwpsReferenceNetBufferList(buffers, TRUE); } else if (buffers != NULL) @@ -2879,7 +2898,7 @@ static BOOL windivert_reinject_packet(BOOL sniff_mode, BOOL forward, } clone = TRUE; completion = windivert_reinject_clone_complete; - comp_handle = (HANDLE)buffers; + compl_handle = (HANDLE)buffers; FwpsReferenceNetBufferList(buffers, TRUE); } else if (packet != NULL) @@ -2919,7 +2938,7 @@ static BOOL windivert_reinject_packet(BOOL sniff_mode, BOOL forward, } clone = FALSE; completion = windivert_inject_complete; - comp_handle = (HANDLE)NULL; + compl_handle = (HANDLE)NULL; } else return TRUE; @@ -2929,19 +2948,19 @@ static BOOL windivert_reinject_packet(BOOL sniff_mode, BOOL forward, { status = FwpsInjectForwardAsync0(handle, (HANDLE)priority, 0, (isipv4? AF_INET: AF_INET6), UNSPECIFIED_COMPARTMENT_ID, - if_idx, buffers_cpy, completion, comp_handle); + if_idx, buffers_cpy, completion, compl_handle); } else if (direction == WINDIVERT_DIRECTION_OUTBOUND) { status = FwpsInjectNetworkSendAsync0(handle, (HANDLE)priority, 0, UNSPECIFIED_COMPARTMENT_ID, buffers_cpy, - completion, comp_handle); + completion, compl_handle); } else { status = FwpsInjectNetworkReceiveAsync0(handle, (HANDLE)priority, 0, UNSPECIFIED_COMPARTMENT_ID, if_idx, - sub_if_idx, buffers_cpy, completion, comp_handle); + sub_if_idx, buffers_cpy, completion, compl_handle); } if (!NT_SUCCESS(status))