Usando o Redirecionamento de Associação ou Conexão

O recurso de redirecionamento de conexão/associação da Plataforma de Filtragem do Windows (WFP) permite que os drivers de texto explicativo ALE (imposição de camada de aplicativo) inspecionem e, se desejado, redirecionem conexões.

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

Nota 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 proxy em vez do destino original. O serviço proxy tem dois soquetes: um para a conexão original redirecionada e outro para a nova conexão de saída com proxie.

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 , para 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ó tem suporte na camada de redirecionamento de associação. Não há suporte para isso na camada connect-redirect.

Camadas usadas para redirecionamento

O redirecionamento pode ser executado por drivers de texto explicativo 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 em camadas de associação afetam todas as conexões que estão usando esse soquete.

As camadas de redirecionamento só estão disponíveis para o 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 FwpsCalloutRegister0 mais antiga.

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

Executando 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 nela 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 classificarFn0 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 o FwpsCalloutRegister0 mais antigo.

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 pode ser usado para redirecionar conexões TCP. Esse identificador deve ser armazenado em cache e usado para todos os redirecionamentos. (Esta etapa é omitida para o Windows 7 e anterior.)

  2. Em 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 a seguir:

      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 a seguir:

      // 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 de 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. No serviço 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 a seguir:

    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 proxy (que pode estar no modo de usuário ou no modo kernel), você deve definir registros de redirecionamento no soquete de conexão proxy, conforme mostrado no exemplo a seguir para criar um 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 pode ser usado para redirecionar conexões TCP. (Esta etapa é omitida para o Windows 7 e anterior.)

  2. Em 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 do driver de texto explicativo.

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

    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 de camada graváveis 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.

    Começando com 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 funcione.

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

    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 novamente autorizado 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 exemplo a seguir:

    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.

Manipulando o redirecionamento de conexão de vários textos explicativos

É 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 aguardar uma classificação. O texto explicativo deve testar o sinalizador FWPS_RIGHT_ACTION_WRITE para marcar os direitos do texto explicativo retornar uma ação. Se esse sinalizador não estiver definido, o texto explicativo ainda poderá retornar uma ação FWP_ACTION_BLOCK para vetar uma ação de FWP_ACTION_PERMIT que foi retornada por um texto explicativo anterior.

Em Windows 8 e posteriores, 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 ela 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 marcar para redirecionamento local, conforme mostrado no exemplo a seguir:

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 do ALE (FWPS_LAYER_ALE_AUTH_CONNECT_V4 ou FWPS_LAYER_ALE_AUTH_CONNECT_V6) e marcar os dois valores de metadados a seguir para obter indicações de onde o sinalizador de 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 para o 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 do ALE que FWPS_METADATA_FIELD_LOCAL_REDIRECT_TARGET_ID.

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

Nomes de Version-Independent WFP e direcionamento de versões específicas do Windows