locked
Understanding FWPM_LAYER_ALE_CONNECT_REDIRECT RRS feed

  • Question

  • Hello,

    My understanding so far is that FWPM_LAYER_ALE_CONNECT_REDIRECT is able to redirect a starting TCP connection to another destination. I already wrote a callout driver, installed the filters and my classify function get's called. 

    I need to redirect all traffic to a local port, like 127.0.0.1:80 to another port like 127.0.0.1:8080. 

    FWPM_LAYER_ALE_CONNECT_REDIRECT seems to do the job when I try to connect to another machine on my local network. A connect to myothermachine:80 is transparently changed to myothermachine:8080. 

    But for localhost the behaviour seems to differ. The client tries to connect, then a few seconds pass, then the client gets an error and at the same time the server gets a connection (the accept succeeds on the server, just to be followed by an immediate disconnect). This is my code:

    VOID NTAPI ALEConnectRedirectClassifyFn( IN const FWPS_INCOMING_VALUES *inFixedValues, IN const FWPS_INCOMING_METADATA_VALUES *inMetaValues, IN OUT VOID *layerData, _In_opt_ const void* classifyContext, IN const FWPS_FILTER *filter, IN UINT64 flowContext, IN OUT FWPS_CLASSIFY_OUT *classifyOut ) { UINT64 classifyHandle = 0; NTSTATUS status; FWPS_CONNECT_REQUEST0* connectRequest; UNREFERENCED_PARAMETER(inFixedValues); UNREFERENCED_PARAMETER(flowContext); UNREFERENCED_PARAMETER(layerData); status = FwpsAcquireClassifyHandle((void*)classifyContext, (UINT32)0, &classifyHandle); if (!NT_SUCCESS(status)) { log("SMBRedirect: Failure to aquire classify handle.\n"); goto Fail; } #if(NTDDI_VERSION >= NTDDI_WIN8) FWPS_CONNECTION_REDIRECT_STATE redirectState = FwpsQueryConnectionRedirectState( inMetaValues->redirectRecords, redirectHandle, NULL ); if (redirectState != FWPS_CONNECTION_NOT_REDIRECTED) { log("SMBRedirect: Connection was already redirected (presumably by us). Ignoring it.\n"); goto Exit; } #else UNREFERENCED_PARAMETER(inMetaValues); #endif status = FwpsAcquireWritableLayerDataPointer(classifyHandle, filter->filterId, 0, &connectRequest, classifyOut); if (!NT_SUCCESS(status)) { log("SMBRedirect: Failure to aquire classify handle.\n"); goto Fail; } SOCKADDR_IN* remoteAddr = (SOCKADDR_IN*)&connectRequest->remoteAddressAndPort; SOCKADDR_IN* localAddr = (SOCKADDR_IN*)&connectRequest->localAddressAndPort; UINT32 localAddrIp = localAddr->sin_addr.S_un.S_addr; UINT16 localAddrPort = localAddr->sin_port; UINT32 remoteAddrIp = remoteAddr->sin_addr.S_un.S_addr; UINT16 remoteAddrPort = remoteAddr->sin_port; log("SMBRedirect: In ALEConnectRedirectClassifyFn, intercepting connection from %08x:%d to %08x:%d.\n", ntohl(localAddrIp), ntohs(localAddrPort), ntohl(remoteAddrIp),ntohs(remoteAddrPort)); int port = ntohs(remoteAddr->sin_port); if (port == PORT_1) { remoteAddr->sin_port = htons(PORT_2); log("SMBRedirect: Redirecting connection from port %d to %d.\n", PORT_1, PORT_2); } #if(NTDDI_VERSION >= NTDDI_WIN8) connectRequest->localRedirectHandle = redirectHandle; #endif connectRequest->localRedirectTargetPID = 0xFFFF; FwpsApplyModifiedLayerData(classifyHandle, connectRequest,0);

    Exit: if (classifyHandle != 0) { FwpsReleaseClassifyHandle(classifyHandle); } return; Fail: goto Exit; }

    Also I do not understand why I have to pass the local PID. I believe it has something to do with authentication, with the passing of the redirect information to the proxy so it can really act as a transparent local proxy. But I don't want a proxy, I want a replacement service that just doesn't cares about the original destination of my connection. Is that possible at all?

    I test this on Windows 7 SP 1 with Visual Studio 2015 and Target Platform Version 10.0.14393.0 with the related SDK and DDK.

    Also headaches makes the filtering logic. I can filter by the destination port, but not by the destination IP. This works as expected:

    		aleConnectRedirectConditions[condNo].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT;
    		aleConnectRedirectConditions[condNo].matchType = FWP_MATCH_EQUAL;
    		aleConnectRedirectConditions[condNo].conditionValue.type = FWP_UINT16;
    		aleConnectRedirectConditions[condNo].conditionValue.uint16 = port;

    But this fails and never matches anything:

    	        aleConnectRedirectConditions[condNo].fieldKey = FWPM_CONDITION_IP_REMOTE_ADDRESS;
    		aleConnectRedirectConditions[condNo].matchType = FWP_MATCH_EQUAL;
    		aleConnectRedirectConditions[condNo].conditionValue.type = FWP_UINT32;
    		aleConnectRedirectConditions[condNo].conditionValue.uint32 = 0x7f000002; // 127.0.0.2

    PS: I already wrote callouts that do the port-switcheridoo in the inbound and outbound packet layer, which does a nice job hiding the local service at port 80 at one of the external IPs from external visitors which get nicely redirected to port 8080 in that case. I wasn't able to do that on the transport layer because the internal WFP or TCP stack seems to get mixed up, and also I didn't make that work on loopback traffic. If can solve my above problem only with other layers, please also state that. 

    OK, here are all my questions in concise form:

    1. Why do I need to pass the proxyPID? I do not have to this for external redirect targets.

    2. I there I was I can skip passing the proxyPID for local services?

    3. Is there any way I can make the FWPM_LAYER_ALE_CONNECT_REDIRECT behave for local targets like for remote targets?

    4. I want to install the redirect before my local proxy starts up. How should I know that PID? 

    5. Why does my IP filter not match? 


    Tuesday, May 15, 2018 5:10 PM

All replies


  • Anwering some of my own questions:

    1. No need for it.

    2. Yes, can skip it.

    3. It does. My fault was that I tested it with a server that bound to the "any" address, and in that case it does not work. The server must be bind to the specific address. While I write this, might it be that the redirect destination can be set to some kind of "any" address to match these servers?

    4. Again, not need for the pid.

    The last one is still of interest. I cannot filter the destination address in connects. But maybe I should just implement that within the classify filter.



    Tuesday, May 15, 2018 6:50 PM