Freigeben über


Verwenden der Bind- oder Connect-Umleitung

Die Funktion connect/bind redirection der Windows Filtering Platform (WFP) ermöglicht es ALE-Callout-Treibern (Application Layer Enforcement), Verbindungen zu überprüfen und, falls gewünscht, umzuleiten.

Diese Funktion ist in Windows 7 und höher verfügbar.

Hinweis Das Modul ClassifyFunctions_ProxyCallouts.cpp im WFP-Treiberbeispiel enthält Code, der connect/bind redirect demonstriert.

Ein WFP-Verbindungsumleitungsaufruf leitet die Verbindungsanfrage einer Anwendung so um, dass sich die Anwendung mit einem Proxy-Dienst statt mit dem ursprünglichen Ziel verbindet. Der Proxy-Dienst verfügt über zwei Sockets: einen für die umgeleitete ursprüngliche Verbindung und einen für die neue, ausgehende Proxy-Verbindung.

Ein WFP--Umleitungseintrag ist ein Puffer mit intransparenten Daten, die WFP auf einer ausgehenden Proxy-Verbindung in den Schichten FWPM_LAYER_ALE_AUTH_CONNECT_REDIRECT_V4 und FWPM_LAYER_ALE_AUTH_CONNECT_REDIRECT_V6 festlegen muss, damit die umgeleitete Verbindung und die ursprüngliche Verbindung logisch zusammenhängen.

Das Ändern der lokalen Adresse und des Ports eines Flows wird nur in der bind-redirect Schicht unterstützt. Diese Funktionalität wird in der connect-redirect Schicht nicht unterstützt.

Für die Umleitung verwendete Schichten

Callout-Treiber können die Umleitung auf den folgenden Schichten durchführen, die als „redirect-Schichten“ bezeichnet werden:

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

Die Schicht, auf der die Umleitung durchgeführt wird, bestimmt die Auswirkung der Änderung. Änderungen auf connect-Schichten wirken sich nur auf den Flow aus, der verbunden wird. Änderungen auf der bind-Schicht wirken sich auf alle Verbindungen aus, die diesen Socket verwenden.

Die Umleitungsschichten sind nur für Windows 7 und neuere Versionen von Windows verfügbar. Callout-Treiber, die die Klassifizierung auf diesen Schichten unterstützen, müssen sich mit FwpsCalloutRegister1 oder höher registrieren, nicht mit der älteren Funktion FwpsCalloutRegister0.

Wichtig

 Die Umleitung ist nicht für alle Arten des Datenverkehrs im Netzwerk verfügbar. Die Arten von Paketen, die für die Umleitung unterstützt werden, sind in der folgenden Liste aufgeführt:

  • TCP
  • UDP
  • Raw UDPv4 ohne die Option "header include"
  • Unformatierter ICMP

Umleitung durchführen

Um eine Verbindung umzuleiten, muss der Callout-Treiber eine beschreibbare Kopie der TCP 4-Tupel-Informationen abrufen, sie bei Bedarf ändern und die Änderungen anwenden. Es stehen eine Reihe neuer Funktionen zur Verfügung, um beschreibbare Daten der Schicht abzurufen und sie über die Engine anzuwenden. Callout-Treiber haben die Möglichkeit, Änderungen entweder inline in ihren classifyFn- Funktionen oder asynchron in einer anderen Funktion vorzunehmen.

Callout-Treiber, die eine Umleitung implementieren, müssen classifyFn1 oder höher anstelle von classifyFn0 als Callout-Funktion für die Klassifizierung verwenden. Um classifyFn1 oder höher zu verwenden, muss der Callout durch den Aufruf von FwpsCalloutRegister1 oder höher registriert werden, nicht durch den älteren FwpsCalloutRegister0.

Um eine Umleitung inline durchzuführen, muss ein Callout-Treiber die folgenden Schritte in seiner Implementierung von classifyFn durchführen:

  1. Rufen Sie FwpsRedirectHandleCreate0 auf, um ein Handle abzurufen, das zur Umleitung von TCP-Verbindungen verwendet werden kann. Dieses Handle sollte zwischengespeichert und für alle Umleitungen verwendet werden. (Dieser Schritt entfällt bei Windows 7 und früher).

  2. In Windows 8 und höher müssen Sie den Status der Umleitung der Verbindung mit der Funktion FwpsQueryConnectionRedirectState0 in Ihrem Callout-Treiber abfragen. Dies muss geschehen, um eine unendliche Umleitung zu verhindern.

  3. Rufen Sie FwpsAcquireClassifyHandle0 auf, um ein Handle abzurufen, das für nachfolgende Funktionsaufrufe verwendet werden soll.

  4. Rufen Sie FwpsAcquireWritableLayerDataPointer0 auf, um die beschreibbare Datenstruktur für die Schicht zu erhalten, in der classifyFn aufgerufen wurde. Übertragen Sie den Parameter writableLayerDataOut auf die Struktur, die der Schicht entspricht, entweder FWPS_BIND_REQUEST0 oder FWPS_CONNECT_REQUEST0.

    Ab Windows 8 müssen Sie, wenn Ihr Callout-Treiber zu einem lokalen Dienst umgeleitet wird, FwpsRedirectHandleCreate0 aufrufen, um das localRedirectHandle-Mitglied der FWPS_CONNECT_REQUEST0-Struktur zu füllen, damit das lokale Proxy funktioniert.

  5. Nehmen Sie bei Bedarf Änderungen an den Daten der Schicht vor:

    1. Speichern Sie das ursprüngliche Ziel im lokalen Umleitungskontext, wie im folgenden Beispiel gezeigt:

      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. Ändern Sie die Remote-Adresse wie im folgenden Beispiel gezeigt:

      // 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. Wenn Ihr Callout-Treiber zu einem lokalen Dienst umgeleitet wird, sollte er die lokale Proxy PID im localRedirectTargetPID-Mitglied der FWPS_CONNECT_REQUEST0-Struktur festlegen.

    4. Wenn Ihr Callout-Treiber zu einem lokalen Dienst umgeleitet wird, sollte er das von FwpsRedirectHandleCreate0 zurückgegebene Umleitungshandle im localRedirectHandle-Mitglied der FWPS_CONNECT_REQUEST0-Struktur festlegen.

  6. Rufen Sie FwpsApplyModifiedLayerData0 auf, um die vorgenommenen Änderungen an den Daten anzuwenden.

  7. In Ihrem Proxy-Dienst (der sich im Benutzer- oder Kernel-Modus befinden kann) müssen Sie die umgeleiteten Einträge und Kontexte abfragen, wie im folgenden Beispiel gezeigt:

    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. In Ihrem Proxy-Dienst (der sich im Benutzermodus oder im Kernel-Modus befinden kann) müssen Sie Einträge zur Umleitung auf dem Proxy-Verbindungssocket festlegen, wie im folgenden Beispiel gezeigt, um einen neuen ausgehenden Socket zu erstellen:

    proxySock = WSASocket(…);
    result = WSAIoctl(
                 proxySock,
                 SIO_SET_WFP_CONNECTION_REDIRECT_RECORDS,
                 redirectRecords, …);
    
  9. Rufen Sie FwpsReleaseClassifyHandle0 auf, um das in Schritt 2 abgerufene Klassifizierungshandle freizugeben.

  10. Rufen Sie FwpsRedirectHandleDestroy0 auf, um das in Schritt 1 abgerufene Handle zu zerstören.

Um eine Umleitung asynchron durchzuführen, muss ein Callout-Treiber die folgenden Schritte ausführen:

  1. Rufen Sie FwpsRedirectHandleCreate0 auf, um ein Handle abzurufen, das zur Umleitung von TCP-Verbindungen verwendet werden kann. (Dieser Schritt entfällt bei Windows 7 und früher).

  2. In Windows 8 und höher müssen Sie den Status der Umleitung der Verbindung mit der Funktion FwpsQueryConnectionRedirectState0 in Ihrem Callout-Treiber abfragen.

  3. Rufen Sie FwpsAcquireClassifyHandle0 auf, um ein Handle abzurufen, das für nachfolgende Funktionsaufrufe verwendet werden soll. Dieser Schritt sowie die Schritte 2 und 3 werden in der Callout-Funktion classifyFn des Callout-Treibers ausgeführt.

  4. Rufen Sie FwpsPendClassify0 auf, um die Klassifizierung in einen schwebenden Status zu versetzen, wie im folgenden Beispiel gezeigt:

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

Hinweis

Wenn Sie Windows 7 als Ziel haben, müssen Sie die folgenden Schritte in einer separaten Worker-Funktion ausführen. Wenn Sie Windows 8 oder höher verwenden, können Sie alle Schritte für die asynchrone Umleitung innerhalb der classifyFn ausführen und Schritt 5 ignorieren.

  1. Senden Sie das Klassifizierungshandle und die schreibbaren Daten der Schicht an eine andere Funktion zur asynchronen Verarbeitung. Die übrigen Schritte werden in dieser Funktion ausgeführt, nicht in der Implementierung von classifyFn im Callout-Treiber.

  2. Rufen Sie FwpsAcquireWritableLayerDataPointer0 auf, um die beschreibbare Datenstruktur für die Schicht zu erhalten, in der classifyFn aufgerufen wurde. Übertragen Sie den Parameter writableLayerDataOut auf die Struktur, die der Schicht entspricht, entweder FWPS_BIND_REQUEST0 oder FWPS_CONNECT_REQUEST0.

    Ab Windows 8 müssen Sie, wenn Ihr Callout-Treiber lokal umgeleitet wird, FwpsRedirectHandleCreate0 aufrufen, um das localRedirectHandle-Mitglied der FWPS_CONNECT_REQUEST0-Struktur zu füllen, damit das Proxy funktioniert.

  3. Speichern Sie alle callout-spezifischen Kontextinformationen in einer privaten Kontextstruktur, wie im folgenden Beispiel gezeigt:

    redirectContext->classifyHandle = classifyHandle;
    redirectContext->connectRequest = connectRequest;
    redirectContext->classifyOut = *classifyOut; // deep copy
    // store original destination IP, port
    
  4. Nehmen Sie bei Bedarf Änderungen an den Daten der Schicht vor.

  5. Rufen Sie FwpsApplyModifiedLayerData0 auf, um die vorgenommenen Änderungen an den Daten anzuwenden. Legen Sie das Flag FWPS_CLASSIFY_FLAG_REAUTHORIZE_IF_MODIFIED_BY_OTHERS fest, wenn Sie für den Fall, dass ein anderer Callout die Daten weiter verändert, erneut autorisiert werden möchten.

  6. Rufen Sie FwpsCompleteClassify0 auf, um den Klassifizierungsvorgang asynchron abzuschließen, wie im folgenden Beispiel gezeigt:

    FwpsCompleteClassify(
            redirectContext->classifyHandle,
            0,
            &redirectContext->classifyOut);
    classifyOut->actionType = FWP_ACTION_PERMIT;
    classifyOut->rights |= FWPS_RIGHT_ACTION_WRITE;
    
  7. Rufen Sie FwpsReleaseClassifyHandle0 auf, um das in Schritt 1 abgerufene Klassifizierungshandle freizugeben.

Behandlung der Umleitung von Verbindungen aus mehreren Aufrufen

Es ist möglich, dass mehr als ein Callout-Treiber eine Verbindungsumleitung für denselben Flow initiiert. Callouts, die eine Verbindungsumleitung durchführen, sollten sich der anderen Anfragen bewusst sein und entsprechend reagieren.

Das Flag FWPS_RIGHT_ACTION_WRITE sollte immer dann festgelegt werden, wenn ein Callout eine Klassifizierung vornimmt. Ihr Callout sollte auf das Flag FWPS_RIGHT_ACTION_WRITE testen, um zu prüfen, ob Ihr Callout das Recht hat, eine Aktion zurückzugeben. Wenn dieses Flag nicht festgelegt ist, kann Ihr Callout trotzdem eine FWP_ACTION_BLOCK-Aktion zurückgeben, um ein Veto gegen eine FWP_ACTION_PERMIT-Aktion einzulegen, die von einem früheren Callout zurückgegeben wurde.

In Windows 8 und höher muss Ihr Callout-Treiber den Status der Umleitung der Verbindung abfragen (um festzustellen, ob Ihr Callout-Treiber oder ein anderer Callout-Treiber ihn geändert hat), indem er die Funktion FwpsQueryConnectionRedirectState0 verwendet. Wenn die Verbindung von Ihrem Callout-Treiber umgeleitet wird oder wenn sie zuvor von Ihrem Callout-Treiber umgeleitet wurde, sollte der Callout-Treiber nichts unternehmen. Andernfalls sollte er auch auf eine lokale Umleitung prüfen, wie im folgenden Beispiel gezeigt:

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

Wenn die Verbindung zu einem lokalen Proxy besteht, sollte Ihr Callout-Treiber nicht versuchen, die Verbindung umzuleiten.

Callout-Treiber, die eine Verbindungsumleitung verwenden, sollten sich in der ALE-Autorisierungs-Connect-Schicht (FWPS_LAYER_ALE_AUTH_CONNECT_V4 oder FWPS_LAYER_ALE_AUTH_CONNECT_V6) registrieren und die folgenden beiden Metadatenwerte auf Hinweise prüfen, bei denen das Flag FWP_CONDITION_FLAG_IS_CONNECTION_REDIRECTED festgelegt ist:

  • FWPS_METADATA_FIELD_LOCAL_REDIRECT_TARGET_PID enthält den Prozess-Identifikator für den Prozess, der für den umgeleiteten Flow verantwortlich ist.

  • FWPS_METADATA_FIELD_ORIGINAL_DESTINATION enthält die Adresse des ursprünglichen Ziels für den Flow.

Die Struktur FWPS_CONNECT_REQUEST0 enthält ein Mitglied namens localRedirectTargetPID. Damit eine Loopback-Connect-Umleitung gültig ist, muss dieses Feld die PID des Prozesses enthalten, der für den umgeleiteten Flow verantwortlich sein wird. Dies sind dieselben Daten, die die Engine in der ALE-Autorisierungsschicht als FWPS_METADATA_FIELD_LOCAL_REDIRECT_TARGET_ID weitergibt.

Ab Windows 8 muss der Proxy-Dienst die SIO_QUERY_WFP_CONNECTION_REDIRECT_RECORDS und SIO_QUERY_WFP_CONNECTION_REDIRECT_CONTEXT IOCTLs mit WSAIoctl gegen den ursprünglichen Endpunkt des Proxy-Dienstes ausgeben. Zusätzlich muss der IOCTL SIO_SET_WFP_CONNECTION_REDIRECT_RECORDS mit WSAIoctl auf dem neuen (Proxy) Socket ausgegeben werden.

WFP Versionsunabhängige Namen und zielspezifische Versionen von Windows