ProxyConnectionFactory should not ignore TLVs
Signed-off-by: Dmitry Kornilov <dmitry.kornilov@oracle.com>
This commit is contained in:
parent
5fe202f29f
commit
ab94409574
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue