Uso di Bind o Connect Redirection

La funzionalità di reindirizzamento di connessione/associazione di Windows Filtering Platform (WFP) consente ai driver di callout del livello applicazione di controllare e, se desiderato, reindirizzare le connessioni.

Questa funzionalità è disponibile in Windows 7 e versioni successive.

Nota Il modulo ClassifyFunctions_ProxyCallouts.cpp nell'esempio di driver WFP include il codice che illustra il reindirizzamento di connessione/associazione.

Un callout di reindirizzamento connessione WFP reindirizza la richiesta di connessione di un'applicazione in modo che l'applicazione si connette a un servizio proxy anziché alla destinazione originale. Il servizio proxy ha due socket: uno per la connessione originale reindirizzata e una per la nuova connessione in uscita proxied.

Un record di reindirizzamento WFP è un buffer di dati opachi che WFP deve impostare su una connessione proxy in uscita ai livelli FWPM_LAYER_ALE_AUTH_CONNECT_REDIRECT_V4 e FWPM_LAYER_ALE_AUTH_CONNECT_REDIRECT_V6 , in modo che la connessione reindirizzata e la connessione originale siano logicamente correlate.

La modifica dell'indirizzo locale e della porta di un flusso è supportata solo nel livello di reindirizzamento di associazione. Questa operazione non è supportata nel livello di reindirizzamento con connessione.

Livelli usati per il reindirizzamento

Il reindirizzamento può essere eseguito dai driver callout nei livelli seguenti, denominati "livelli di reindirizzamento":

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

Il livello in corrispondenza del quale viene eseguito il reindirizzamento determina l'effetto della modifica. Le modifiche a livelli di connessione influiscono solo sul flusso connesso. Le modifiche a livelli di associazione influiscono su tutte le connessioni che usano tale socket.

I livelli di reindirizzamento sono disponibili solo per Windows 7 e versioni successive di Windows. I driver di callout che supportano la classificazione in questi livelli devono registrare usando FwpsCalloutRegister1 o versione successiva, non la funzione FwpsCalloutRegister0 precedente.

Importante

 Il reindirizzamento non è disponibile per l'uso con tutti i tipi di traffico di rete. I tipi di pacchetti supportati per il reindirizzamento sono visualizzati nell'elenco seguente:

  • TCP
  • UDP
  • UDPv4 non elaborato senza l'opzione di inclusione dell'intestazione
  • ICMP non elaborato

Esecuzione del reindirizzamento

Per reindirizzare una connessione, il driver callout deve ottenere una copia scrivibile delle informazioni tcp 4-tuple, apportare modifiche in base alle esigenze e applicare le modifiche. Viene fornito un set di nuove funzioni per ottenere dati di livello scrivibili e applicarli tramite il motore. I driver callout hanno la possibilità di apportare modifiche inline nelle funzioni di classificazioneFn o in modo asincrono in un'altra funzione.

I driver di callout che implementano il reindirizzamento devono usare classificaFn1 o versioni successive anziché classificareFn0 come funzione di callout di classificazione. Per usare classificazioneFn1 o versione successiva, il callout deve essere registrato chiamando FwpsCalloutRegister1 o versione successiva, non il precedente FwpsCalloutRegister0.

Per eseguire il reindirizzamento inline, un driver callout deve eseguire i passaggi seguenti nell'implementazione di classificaFn:

  1. Chiamare FwpsRedirectHandleCreate0 per ottenere un handle che può essere usato per reindirizzare le connessioni TCP. Questo handle deve essere memorizzato nella cache e usato per tutte le reindirizzamente. Questo passaggio viene omesso per Windows 7 e versioni precedenti.

  2. In Windows 8 e versioni successive è necessario eseguire una query sullo stato di reindirizzamento della connessione usando la funzione FwpsQueryConnectionRedirectState0 nel driver di callout. Questa operazione deve essere eseguita per evitare il reindirizzamento infinito.

  3. Chiamare FwpsAcquireClassifyHandle0 per ottenere un handle che verrà usato per le chiamate di funzione successive.

  4. Chiamare FwpsAcquireWritableLayerDataPointer0 per ottenere la struttura di dati scrivibile per il livello in cui è stato chiamato la classificazioneFn . Eseguire il cast del parametro writableLayerData nella struttura corrispondente al livello, FWPS_BIND_REQUEST0 o FWPS_CONNECT_REQUEST0.

    A partire da Windows 8, se il driver di callout reindirizza a un servizio locale, è necessario chiamare FwpsRedirectHandleCreate0 per compilare il membro localRedirectHandle della struttura FWPS_CONNECT_REQUEST0 per rendere funzionante il proxy locale.

  5. Apportare modifiche ai dati del livello in base alle esigenze:

    1. Salvare la destinazione originale nel contesto di reindirizzamento locale, come illustrato nell'esempio seguente:

      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. Modificare l'indirizzo remoto come illustrato nell'esempio seguente:

      // 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 il driver di callout viene reindirizzato a un servizio locale, deve impostare il PID proxy locale nel membro localRedirectTargetPID della struttura FWPS_CONNECT_REQUEST0 .

    4. Se il driver di callout viene reindirizzato a un servizio locale, deve impostare l'handle di reindirizzamento restituito da FwpsRedirectHandleCreate0 nel membro localRedirectHandle della struttura FWPS_CONNECT_REQUEST0.

  6. Chiamare FwpsApplyModifiedLayerData0 per applicare le modifiche apportate ai dati.

  7. Nel servizio proxy (che potrebbe essere in modalità utente o in modalità kernel), è necessario eseguire query su record e contesti di reindirizzamento, come illustrato nell'esempio seguente:

    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. Nel servizio proxy (che potrebbe essere in modalità utente o in modalità kernel), è necessario impostare record di reindirizzamento nel socket di connessione proxy, come illustrato nell'esempio seguente per creare un nuovo socket in uscita:

    proxySock = WSASocket(…);
    result = WSAIoctl(
                 proxySock,
                 SIO_SET_WFP_CONNECTION_REDIRECT_RECORDS,
                 redirectRecords, …);
    
  9. Chiamare FwpsReleaseClassifyHandle0 per rilasciare l'handle di classificazione ottenuto nel passaggio 2.

  10. Chiamare FwpsRedirectHandleDestroy0 per eliminare l'handle ottenuto nel passaggio 1.

Per eseguire il reindirizzamento in modo asincrono, un driver callout deve eseguire la procedura seguente:

  1. Chiamare FwpsRedirectHandleCreate0 per ottenere un handle che può essere usato per reindirizzare le connessioni TCP. Questo passaggio viene omesso per Windows 7 e versioni precedenti.

  2. In Windows 8 e versioni successive è necessario eseguire una query sullo stato di reindirizzamento della connessione usando la funzione FwpsQueryConnectionRedirectState0 nel driver di callout.

  3. Chiamare FwpsAcquireClassifyHandle0 per ottenere un handle che verrà usato per le chiamate di funzione successive. Questo passaggio e i passaggi 2 e 3 vengono eseguiti nella funzione di callout del driver di classificazioneFn .

  4. Chiamare FwpsPendClassify0 per inserire la classificazione in uno stato in sospeso, come illustrato nell'esempio seguente:

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

Nota

Se si usa Windows 7, è necessario eseguire la procedura seguente in una funzione di lavoro separata. Se si ha la destinazione Windows 8 o versioni successive, è possibile eseguire tutti i passaggi per il reindirizzamento asincrono dall'interno della classificazioneFn e ignorare il passaggio 5.

  1. Inviare l'handle di classificazione e i dati del livello scrivibili a un'altra funzione per l'elaborazione asincrona. I passaggi rimanenti vengono eseguiti in tale funzione, non nell'implementazione del driver di callout di classificazioneFn.

  2. Chiamare FwpsAcquireWritableLayerDataPointer0 per ottenere la struttura di dati scrivibile per il livello in cui è stato chiamato la classificazioneFn . Eseguire il cast del parametro writableLayerData nella struttura corrispondente al livello, FWPS_BIND_REQUEST0 o FWPS_CONNECT_REQUEST0.

    A partire da Windows 8, se il driver di callout viene reindirizzato in locale, è necessario chiamare FwpsRedirectHandleCreate0 per compilare il membro localRedirectHandle della struttura FWPS_CONNECT_REQUEST0 per rendere il proxy funzionante.

  3. Archiviare tutte le informazioni di contesto specifiche del callout in una struttura di contesto privata, come illustrato nell'esempio seguente:

    redirectContext->classifyHandle = classifyHandle;
    redirectContext->connectRequest = connectRequest;
    redirectContext->classifyOut = *classifyOut; // deep copy
    // store original destination IP, port
    
  4. Apportare modifiche ai dati del livello in base alle esigenze.

  5. Chiamare FwpsApplyModifiedLayerData0 per applicare le modifiche apportate ai dati. Impostare il flag di FWPS_CLASSIFY_FLAG_REAUTHORIZE_IF_MODIFIED_BY_OTHERS se si desidera essere nuovamente autorizzati nel caso in cui un altro callout modifica ulteriormente i dati.

  6. Chiamare FwpsCompleteClassify0 per completare l'operazione di classificazione in modo asincrono, come illustrato nell'esempio seguente:

    FwpsCompleteClassify(
            redirectContext->classifyHandle,
            0,
            &redirectContext->classifyOut);
    classifyOut->actionType = FWP_ACTION_PERMIT;
    classifyOut->rights |= FWPS_RIGHT_ACTION_WRITE;
    
  7. Chiamare FwpsReleaseClassifyHandle0 per rilasciare l'handle di classificazione ottenuto nel passaggio 1.

Gestione del reindirizzamento della connessione da più callout

È possibile che più di un driver callout avvii il reindirizzamento della connessione per lo stesso flusso. I callout che eseguono il reindirizzamento della connessione devono essere consapevoli di altre richieste e rispondere in modo appropriato.

Il flag FWPS_RIGHT_ACTION_WRITE deve essere impostato ogni volta che un callout penna una classificazione. Il callout deve testare il flag di FWPS_RIGHT_ACTION_WRITE per controllare i diritti per il callout per restituire un'azione. Se questo flag non è impostato, il callout può comunque restituire un'azione di FWP_ACTION_BLOCK per veto un'azione FWP_ACTION_PERMIT restituita da un callout precedente.

In Windows 8 e versioni successive, il driver di callout deve eseguire una query sullo stato di reindirizzamento della connessione (per verificare se il driver di callout o un altro driver di callout lo ha modificato) usando la funzione FwpsQueryConnectionRedirectState0. Se la connessione viene reindirizzata dal driver di callout o se è stata reindirizzata in precedenza dal driver di callout, il driver di callout non deve eseguire alcuna operazione. In caso contrario, dovrebbe anche verificare la presenza di reindirizzamento locale, come illustrato nell'esempio seguente:

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 la connessione è a un proxy locale, il driver di callout non deve tentare di reindirizzarlo.

I driver di callout che usano il reindirizzamento della connessione devono registrare nel livello di connessione dell'autorizzazione ALE (FWPS_LAYER_ALE_AUTH_CONNECT_V4 o FWPS_LAYER_ALE_AUTH_CONNECT_V6) e controllare i due valori di metadati seguenti per le indicazioni in cui è impostato il flag di FWP_CONDITION_FLAG_IS_CONNECTION_REDIRECTED :

  • FWPS_METADATA_FIELD_LOCAL_REDIRECT_TARGET_PID contiene l'identificatore di processo per il processo responsabile del flusso reindirizzato.

  • FWPS_METADATA_FIELD_ORIGINAL_DESTINATION contiene l'indirizzo della destinazione originale per il flusso.

La struttura FWPS_CONNECT_REQUEST0 contiene un membro denominato localRedirectTargetPID. Per qualsiasi reindirizzamento della connessione loopback valido, questo campo deve essere popolato con il PID del processo che sarà responsabile del flusso di reindirizzamento. Si tratta degli stessi dati che il motore passa ai livelli di connessione dell'autorizzazione ALE come FWPS_METADATA_FIELD_LOCAL_REDIRECT_TARGET_ID.

A partire da Windows 8, il servizio proxy deve emettere i SIO_QUERY_WFP_CONNECTION_REDIRECT_RECORDS e SIO_QUERY_WFP_CONNECTION_REDIRECT_CONTEXT IOCTLs, usando WSAIoctl, sull'endpoint originale del servizio proxy. Inoltre, il SIO_SET_WFP_CONNECTION_REDIRECT_RECORDS IOCTL deve essere rilasciato, usando WSAIoctl, nel nuovo socket (proxied).

Nomi Version-Independent WFP e destinazione versioni specifiche di Windows