Comment connecter un socket SSL via un proxy HTTP?

J'essaie d'utiliser Java (Android) pour me connecter à un serveur avec un socket SSL. Notez qu'il ne s'agit pas de données HTTP. C'est un protocole propriétaire avec un mélange de texte et de données binaires.

Je souhaite relayer cette connexion SSL via un proxy HTTP, mais je suis confronté à beaucoup de problèmes. En ce moment, le scénario que j'utilise et que mon navigateur semble utiliser avec un proxy squid est le suivant

  • Android - La découverte Bluetooth ne trouve aucun périphérique
  • Comment créer une bannière admob par programme?
  • Obtenir une chaîne de package à partir d'un manifeste d'Android
  • Android Obtenez le chemin Uri pour déposer auprès de Google Drive
  • Comment faire n'importe quel code de couleur html semi transparent
  • GetHeight () vs getLayoutParams (). Hauteur
  • [Client] -> [connexion http] -> [proxy] -> [connexion ssl] -> [serveur]

    Cela fonctionne pour le navigateur, car après la connexion ssl, la négociation TLS se déroule immédiatement. Cependant, mon code ne semble pas le faire.

    final TrustManager[] trustManager = new TrustManager[] { new MyX509TrustManager() }; final SSLContext context = SSLContext.getInstance("TLS"); context.init(null, trustManager, null); SSLSocketFactory factory = context.getSocketFactory(); Socket s = factory.createSocket(new Socket(proxy_ip, 3128), hostName, port, true); 

    Le problème que j'ai est que createSocket NE JAMAIS RETOURNER. Avec un vidage wireshark de la machine proxy, je peux voir qu'une prise de main tcp a lieu entre le proxy et le serveur. Avec les vidages des sessions Web, je peux voir que le client déclenche habituellement une poignée de main SSL à ce stade, ce qui ne se produit pas dans mon scénario.

    Ce n'est pas un problème avec le gestionnaire de confiance, car le certificat ne me reviens jamais et il n'est jamais validé.

    MODIFIER :

    Après discussion, c'est la version plus complète du code que j'essaie d'exécuter. Cette version ci-dessus avec le simple (nouveau Socket (…)) comme paramètre est quelque chose que j'ai essayé plus tard.

    La version originale du code que je tente de déboguer lance
    java.net.ConnectException: failed to connect to /192.168.1.100 (port 443): connect failed: ETIMEDOUT (Connection timed out)

    La séquence est comme suit (un peu simplifié à nouveau):

     final Socket proxySocket = new Socket(); proxySocket.connect(proxyAddress, 2000); // 2 seconds as the connection timeout for connecting to the proxy server [Start a thread and write to outputStream=socket.getOutputStream()] final String proxyRequest = String.format("CONNECT %s:%d HTTP/1.1\r\nProxy-Connection: keep-alive\r\nConnection: keep-alive\r\nHost: %s:%d\r\n\r\n", hostName, port, hostName, port); outputStream.close(); // Closing or not doesn't change anything [Stop using that thread and let it exit by reaching the end of its main function] 

    Ensuite, lisez la réponse avec le code suivant:

      final InputStreamReader isr = new InputStreamReader(proxySocket.getInputStream()); final BufferedReader br = new BufferedReader(isr); final String statusLine = br.readLine(); boolean proxyConnectSuccess = false; // readLine consumed the CRLF final Pattern statusLinePattern = Pattern.compile("^HTTP/\\d+\\.\\d+ (\\d\\d\\d) .*"); final Matcher statusLineMatcher = statusLinePattern.matcher(statusLine); if (statusLineMatcher.matches()) { final String statusCode = statusLineMatcher.group(1); if (null != statusCode && 0 < statusCode.length() && '2' == statusCode.charAt(0)) { proxyConnectSuccess = true; } } // Consume rest of proxy response String line; while ( "".equals((line = br.readLine())) == false ) { } 

    Je peux dire que ce code fonctionne car il fonctionne sans SSL. Le socket créé ici, proxySocket est celui qui est transmis à la fonction createSocket au lieu de simplement créer un nouveau sur la volée comme dans mon exemple d'origine.

    3 Solutions collect form web for “Comment connecter un socket SSL via un proxy HTTP?”

    java.net.Proxy ou les propriétés https.proxyHost/proxyPort , ne prennent en charge que HTTP proxying via HttpURLConnection, pas via un Socket.

    Pour que cela fonctionne pour un SSLSocket vous-même, il vous suffit de créer un socket en clair, émettre une commande HTTP CONNECT , vérifier la réponse pour 200, puis l'envelopper dans un SSLSocket.

    EDIT Lorsque vous envoyez la commande CONNECT, vous ne devez pas fermer le socket, bien sûr; Et lorsque vous lisez sa réponse, vous ne devez pas utiliser un BufferedReader, sinon vous allez perdre des données; Soit lisez la ligne à la main ou utilisez DataInputStream.readLine(), malgré sa dépréciation. Vous devez également suivre la RFC 2616 entièrement.

    Vous devez utiliser javax.net lib . Vous pouvez archiver sur votre cible en utilisant javax.net.ssl. * .

    Je pense que vous pouvez obtenir une solution en utilisant les documents oracle. Voici le lien pour cela.

    SSLSocketClientWithTunneling

    Je n'ai pas le temps de tester / écrire une solution ciblée maintenant, mais la mise à niveau du socket sur SSLSocket avec STARTTLS: recv failed semble couvrir le problème de base.

    Dans votre cas, vous devez vous connecter au proxy, émettre un proxy connect, puis mettre à niveau la connexion – essentiellement vous CONNECT prend la place des STARTTLS dans la question référencée, et la vérification de "670" n'est pas nécessaire.

    coAndroid est un fan Android de Google, tout sur les téléphones Android, Android Wear, Android Dev et Android Games Apps.