From f254dbc0b6d54e47e4aadf8dfd5ce7800874e9e0 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 25 Nov 2016 08:56:15 +0100 Subject: [PATCH] Fixes #1130 - PROXY protocol support reports incorrect remote address. --- .../org/eclipse/jetty/server/HttpChannel.java | 5 +- .../eclipse/jetty/server/HttpConnection.java | 27 +++++ .../jetty/server/ProxyProtocolTest.java | 114 ++++++++++++++++++ 3 files changed, 142 insertions(+), 4 deletions(-) create mode 100644 jetty-server/src/test/java/org/eclipse/jetty/server/ProxyProtocolTest.java diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index 8093f46d7ed..23f11fc87a5 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -519,10 +519,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H @Override public void proxied(String protocol, String sAddr, String dAddr, int sPort, int dPort) { - _request.setAttribute("PROXY", protocol); - _request.setServerName(sAddr); - _request.setServerPort(dPort); - _request.setRemoteAddr(InetSocketAddress.createUnresolved(sAddr,sPort)); + throw new UnsupportedOperationException(); } @Override diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index c489ae9b3da..59add23d6f4 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.server; import java.io.IOException; +import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.WritePendingException; import java.util.concurrent.RejectedExecutionException; @@ -500,11 +501,37 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http protected class HttpChannelOverHttp extends HttpChannel { + private InetSocketAddress _localAddr; + private InetSocketAddress _remoteAddr; + public HttpChannelOverHttp(Connector connector, HttpConfiguration config, EndPoint endPoint, HttpTransport transport, HttpInput input) { super(connector,config,endPoint,transport,input); } + @Override + public void proxied(String protocol, String remoteAddress, String localAddress, int remotePort, int localPort) + { + _localAddr = InetSocketAddress.createUnresolved(localAddress, localPort); + _remoteAddr = InetSocketAddress.createUnresolved(remoteAddress, remotePort); + } + + @Override + public InetSocketAddress getLocalAddress() + { + if (_localAddr != null) + return _localAddr; + return super.getLocalAddress(); + } + + @Override + public InetSocketAddress getRemoteAddress() + { + if (_remoteAddr != null) + return _remoteAddr; + return super.getRemoteAddress(); + } + @Override public void earlyEOF() { diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ProxyProtocolTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ProxyProtocolTest.java new file mode 100644 index 00000000000..ea3f43e79b5 --- /dev/null +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ProxyProtocolTest.java @@ -0,0 +1,114 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.server; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.Socket; +import java.nio.charset.StandardCharsets; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; + +public class ProxyProtocolTest +{ + private Server server; + private ServerConnector connector; + + private void start(Handler handler) throws Exception + { + server = new Server(); + connector = new ServerConnector(server); + server.addConnector(connector); + server.setHandler(handler); + server.start(); + } + + @After + public void destroy() throws Exception + { + if (server != null) + server.stop(); + } + + @Test + public void testProxyProtocol() throws Exception + { + final String remoteAddr = "192.168.0.0"; + final int remotePort = 12345; + start(new AbstractHandler() + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + if (remoteAddr.equals(request.getRemoteAddr()) && + remotePort == request.getRemotePort()) + baseRequest.setHandled(true); + } + }); + + try (Socket socket = new Socket("localhost", connector.getLocalPort())) + { + String request1 = "" + + "PROXY TCP4 " + remoteAddr + " 127.0.0.0 " + remotePort + " 8080\r\n" + + "GET /1 HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "\r\n"; + OutputStream output = socket.getOutputStream(); + output.write(request1.getBytes(StandardCharsets.UTF_8)); + output.flush(); + + InputStream input = socket.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)); + String response1 = reader.readLine(); + Assert.assertTrue(response1.startsWith("HTTP/1.1 200 ")); + while (true) + { + if (reader.readLine().isEmpty()) + break; + } + + // Send a second request to verify that the proxied IP is retained. + String request2 = "" + + "GET /2 HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "Connection: close\r\n" + + "\r\n"; + output.write(request2.getBytes(StandardCharsets.UTF_8)); + output.flush(); + + String response2 = reader.readLine(); + Assert.assertTrue(response2.startsWith("HTTP/1.1 200 ")); + while (true) + { + if (reader.readLine() == null) + break; + } + } + } +}