diff options
| author | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
|---|---|---|
| committer | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
| commit | 97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch) | |
| tree | 46f3701832d70b420eb0fc0eb93261f9da45db3f /network/trans/ddproxy/sys | |
| parent | ef1905bf1e8825bb31120dfb27e0daf3154d859a (diff) | |
Initial publish
Diffstat (limited to 'network/trans/ddproxy/sys')
| -rw-r--r-- | network/trans/ddproxy/sys/DD_drv.c | 1059 | ||||
| -rw-r--r-- | network/trans/ddproxy/sys/DD_proxy.c | 1039 | ||||
| -rw-r--r-- | network/trans/ddproxy/sys/DD_proxy.h | 251 | ||||
| -rw-r--r-- | network/trans/ddproxy/sys/ddproxy.inf | 63 | ||||
| -rw-r--r-- | network/trans/ddproxy/sys/ddproxy.vcxproj | 185 | ||||
| -rw-r--r-- | network/trans/ddproxy/sys/ddproxy.vcxproj.Filters | 29 |
6 files changed, 2626 insertions, 0 deletions
diff --git a/network/trans/ddproxy/sys/DD_drv.c b/network/trans/ddproxy/sys/DD_drv.c new file mode 100644 index 00000000..18509e53 --- /dev/null +++ b/network/trans/ddproxy/sys/DD_drv.c @@ -0,0 +1,1059 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved + +Abstract: + + Datagram-Data Transparent Proxy Callout Driver Sample. + + This sample callout driver intercepts UDP and non-error ICMP traffic + of interest and proxies them to a new destination address and/or port + (for UDP); response traffic will be proxied back to have the original + tuple values. The proxying is transparent to the application. + + Inspection parameters and proxy settings are configurable via the + following registry values -- + + HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ddproxy\Parameters + + o InspectUdp (REG_DWORD) : 0 (ICMP); 1 (UDP, default) + o DestinationAddressToIntercept (REG_SZ) : literal IPv4/IPv6 string + (e.g. �10.0.0.1�) + o DestinationPortToIntercept (REG_DWORD) : applicable if InspectUdp is 1 + o NewDestinationAddress(REG_SZ) : literal IPv4/IPv6 string + o NewDestinationPort(REG_DWORD) + + The sample is IP version agnostic. It performs proxying for both IPv4 + and IPv6 traffic. + +Environment: + + Kernel mode + +--*/ + +#include <ntddk.h> +#include <wdf.h> + +#pragma warning(push) +#pragma warning(disable:4201) // unnamed struct/union + +#include <fwpsk.h> + +#pragma warning(pop) + +#include <fwpmk.h> + +#include <ws2ipdef.h> +#include <in6addr.h> +#include <ip2string.h> + +#include "DD_proxy.h" + +#define INITGUID +#include <guiddef.h> + +// +// Configurable parameters (addresses and ports are in host order) +// + +BOOLEAN configInspectUdp = TRUE; + +UINT16 configInspectDestPort = 5001; +UINT8* configInspectDestAddrV4 = NULL; +UINT8* configInspectDestAddrV6 = NULL; + +UINT16 configNewDestPort = 5001; +UINT8* configNewDestAddrV4 = NULL; +UINT8* configNewDestAddrV6 = NULL; + +SOCKADDR_STORAGE destAddr, newDestAddr; + +// +// Callout and sublayer GUIDs +// + +// b16b0a6e-2b2a-41a3-8b39-bd3ffc855ff8 +DEFINE_GUID( + DD_PROXY_CALLOUT_V4, + 0xb16b0a6e, + 0x2b2a, + 0x41a3, + 0x8b, 0x39, 0xbd, 0x3f, 0xfc, 0x85, 0x5f, 0xf8 +); +// 2cebde39-1f59-48d1-a5d9-3e2458351476 +DEFINE_GUID( + DD_PROXY_CALLOUT_V6, + 0x2cebde39, + 0x1f59, + 0x48d1, + 0xa5, 0xd9, 0x3e, 0x24, 0x58, 0x35, 0x14, 0x76 +); +// ee93719d-ad5d-48c9-ae46-7270367d205d +DEFINE_GUID( + DD_PROXY_FLOW_ESTABLISHED_CALLOUT_V4, + 0xee93719d, + 0xad5d, + 0x48c9, + 0xae, 0x46, 0x72, 0x70, 0x36, 0x7d, 0x20, 0x5d +); + +// 1e3d3d13-0588-4167-82a3-14f68c98de86 +DEFINE_GUID( + DD_PROXY_FLOW_ESTABLISHED_CALLOUT_V6, + 0x1e3d3d13, + 0x0588, + 0x4167, + 0x82, 0xa3, 0x14, 0xf6, 0x8c, 0x98, 0xde, 0x86 +); + +// 0104fd7e-c825-414e-94c9-f0d525bbc169 +DEFINE_GUID( + DD_PROXY_SUBLAYER, + 0x0104fd7e, + 0xc825, + 0x414e, + 0x94, 0xc9, 0xf0, 0xd5, 0x25, 0xbb, 0xc1, 0x69 +); + +// +// Callout driver global variables +// + +DEVICE_OBJECT* gWdmDevice; + +HANDLE gEngineHandle; +UINT32 gFlowEstablishedCalloutIdV4, gCalloutIdV4; +UINT32 gFlowEstablishedCalloutIdV6, gCalloutIdV6; + +HANDLE gInjectionHandle; + +LIST_ENTRY gFlowList; +KSPIN_LOCK gFlowListLock; + +LIST_ENTRY gPacketQueue; +KSPIN_LOCK gPacketQueueLock; +KEVENT gPacketQueueEvent; + +BOOLEAN gDriverUnloading = FALSE; +void* gThreadObj; + +DRIVER_INITIALIZE DriverEntry; +EVT_WDF_DRIVER_UNLOAD EvtDriverUnload; + +// +// Callout driver implementation +// + +NTSTATUS +DDProxyLoadIPAddress( + _In_ const WDFKEY key, + _In_ const UNICODE_STRING* valueName, + _Out_ SOCKADDR_STORAGE* result + ) +{ + NTSTATUS status; + PWSTR terminator; + DECLARE_UNICODE_STRING_SIZE(value, INET6_ADDRSTRLEN); + IN_ADDR *resultV4 = &((SOCKADDR_IN*)result)->sin_addr; + IN6_ADDR *resultV6 = &((SOCKADDR_IN6*)result)->sin6_addr; + + status = WdfRegistryQueryUnicodeString(key, valueName, NULL, &value); + result->ss_family = AF_UNSPEC; + + if (NT_SUCCESS(status)) + { + // The Registry API does not guarantee that the string will be + // null-terminated. + // Defensively null-terminate the string. + value.Length = min(value.Length, value.MaximumLength - sizeof(WCHAR)); + value.Buffer[value.Length/sizeof(WCHAR)] = UNICODE_NULL; + + status = RtlIpv4StringToAddressW( + value.Buffer, + TRUE, + &terminator, + resultV4 + ); + + if (NT_SUCCESS(status)) + { + resultV4->S_un.S_addr = RtlUlongByteSwap(resultV4->S_un.S_addr); + result->ss_family = AF_INET; + } + else + { + status = RtlIpv6StringToAddressW( + value.Buffer, + &terminator, + resultV6 + ); + + if (NT_SUCCESS(status)) + { + result->ss_family = AF_INET6; + } + } + } + + return status; +} + +NTSTATUS +DDProxyLoadConfig( + _In_ const WDFKEY key + ) +{ + NTSTATUS status = STATUS_SUCCESS; + DECLARE_CONST_UNICODE_STRING(inspectUdpValueName, L"InspectUdp"); + DECLARE_CONST_UNICODE_STRING(destAddrValueName, L"DestinationAddressToIntercept"); + DECLARE_CONST_UNICODE_STRING(destPortValueName, L"DestinationPortToIntercept"); + DECLARE_CONST_UNICODE_STRING(newDestAddrValueName, L"NewDestinationAddress"); + DECLARE_CONST_UNICODE_STRING(newDestPortValueName, L"NewDestinationPort"); + + ULONG ulongValue; + + if (NT_SUCCESS(WdfRegistryQueryULong( + key, + &inspectUdpValueName, + &ulongValue + ))) + { + configInspectUdp = (ulongValue != 0); + } + + + if (NT_SUCCESS(DDProxyLoadIPAddress( + key, + &destAddrValueName, + &destAddr + ))) + { + if (destAddr.ss_family == AF_INET) + { + configInspectDestAddrV4 = &((SOCKADDR_IN*)&destAddr)->sin_addr.S_un.S_un_b.s_b1; + } + else if (destAddr.ss_family == AF_INET6) + { + configInspectDestAddrV6 = (UINT8*)(&((SOCKADDR_IN6*)&destAddr)->sin6_addr.u.Byte[0]); + } + } + + if (NT_SUCCESS(WdfRegistryQueryULong( + key, + &destPortValueName, + &ulongValue + ))) + { + configInspectDestPort = (USHORT) ulongValue; + } + + if (NT_SUCCESS(DDProxyLoadIPAddress( + key, + &newDestAddrValueName, + &newDestAddr + ))) + { + if (destAddr.ss_family == AF_INET) + { + configNewDestAddrV4 = &((SOCKADDR_IN*)&newDestAddr)->sin_addr.S_un.S_un_b.s_b1; + } + else if (destAddr.ss_family == AF_INET6) + { + configNewDestAddrV6 = (UINT8*)(&((SOCKADDR_IN6*)&newDestAddr)->sin6_addr.u.Byte[0]); + } + } + + if (NT_SUCCESS(WdfRegistryQueryULong( + key, + &newDestPortValueName, + &ulongValue + ))) + { + configNewDestPort = (USHORT) ulongValue; + } + + return status; +} + +NTSTATUS +DDProxyAddFilter( + _In_ const PWSTR filterName, + _In_ const PWSTR filterDesc, + _In_reads_(16) const UINT8* remoteAddr, + _In_ USHORT remotePort, + _In_ FWP_DIRECTION direction, + _In_ UINT64 context, + _In_ const GUID* layerKey, + _In_ const GUID* calloutKey + ) +{ + NTSTATUS status = STATUS_SUCCESS; + + FWPM_FILTER filter = {0}; + FWPM_FILTER_CONDITION filterConditions[3] = {0}; + UINT conditionIndex; + + filter.layerKey = *layerKey; + filter.displayData.name = (wchar_t*)filterName; + filter.displayData.description = (wchar_t*)filterDesc; + + filter.action.type = FWP_ACTION_CALLOUT_TERMINATING; + filter.action.calloutKey = *calloutKey; + filter.filterCondition = filterConditions; + filter.subLayerKey = DD_PROXY_SUBLAYER; + filter.weight.type = FWP_EMPTY; // auto-weight. + filter.rawContext = context; + + conditionIndex = 0; + + if (remoteAddr != NULL) + { + filterConditions[conditionIndex].fieldKey = + FWPM_CONDITION_IP_REMOTE_ADDRESS; + filterConditions[conditionIndex].matchType = FWP_MATCH_EQUAL; + + if (IsEqualGUID(layerKey, &FWPM_LAYER_DATAGRAM_DATA_V4) || + IsEqualGUID(layerKey, &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4)) + { + filterConditions[conditionIndex].conditionValue.type = FWP_UINT32; + filterConditions[conditionIndex].conditionValue.uint32 = + *(UINT32*)remoteAddr; + } + else + { + filterConditions[conditionIndex].conditionValue.type = + FWP_BYTE_ARRAY16_TYPE; + filterConditions[conditionIndex].conditionValue.byteArray16 = + (FWP_BYTE_ARRAY16*)remoteAddr; + } + + conditionIndex++; + } + + filterConditions[conditionIndex].fieldKey = FWPM_CONDITION_DIRECTION; + filterConditions[conditionIndex].matchType = FWP_MATCH_EQUAL; + filterConditions[conditionIndex].conditionValue.type = FWP_UINT32; + filterConditions[conditionIndex].conditionValue.uint32 = direction; + + conditionIndex++; + + if (configInspectUdp) + { + filterConditions[conditionIndex].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT; + filterConditions[conditionIndex].matchType = FWP_MATCH_EQUAL; + filterConditions[conditionIndex].conditionValue.type = FWP_UINT16; + filterConditions[conditionIndex].conditionValue.uint16 = remotePort; + + conditionIndex++; + } + + filter.numFilterConditions = conditionIndex; + + status = FwpmFilterAdd( + gEngineHandle, + &filter, + NULL, + NULL); + + return status; +} + +NTSTATUS +DDProxyRegisterFlowEstablishedCallouts( + _In_ const GUID* layerKey, + _In_ const GUID* calloutKey, + _Inout_ void* deviceObject, + _Out_ UINT32* calloutId + ) +/* ++ + + This function registers callouts and filters at the following layers + to intercept flow creations for the original and the proxy flows. + + FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4 + FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6 + +-- */ +{ + NTSTATUS status = STATUS_SUCCESS; + + FWPS_CALLOUT sCallout = {0}; + FWPM_CALLOUT mCallout = {0}; + + FWPM_DISPLAY_DATA displayData = {0}; + + BOOLEAN calloutRegistered = FALSE; + + sCallout.calloutKey = *calloutKey; + sCallout.classifyFn = DDProxyFlowEstablishedClassify; + sCallout.notifyFn = DDProxyFlowEstablishedNotify; + + status = FwpsCalloutRegister( + deviceObject, + &sCallout, + calloutId + ); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + calloutRegistered = TRUE; + + displayData.name = L"Datagram-Data Proxy Flow-Established Callout"; + displayData.description = + L"Intercepts flow creations for the original and the proxy flows"; + + mCallout.calloutKey = *calloutKey; + mCallout.displayData = displayData; + mCallout.applicableLayer = *layerKey; + + status = FwpmCalloutAdd( + gEngineHandle, + &mCallout, + NULL, + NULL + ); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + status = DDProxyAddFilter( + L"Datagram-Data Proxy Flow-Established Filter (Original Flow)", + L"Intercepts flow creations for the original flow", + IsEqualGUID(layerKey, &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4) ? + configInspectDestAddrV4 : configInspectDestAddrV6, + configInspectDestPort, + FWP_DIRECTION_OUTBOUND, + DD_PROXY_FLOW_ORIGINAL, + layerKey, + calloutKey + ); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + status = DDProxyAddFilter( + L"Datagram-Data Proxy Flow-Established Filter (Proxy Flow)", + L"Intercepts flow creations for the proxy flow", + IsEqualGUID(layerKey, &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4) ? + configNewDestAddrV4 : configNewDestAddrV6, + configNewDestPort, + FWP_DIRECTION_OUTBOUND, + DD_PROXY_FLOW_PROXY, + layerKey, + calloutKey + ); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + +Exit: + + if (!NT_SUCCESS(status)) + { + if (calloutRegistered) + { + FwpsCalloutUnregisterById(*calloutId); + *calloutId = 0; + } + } + + return status; +} + +NTSTATUS +DDProxyRegisterDatagramDataCallouts( + _In_ const GUID* layerKey, + _In_ const GUID* calloutKey, + _Inout_ void* deviceObject, + _Out_ UINT32* calloutId + ) +/* ++ + + This function registers callouts and filters that intercept TCP traffic at + WFP FWPM_LAYER_DATAGRAM_DATA_V4 or FWPM_LAYER_DATAGRAM_DATA_V6 layer. + +-- */ +{ + NTSTATUS status = STATUS_SUCCESS; + + FWPS_CALLOUT sCallout = {0}; + FWPM_CALLOUT mCallout = {0}; + + FWPM_DISPLAY_DATA displayData = {0}; + + BOOLEAN calloutRegistered = FALSE; + + sCallout.calloutKey = *calloutKey; + sCallout.classifyFn = DDProxyClassify; + sCallout.notifyFn = DDProxyNotify; + sCallout.flowDeleteFn = DDProxyFlowDelete; + sCallout.flags = FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW; + + status = FwpsCalloutRegister( + deviceObject, + &sCallout, + calloutId + ); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + calloutRegistered = TRUE; + + displayData.name = L"Datagram-Data Proxy Callout"; + displayData.description = L"Proxies destination address/port for UDP/ICMP"; + + mCallout.calloutKey = *calloutKey; + mCallout.displayData = displayData; + mCallout.applicableLayer = *layerKey; + + status = FwpmCalloutAdd( + gEngineHandle, + &mCallout, + NULL, + NULL + ); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + status = DDProxyAddFilter( + L"Datagram-Data Proxy Filter (Outbound)", + L"Proxies destination address/port for UDP/ICMP", + IsEqualGUID(layerKey, &FWPM_LAYER_DATAGRAM_DATA_V4) ? + configInspectDestAddrV4 : configInspectDestAddrV6, + configInspectDestPort, + FWP_DIRECTION_OUTBOUND, + 0, + layerKey, + calloutKey + ); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + status = DDProxyAddFilter( + L"Datagram-Data Proxy Filter (Inbound)", + L"Proxies destination address/port for UDP/ICMP", + IsEqualGUID(layerKey, &FWPM_LAYER_DATAGRAM_DATA_V4) ? + configNewDestAddrV4 : configNewDestAddrV6, + configNewDestPort, + FWP_DIRECTION_INBOUND, + 0, + layerKey, + calloutKey + ); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + +Exit: + + if (!NT_SUCCESS(status)) + { + if (calloutRegistered) + { + FwpsCalloutUnregisterById(*calloutId); + *calloutId = 0; + } + } + + return status; +} + +NTSTATUS +DDProxyRegisterCallouts( + _Inout_ void* deviceObject + ) +/* ++ + + This function registers dynamic callouts and filters that intercept UDP or + non-error ICMP traffic at WFP FWPM_LAYER_DATAGRAM_DATA_V{4|6} and + FWPM_LAYER_ALE_FLOW_ESTABLISHED_V{4|6} layers. + + Callouts and filters will be removed during DriverUnload. + +-- */ +{ + NTSTATUS status = STATUS_SUCCESS; + FWPM_SUBLAYER DDProxySubLayer; + + BOOLEAN engineOpened = FALSE; + BOOLEAN inTransaction = FALSE; + + FWPM_SESSION session = {0}; + + session.flags = FWPM_SESSION_FLAG_DYNAMIC; + + status = FwpmEngineOpen( + NULL, + RPC_C_AUTHN_WINNT, + NULL, + &session, + &gEngineHandle + ); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + engineOpened = TRUE; + + status = FwpmTransactionBegin(gEngineHandle, 0); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + inTransaction = TRUE; + + RtlZeroMemory(&DDProxySubLayer, sizeof(FWPM_SUBLAYER)); + + DDProxySubLayer.subLayerKey = DD_PROXY_SUBLAYER; + DDProxySubLayer.displayData.name = L"Datagram-Data Proxy Sub-Layer"; + DDProxySubLayer.displayData.description = + L"Sub-Layer for use by Datagram-Data Proxy callouts"; + DDProxySubLayer.flags = 0; + DDProxySubLayer.weight = FWP_EMPTY; // auto-weight.; + + status = FwpmSubLayerAdd(gEngineHandle, &DDProxySubLayer, NULL); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + status = DDProxyRegisterFlowEstablishedCallouts( + &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4, + &DD_PROXY_FLOW_ESTABLISHED_CALLOUT_V4, + deviceObject, + &gFlowEstablishedCalloutIdV4 + ); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + status = DDProxyRegisterFlowEstablishedCallouts( + &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6, + &DD_PROXY_FLOW_ESTABLISHED_CALLOUT_V6, + deviceObject, + &gFlowEstablishedCalloutIdV6 + ); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + status = DDProxyRegisterDatagramDataCallouts( + &FWPM_LAYER_DATAGRAM_DATA_V4, + &DD_PROXY_CALLOUT_V4, + deviceObject, + &gCalloutIdV4 + ); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + status = DDProxyRegisterDatagramDataCallouts( + &FWPM_LAYER_DATAGRAM_DATA_V6, + &DD_PROXY_CALLOUT_V6, + deviceObject, + &gCalloutIdV6 + ); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + status = FwpmTransactionCommit(gEngineHandle); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + inTransaction = FALSE; + +Exit: + + if (!NT_SUCCESS(status)) + { + if (inTransaction) + { + FwpmTransactionAbort(gEngineHandle); + _Analysis_assume_lock_not_held_(gEngineHandle); // Potential leak if "FwpmTransactionAbort" fails + } + if (engineOpened) + { + FwpmEngineClose(gEngineHandle); + gEngineHandle = NULL; + } + } + + return status; +} + +void +DDProxyUnregisterCallouts(void) +{ + FwpmEngineClose(gEngineHandle); + gEngineHandle = NULL; + + FwpsCalloutUnregisterById(gCalloutIdV6); + FwpsCalloutUnregisterById(gCalloutIdV4); + + FwpsCalloutUnregisterById(gFlowEstablishedCalloutIdV6); + FwpsCalloutUnregisterById(gFlowEstablishedCalloutIdV4); +} + +void +DDProxyRemoveFlows(void) +{ + while (!IsListEmpty(&gFlowList)) + { + KLOCK_QUEUE_HANDLE flowListLockHandle; + LIST_ENTRY* listEntry = NULL; + DD_PROXY_FLOW_CONTEXT* flowContext; + + KeAcquireInStackQueuedSpinLock( + &gFlowListLock, + &flowListLockHandle + ); + + if (!IsListEmpty(&gFlowList)) + { + listEntry = RemoveHeadList(&gFlowList); + } + + // + // Releasing the lock here since removing the flow context + // will invoke the callout's flowDeleteFn synchronously + // if there are no active classifications in progress. + // + KeReleaseInStackQueuedSpinLock(&flowListLockHandle); + + if (listEntry != NULL) + { + flowContext = CONTAINING_RECORD( + listEntry, + DD_PROXY_FLOW_CONTEXT, + listEntry + ); + + flowContext->deleted = TRUE; + + FwpsFlowRemoveContext( + flowContext->flowId, + flowContext->layerId, + flowContext->calloutId + ); + } + } +} + +_Function_class_(EVT_WDF_DRIVER_UNLOAD) +_IRQL_requires_same_ +_IRQL_requires_max_(PASSIVE_LEVEL) +void +EvtDriverUnload( + _In_ WDFDRIVER driverObject + ) +{ + KLOCK_QUEUE_HANDLE packetQueueLockHandle; + KLOCK_QUEUE_HANDLE flowListLockHandle; + + UNREFERENCED_PARAMETER(driverObject); + + KeAcquireInStackQueuedSpinLock( + &gPacketQueueLock, + &packetQueueLockHandle + ); + + KeAcquireInStackQueuedSpinLock( + &gFlowListLock, + &flowListLockHandle + ); + + gDriverUnloading = TRUE; + + KeReleaseInStackQueuedSpinLock(&flowListLockHandle); + + // + // Any associated flow contexts must be removed before + // a callout can be successfully unregistered. + // + DDProxyRemoveFlows(); + + if (IsListEmpty(&gPacketQueue)) + { + KeSetEvent( + &gPacketQueueEvent, + IO_NO_INCREMENT, + FALSE + ); + } + + KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle); + + NT_ASSERT(gThreadObj != NULL); + + KeWaitForSingleObject( + gThreadObj, + Executive, + KernelMode, + FALSE, + NULL + ); + + ObDereferenceObject(gThreadObj); + + DDProxyUnregisterCallouts(); + + FwpsInjectionHandleDestroy(gInjectionHandle); +} + +// +// Create the minimal WDF Driver and Device objects required for a WFP callout +// driver. +// +NTSTATUS +DDProxyInitDriverObjects( + _Inout_ DRIVER_OBJECT* driverObject, + _In_ const UNICODE_STRING* registryPath, + _Out_ WDFDRIVER* pDriver, + _Out_ WDFDEVICE* pDevice + ) +{ + NTSTATUS status; + WDF_DRIVER_CONFIG config; + PWDFDEVICE_INIT pInit = NULL; + + WDF_DRIVER_CONFIG_INIT( + &config, + WDF_NO_EVENT_CALLBACK + ); + + config.DriverInitFlags |= WdfDriverInitNonPnpDriver; + config.EvtDriverUnload = EvtDriverUnload; + + status = WdfDriverCreate( + driverObject, + registryPath, + WDF_NO_OBJECT_ATTRIBUTES, + &config, + pDriver + ); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + pInit = WdfControlDeviceInitAllocate( + *pDriver, + &SDDL_DEVOBJ_KERNEL_ONLY + ); + + if (!pInit) + { + status = STATUS_INSUFFICIENT_RESOURCES; + goto Exit; + } + + WdfDeviceInitSetDeviceType( + pInit, + FILE_DEVICE_NETWORK + ); + + WdfDeviceInitSetCharacteristics( + pInit, + FILE_DEVICE_SECURE_OPEN, + FALSE + ); + + WdfDeviceInitSetCharacteristics( + pInit, + FILE_AUTOGENERATED_DEVICE_NAME, + TRUE + ); + + status = WdfDeviceCreate( + &pInit, + WDF_NO_OBJECT_ATTRIBUTES, + pDevice + ); + + if (!NT_SUCCESS(status)) + { + WdfDeviceInitFree(pInit); + goto Exit; + } + + WdfControlFinishInitializing(*pDevice); + +Exit: + return status; +} + + +NTSTATUS +DriverEntry( + DRIVER_OBJECT* driverObject, + UNICODE_STRING* registryPath + ) +{ + NTSTATUS status; + WDFDRIVER driver; + WDFDEVICE device; + WDFKEY configKey; + HANDLE threadHandle; + + // Request NX Non-Paged Pool when available + ExInitializeDriverRuntime(DrvRtPoolNxOptIn); + + status = DDProxyInitDriverObjects( + driverObject, + registryPath, + &driver, + &device + ); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + status = WdfDriverOpenParametersRegistryKey( + driver, + KEY_READ, + WDF_NO_OBJECT_ATTRIBUTES, + &configKey + ); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + status = DDProxyLoadConfig(configKey); + + if (!NT_SUCCESS(status)) + { + status = STATUS_DEVICE_CONFIGURATION_ERROR; + goto Exit; + } + + // + // To proxy UDP traffic, a new destination port or a pair of inspect and + // proxy ip address need to be pre-configured. To proxy UDP traffic, a + // pair of inspect and proxy ip addresses must be pre-configured. + // + if (configInspectUdp) + { + if ((configInspectDestPort == configNewDestPort) && + (((configInspectDestAddrV4 == NULL) || + (configNewDestAddrV4 == NULL)) && + ((configInspectDestAddrV6 == NULL) || + (configNewDestAddrV6 == NULL)))) + { + status = STATUS_DEVICE_CONFIGURATION_ERROR; + goto Exit; + } + } + else + { + if (((configInspectDestAddrV4 == NULL) || + (configNewDestAddrV4 == NULL)) && + ((configInspectDestAddrV6 == NULL) || + (configNewDestAddrV6 == NULL))) + { + status = STATUS_DEVICE_CONFIGURATION_ERROR; + goto Exit; + } + } + + status = FwpsInjectionHandleCreate( + AF_UNSPEC, + FWPS_INJECTION_TYPE_TRANSPORT, + &gInjectionHandle + ); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + InitializeListHead(&gFlowList); + KeInitializeSpinLock(&gFlowListLock); + + InitializeListHead(&gPacketQueue); + KeInitializeSpinLock(&gPacketQueueLock); + KeInitializeEvent( + &gPacketQueueEvent, + NotificationEvent, + FALSE + ); + + gWdmDevice = WdfDeviceWdmGetDeviceObject(device); + + status = DDProxyRegisterCallouts(gWdmDevice); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + status = PsCreateSystemThread( + &threadHandle, + THREAD_ALL_ACCESS, + NULL, + NULL, + NULL, + DDProxyWorker, + NULL + ); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + status = ObReferenceObjectByHandle( + threadHandle, + 0, + NULL, + KernelMode, + &gThreadObj, + NULL + ); + NT_ASSERT(NT_SUCCESS(status)); + + ZwClose(threadHandle); + +Exit: + + if (!NT_SUCCESS(status)) + { + if (gEngineHandle != NULL) + { + DDProxyUnregisterCallouts(); + } + if (gInjectionHandle != NULL) + { + FwpsInjectionHandleDestroy(gInjectionHandle); + } + } + + return status; +} diff --git a/network/trans/ddproxy/sys/DD_proxy.c b/network/trans/ddproxy/sys/DD_proxy.c new file mode 100644 index 00000000..a75e2cf9 --- /dev/null +++ b/network/trans/ddproxy/sys/DD_proxy.c @@ -0,0 +1,1039 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved + +Abstract: + + This file implements the classifyFn, notifiFn, and flowDeleteFn callout + functions for the flow-established and datagram-data callouts. In addition + the system worker thread that performs the actual packet modifications + is also implemented here along with the eventing mechanisms shared between + the classify function and the worker thread. + + Packet modification is done out-of-band by a system worker thread using + the reference-drop-clone-modify-reinject mechanism. Therefore the sample + can serve as a base in scenarios where filtering/modification decision + cannot be made within the classifyFn() callout and instead must be made, + for example, by an user-mode application. + +Environment: + + Kernel mode + +--*/ + +#include <ntddk.h> + +#pragma warning(push) +#pragma warning(disable:4201) // unnamed struct/union + +#include <fwpsk.h> + +#pragma warning(pop) + +#include <fwpmk.h> + +#include "DD_proxy.h" + +__inline +void +DDProxyFreePendedPacket( + _Inout_ __drv_freesMem(Mem) DD_PROXY_PENDED_PACKET* packet, + _Inout_opt_ __drv_freesMem(Mem) WSACMSGHDR* controlData + ) +{ + FwpsDereferenceNetBufferList(packet->netBufferList, FALSE); + DDProxyDereferenceFlowContext(packet->belongingFlow); + if (controlData != NULL) + { + ExFreePoolWithTag(controlData, DD_PROXY_CONTROL_DATA_POOL_TAG); + } + ExFreePoolWithTag(packet, DD_PROXY_PENDED_PACKET_POOL_TAG); +} + +#if(NTDDI_VERSION >= NTDDI_WIN7) + +void +DDProxyFlowEstablishedClassify( + _In_ const FWPS_INCOMING_VALUES* inFixedValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues, + _Inout_opt_ void* layerData, + _In_opt_ const void* classifyContext, + _In_ const FWPS_FILTER* filter, + _In_ UINT64 flowContext, + _Inout_ FWPS_CLASSIFY_OUT* classifyOut + ) + +#else + +void +DDProxyFlowEstablishedClassify( + _In_ const FWPS_INCOMING_VALUES* inFixedValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues, + _Inout_opt_ void* layerData, + _In_ const FWPS_FILTER* filter, + _In_ UINT64 flowContext, + _Inout_ FWPS_CLASSIFY_OUT* classifyOut + ) + +#endif /// (NTDDI_VERSION >= NTDDI_WIN7) + +/* ++ + + This is the classifyFn function of the flow-established callout. It + allocates flow context for the original and the proxy flow and associates + them with the indicated flow-id. This function also stores information + common to both flows in the context. The flow context is inserted into the + global flow list. + +-- */ +{ + NTSTATUS status = STATUS_SUCCESS; + + BOOLEAN locked = FALSE; + + KLOCK_QUEUE_HANDLE flowListLockHandle; + + DD_PROXY_FLOW_CONTEXT* flowContextLocal = NULL; + + UNREFERENCED_PARAMETER(layerData); +#if(NTDDI_VERSION >= NTDDI_WIN7) + UNREFERENCED_PARAMETER(classifyContext); +#endif /// (NTDDI_VERSION >= NTDDI_WIN7) + UNREFERENCED_PARAMETER(flowContext); + + flowContextLocal = ExAllocatePoolWithTag( + NonPagedPool, + sizeof(DD_PROXY_FLOW_CONTEXT), + DD_PROXY_FLOW_CONTEXT_POOL_TAG + ); + + if (flowContextLocal == NULL) + { + status = STATUS_NO_MEMORY; + goto Exit; + } + + RtlZeroMemory(flowContextLocal, sizeof(DD_PROXY_FLOW_CONTEXT)); + + flowContextLocal->refCount = 1; + flowContextLocal->flowType = (DD_PROXY_FLOW_TYPE)(filter->context); + flowContextLocal->addressFamily = + (inFixedValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4) ? + AF_INET : AF_INET6; + NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, + FWPS_METADATA_FIELD_FLOW_HANDLE)); + flowContextLocal->flowId = inMetaValues->flowHandle; + + // + // Note that since the consumer of the flow context is the datagram-data + // layer classifyFn, layerId and calloutId are set to those of DD and not + // flow-established. + // + flowContextLocal->layerId = + (flowContextLocal->addressFamily == AF_INET) ? + FWPS_LAYER_DATAGRAM_DATA_V4 : FWPS_LAYER_DATAGRAM_DATA_V6; + flowContextLocal->calloutId = + (flowContextLocal->addressFamily == AF_INET) ? + gCalloutIdV4 : gCalloutIdV6; + + if (flowContextLocal->addressFamily == AF_INET) + { + // Prefast thinks we are ignoring this return value. + // If driver is unloading, we give up and ignore it on purpose. + // Otherwise, we put the pointer onto the list, but we make it opaque + // by casting it as a UINT64, and this tricks Prefast. + flowContextLocal->ipv4LocalAddr = + RtlUlongByteSwap( + inFixedValues->incomingValue\ + [FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_ADDRESS].value.uint32 + ); + flowContextLocal->protocol = + inFixedValues->incomingValue\ + [FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_PROTOCOL].value.uint8; + } + else + { + RtlCopyMemory( + (UINT8*)&flowContextLocal->localAddr, + inFixedValues->incomingValue\ + [FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_LOCAL_ADDRESS].value.byteArray16, + sizeof(FWP_BYTE_ARRAY16) + ); + flowContextLocal->protocol = + inFixedValues->incomingValue\ + [FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_PROTOCOL].value.uint8; + } + + if (flowContextLocal->flowType == DD_PROXY_FLOW_ORIGINAL) + { + flowContextLocal->toRemoteAddr = + (flowContextLocal->addressFamily == AF_INET) ? + configNewDestAddrV4 : configNewDestAddrV6; + // host-order -> network-order conversion for port. + flowContextLocal->toRemotePort = RtlUshortByteSwap(configNewDestPort); + } + else + { + NT_ASSERT(flowContextLocal->flowType == DD_PROXY_FLOW_PROXY); + flowContextLocal->toRemoteAddr = + (flowContextLocal->addressFamily == AF_INET) ? + configInspectDestAddrV4 : configInspectDestAddrV6; + // host-order -> network-order conversion for port. + // See PREfast comments above. Opaque pointer tricks PREfast. + flowContextLocal->toRemotePort = RtlUshortByteSwap(configInspectDestPort); + } + if ((flowContextLocal->toRemoteAddr != NULL) && + (flowContextLocal->addressFamily == AF_INET)) + { + // host-order -> network-order conversion for Ipv4 address. + // See PREfast comments above. Opaque pointer tricks PREfast. + flowContextLocal->ipv4NetworkOrderStorage = + RtlUlongByteSwap(*(ULONG*)(flowContextLocal->toRemoteAddr)); + flowContextLocal->toRemoteAddr = + (UINT8*)&flowContextLocal->ipv4NetworkOrderStorage; + } + + KeAcquireInStackQueuedSpinLock( + &gFlowListLock, + &flowListLockHandle + ); + + locked = TRUE; + + if (!gDriverUnloading) + { + // + // Associate DD_PROXY_FLOW_CONTEXT with the indicated flow-id to be + // accessible by the Datagram-Data classifyFn. (i.e. when a packet + // belongs to the same flow being classified at Datagram-Data layer, + // DD_PROXY_FLOW_CONTEXT will be passed onto the classifyFn as the + // "flowContext" parameter. + // + status = FwpsFlowAssociateContext( + flowContextLocal->flowId, + flowContextLocal->layerId, + flowContextLocal->calloutId, + (UINT64)flowContextLocal + ); + if(!NT_SUCCESS(status)) + { + goto Exit; + } + + InsertHeadList(&gFlowList, &flowContextLocal->listEntry); + flowContextLocal = NULL; // ownership transferred + } + + classifyOut->actionType = FWP_ACTION_PERMIT; + + if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT) + { + classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; + } + + +Exit: + + if(locked) + { + KeReleaseInStackQueuedSpinLock(&flowListLockHandle); + } + + if (flowContextLocal != NULL) + { + ExFreePoolWithTag(flowContextLocal, DD_PROXY_FLOW_CONTEXT_POOL_TAG); + } + + if(!NT_SUCCESS(status)) + { + classifyOut->actionType = FWP_ACTION_BLOCK; + classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; + } + + return; +} + +#if(NTDDI_VERSION >= NTDDI_WIN7) + +void +DDProxyClassify( + _In_ const FWPS_INCOMING_VALUES* inFixedValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues, + _Inout_opt_ void* layerData, + _In_opt_ const void* classifyContext, + _In_ const FWPS_FILTER* filter, + _In_ UINT64 flowContext, + _Inout_ FWPS_CLASSIFY_OUT* classifyOut + ) + +#else + +void +DDProxyClassify( + _In_ const FWPS_INCOMING_VALUES* inFixedValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues, + _Inout_opt_ void* layerData, + _In_ const FWPS_FILTER* filter, + _In_ UINT64 flowContext, + _Inout_ FWPS_CLASSIFY_OUT* classifyOut + ) + +#endif /// (NTDDI_VERSION >= NTDDI_WIN7) +/* ++ + + This is the classifyFn function of the datagram-data callout. It + allocates a packet structure to store the classify and meta data and + it references the net buffer list for out-of-band modification and + re-injection. The packet structure will be queued to the global packet + queue. The worker thread will then be signaled, if idle, to process + the queue. + +-- */ +{ + DD_PROXY_PENDED_PACKET* packet = NULL; + DD_PROXY_FLOW_CONTEXT* flowContextLocal = (DD_PROXY_FLOW_CONTEXT*)(DWORD_PTR)flowContext; + + FWPS_PACKET_INJECTION_STATE packetState; + KLOCK_QUEUE_HANDLE packetQueueLockHandle; + BOOLEAN signalWorkerThread; + +#if(NTDDI_VERSION >= NTDDI_WIN7) + UNREFERENCED_PARAMETER(classifyContext); +#endif + UNREFERENCED_PARAMETER(filter); + + _Analysis_assume_(layerData != NULL); + + // + // We don't have the necessary right to alter the packet. + // + if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0) + { + goto Exit; + } + + // + // We don't re-inspect packets that we've inspected earlier. + // + packetState = FwpsQueryPacketInjectionState( + gInjectionHandle, + layerData, + NULL + ); + + if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) || + (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF)) + { + classifyOut->actionType = FWP_ACTION_PERMIT; + if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT) + { + classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; + } + + goto Exit; + } + + packet = ExAllocatePoolWithTag( + NonPagedPool, + sizeof(DD_PROXY_PENDED_PACKET), + DD_PROXY_PENDED_PACKET_POOL_TAG + ); + + if (packet == NULL) + { + classifyOut->actionType = FWP_ACTION_BLOCK; + classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; + goto Exit; + } + + RtlZeroMemory(packet, sizeof(DD_PROXY_PENDED_PACKET)); + + NT_ASSERT(flowContextLocal != NULL); + + packet->belongingFlow = flowContextLocal; + DDProxyReferenceFlowContext(packet->belongingFlow); + if (flowContextLocal->addressFamily == AF_INET) + { + NT_ASSERT(inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4); + packet->direction = + inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_DIRECTION].\ + value.uint32; + } + else + { + NT_ASSERT(inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6); + packet->direction = + inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V6_DIRECTION].\ + value.uint32; + } + packet->netBufferList = layerData; + + // + // Reference the net buffer list to make it accessible outside of + // classifyFn. + // + FwpsReferenceNetBufferList(packet->netBufferList, TRUE); + + NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, + FWPS_METADATA_FIELD_COMPARTMENT_ID)); + packet->compartmentId = inMetaValues->compartmentId; + + if (packet->direction == FWP_DIRECTION_OUTBOUND) + { + NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT( + inMetaValues, + FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE)); + packet->endpointHandle = inMetaValues->transportEndpointHandle; + + if (flowContextLocal->addressFamily == AF_INET) + { + // See PREfast comments above. Opaque pointer tricks PREfast. + packet->ipv4RemoteAddr = + RtlUlongByteSwap( /* host-order -> network-order conversion */ + inFixedValues->incomingValue\ + [FWPS_FIELD_DATAGRAM_DATA_V4_IP_REMOTE_ADDRESS].value.uint32 + ); + } + else + { + RtlCopyMemory( + (UINT8*)&packet->remoteAddr, + inFixedValues->incomingValue\ + [FWPS_FIELD_DATAGRAM_DATA_V6_IP_REMOTE_ADDRESS].value.byteArray16, + sizeof(FWP_BYTE_ARRAY16) + ); + + } + packet->remoteScopeId = inMetaValues->remoteScopeId; + + if (FWPS_IS_METADATA_FIELD_PRESENT( + inMetaValues, + FWPS_METADATA_FIELD_TRANSPORT_CONTROL_DATA)) + { + NT_ASSERT(inMetaValues->controlDataLength > 0); + + packet->controlData = ExAllocatePoolWithTag( + NonPagedPool, + inMetaValues->controlDataLength, + DD_PROXY_CONTROL_DATA_POOL_TAG + ); + if (packet->controlData == NULL) + { + classifyOut->actionType = FWP_ACTION_BLOCK; + classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; + goto Exit; + } + + RtlCopyMemory( + packet->controlData, + inMetaValues->controlData, + inMetaValues->controlDataLength + ); + + packet->controlDataLength = inMetaValues->controlDataLength; + } + } + else + { + NT_ASSERT(packet->direction == FWP_DIRECTION_INBOUND); + + if (flowContextLocal->addressFamily == AF_INET) + { + NT_ASSERT(inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4); + packet->interfaceIndex = + inFixedValues->incomingValue\ + [FWPS_FIELD_DATAGRAM_DATA_V4_INTERFACE_INDEX].value.uint32; + packet->subInterfaceIndex = + inFixedValues->incomingValue\ + [FWPS_FIELD_DATAGRAM_DATA_V4_SUB_INTERFACE_INDEX].value.uint32; + } + else + { + NT_ASSERT(inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6); + packet->interfaceIndex = + inFixedValues->incomingValue\ + [FWPS_FIELD_DATAGRAM_DATA_V6_INTERFACE_INDEX].value.uint32; + packet->subInterfaceIndex = + inFixedValues->incomingValue\ + [FWPS_FIELD_DATAGRAM_DATA_V6_SUB_INTERFACE_INDEX].value.uint32; + } + + NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT( + inMetaValues, + FWPS_METADATA_FIELD_IP_HEADER_SIZE)); + NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT( + inMetaValues, + FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)); + packet->ipHeaderSize = inMetaValues->ipHeaderSize; + packet->transportHeaderSize = inMetaValues->transportHeaderSize; + + packet->nblOffset = + NET_BUFFER_DATA_OFFSET(NET_BUFFER_LIST_FIRST_NB(packet->netBufferList)); + } + + KeAcquireInStackQueuedSpinLock( + &gPacketQueueLock, + &packetQueueLockHandle + ); + + if (!gDriverUnloading) + { + signalWorkerThread = IsListEmpty(&gPacketQueue); + + InsertTailList(&gPacketQueue, &packet->listEntry); + packet = NULL; // ownership transferred + + classifyOut->actionType = FWP_ACTION_BLOCK; + classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; + classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; + } + else + { + // + // Driver is being unloaded, permit any incoming packets. + // + signalWorkerThread = FALSE; + + classifyOut->actionType = FWP_ACTION_PERMIT; + if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT) + { + classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; + } + } + + if (signalWorkerThread) + { + KeSetEvent( + &gPacketQueueEvent, + 0, + FALSE + ); + } + + KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle); + +Exit: + + if (packet != NULL) + { + DDProxyFreePendedPacket(packet, packet->controlData); + } + + return; +} + +NTSTATUS +DDProxyFlowEstablishedNotify( + _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType, + _In_ const GUID* filterKey, + _Inout_ const FWPS_FILTER* filter + ) +{ + UNREFERENCED_PARAMETER(notifyType); + UNREFERENCED_PARAMETER(filterKey); + UNREFERENCED_PARAMETER(filter); + + return STATUS_SUCCESS; +} + +NTSTATUS +DDProxyNotify( + _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType, + _In_ const GUID* filterKey, + _Inout_ const FWPS_FILTER* filter + ) +{ + UNREFERENCED_PARAMETER(notifyType); + UNREFERENCED_PARAMETER(filterKey); + UNREFERENCED_PARAMETER(filter); + + return STATUS_SUCCESS; +} + +void +DDProxyFlowDelete( + _In_ UINT16 layerId, + _In_ UINT32 calloutId, + _In_ UINT64 flowContext + ) +/* ++ + + This is the flowDeleteFn function of the datagram-data callout. It + removes the flow context from the global flow list and dereference the + context. + +-- */ +{ + DD_PROXY_FLOW_CONTEXT* flowContextLocal = (DD_PROXY_FLOW_CONTEXT*)(DWORD_PTR)flowContext; + + KLOCK_QUEUE_HANDLE flowListLockHandle; + + UNREFERENCED_PARAMETER(layerId); + UNREFERENCED_PARAMETER(calloutId); + + KeAcquireInStackQueuedSpinLock( + &gFlowListLock, + &flowListLockHandle + ); + + if (!flowContextLocal->deleted) + { + RemoveEntryList(&flowContextLocal->listEntry); + } + + KeReleaseInStackQueuedSpinLock(&flowListLockHandle); + + DDProxyDereferenceFlowContext(flowContextLocal); +} + +typedef struct UDP_HEADER_ { + UINT16 srcPort; + UINT16 destPort; + UINT16 length; + UINT16 checksum; +} UDP_HEADER; + +void DDProxyInjectComplete( + _Inout_ void* context, + _Inout_ NET_BUFFER_LIST* netBufferList, + _In_ BOOLEAN dispatchLevel + ) +{ + DD_PROXY_PENDED_PACKET* packet = context; + UNREFERENCED_PARAMETER(dispatchLevel); + + FwpsFreeCloneNetBufferList(netBufferList, 0); + + DDProxyFreePendedPacket(packet, packet->controlData); +} + +NTSTATUS +DDProxyCloneModifyReinjectOutbound( + _In_ DD_PROXY_PENDED_PACKET* packet + ) +/* ++ + + This function clones the outbound net buffer list and, if needed, + modifies the destination port of all indicated packets (i.e. NET_BUFFER) + and/or send-injects the clone to a new destination address. + +-- */ +{ + NTSTATUS status = STATUS_SUCCESS; + + NET_BUFFER_LIST* clonedNetBufferList = NULL; + UDP_HEADER* udpHeader; + FWPS_TRANSPORT_SEND_PARAMS sendArgs = {0}; + + status = FwpsAllocateCloneNetBufferList( + packet->netBufferList, + NULL, + NULL, + 0, + &clonedNetBufferList + ); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + // + // Check to see if port modification is required. + // + if ((packet->belongingFlow->protocol == IPPROTO_UDP) && + (packet->belongingFlow->toRemotePort != 0)) + { + NET_BUFFER* netBuffer; + + // + // The data offset of outbound transport packets is the beginning of + // transport header (e.g. UDP header). The IP header has not yet been + // constructed at Datagram-Data (or outbound Transport) layer. + // + // Note the packet offset is inherited by the clone. + // + + // + // Outbound net buffer list can contain more than one net buffer (e.g. + // one UDP packet). + // + + for (netBuffer = NET_BUFFER_LIST_FIRST_NB(clonedNetBufferList); + netBuffer != NULL; + netBuffer = NET_BUFFER_NEXT_NB(netBuffer)) + { + udpHeader = NdisGetDataBuffer( + netBuffer, + sizeof(UDP_HEADER), + NULL, + sizeof(UINT16), + 0 + ); + NT_ASSERT(udpHeader != NULL); // We can assume UDP header in a net buffer + // is contiguous and 2-byte aligned. + _Analysis_assume_(udpHeader != NULL); + + udpHeader->destPort = packet->belongingFlow->toRemotePort; + udpHeader->checksum = 0; + } + } + + // + // Determine whehter we need to proxy the destination address. If not, + // we set the remoteAddress to the same address that was initially + // classified. + // + sendArgs.remoteAddress = + (packet->belongingFlow->toRemoteAddr ? packet->belongingFlow->toRemoteAddr + : (UINT8*)&packet->remoteAddr); + sendArgs.remoteScopeId = packet->remoteScopeId; + sendArgs.controlData = packet->controlData; + sendArgs.controlDataLength = packet->controlDataLength; + + // + // Send-inject the modified net buffer list to the new destination address. + // + + status = FwpsInjectTransportSendAsync( + gInjectionHandle, + NULL, + packet->endpointHandle, + 0, + &sendArgs, + packet->belongingFlow->addressFamily, + packet->compartmentId, + clonedNetBufferList, + DDProxyInjectComplete, + packet + ); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + clonedNetBufferList = NULL; // ownership transferred to the + // completion function. + +Exit: + + if (clonedNetBufferList != NULL) + { + FwpsFreeCloneNetBufferList(clonedNetBufferList, 0); + } + + return status; +} + +NTSTATUS +DDProxyCloneModifyReinjectInbound( + _In_ DD_PROXY_PENDED_PACKET* packet + ) +/* ++ + + This function clones the inbound net buffer list and, if needed, + modifies the source port and/or source address and receive-injects + the clone back to the tcpip stack. + +-- */ +{ + NTSTATUS status = STATUS_SUCCESS; + + NET_BUFFER_LIST* clonedNetBufferList = NULL; + NET_BUFFER* netBuffer; + UDP_HEADER* udpHeader; + ULONG nblOffset; + NDIS_STATUS ndisStatus; + + // + // For inbound net buffer list, we can assume it contains only one + // net buffer. + // + netBuffer = NET_BUFFER_LIST_FIRST_NB(packet->netBufferList); + + nblOffset = NET_BUFFER_DATA_OFFSET(netBuffer); + + // + // The TCP/IP stack could have retreated the net buffer list by the + // transportHeaderSize amount; detect the condition here to avoid + // retreating twice. + // + if (nblOffset != packet->nblOffset) + { + NT_ASSERT(packet->nblOffset - nblOffset == packet->transportHeaderSize); + packet->transportHeaderSize = 0; + } + + // + // Adjust the net buffer list offset to the start of the IP header. + // + ndisStatus = NdisRetreatNetBufferDataStart( + netBuffer, + packet->ipHeaderSize + packet->transportHeaderSize, + 0, + NULL + ); + _Analysis_assume_(ndisStatus == NDIS_STATUS_SUCCESS); + + // + // Note that the clone will inherit the original net buffer list's offset. + // + + status = FwpsAllocateCloneNetBufferList( + packet->netBufferList, + NULL, + NULL, + 0, + &clonedNetBufferList + ); + + // + // Undo the adjustment on the original net buffer list. + // + + NdisAdvanceNetBufferDataStart( + netBuffer, + packet->ipHeaderSize + packet->transportHeaderSize, + FALSE, + NULL + ); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + // + // Check to see if port modification is required. + // + if ((packet->belongingFlow->protocol == IPPROTO_UDP) && + (packet->belongingFlow->toRemotePort != 0)) + { + netBuffer = NET_BUFFER_LIST_FIRST_NB(clonedNetBufferList); + + // + // Advance to the beginning of the transport header (i.e. UDP header). + // + NdisAdvanceNetBufferDataStart( + netBuffer, + packet->ipHeaderSize, + FALSE, + NULL + ); + + udpHeader = NdisGetDataBuffer( + netBuffer, + sizeof(UDP_HEADER), + NULL, + sizeof(UINT16), + 0 + ); + NT_ASSERT(udpHeader != NULL); // We can assume UDP header in a net buffer + // is contiguous and 2-byte aligned. + _Analysis_assume_(udpHeader != NULL); + + udpHeader->destPort = + packet->belongingFlow->toRemotePort; + // This is our new source port -- or + // the destination port of the original + // outbound traffic. + udpHeader->checksum = 0; + + // + // Undo the advance. Net buffer list needs to be positioned at the + // beginning of IP header for address modification and/or receive- + // injection. + // + ndisStatus = NdisRetreatNetBufferDataStart( + netBuffer, + packet->ipHeaderSize, + 0, + NULL + ); + _Analysis_assume_(ndisStatus == NDIS_STATUS_SUCCESS); + + } + + if (packet->belongingFlow->toRemoteAddr != NULL) + { + status = FwpsConstructIpHeaderForTransportPacket( + clonedNetBufferList, + packet->ipHeaderSize, + packet->belongingFlow->addressFamily, + packet->belongingFlow->toRemoteAddr, + // This is our new source address -- + // or the destination address of the + // original outbound traffic. + (UINT8*)&packet->belongingFlow->localAddr, + // This is the destination address of + // the clone -- or the source of the + // original outbound traffic. + packet->belongingFlow->protocol, + 0, + NULL, + 0, + 0, + NULL, + 0, + 0 + ); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + } + + status = FwpsInjectTransportReceiveAsync( + gInjectionHandle, + NULL, + NULL, + 0, + packet->belongingFlow->addressFamily, + packet->compartmentId, + packet->interfaceIndex, + packet->subInterfaceIndex, + clonedNetBufferList, + DDProxyInjectComplete, + packet + ); + + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + clonedNetBufferList = NULL; // ownership transferred to the + // completion function. + +Exit: + + if (clonedNetBufferList != NULL) + { + FwpsFreeCloneNetBufferList(clonedNetBufferList, 0); + } + + return status; +} + +void +DDProxyWorker( + _In_ void* StartContext + ) +/* ++ + + This worker thread waits for the packet queue event when the queue is + empty; and it will be woken up when there are packets queued needing to + be proxied to or from the new destination address/port. Once awaking, + It will run in a loop to clone-modify-reinject packets until the packet + queue is exhausted (and it will go to sleep waiting for more work). + + The worker thread will end once it detected the driver is unloading. + +-- */ +{ + DD_PROXY_PENDED_PACKET* packet; + LIST_ENTRY* listEntry; + KLOCK_QUEUE_HANDLE packetQueueLockHandle; + + UNREFERENCED_PARAMETER(StartContext); + + for(;;) + { + KeWaitForSingleObject( + &gPacketQueueEvent, + Executive, + KernelMode, + FALSE, + NULL + ); + + if (gDriverUnloading) + { + break; + } + + NT_ASSERT(!IsListEmpty(&gPacketQueue)); + + KeAcquireInStackQueuedSpinLock( + &gPacketQueueLock, + &packetQueueLockHandle + ); + + listEntry = RemoveHeadList(&gPacketQueue); + + KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle); + + packet = CONTAINING_RECORD( + listEntry, + DD_PROXY_PENDED_PACKET, + listEntry + ); + + if (!packet->belongingFlow->deleted) + { + NTSTATUS status; + + if (packet->direction == FWP_DIRECTION_OUTBOUND) + { + status = DDProxyCloneModifyReinjectOutbound(packet); + } + else + { + status = DDProxyCloneModifyReinjectInbound(packet); + } + + if (NT_SUCCESS(status)) + { + packet = NULL; // ownership transferred. + } + } + + if (packet != NULL) + { + DDProxyFreePendedPacket(packet, packet->controlData); + } + + KeAcquireInStackQueuedSpinLock( + &gPacketQueueLock, + &packetQueueLockHandle + ); + + if (IsListEmpty(&gPacketQueue) && !gDriverUnloading) + { + KeClearEvent(&gPacketQueueEvent); + } + + KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle); + } + + NT_ASSERT(gDriverUnloading); + + // + // Discard all the pended packets if driver is being unloaded. + // + + KeAcquireInStackQueuedSpinLock( + &gPacketQueueLock, + &packetQueueLockHandle + ); + + while (!IsListEmpty(&gPacketQueue)) + { + listEntry = RemoveHeadList(&gPacketQueue); + + packet = CONTAINING_RECORD( + listEntry, + DD_PROXY_PENDED_PACKET, + listEntry + ); + + DDProxyFreePendedPacket(packet, packet->controlData); + } + + KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle); + PsTerminateSystemThread(STATUS_SUCCESS); + + +} diff --git a/network/trans/ddproxy/sys/DD_proxy.h b/network/trans/ddproxy/sys/DD_proxy.h new file mode 100644 index 00000000..197b0ff9 --- /dev/null +++ b/network/trans/ddproxy/sys/DD_proxy.h @@ -0,0 +1,251 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved + +Abstract: + + This header files declares common data types and function prototypes used + throughout the Datagram-Data transparent proxy sample. + +Environment: + + Kernel mode + +--*/ + +#ifndef _DD_PROXY_H_ +#define _DD_PROXY_H_ + +typedef enum DD_PROXY_FLOW_TYPE_ +{ + DD_PROXY_FLOW_ORIGINAL, + DD_PROXY_FLOW_PROXY +} DD_PROXY_FLOW_TYPE; + +// +// DD_PROXY_FLOW_CONTEXT is the object type we used to stored information +// specific flow. This callout driver maintains two kind of flow contexts -- +// the original flow and the flow being proxied to. +// + +typedef struct DD_PROXY_FLOW_CONTEXT_ +{ + LIST_ENTRY listEntry; + + BOOLEAN deleted; + + DD_PROXY_FLOW_TYPE flowType; + ADDRESS_FAMILY addressFamily; + + #pragma warning(push) + #pragma warning(disable: 4201) //NAMELESS_STRUCT_UNION + union + { + FWP_BYTE_ARRAY16 localAddr; + UINT32 ipv4LocalAddr; + }; + #pragma warning(pop) + + + UINT8 protocol; + + UINT64 flowId; + UINT16 layerId; + UINT32 calloutId; + + UINT32 ipv4NetworkOrderStorage; + + // + // For DD_PROXY_FLOW_ORIGINAL type, toRemote* is the new address/port + // we are proxing to. For DD_PROXY_FLOW_PROXY type, it is the address/ + // port that we will need to revert to. + // + UINT8* toRemoteAddr; + UINT16 toRemotePort; + + LONG refCount; +} DD_PROXY_FLOW_CONTEXT; + +// +// DD_PROXY_PENDED_PACKET is the object type we used to store all information +// needed for out-of-band packet modification and re-injection. This type +// also points back to the flow context the packet belongs to. + +typedef struct DD_PROXY_PENDED_PACKET_ +{ + LIST_ENTRY listEntry; + + DD_PROXY_FLOW_CONTEXT* belongingFlow; + FWP_DIRECTION direction; + + // + // Common fields for inbound and outbound traffic. + // + NET_BUFFER_LIST* netBufferList; + COMPARTMENT_ID compartmentId; + + // + // Data fields for outbound packet re-injection. + // + UINT64 endpointHandle; + + #pragma warning(push) + #pragma warning(disable: 4201) //NAMELESS_STRUCT_UNION + union + { + FWP_BYTE_ARRAY16 remoteAddr; + UINT32 ipv4RemoteAddr; + }; + #pragma warning(pop) + + SCOPE_ID remoteScopeId; + WSACMSGHDR* controlData; + ULONG controlDataLength; + + // + // Data fields for inbound packet re-injection. + // + ULONG nblOffset; + UINT32 ipHeaderSize; + UINT32 transportHeaderSize; + IF_INDEX interfaceIndex; + IF_INDEX subInterfaceIndex; +} DD_PROXY_PENDED_PACKET; + +// +// Pooltags used by this callout driver. +// +#define DD_PROXY_FLOW_CONTEXT_POOL_TAG 'olfD' +#define DD_PROXY_PENDED_PACKET_POOL_TAG 'kppD' +#define DD_PROXY_CONTROL_DATA_POOL_TAG 'dcdD' + +// +// Shared global data. +// +extern UINT16 configInspectDestPort; +extern UINT8* configInspectDestAddrV4; +extern UINT8* configInspectDestAddrV6; + +extern UINT16 configNewDestPort; +extern UINT8* configNewDestAddrV4; +extern UINT8* configNewDestAddrV6; + +extern HANDLE gInjectionHandle; + +extern LIST_ENTRY gFlowList; +extern KSPIN_LOCK gFlowListLock; + +extern LIST_ENTRY gPacketQueue; +extern KSPIN_LOCK gPacketQueueLock; +extern KEVENT gPacketQueueEvent; + +extern UINT32 gCalloutIdV4; +extern UINT32 gCalloutIdV6; + +extern BOOLEAN gDriverUnloading; + +// +// Utility functions +// + +__inline void +DDProxyReferenceFlowContext( + _Inout_ DD_PROXY_FLOW_CONTEXT* flowContext + ) +{ + NT_ASSERT(flowContext->refCount > 0); + InterlockedIncrement(&flowContext->refCount); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +__inline +void +DDProxyDereferenceFlowContext( + _Inout_ DD_PROXY_FLOW_CONTEXT* flowContext + ) +{ + NT_ASSERT(flowContext->refCount > 0); + InterlockedDecrement(&flowContext->refCount); + if (flowContext->refCount == 0) + { + ExFreePoolWithTag(flowContext, DD_PROXY_FLOW_CONTEXT_POOL_TAG); + } +} + +// +// Shared function prototypes +// + +#if(NTDDI_VERSION >= NTDDI_WIN7) + +void +DDProxyFlowEstablishedClassify( + _In_ const FWPS_INCOMING_VALUES* inFixedValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues, + _Inout_opt_ void* layerData, + _In_opt_ const void* classifyContext, + _In_ const FWPS_FILTER* filter, + _In_ UINT64 flowContext, + _Inout_ FWPS_CLASSIFY_OUT* classifyOut + ); + +void +DDProxyClassify( + _In_ const FWPS_INCOMING_VALUES* inFixedValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues, + _Inout_opt_ void* layerData, + _In_opt_ const void* classifyContext, + _In_ const FWPS_FILTER* filter, + _In_ UINT64 flowContext, + _Inout_ FWPS_CLASSIFY_OUT* classifyOut + ); + +#else + +void +DDProxyFlowEstablishedClassify( + _In_ const FWPS_INCOMING_VALUES* inFixedValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues, + _Inout_opt_ void* layerData, + _In_ const FWPS_FILTER* filter, + _In_ UINT64 flowContext, + _Inout_ FWPS_CLASSIFY_OUT* classifyOut + ); + +void +DDProxyClassify( + _In_ const FWPS_INCOMING_VALUES* inFixedValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues, + _Inout_opt_ void* layerData, + _In_ const FWPS_FILTER* filter, + _In_ UINT64 flowContext, + _Inout_ FWPS_CLASSIFY_OUT* classifyOut + ); + +#endif /// (NTDDI_VERSION >= NTDDI_WIN7) + +void +DDProxyFlowDelete( + _In_ UINT16 layerId, + _In_ UINT32 calloutId, + _In_ UINT64 flowContext + ); + +NTSTATUS +DDProxyFlowEstablishedNotify( + _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType, + _In_ const GUID* filterKey, + _Inout_ const FWPS_FILTER* filter + ); + + +NTSTATUS +DDProxyNotify( + _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType, + _In_ const GUID* filterKey, + _Inout_ const FWPS_FILTER* filter + ); + +KSTART_ROUTINE DDProxyWorker; + +#endif // _DD_PROXY_H_ diff --git a/network/trans/ddproxy/sys/ddproxy.inf b/network/trans/ddproxy/sys/ddproxy.inf new file mode 100644 index 00000000..dd504967 --- /dev/null +++ b/network/trans/ddproxy/sys/ddproxy.inf @@ -0,0 +1,63 @@ +;;; +;;; Copyright (c) Microsoft Corporation. All rights reserved +;;; +;;; Abstract: +;;; DatagramData Proxy Callout sample driver install configuration. +;;; + +[Version] + Signature = "$Windows NT$" + Class = WFPCALLOUTS + ClassGuid = {57465043-616C-6C6F-7574-5F636C617373} + Provider = %Contoso% + CatalogFile = DDProxy.cat + DriverVer = 11/24/2014,14.24.55.836 + +[SourceDisksNames] + 1 = %DDProxyDisk%,,,"" + +[SourceDisksFiles] + DDProxy.sys = 1,, + +[DestinationDirs] + DefaultDestDir = 12 ; %WinDir%\System32\Drivers + DDProxy.DriverFiles = 12 ; %WinDir%\System32\Drivers + +[DefaultInstall] + OptionDesc = %DDProxyServiceDesc% + CopyFiles = DDProxy.DriverFiles + +[DefaultInstall.Services] + AddService = %DDProxyServiceName%,,DDProxy.Service + +[DefaultUninstall] + DelFiles = DDProxy.DriverFiles + +[DefaultUninstall.Services] + DelService = %DDProxyServiceName%,0x200 ; SPSVCINST_STOPSERVICE + DelReg = DDProxy.DelRegistry + +[DDProxy.DriverFiles] + DDProxy.sys,,,0x00000040 ; COPYFLG_OVERWRITE_OLDER_ONLY + +[DDProxy.Service] + DisplayName = %DDProxyServiceName% + Description = %DDProxyServiceDesc% + ServiceType = 1 ; SERVICE_KERNEL_DRIVER + StartType = 3 ; SERVICE_DEMAND_START + ErrorControl = 1 ; SERVICE_ERROR_NORMAL + ServiceBinary = %12%\DDProxy.sys ; %WinDir%\System32\Drivers\DDProxy.sys + AddReg = DDProxy.AddRegistry + +[DDProxy.AddRegistry] + HKR,"Parameters","DestinationAddressToIntercept",0x00000000,"10.0.0.1" ; FLG_ADDREG_TYPE_SZ + HKR,"Parameters","NewDestinationAddress",0x00000000,"10.0.0.2" ; FLG_ADDREG_TYPE_SZ + +[DDProxy.DelRegistry] + HKR,"Parameters",,, + +[Strings] + Contoso = "Contoso Ltd." + DDProxyDisk = "DatagramData Proxy Installation Disk" + DDProxyServiceDesc = "DatagramData Proxy Callout Driver" + DDProxyServiceName = "DDProxy"
\ No newline at end of file diff --git a/network/trans/ddproxy/sys/ddproxy.vcxproj b/network/trans/ddproxy/sys/ddproxy.vcxproj new file mode 100644 index 00000000..9fd6e6af --- /dev/null +++ b/network/trans/ddproxy/sys/ddproxy.vcxproj @@ -0,0 +1,185 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{F5ED1745-0947-474A-924D-CB5D3D2D6C5E}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{91B8C3EC-EC68-40D0-BDAE-FECDC2A5A69E}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>ddproxy</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>ddproxy</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>ddproxy</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>ddproxy</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="dd_drv.c" /> + <ClCompile Include="dd_proxy.c" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/network/trans/ddproxy/sys/ddproxy.vcxproj.Filters b/network/trans/ddproxy/sys/ddproxy.vcxproj.Filters new file mode 100644 index 00000000..9728a6bb --- /dev/null +++ b/network/trans/ddproxy/sys/ddproxy.vcxproj.Filters @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{667070D4-ABD3-4134-83D9-C2E8E3B4D990}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{55D8461C-9BC4-4CBA-8364-1C9E8628AD2E}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> + <UniqueIdentifier>{89C687B6-C04D-48DD-BFC4-36AB091E7E94}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{3E15A537-E520-445D-AFC4-4CFCEF6234E6}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="dd_drv.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="dd_proxy.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file |
