From ab944095747204bbcbe6feccbd6c4eb055e17016 Mon Sep 17 00:00:00 2001 From: Dmitry Kornilov Date: Wed, 19 Feb 2020 15:07:38 +0100 Subject: [PATCH] ProxyConnectionFactory should not ignore TLVs Signed-off-by: Dmitry Kornilov --- .../java/org/eclipse/jetty/io/EndPoint.java | 12 ++++- .../eclipse/jetty/io/ssl/SslConnection.java | 11 +++- .../jetty/server/ProxyConnectionFactory.java | 52 +++++++++++++++++-- .../jetty/server/ProxyProtocolTest.java | 33 ++++++++++-- 4 files changed, 98 insertions(+), 10 deletions(-) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java index f53417c3b37..09126f49124 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java @@ -95,7 +95,17 @@ import org.eclipse.jetty.util.thread.Invocable; */ public interface EndPoint extends Closeable { - + /** + * Marks an EndPoint that wraps another EndPoint. + */ + public interface Wrapper + { + /** + * @return The wrapped EndPoint + */ + EndPoint unwrap(); + } + /** * @return The local Inet address to which this EndPoint is bound, or null * if this EndPoint does not represent a network connection. diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java index 86123a2c991..4b6d5b06424 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java @@ -457,7 +457,7 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr return getEndPoint().flush(output); } - public class DecryptedEndPoint extends AbstractEndPoint + public class DecryptedEndPoint extends AbstractEndPoint implements EndPoint.Wrapper { private final Callback _incompleteWriteCallback = new IncompleteWriteCallback(); private Throwable _failure; @@ -469,6 +469,12 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr super.setIdleTimeout(-1); } + @Override + public EndPoint unwrap() + { + return getEndPoint(); + } + @Override public long getIdleTimeout() { @@ -682,7 +688,7 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr try { _underflown = false; - unwrapResult = unwrap(_sslEngine, _encryptedInput, appIn); + unwrapResult = SslConnection.this.unwrap(_sslEngine, _encryptedInput, appIn); } finally { @@ -1554,5 +1560,6 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr return String.format("SSL@%h.DEP.writeCallback", SslConnection.this); } } + } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java index 2460b5803eb..f10037a28c5 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java @@ -49,7 +49,7 @@ public class ProxyConnectionFactory extends DetectorConnectionFactory { public static final String TLS_VERSION = "TLS_VERSION"; private static final Logger LOG = Log.getLogger(ProxyConnectionFactory.class); - + public ProxyConnectionFactory() { this(null); @@ -366,9 +366,10 @@ public class ProxyConnectionFactory extends DetectorConnectionFactory { 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A }; + private final String _nextProtocol; private int _maxProxyHeader = 1024; - + private ProxyV2ConnectionFactory(String nextProtocol) { super("proxy"); @@ -649,6 +650,13 @@ public class ProxyConnectionFactory extends DetectorConnectionFactory } break; } + // PP2_TYPE_MIN_CUSTOM .. PP2_TYPE_MAX_CUSTOM + case 0xE0: case 0xE1: case 0xE2: case 0xE3: + case 0xE4: case 0xE5: case 0xE6: case 0xE7: + case 0xE8: case 0xE9: case 0xEA: case 0xEB: + case 0xEC: case 0xED: case 0xEE: case 0xEF: + proxyEndPoint.setCustomValue(type, value); + break; case 0x01: // PP2_TYPE_ALPN case 0x02: // PP2_TYPE_AUTHORITY case 0x03: // PP2_TYPE_CRC32C @@ -751,11 +759,15 @@ public class ProxyConnectionFactory extends DetectorConnectionFactory } } - public static class ProxyEndPoint extends AttributesMap implements EndPoint + public static class ProxyEndPoint extends AttributesMap implements EndPoint, EndPoint.Wrapper { + private static final int PP2_TYPE_MIN_CUSTOM = 0xE0; + private static final int PP2_TYPE_MAX_CUSTOM = 0xEF; + private final EndPoint _endp; private final InetSocketAddress _remote; private final InetSocketAddress _local; + private byte[][] customValues; public ProxyEndPoint(EndPoint endp, InetSocketAddress remote, InetSocketAddress local) { @@ -764,6 +776,40 @@ public class ProxyConnectionFactory extends DetectorConnectionFactory _local = local; } + public EndPoint unwrap() + { + return _endp; + } + + /** + * Sets a custom TLV vector. See section 2.2.7 of the PROXY + * protocol specification. + * + * @param type must be between 0xE0..0xEF inclusive. + * @param value the custom value + */ + public synchronized void setCustomValue(int type, byte[] value) + { + int index = type - PP2_TYPE_MIN_CUSTOM; + if (customValues == null) + { + customValues = new byte[PP2_TYPE_MAX_CUSTOM - PP2_TYPE_MIN_CUSTOM + 1][]; + } + customValues[index] = value; + } + + /** + * Gets a custom TLV vector. + * + * @param type must be between 0xE0..0xEF inclusive. + * @return the custom value or null if not set + */ + public synchronized byte[] getCustomValue(int type) + { + return customValues == null ? null + : customValues[type - PP2_TYPE_MIN_CUSTOM]; + } + @Override public void close(Throwable cause) { 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 index 3cffef8c297..dcbdc9f69c0 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ProxyProtocolTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ProxyProtocolTest.java @@ -25,10 +25,14 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; import java.nio.charset.StandardCharsets; +import java.util.Arrays; + import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.server.ProxyConnectionFactory.ProxyEndPoint; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.util.TypeUtil; import org.junit.jupiter.api.AfterEach; @@ -118,15 +122,29 @@ public class ProxyProtocolTest { final String remoteAddr = "192.168.0.1"; final int remotePort = 12345; + final byte[] customE0 = new byte[] {1, 2}; + final byte[] customE1 = new byte[] {-1, -1, -1}; + start(new AbstractHandler() { @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - if (remoteAddr.equals(request.getRemoteAddr()) && + if (validateEndPoint(baseRequest) && + remoteAddr.equals(request.getRemoteAddr()) && remotePort == request.getRemotePort()) baseRequest.setHandled(true); } + + private boolean validateEndPoint(Request request) + { + HttpConnection con = (HttpConnection)request.getAttribute(HttpConnection.class.getName()); + EndPoint endPoint = con.getEndPoint(); + ProxyEndPoint proxyEndPoint = (ProxyEndPoint)endPoint; + return Arrays.equals(customE0, proxyEndPoint.getCustomValue(0xE0)) && + Arrays.equals(customE1, proxyEndPoint.getCustomValue(0xE1)) && + proxyEndPoint.getCustomValue(0xE2) == null; + } }); try (Socket socket = new Socket("localhost", connector.getLocalPort())) @@ -141,8 +159,8 @@ public class ProxyProtocolTest // 0x1 : AF_INET 0x1 : STREAM. Address length is 2*4 + 2*2 = 12 bytes. "11" + - // length of remaining header (4+4+2+2+6+3 = 21) - "0015" + + // length of remaining header (4+4+2+2+3+6+5+6 = 32) + "0020" + // uint32_t src_addr; uint32_t dst_addr; uint16_t src_port; uint16_t dst_port; "C0A80001" + @@ -154,7 +172,13 @@ public class ProxyProtocolTest "040000" + // NOOP value ABCDEF - "040003ABCDEF"; + "040003ABCDEF" + + + // Custom 0xEO {0x01,0x02} + "E000020102" + + + // Custom 0xE1 {0xFF,0xFF,0xFF} + "E10003FFFFFF"; String request1 = "GET /1 HTTP/1.1\r\n" + @@ -193,4 +217,5 @@ public class ProxyProtocolTest } } } + }