Partager via


Utilisation d'une redirection de liaison ou connexion

La fonctionnalité de redirection de connexion/bind de la Windows Filtering Platform (WFP) permet aux pilotes d’appel de l’application layer enforcement (ALE) d’inspecter et, si nécessaire, de rediriger les connexions.

Cette fonctionnalité est disponible dans Windows 7 et les versions ultérieures.

Remarque : Le module ClassifyFunctions_ProxyCallouts.cpp dans l’exemple de pilote WFP inclut un code qui illustre la redirection de connexion/bind.

Un appel de redirection de connexion de WFP redirige la demande de connexion d’une application afin que celle-ci se connecte à un service proxy plutôt qu’à la destination d’origine. Le service proxy dispose de deux sockets : un pour la connexion redirigée d’origine et un pour la nouvelle connexion sortante proxifiée.

Un enregistrement de redirection WFP est un tampon de données opaques que WFP doit définir sur une connexion proxy sortante aux couches FWPM_LAYER_ALE_AUTH_CONNECT_REDIRECT_V4 et FWPM_LAYER_ALE_AUTH_CONNECT_REDIRECT_V6, afin que la connexion redirigée et la connexion d’origine soient logiquement liées.

Le changement de l’adresse et du port locaux d’un flux n’est pris en charge que dans la couche de redirection bind. Cette fonctionnalité n’est pas prise en charge dans la couche de redirection de connexion.

Couches utilisées pour la redirection

Les pilotes d’appel peuvent effectuer une redirection aux couches suivantes, appelées « couches de redirection » :

  • 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)

La couche à laquelle la redirection est effectuée détermine l’effet du changement. Les changements aux couches de connexion n’affectent que le flux en cours de connexion. Les changements aux couches bind affectent toutes les connexions utilisant ce socket.

Les couches de redirection ne sont disponibles que pour Windows 7 et les versions ultérieures de Windows. Les pilotes d’appel qui prennent en charge la classification à ces couches doivent s’enregistrer à l’aide de la fonction FwpsCalloutRegister1 ou une fonction plus récente, et non de l’ancienne fonction FwpsCalloutRegister0.

Important

 La redirection n’est pas disponible pour tous les types de trafic réseau. Les types de paquets pris en charge pour la redirection sont indiqués dans la liste suivante :

  • TCP
  • UDP
  • UDPv4 brut sans l’option d’inclusion de l’en-tête
  • ICMP brut

Effectuer la redirection

Pour rediriger une connexion, le pilote d’appel doit obtenir une copie modifiable des informations du quadruplet TCP, y apporter les modifications nécessaires, puis appliquer les modifications. Un ensemble de nouvelles fonctions est fourni pour obtenir des données de couche modifiables et les appliquer via le moteur. Les pilotes d’appel ont la possibilité d’apporter des modifications soit en ligne dans leurs fonctions classifyFn, soit de manière asynchrone dans une autre fonction.

Les pilotes d’appel qui implémentent la redirection doivent utiliser classifyFn1 ou une fonction ultérieure au lieu de classifyFn0 comme fonction d’appel de classification. Pour utiliser classifyFn1 ou une fonction plus récente, l’appel doit être enregistré en appelant FwpsCalloutRegister1 ou une version supérieure, et non l’ancienne fonction FwpsCalloutRegister0.

Pour effectuer une redirection en ligne, un pilote d’appel doit effectuer les étapes suivantes dans son implémentation de classifyFn :

  1. Appelez FwpsRedirectHandleCreate0 pour obtenir un handle qui pourra être utilisé pour rediriger les connexions TCP. Ce handle doit être mis en cache et utilisé pour toutes les redirections. (Cette étape est omise pour Windows 7 et les versions antérieures.)

  2. Dans Windows 8 et les versions ultérieures, vous devez interroger l’état de redirection de la connexion en utilisant la fonction FwpsQueryConnectionRedirectState0 dans votre pilote d’appel. Cela doit être fait pour éviter les redirections infinies.

  3. Appelez FwpsAcquireClassifyHandle0 pour obtenir un handle qui sera utilisé pour les appels de fonctions suivants.

  4. Appelez FwpsAcquireWritableLayerDataPointer0 pour obtenir la structure de données modifiable pour la couche dans laquelle classifyFn a été appelé. Convertissez le paramètre de sortie writableLayerData en la structure correspondant à la couche, soit FWPS_BIND_REQUEST0, soit FWPS_CONNECT_REQUEST0.

    À partir de Windows 8, si votre pilote d’appel redirige vers un service local, vous devez appeler FwpsRedirectHandleCreate0 pour remplir le membre localRedirectHandle de la structure FWPS_CONNECT_REQUEST0 afin que le proxy local fonctionne.

  5. Apportez les modifications nécessaires aux données de la couche :

    1. Enregistrez la destination d’origine dans le contexte de redirection local, comme indiqué dans l’exemple suivant :

      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. Modifiez l’adresse distante, comme indiqué dans l’exemple suivant :

      // 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. Si votre pilote d’appel redirige vers un service local, il doit définir le PID du proxy local dans le membre localRedirectTargetPID de la structure FWPS_CONNECT_REQUEST0.

    4. Si votre pilote d’appel redirige vers un service local, il doit définir le handle de redirection renvoyé par FwpsRedirectHandleCreate0 dans le membre localRedirectHandle de la structure FWPS_CONNECT_REQUEST0.

  6. Appelez FwpsApplyModifiedLayerData0 pour appliquer les modifications apportées aux données.

  7. Dans votre service proxy (qui peut être en mode utilisateur ou en mode noyau), vous devez interroger les enregistrements et contextes de redirection comme indiqué dans l’exemple suivant :

    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. Dans votre service proxy (qui peut être en mode utilisateur ou en mode noyau), vous devez définir des enregistrements de redirection sur le socket de connexion proxy comme indiqué dans l’exemple suivant pour créer un nouveau socket sortant :

    proxySock = WSASocket(…);
    result = WSAIoctl(
                 proxySock,
                 SIO_SET_WFP_CONNECTION_REDIRECT_RECORDS,
                 redirectRecords, …);
    
  9. Appelez FwpsReleaseClassifyHandle0 pour libérer le handle de classification obtenu à l’étape 2.

  10. Appelez FwpsRedirectHandleDestroy0 pour détruire le handle obtenu à l’étape 1.

Pour effectuer une redirection de manière asynchrone, un pilote d’appel doit effectuer les étapes suivantes :

  1. Appelez FwpsRedirectHandleCreate0 pour obtenir un handle qui pourra être utilisé pour rediriger les connexions TCP. (Cette étape est omise pour Windows 7 et les versions antérieures.)

  2. Dans Windows 8 et les versions ultérieures, vous devez interroger l’état de redirection de la connexion en utilisant la fonction FwpsQueryConnectionRedirectState0 dans votre pilote d’appel.

  3. Appelez FwpsAcquireClassifyHandle0 pour obtenir un handle qui sera utilisé pour les appels de fonctions suivants. Cette étape et les étapes 2 et 3 sont effectuées dans la fonction d’appel classifyFn du pilote d’appel.

  4. Appelez FwpsPendClassify0 pour placer la classification dans un état en attente, comme indiqué dans l’exemple suivant :

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

Remarque

Si vous ciblez Windows 7, vous devez effectuer les étapes suivantes dans une fonction de travail distincte. Si vous ciblez Windows 8 ou une version ultérieure, vous pouvez effectuer toutes les étapes de la redirection asynchrone dans la fonction classifyFn et ignorer l’étape 5.

  1. Envoyez le handle de classification et les données de couche modifiables à une autre fonction pour un traitement asynchrone. Les étapes restantes sont effectuées dans cette fonction, et non dans l’implémentation de la fonction classifyFn du pilote d’appel.

  2. Appelez FwpsAcquireWritableLayerDataPointer0 pour obtenir la structure de données modifiable pour la couche dans laquelle classifyFn a été appelé. Convertissez le paramètre de sortie writableLayerData en la structure correspondant à la couche, soit FWPS_BIND_REQUEST0, soit FWPS_CONNECT_REQUEST0.

    À partir de Windows 8, si votre pilote d’appel redirige localement, vous devez appeler FwpsRedirectHandleCreate0 pour remplir le membre localRedirectHandle de la structure FWPS_CONNECT_REQUEST0 afin que le proxy fonctionne.

  3. Stockez toutes les informations de contexte spécifiques à l’appel dans une structure de contexte privée, comme indiqué dans l’exemple suivant :

    redirectContext->classifyHandle = classifyHandle;
    redirectContext->connectRequest = connectRequest;
    redirectContext->classifyOut = *classifyOut; // deep copy
    // store original destination IP, port
    
  4. Apportez les modifications nécessaires aux données de la couche.

  5. Appelez FwpsApplyModifiedLayerData0 pour appliquer les modifications apportées aux données. Définissez l’indicateur FWPS_CLASSIFY_FLAG_REAUTHORIZE_IF_MODIFIED_BY_OTHERS si vous souhaitez être ré-autorisé dans le cas où un autre appel modifierait les données.

  6. Appelez FwpsCompleteClassify0 pour terminer l’opération de classification de manière asynchrone, comme indiqué dans l’exemple suivant :

    FwpsCompleteClassify(
            redirectContext->classifyHandle,
            0,
            &redirectContext->classifyOut);
    classifyOut->actionType = FWP_ACTION_PERMIT;
    classifyOut->rights |= FWPS_RIGHT_ACTION_WRITE;
    
  7. Appelez FwpsReleaseClassifyHandle0 pour libérer le handle de classification obtenu à l’étape 1.

Gestion de la redirection de connexion à partir de plusieurs pilotes d’appel

Il est possible que plusieurs pilotes d’appel initient une redirection de connexion pour le même flux. Les pilotes d’appel qui effectuent une redirection de connexion doivent être conscients des autres demandes et répondre de manière appropriée.

L’indicateur FWPS_RIGHT_ACTION_WRITE doit être défini chaque fois qu’un appel place une classification en attente. Votre pilote d’appel doit tester l’indicateur FWPS_RIGHT_ACTION_WRITE pour vérifier les droits de votre appel à renvoyer une action. Si cet indicateur n’est pas défini, votre appel peut toujours renvoyer une action FWP_ACTION_BLOCK pour opposer un veto à une action FWP_ACTION_PERMIT qui a été renvoyée par un appel précédent.

Dans Windows 8 et les versions ultérieures, votre pilote d’appel doit interroger l’état de redirection de la connexion (pour voir si votre pilote d’appel ou un autre a modifié la connexion) en utilisant la fonction FwpsQueryConnectionRedirectState0. Si la connexion est redirigée par votre pilote d’appel, ou si elle a déjà été redirigée par votre pilote d’appel, le pilote d’appel ne doit rien faire. Sinon, il doit également vérifier la redirection locale, comme indiqué dans l’exemple suivant :

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);
    }
}

Si la connexion est destinée à un proxy local, votre pilote d’appel ne doit pas tenter de la rediriger.

Les pilotes d’appel qui utilisent la redirection de connexion doivent s’enregistrer à la couche d’autorisation de connexion ALE (FWPS_LAYER_ALE_AUTH_CONNECT_V4 ou FWPS_LAYER_ALE_AUTH_CONNECT_V6) et vérifier les deux valeurs de métadonnées suivantes pour des indications où l’indicateur FWP_CONDITION_FLAG_IS_CONNECTION_REDIRECTED est défini :

  • FWPS_METADATA_FIELD_LOCAL_REDIRECT_TARGET_PID contient l’identifiant du processus responsable du flux redirigé.

  • FWPS_METADATA_FIELD_ORIGINAL_DESTINATION contient l’adresse de la destination d’origine du flux.

La structure FWPS_CONNECT_REQUEST0 contient un membre appelé localRedirectTargetPID. Pour qu’une redirection de connexion loopback soit valide, ce champ doit être rempli avec le PID du processus qui sera responsable du flux redirigé. Il s’agit des mêmes données que le moteur transmet aux couches d’autorisation de connexion ALE sous la forme FWPS_METADATA_FIELD_LOCAL_REDIRECT_TARGET_ID.

À partir de Windows 8, le service proxy doit émettre les IOCTLs SIO_QUERY_WFP_CONNECTION_REDIRECT_RECORDS et SIO_QUERY_WFP_CONNECTION_REDIRECT_CONTEXT, en utilisant WSAIoctl, contre le point de terminaison d’origine du service proxy. En outre, l’IOCTL SIO_SET_WFP_CONNECTION_REDIRECT_RECORDS doit être émis, en utilisant WSAIoctl, sur le nouveau socket (proxifié).

Noms indépendants de la version de WFP et ciblage de versions spécifiques de Windows