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

ProxyHandler ignores the overridden sourceAddress set by ProxyPeerAddressHandler

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Done
    • Icon: Major Major
    • 1.4.24.Final, 2.0.4.Final
    • 2.0.3.Final
    • Proxy
    • None
    • Hide

      Setup two Undertow instances:

      • Application
      • Proxy - has ProxyHandler behind ProxyPeerAddressHandler
      import io.undertow.Handlers;
      import io.undertow.Undertow;
      import io.undertow.server.handlers.proxy.LoadBalancingProxyClient;
      import io.undertow.servlet.Servlets;
      import io.undertow.servlet.api.DeploymentInfo;
      import io.undertow.servlet.api.DeploymentManager;
      
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      import java.net.URI;
      
      public class App {
          public static void main(String[] args) throws ServletException {
              // Application
              DeploymentInfo servletBuilder = Servlets.deployment()
                      .setClassLoader(App.class.getClassLoader())
                      .setContextPath("/")
                      .setDeploymentName("test.war")
                      .addServlets(Servlets.servlet("x-forwarded-for-printer", RequestPrinter.class).addMapping("/*"));
              DeploymentManager manager = Servlets.defaultContainer().addDeployment(servletBuilder);
              manager.deploy();
      
              Undertow applicationServer = Undertow.builder()
                      .addHttpListener(8080, "localhost")
                      .setHandler(manager.start())
                      .build();
              applicationServer.start();
      
              // Load Balancer
              LoadBalancingProxyClient proxyClient = new LoadBalancingProxyClient();
              proxyClient.addHost(URI.create("http://localhost:8080"));
              Undertow loadBalancer = Undertow.builder()
                      .addHttpListener(8180, "localhost")
                      // ProxyHandler behind ProxyPeerAddressHandler
                      .setHandler(Handlers.proxyPeerAddress(Handlers.proxyHandler(proxyClient)))
                      .build();
      
              loadBalancer.start();
          }
      
          public static class RequestPrinter extends HttpServlet {
              @Override
              protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                  resp.getOutputStream().println("X-Forwarded-For: " + req.getHeader("X-Forwarded-For"));
              }
          }
      }
      

      Pretend that we are a load balancer and the real client ip is 1.2.3.4:

      curl -H 'X-Forwarded-For: 1.2.3.4' http://localhost:8180/
      

      Expected result:

      X-Forwarded-For: 1.2.3.4
      

      Actual result:

      X-Forwarded-For: 127.0.0.1
      
      Show
      Setup two Undertow instances: Application Proxy - has ProxyHandler behind ProxyPeerAddressHandler import io.undertow.Handlers; import io.undertow.Undertow; import io.undertow.server.handlers.proxy.LoadBalancingProxyClient; import io.undertow.servlet.Servlets; import io.undertow.servlet.api.DeploymentInfo; import io.undertow.servlet.api.DeploymentManager; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URI; public class App { public static void main( String [] args) throws ServletException { // Application DeploymentInfo servletBuilder = Servlets.deployment() .setClassLoader(App. class. getClassLoader()) .setContextPath( "/" ) .setDeploymentName( "test.war" ) .addServlets(Servlets.servlet( "x-forwarded- for -printer" , RequestPrinter.class).addMapping( "/*" )); DeploymentManager manager = Servlets.defaultContainer().addDeployment(servletBuilder); manager.deploy(); Undertow applicationServer = Undertow.builder() .addHttpListener(8080, "localhost" ) .setHandler(manager.start()) .build(); applicationServer.start(); // Load Balancer LoadBalancingProxyClient proxyClient = new LoadBalancingProxyClient(); proxyClient.addHost(URI.create( "http: //localhost:8080" )); Undertow loadBalancer = Undertow.builder() .addHttpListener(8180, "localhost" ) // ProxyHandler behind ProxyPeerAddressHandler .setHandler(Handlers.proxyPeerAddress(Handlers.proxyHandler(proxyClient))) .build(); loadBalancer.start(); } public static class RequestPrinter extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getOutputStream().println( "X-Forwarded-For: " + req.getHeader( "X-Forwarded-For" )); } } } Pretend that we are a load balancer and the real client ip is 1.2.3.4: curl -H 'X-Forwarded-For: 1.2.3.4' http://localhost:8180/ Expected result: X-Forwarded-For: 1.2.3.4 Actual result: X-Forwarded-For: 127.0.0.1

      Our application is setup like this:

      We obviously need to know the real client address inside the application. This is normally achieved by forwarding the client address inside the X-Forwarded-For header through the load balancer chain.

      Undertow, when used as a load balancer / proxy, provides two ways to handle X-Forwarded-* headers that arrive within the request (from a load balancer that handles the request before Undertow):

      1. reuseXForwarded setting of ProxyHandler - "inspect already existing X-Forwarded-* headers, append information about the current node"
      2. ProxyPeerAddressHandler - "take X-Forwarded-* headers and pretend that they contain real client address, protocol, etc"

      The problems:

      • reuseXForwarded cannot be set when Undertow's mod-proxy filter is used, because ProxyHandler instance gets dynamically built / instantiated by ModCluster and there's no possibility to control reuseXForwarded's value
      • ProxyHandler, when used together with ProxyPeerAddressHandler (in Wildfly, this can be done by setting "proxy-address-forwarding" of "http-listener" to true), does not use sourceAddress set by ProxyPeerAddressHandler, but rather reads exchange.getConnection().getPeerAddress(). This ticket is about this bug.

              sdouglas1@redhat.com Stuart Douglas (Inactive)
              pfyod_jira Pavels Fjodorovs (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

                Created:
                Updated:
                Resolved: