Uploaded image for project: 'Undertow'
  1. Undertow
  2. UNDERTOW-1850

ProxyHandler not working correctly with chained proxy

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: Major Major
    • None
    • 2.2.4.Final
    • Proxy
    • None
    • Hide
      Undertow app = Undertow.builder().addHttpListener(8082, "localhost").setHandler(new HttpHandler() {
         public void handleRequest(HttpServerExchange exchange) throws Exception {
            exchange.getResponseSender().send("Hello world!");
         }
      }).build();
      app.start();
      
      // simulates the corporate proxy
      Undertow proxy2 = Undertow.builder().addHttpListener(8081, "localhost").setHandler(new ConnectHandler(ResponseCodeHandler.HANDLE_404)).build();
      proxy2.start();
      
      ProxyClient proxyClient = new LoadBalancingProxyClient().addHost(new URI("http://localhost:8081"));
      final HttpHandler proxyHandler = ProxyHandler.builder().setProxyClient(proxyClient)
         .setRewriteHostHeader(true)
         .setReuseXForwarded(true)
         .setNext(ResponseCodeHandler.HANDLE_404).build();
      final HttpHandler dumpingHandler = new RequestDumpingHandler(proxyHandler);
      Undertow proxy1 = Undertow.builder().addHttpListener(8080, "localhost").setHandler(dumpingHandler).build();
      proxy1.start();
      
      curl -vvv -x http://localhost:8080 -p https://localhost:8082
      
      Show
      Undertow app = Undertow.builder().addHttpListener(8082, "localhost" ).setHandler( new HttpHandler() { public void handleRequest(HttpServerExchange exchange) throws Exception { exchange.getResponseSender().send( "Hello world!" ); } }).build(); app.start(); // simulates the corporate proxy Undertow proxy2 = Undertow.builder().addHttpListener(8081, "localhost" ).setHandler( new ConnectHandler(ResponseCodeHandler.HANDLE_404)).build(); proxy2.start(); ProxyClient proxyClient = new LoadBalancingProxyClient().addHost( new URI( "http: //localhost:8081" )); final HttpHandler proxyHandler = ProxyHandler.builder().setProxyClient(proxyClient) .setRewriteHostHeader( true ) .setReuseXForwarded( true ) .setNext(ResponseCodeHandler.HANDLE_404).build(); final HttpHandler dumpingHandler = new RequestDumpingHandler(proxyHandler); Undertow proxy1 = Undertow.builder().addHttpListener(8080, "localhost" ).setHandler(dumpingHandler).build(); proxy1.start(); curl -vvv -x http: //localhost:8080 -p https://localhost:8082
    • Undefined

      Not sure if this is actually supported but it seems to work too well to be accidential. We want to use Undertow in our Java app to act as a proxy server which then connects to another (corporate) proxy server using the CONNECT method:

      client --> Undertow proxy server --> corporate proxy --> internet

      I tried using a ProxyHandler and configured the corporate proxy via a LoadBalancingProxyClient. When sending a request via the proxy chain, a CONNECT tunnel is successfully created from Undertow to the target site. However, Undertow does not yet send a 200 Connection Established to the client. When using Squid to simulate the corporate proxy, there is a ~30s delay (probably some timeout on the squid side) and after that Undertow sends a 200 response to the client. The client the tries to do a TLS handshake but does not succeed because (I think) the tunnel is already closed. In the code snipped I attached, there is no such delay but other than that the problem manifests in the same way.

      curl output:

      $ curl -vvv -x http://localhost:8080 -p https://localhost:8082
        % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                       Dload  Upload   Total   Spent    Left  Speed
        0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying ::1:8080...
      *   Trying 127.0.0.1:8080...
      * Connected to localhost (127.0.0.1) port 8080 (#0)
      * allocate connect buffer!
      * Establish HTTP proxy tunnel to localhost:8082
      > CONNECT localhost:8082 HTTP/1.1
      > Host: localhost:8082
      > User-Agent: curl/7.70.0
      > Proxy-Connection: Keep-Alive
      >
      < HTTP/1.1 200 OK
      < Connection: close
      < Content-Length: 0
      * Ignoring Content-Length in CONNECT 200 response
      < Date: Tue, 23 Feb 2021 13:43:17 GMT
      <
      * Proxy replied 200 to CONNECT request
      * CONNECT phase completed!
      * ALPN, offering h2
      * ALPN, offering http/1.1
      * successfully set certificate verify locations:
      *   CAfile: C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt
        CApath: none
      } [5 bytes data]
      * TLSv1.3 (OUT), TLS handshake, Client hello (1):
      } [512 bytes data]
      * OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to localhost:8082
      * Closing connection 0
      curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to localhost:8082
      

      Wireshark (with Squid as corporate proxy on Port 3128 trying to get microsoft.com):

      Undertow Log:

      14:43:07.947 [main] DEBUG io.undertow - Configuring listener with protocol HTTP for interface localhost and port 8080
      14:43:07.947 [XNIO-3 I/O-10] DEBUG org.xnio.nio - Started channel thread 'XNIO-3 I/O-10', selector sun.nio.ch.WindowsSelectorImpl@9f5bf45
      14:43:07.947 [XNIO-3 Accept] DEBUG org.xnio.nio - Started channel thread 'XNIO-3 Accept', selector sun.nio.ch.WindowsSelectorImpl@661884b4
      14:43:17.479 [XNIO-3 I/O-11] DEBUG io.undertow.server.handlers.proxy - Sending request ClientRequest{path='localhost:8082', method=CONNECT, protocol=HTTP/1.1} to target localhost/127.0.0.1:8081 for exchange HttpServerExchange{ CONNECT localhost:8082}
      14:43:17.484 [XNIO-3 I/O-11] DEBUG io.undertow.server.handlers.proxy - Sent request ClientRequest{path='localhost:8082', method=CONNECT, protocol=HTTP/1.1} to target kubernetes.docker.internal for exchange HttpServerExchange{ CONNECT localhost:8082}
      14:43:17.484 [XNIO-3 I/O-11] DEBUG i.u.client.http.HttpClientExchange - request terminated for request to localhost/127.0.0.1:8081 localhost:8082
      14:43:17.484 [XNIO-3 I/O-11] DEBUG io.undertow.server.handlers.proxy - Received response ClientResponse{responseHeaders={Connection=[keep-alive], Content-Length=[0], Date=[Tue, 23 Feb 2021 13:43:17 GMT]}, responseCode=200, status='OK', protocol=HTTP/1.1} for request ClientRequest{path='localhost:8082', method=CONNECT, protocol=HTTP/1.1} for exchange HttpServerExchange{ CONNECT localhost:8082}
      14:43:17.500 [XNIO-3 I/O-11] DEBUG i.u.client.http.HttpClientExchange - response terminated for request to localhost/127.0.0.1:8081 localhost:8082
      14:43:17.500 [XNIO-3 I/O-11] DEBUG i.u.client.http.HttpClientConnection - exchange complete in connection to localhost/127.0.0.1:8081
      14:43:17.500 [XNIO-3 I/O-11] INFO  io.undertow.request.dump - 
      ----------------------------REQUEST---------------------------
                     URI=localhost:8082
       characterEncoding=null
           contentLength=-1
             contentType=null
                  header=Proxy-Connection=Keep-Alive
                  header=User-Agent=curl/7.70.0
                  header=Host=localhost:8082
                  locale=[]
                  method=CONNECT
                protocol=HTTP/1.1
             queryString=
              remoteAddr=/127.0.0.1:55977
              remoteHost=kubernetes.docker.internal
                  scheme=http
                    host=localhost:8082
              serverPort=8080
                isSecure=false
      --------------------------RESPONSE--------------------------
           contentLength=0
             contentType=null
                  header=Connection=close
                  header=Content-Length=0
                  header=Date=Tue, 23 Feb 2021 13:43:17 GMT
                  status=200==============================================================
      14:44:17.542 [XNIO-1 I/O-4] DEBUG io.undertow.request - Timing out idle connection from /127.0.0.1:55979
      

        1. capture.pcapng
          6 kB
          Sebastian Suminski
        2. image-2021-02-23-14-01-33-319.png
          7 kB
          Sebastian Suminski

              flaviarnn Flavia Rainone
              sesu-bio Sebastian Suminski (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

                Created:
                Updated: