ProxyConnectionFactory should not ignore TLVs

Signed-off-by: Dmitry Kornilov <dmitry.kornilov@oracle.com>
This commit is contained in:
Dmitry Kornilov 2020-02-19 15:07:38 +01:00
parent 5fe202f29f
commit ab94409574
4 changed files with 98 additions and 10 deletions

View File

@ -95,7 +95,17 @@ import org.eclipse.jetty.util.thread.Invocable;
*/ */
public interface EndPoint extends Closeable public interface EndPoint extends Closeable
{ {
/**
* Marks an <code>EndPoint</code> that wraps another <code>EndPoint</code>.
*/
public interface Wrapper
{
/**
* @return The wrapped <code>EndPoint</code>
*/
EndPoint unwrap();
}
/** /**
* @return The local Inet address to which this <code>EndPoint</code> is bound, or <code>null</code> * @return The local Inet address to which this <code>EndPoint</code> is bound, or <code>null</code>
* if this <code>EndPoint</code> does not represent a network connection. * if this <code>EndPoint</code> does not represent a network connection.

View File

@ -457,7 +457,7 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
return getEndPoint().flush(output); return getEndPoint().flush(output);
} }
public class DecryptedEndPoint extends AbstractEndPoint public class DecryptedEndPoint extends AbstractEndPoint implements EndPoint.Wrapper
{ {
private final Callback _incompleteWriteCallback = new IncompleteWriteCallback(); private final Callback _incompleteWriteCallback = new IncompleteWriteCallback();
private Throwable _failure; private Throwable _failure;
@ -469,6 +469,12 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
super.setIdleTimeout(-1); super.setIdleTimeout(-1);
} }
@Override
public EndPoint unwrap()
{
return getEndPoint();
}
@Override @Override
public long getIdleTimeout() public long getIdleTimeout()
{ {
@ -682,7 +688,7 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
try try
{ {
_underflown = false; _underflown = false;
unwrapResult = unwrap(_sslEngine, _encryptedInput, appIn); unwrapResult = SslConnection.this.unwrap(_sslEngine, _encryptedInput, appIn);
} }
finally finally
{ {
@ -1554,5 +1560,6 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
return String.format("SSL@%h.DEP.writeCallback", SslConnection.this); return String.format("SSL@%h.DEP.writeCallback", SslConnection.this);
} }
} }
} }
} }

View File

@ -49,7 +49,7 @@ public class ProxyConnectionFactory extends DetectorConnectionFactory
{ {
public static final String TLS_VERSION = "TLS_VERSION"; public static final String TLS_VERSION = "TLS_VERSION";
private static final Logger LOG = Log.getLogger(ProxyConnectionFactory.class); private static final Logger LOG = Log.getLogger(ProxyConnectionFactory.class);
public ProxyConnectionFactory() public ProxyConnectionFactory()
{ {
this(null); this(null);
@ -366,9 +366,10 @@ public class ProxyConnectionFactory extends DetectorConnectionFactory
{ {
0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A
}; };
private final String _nextProtocol; private final String _nextProtocol;
private int _maxProxyHeader = 1024; private int _maxProxyHeader = 1024;
private ProxyV2ConnectionFactory(String nextProtocol) private ProxyV2ConnectionFactory(String nextProtocol)
{ {
super("proxy"); super("proxy");
@ -649,6 +650,13 @@ public class ProxyConnectionFactory extends DetectorConnectionFactory
} }
break; 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 0x01: // PP2_TYPE_ALPN
case 0x02: // PP2_TYPE_AUTHORITY case 0x02: // PP2_TYPE_AUTHORITY
case 0x03: // PP2_TYPE_CRC32C 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 EndPoint _endp;
private final InetSocketAddress _remote; private final InetSocketAddress _remote;
private final InetSocketAddress _local; private final InetSocketAddress _local;
private byte[][] customValues;
public ProxyEndPoint(EndPoint endp, InetSocketAddress remote, InetSocketAddress local) public ProxyEndPoint(EndPoint endp, InetSocketAddress remote, InetSocketAddress local)
{ {
@ -764,6 +776,40 @@ public class ProxyConnectionFactory extends DetectorConnectionFactory
_local = local; _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 @Override
public void close(Throwable cause) public void close(Throwable cause)
{ {

View File

@ -25,10 +25,14 @@ import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.Socket; import java.net.Socket;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; 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.server.handler.AbstractHandler;
import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.TypeUtil;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
@ -118,15 +122,29 @@ public class ProxyProtocolTest
{ {
final String remoteAddr = "192.168.0.1"; final String remoteAddr = "192.168.0.1";
final int remotePort = 12345; final int remotePort = 12345;
final byte[] customE0 = new byte[] {1, 2};
final byte[] customE1 = new byte[] {-1, -1, -1};
start(new AbstractHandler() start(new AbstractHandler()
{ {
@Override @Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException 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()) remotePort == request.getRemotePort())
baseRequest.setHandled(true); 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())) 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. // 0x1 : AF_INET 0x1 : STREAM. Address length is 2*4 + 2*2 = 12 bytes.
"11" + "11" +
// length of remaining header (4+4+2+2+6+3 = 21) // length of remaining header (4+4+2+2+3+6+5+6 = 32)
"0015" + "0020" +
// uint32_t src_addr; uint32_t dst_addr; uint16_t src_port; uint16_t dst_port; // uint32_t src_addr; uint32_t dst_addr; uint16_t src_port; uint16_t dst_port;
"C0A80001" + "C0A80001" +
@ -154,7 +172,13 @@ public class ProxyProtocolTest
"040000" + "040000" +
// NOOP value ABCDEF // NOOP value ABCDEF
"040003ABCDEF"; "040003ABCDEF" +
// Custom 0xEO {0x01,0x02}
"E000020102" +
// Custom 0xE1 {0xFF,0xFF,0xFF}
"E10003FFFFFF";
String request1 = String request1 =
"GET /1 HTTP/1.1\r\n" + "GET /1 HTTP/1.1\r\n" +
@ -193,4 +217,5 @@ public class ProxyProtocolTest
} }
} }
} }
} }