Usar o redirecionamento de associação ou conexão

O recurso de redirecionamento de conexão/associação da Plataforma para Filtros do Windows (WFP) habilita os drivers de chamada de aplicação da camada de aplicativos (ALE) a inspecionar e, se desejado, redirecionar conexões.

Esse recurso está disponível no Windows 7 e posterior.

Observação: o módulo ClassifyFunctions_ProxyCallouts.cpp no exemplo de driver WFP inclui código que demonstra o redirecionamento de conexão/associação.

Um texto explicativo de redirecionamento de conexão WFP redireciona a solicitação de conexão de um aplicativo para que o aplicativo se conecte a um serviço de proxy em vez do destino original. O serviço de proxy tem dois soquetes: um para a conexão original redirecionada e outro para a nova conexão de saída proxy.

Um registro de redirecionamento do WFP é um buffer de dados opacos que o WFP deve definir em uma conexão de proxy de saída nas camadas FWPM_LAYER_ALE_AUTH_CONNECT_REDIRECT_V4 e FWPM_LAYER_ALE_AUTH_CONNECT_REDIRECT_V6, de modo que a conexão redirecionada e a conexão original estejam logicamente relacionadas.

A alteração do endereço local e da porta de um fluxo só é suportada na camada de redirecionamento de associação. Essa funcionalidade não é compatível com a camada de redirecionamento de conexão.

Camadas usadas para redirecionamento

Os drivers de texto explicativo podem realizar o redirecionamento nas seguintes camadas, que são chamadas de "camadas de redirecionamento":

  • FWPM_LAYER_ALE_BIND_REDIRECT_V4 (FWPS_LAYER_ALE_BIND_REDIRECT_V4)

  • FWPM_LAYER_ALE_BIND_REDIRECT_V6 (FWPS_LAYER_ALE_BIND_REDIRECT_V6)

  • FWPM_LAYER_ALE_CONNECT_REDIRECT_V4 (FWPS_LAYER_ALE_CONNECT_REDIRECT_V4)

  • FWPM_LAYER_ALE_CONNECT_REDIRECT_V6 (FWPS_LAYER_ALE_CONNECT_REDIRECT_V6)

A camada na qual o redirecionamento é executado determina o efeito da alteração. As alterações nas camadas de conexão afetam apenas o fluxo que está sendo conectado. As alterações nas camadas de ligação afetam todas as conexões que estão usando esse soquete.

As camadas de redirecionamento estão disponíveis somente para Windows 7 e versões posteriores do Windows. Os drivers de texto explicativo que dão suporte à classificação nessas camadas devem se registrar usando FwpsCalloutRegister1 ou superior, não a função mais antiga FwpsCalloutRegister0.

Importante

 O redirecionamento não está disponível para uso com todos os tipos de tráfego de rede. Os tipos de pacotes com suporte para redirecionamento são mostrados na seguinte lista:

  • TCP
  • UDP
  • UDPv4 bruto sem a opção de inclusão de cabeçalho
  • ICMP bruto

Executar o redirecionamento

Para redirecionar uma conexão, o driver de texto explicativo deve obter uma cópia gravável das informações de tupla TCP 4, fazer alterações conforme necessário e aplicar as alterações. Um conjunto de novas funções é fornecido para obter dados de camada graváveis e aplicá-los por meio do mecanismo. Os drivers de texto explicativo têm a opção de fazer alterações embutidas em suas funções classifyFn ou de forma assíncrona em outra função.

Os drivers de texto explicativo que implementam o redirecionamento devem usar classifyFn1 ou posterior, em vez de classifyFn0 como sua função de texto explicativo de classificação. Para usar classifyFn1 ou posterior, o texto explicativo deve ser registrado chamando FwpsCalloutRegister1 ou posterior, não a mais antiga FwpsCalloutRegister0.

Para executar o redirecionamento embutido, um driver de texto explicativo deve executar as seguintes etapas em sua implementação de classifyFn:

  1. Chame FwpsRedirectHandleCreate0 para obter um identificador que possa ser usado para redirecionar conexões TCP. Esse identificador deve ser armazenado em cache e usado para todos os redirecionamentos. (Esta etapa é omitida para Windows 7 e versões anteriores.)

  2. No Windows 8 e posterior, você deve consultar o estado de redirecionamento da conexão usando a função FwpsQueryConnectionRedirectState0 no driver de texto explicativo. Isso deve ser feito para evitar o redirecionamento infinito.

  3. Chame FwpsAcquireClassifyHandle0 para obter um identificador que será usado para chamadas de função subsequentes.

  4. Chame FwpsAcquireWritableLayerDataPointer0 para obter a estrutura de dados gravável para a camada na qual classifyFn foi chamado. Converta o parâmetro writableLayerData para a estrutura correspondente à camada, FWPS_BIND_REQUEST0 ou FWPS_CONNECT_REQUEST0..

    A partir do Windows 8, se o driver de texto explicativo estiver redirecionando para um serviço local, você deverá chamar FwpsRedirectHandleCreate0 para preencher o membro localRedirectHandle da estrutura FWPS_CONNECT_REQUEST0 para que o proxy local funcione.

  5. Faça alterações nos dados da camada conforme necessário:

    1. Salve o destino original no contexto de redirecionamento local, conforme mostrado no exemplo seguinte:

      FWPS_CONNECT_REQUEST* connectRequest = redirectContext->connectRequest;
      // Replace "..." with your own redirect context size
      connectRequest->localRedirectContextSize = ...;
      // Store original destination IP/Port information in the localRedirectContext member
      connectRequest->localRedirectContext =    ExAllocatePoolWithTag(…);
      
    2. Modifique o endereço remoto conforme mostrado no exemplo seguinte:

      // Ensure we don't need to worry about crossing any of the TCP/IP stack's zones
      if(INETADDR_ISANY((PSOCKADDR)&(connectRequest->localAddressAndPort)))
      {
         INETADDR_SETLOOPBACK((PSOCKADDR)&(connectRequest->remoteAddressAndPort));
      }
      else
      {
         INETADDR_SET_ADDRESS((PSOCKADDR)&(connectRequest->remoteAddressAndPort),
                               INETADDR_ADDRESS((PSOCKADDR)&(connectRequest->localAddressAndPort)));
      }
      INETADDR_SET_PORT((PSOCKADDR)&connectRequest->remoteAddressAndPort,
                        RtlUshortByteSwap(params->proxyPort));
      
    3. Se o driver de texto explicativo estiver redirecionando para um serviço local, ele deverá definir o PID do proxy local no membro localRedirectTargetPID da estrutura FWPS_CONNECT_REQUEST0.

    4. Se o driver de texto explicativo estiver redirecionando para um serviço local, ele deverá definir o identificador de redirecionamento retornado por FwpsRedirectHandleCreate0 no membro localRedirectHandle da estrutura FWPS_CONNECT_REQUEST0.

  6. Chame FwpsApplyModifiedLayerData0 para aplicar as alterações feitas aos dados.

  7. Em seu serviço de proxy (que pode estar no modo de usuário ou no modo kernel), você deve consultar registros e contextos de redirecionamento, conforme mostrado no exemplo seguinte:

    BYTE* redirectRecords;
    BYTE redirectContext[CONTEXT_SIZE];
    listenSock = WSASocket(…);
    result = bind(listenSock, …);
    result = listen(listenSock, …);
    clientSock = WSAAccept(listenSock, …);
    // opaque data to be set on proxy connection
    result = WSAIoctl(clientSock,
                      SIO_QUERY_WFP_CONNECTION_REDIRECT_RECORDS,
                      redirectRecords, …);
    // callout allocated data, contains original destination information
    result = WSAIoctl(clientSock,
                      SIO_QUERY_WFP_CONNECTION_REDIRECT_CONTEXT,
                      redirectContext, …);
    // extract original destination IP and port from above context
    
  8. No serviço de proxy (que pode estar no modo de usuário ou no modo kernel), você deve definir registros de redirecionamento no soquete de conexão de proxy, conforme mostrado no exemplo seguinte, para criar um novo soquete de saída:

    proxySock = WSASocket(…);
    result = WSAIoctl(
                 proxySock,
                 SIO_SET_WFP_CONNECTION_REDIRECT_RECORDS,
                 redirectRecords, …);
    
  9. Chame FwpsReleaseClassifyHandle0 para liberar o identificador de classificação obtido na etapa 2.

  10. Chame FwpsRedirectHandleDestroy0 para destruir o identificador obtido na etapa 1.

Para executar o redirecionamento de forma assíncrona, um driver de texto explicativo deve executar as seguintes etapas:

  1. Chame FwpsRedirectHandleCreate0 para obter um identificador que possa ser usado para redirecionar conexões TCP. (Esta etapa é omitida para Windows 7 e versões anteriores.)

  2. No Windows 8 e posterior, você deve consultar o estado de redirecionamento da conexão usando a função FwpsQueryConnectionRedirectState0 no driver de texto explicativo.

  3. Chame FwpsAcquireClassifyHandle0 para obter um identificador que será usado para chamadas de função subsequentes. Esta etapa e as etapas 2 e 3 são executadas na função de texto explicativo classifyFn.

  4. Chame FwpsPendClassify0 para colocar a classificação em um estado pendente, conforme mostrado no seguinte exemplo:

    FwpsPendClassify(
            redirectContext->classifyHandle,
            0,
            &redirectContext->classifyOut);
    classifyOut->actionType = FWP_ACTION_BLOCK;
    classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
    

Observação

Se você estiver direcionando o Windows 7, deverá executar as etapas a seguir em uma função de trabalho separada. Se você estiver direcionando Windows 8 ou posterior, poderá executar todas as etapas para redirecionamento assíncrono de dentro do classifyFn e ignorar a Etapa 5.

  1. Envie o identificador de classificação e os dados da camada gravável para outra função para processamento assíncrono. As etapas restantes são executadas nessa função, não na implementação do driver de texto explicativo de classifyFn.

  2. Chame FwpsAcquireWritableLayerDataPointer0 para obter a estrutura de dados gravável para a camada na qual classifyFn foi chamado. Converta o parâmetro writableLayerData para a estrutura correspondente à camada, FWPS_BIND_REQUEST0 ou FWPS_CONNECT_REQUEST0..

    A partir do Windows 8, se o driver de texto explicativo estiver redirecionando localmente, você deverá chamar FwpsRedirectHandleCreate0 para preencher o membro localRedirectHandle da estrutura FWPS_CONNECT_REQUEST0 para que o proxy local funcione.

  3. Armazene todas as informações de contexto específicas do texto explicativo em uma estrutura de contexto privada, conforme mostrado no seguinte exemplo:

    redirectContext->classifyHandle = classifyHandle;
    redirectContext->connectRequest = connectRequest;
    redirectContext->classifyOut = *classifyOut; // deep copy
    // store original destination IP, port
    
  4. Faça alterações nos dados da camada conforme necessário.

  5. Chame FwpsApplyModifiedLayerData0 para aplicar as alterações feitas aos dados. Defina o sinalizador FWPS_CLASSIFY_FLAG_REAUTHORIZE_IF_MODIFIED_BY_OTHERS se desejar ser autorizado novamente caso outro texto explicativo modifique ainda mais os dados.

  6. Chame FwpsCompleteClassify0 para concluir a operação de classificação de forma assíncrona, conforme mostrado no seguinte exemplo:

    FwpsCompleteClassify(
            redirectContext->classifyHandle,
            0,
            &redirectContext->classifyOut);
    classifyOut->actionType = FWP_ACTION_PERMIT;
    classifyOut->rights |= FWPS_RIGHT_ACTION_WRITE;
    
  7. Chame FwpsReleaseClassifyHandle0 para liberar o identificador de classificação obtido na etapa 1.

Manipular o redirecionamento de conexão de várias chamadas

É possível que mais de um driver de texto explicativo inicie o redirecionamento de conexão para o mesmo fluxo. Os textos explicativos que executam o redirecionamento de conexão devem estar cientes de outras solicitações e responder adequadamente.

O sinalizador FWPS_RIGHT_ACTION_WRITE deve ser definido sempre que um texto explicativo enviar uma classificação. Seu texto explicativo deve testar o sinalizador FWPS_RIGHT_ACTION_WRITE para verificar os direitos do texto explicativo para retornar uma ação. Se esse sinalizador não estiver definido, seu texto explicativo ainda poderá retornar uma ação FWP_ACTION_BLOCK para vetar uma ação FWP_ACTION_PERMIT que foi retornada por um texto explicativo anterior.

No Windows 8 e posterior, o driver de texto explicativo deve consultar o estado de redirecionamento da conexão (para ver se o driver de texto explicativo ou outro driver de texto explicativo o modificou) usando a função FwpsQueryConnectionRedirectState0. Se a conexão for redirecionada pelo driver de texto explicativo ou se tiver sido redirecionada anteriormente pelo driver de texto explicativo, o driver de texto explicativo não deverá fazer nada. Caso contrário, ele também deve verificar o redirecionamento local, conforme mostrado no seguinte exemplo:

FwpsAcquireWritableLayerDataPointer(...,(PVOID*)&connectRequest), ...);
if(connectRequest->previousVersion->modifierFilterId != filterId)
{
    if(connectRequest->previousVersion->localRedirectHandle)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        classifyOut->rights &= FWPS_RIGHT_ACTION_WRITE;
        FwpsApplyModifiedLayerData(
                classifyHandle,
                (PVOID)connectRequest,
                FWPS_CLASSIFY_FLAG_REAUTHORIZE_IF_MODIFIED_BY_OTHERS);
    }
}

Se a conexão for com um proxy local, o driver de texto explicativo não deverá tentar redirecioná-la.

Os drivers de texto explicativo que usam o redirecionamento de conexão devem se registrar na camada de conexão de autorização ALE (FWPS_LAYER_ALE_AUTH_CONNECT_V4 ou FWPS_LAYER_ALE_AUTH_CONNECT_V6) e verificar os dois valores de metadados a seguir para obter indicações em que o sinalizador FWP_CONDITION_FLAG_IS_CONNECTION_REDIRECTED está definido:

  • FWPS_METADATA_FIELD_LOCAL_REDIRECT_TARGET_PID contém o identificador de processo para o processo responsável pelo fluxo redirecionado.

  • FWPS_METADATA_FIELD_ORIGINAL_DESTINATION contém o endereço do destino original do fluxo.

A estrutura FWPS_CONNECT_REQUEST0 contém um membro chamado localRedirectTargetPID. Para que qualquer redirecionamento de conexão de loopback seja válido, esse campo deve ser preenchido com o PID do processo que será responsável pelo fluxo redirecionado. Esses são os mesmos dados que o mecanismo passa nas camadas de conexão de autorização ALE como FWPS_METADATA_FIELD_LOCAL_REDIRECT_TARGET_ID.

A partir do Windows 8, o serviço de proxy precisa emitir o SIO_QUERY_WFP_CONNECTION_REDIRECT_RECORDS e SIO_QUERY_WFP_CONNECTION_REDIRECT_CONTEXT IOCTLs, usando WSAIoctl, contra o ponto de extremidade original do serviço de proxy. Além disso, o SIO_SET_WFP_CONNECTION_REDIRECT_RECORDS IOCTL deve ser emitido, usando WSAIoctl, no novo soquete (com proxy).

Nomes independentes de versão do WFP e direcionamento para versões específicas do Windows