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 dd64590fb39..e4d2ff75a17 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 @@ -39,10 +39,8 @@ import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; - -/* ------------------------------------------------------------ */ /** - * ConnectionFactory for the PROXY Protocol. + *

ConnectionFactory for the PROXY Protocol.

*

This factory can be placed in front of any other connection factory * to process the proxy v1 or v2 line before the normal protocol handling

* @@ -50,26 +48,26 @@ import org.eclipse.jetty.util.log.Logger; */ public class ProxyConnectionFactory extends AbstractConnectionFactory { - public static final String TLS_VERSION = "TLS_VERSION"; - private static final Logger LOG = Log.getLogger(ProxyConnectionFactory.class); - private final String _next; - private int _maxProxyHeader=1024; + public static final String TLS_VERSION = "TLS_VERSION"; - /* ------------------------------------------------------------ */ - /** Proxy Connection Factory that uses the next ConnectionFactory + private final String _next; + private int _maxProxyHeader = 1024; + + /** + * Proxy Connection Factory that uses the next ConnectionFactory * on the connector as the next protocol */ public ProxyConnectionFactory() { super("proxy"); - _next=null; + _next = null; } public ProxyConnectionFactory(String nextProtocol) { super("proxy"); - _next=nextProtocol; + _next = nextProtocol; } public int getMaxProxyHeader() @@ -85,34 +83,34 @@ public class ProxyConnectionFactory extends AbstractConnectionFactory @Override public Connection newConnection(Connector connector, EndPoint endp) { - String next=_next; - if (next==null) + String next = _next; + if (next == null) { - for (Iterator i = connector.getProtocols().iterator();i.hasNext();) + for (Iterator i = connector.getProtocols().iterator(); i.hasNext(); ) { - String p=i.next(); + String p = i.next(); if (getProtocol().equalsIgnoreCase(p)) { - next=i.next(); + next = i.next(); break; } } } - return new ProxyProtocolV1orV2Connection(endp,connector,next); + return new ProxyProtocolV1orV2Connection(endp, connector, next); } - + public class ProxyProtocolV1orV2Connection extends AbstractConnection { private final Connector _connector; private final String _next; private ByteBuffer _buffer = BufferUtil.allocate(16); - + protected ProxyProtocolV1orV2Connection(EndPoint endp, Connector connector, String next) { - super(endp,connector.getExecutor()); - _connector=connector; - _next=next; + super(endp, connector.getExecutor()); + _connector = connector; + _next = next; } @Override @@ -127,16 +125,16 @@ public class ProxyConnectionFactory extends AbstractConnectionFactory { try { - while(BufferUtil.space(_buffer)>0) + while (BufferUtil.space(_buffer) > 0) { // Read data - int fill=getEndPoint().fill(_buffer); - if (fill<0) + int fill = getEndPoint().fill(_buffer); + if (fill < 0) { getEndPoint().shutdownOutput(); return; } - if (fill==0) + if (fill == 0) { fillInterested(); return; @@ -144,28 +142,28 @@ public class ProxyConnectionFactory extends AbstractConnectionFactory } // Is it a V1? - switch(_buffer.get(0)) + switch (_buffer.get(0)) { case 'P': { - ProxyProtocolV1Connection v1 = new ProxyProtocolV1Connection(getEndPoint(),_connector,_next,_buffer); + ProxyProtocolV1Connection v1 = new ProxyProtocolV1Connection(getEndPoint(), _connector, _next, _buffer); getEndPoint().upgrade(v1); return; } case 0x0D: { - ProxyProtocolV2Connection v2 = new ProxyProtocolV2Connection(getEndPoint(),_connector,_next,_buffer); + ProxyProtocolV2Connection v2 = new ProxyProtocolV2Connection(getEndPoint(), _connector, _next, _buffer); getEndPoint().upgrade(v2); return; } - default: - LOG.warn("Not PROXY protocol for {}",getEndPoint()); - close(); + default: + LOG.warn("Not PROXY protocol for {}", getEndPoint()); + close(); } } catch (Throwable x) { - LOG.warn("PROXY error for "+getEndPoint(),x); + LOG.warn("PROXY error for " + getEndPoint(), x); close(); } } @@ -177,20 +175,20 @@ public class ProxyConnectionFactory extends AbstractConnectionFactory // 98765432109876543210987654321 // PROXY P R.R.R.R L.L.L.L R Lrn - private final int[] __size = {29,23,21,13,5,3,1}; + private final int[] __size = {29, 23, 21, 13, 5, 3, 1}; private final Connector _connector; private final String _next; - private final StringBuilder _builder=new StringBuilder(); - private final String[] _field=new String[6]; + private final StringBuilder _builder = new StringBuilder(); + private final String[] _field = new String[6]; private int _fields; private int _length; - protected ProxyProtocolV1Connection(EndPoint endp, Connector connector, String next,ByteBuffer buffer) + protected ProxyProtocolV1Connection(EndPoint endp, Connector connector, String next, ByteBuffer buffer) { - super(endp,connector.getExecutor()); - _connector=connector; - _next=next; - _length=buffer.remaining(); + super(endp, connector.getExecutor()); + _connector = connector; + _next = next; + _length = buffer.remaining(); parse(buffer); } @@ -200,24 +198,23 @@ public class ProxyConnectionFactory extends AbstractConnectionFactory super.onOpen(); fillInterested(); } - - + private boolean parse(ByteBuffer buffer) { // parse fields while (buffer.hasRemaining()) { byte b = buffer.get(); - if (_fields<6) + if (_fields < 6) { - if (b==' ' || b=='\r' && _fields==5) + if (b == ' ' || b == '\r' && _fields == 5) { - _field[_fields++]=_builder.toString(); + _field[_fields++] = _builder.toString(); _builder.setLength(0); } - else if (b<' ') + else if (b < ' ') { - LOG.warn("Bad character {} for {}",b&0xFF,getEndPoint()); + LOG.warn("Bad character {} for {}", b & 0xFF, getEndPoint()); close(); return false; } @@ -228,55 +225,54 @@ public class ProxyConnectionFactory extends AbstractConnectionFactory } else { - if (b=='\n') + if (b == '\n') { - _fields=7; + _fields = 7; return true; } - LOG.warn("Bad CRLF for {}",getEndPoint()); + LOG.warn("Bad CRLF for {}", getEndPoint()); close(); return false; } } - return true; } - + @Override public void onFillable() { try { - ByteBuffer buffer=null; - while(_fields<7) + ByteBuffer buffer = null; + while (_fields < 7) { // Create a buffer that will not read too much data // since once read it is impossible to push back for the // real connection to read it. - int size=Math.max(1,__size[_fields]-_builder.length()); - if (buffer==null || buffer.capacity()!=size) - buffer=BufferUtil.allocate(size); + int size = Math.max(1, __size[_fields] - _builder.length()); + if (buffer == null || buffer.capacity() != size) + buffer = BufferUtil.allocate(size); else BufferUtil.clear(buffer); // Read data - int fill=getEndPoint().fill(buffer); - if (fill<0) + int fill = getEndPoint().fill(buffer); + if (fill < 0) { getEndPoint().shutdownOutput(); return; } - if (fill==0) + if (fill == 0) { fillInterested(); return; } - _length+=fill; - if (_length>=108) + _length += fill; + if (_length >= 108) { - LOG.warn("PROXY line too long {} for {}",_length,getEndPoint()); + LOG.warn("PROXY line too long {} for {}", _length, getEndPoint()); close(); return; } @@ -288,44 +284,51 @@ public class ProxyConnectionFactory extends AbstractConnectionFactory // Check proxy if (!"PROXY".equals(_field[0])) { - LOG.warn("Not PROXY protocol for {}",getEndPoint()); + LOG.warn("Not PROXY protocol for {}", getEndPoint()); close(); return; } // Extract Addresses - InetSocketAddress remote=new InetSocketAddress(_field[2],Integer.parseInt(_field[4])); - InetSocketAddress local =new InetSocketAddress(_field[3],Integer.parseInt(_field[5])); + InetSocketAddress remote = new InetSocketAddress(_field[2], Integer.parseInt(_field[4])); + InetSocketAddress local = new InetSocketAddress(_field[3], Integer.parseInt(_field[5])); // Create the next protocol ConnectionFactory connectionFactory = _connector.getConnectionFactory(_next); if (connectionFactory == null) { - LOG.warn("No Next protocol '{}' for {}",_next,getEndPoint()); + LOG.warn("No Next protocol '{}' for {}", _next, getEndPoint()); close(); return; } - - if (LOG.isDebugEnabled()) - LOG.warn("Next protocol '{}' for {} r={} l={}",_next,getEndPoint(),remote,local); - EndPoint endPoint = new ProxyEndPoint(getEndPoint(),remote,local); + if (LOG.isDebugEnabled()) + LOG.warn("Next protocol '{}' for {} r={} l={}", _next, getEndPoint(), remote, local); + + EndPoint endPoint = new ProxyEndPoint(getEndPoint(), remote, local); Connection newConnection = connectionFactory.newConnection(_connector, endPoint); endPoint.upgrade(newConnection); } catch (Throwable x) { - LOG.warn("PROXY error for "+getEndPoint(),x); + LOG.warn("PROXY error for " + getEndPoint(), x); close(); } } } - - - enum Family { UNSPEC, INET, INET6, UNIX }; - enum Transport { UNSPEC, STREAM, DGRAM }; - private static final byte[] MAGIC = new byte[]{0x0D,0x0A,0x0D,0x0A,0x00,0x0D,0x0A,0x51,0x55,0x49,0x54,0x0A}; - + + private enum Family + { + UNSPEC, INET, INET6, UNIX + } + + private enum Transport + { + UNSPEC, STREAM, DGRAM + } + + private static final byte[] MAGIC = new byte[]{0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A}; + public class ProxyProtocolV2Connection extends AbstractConnection { private final Connector _connector; @@ -336,122 +339,135 @@ public class ProxyConnectionFactory extends AbstractConnectionFactory private final int _length; private final ByteBuffer _buffer; - protected ProxyProtocolV2Connection(EndPoint endp, Connector connector, String next,ByteBuffer buffer) - throws IOException + protected ProxyProtocolV2Connection(EndPoint endp, Connector connector, String next, ByteBuffer buffer) throws IOException { - super(endp,connector.getExecutor()); - _connector=connector; - _next=next; - - if (buffer.remaining()!=16) + super(endp, connector.getExecutor()); + _connector = connector; + _next = next; + + if (buffer.remaining() != 16) throw new IllegalStateException(); - + if (LOG.isDebugEnabled()) - LOG.debug("PROXYv2 header {} for {}",BufferUtil.toHexSummary(buffer),this); - + LOG.debug("PROXYv2 header {} for {}", BufferUtil.toHexSummary(buffer), this); + // struct proxy_hdr_v2 { // uint8_t sig[12]; /* hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A */ // uint8_t ver_cmd; /* protocol version and command */ // uint8_t fam; /* protocol family and address */ // uint16_t len; /* number of following bytes part of the header */ // }; - for (int i=0;i>4) + switch (transportAndFamily >> 4) { - case 0: _family=Family.UNSPEC; break; - case 1: _family=Family.INET; break; - case 2: _family=Family.INET6; break; - case 3: _family=Family.UNIX; break; + case 0: + _family = Family.UNSPEC; + break; + case 1: + _family = Family.INET; + break; + case 2: + _family = Family.INET6; + break; + case 3: + _family = Family.UNIX; + break; default: throw new IOException("Bad PROXY protocol v2 family"); } - - switch(0xf&transportAndFamily) - { - case 0: _transport=Transport.UNSPEC; break; - case 1: _transport=Transport.STREAM; break; - case 2: _transport=Transport.DGRAM; break; - default: - throw new IOException("Bad PROXY protocol v2 family"); - } - - _length = buffer.getChar(); - - if (!_local && (_family==Family.UNSPEC || _family==Family.UNIX || _transport!=Transport.STREAM)) - throw new IOException(String.format("Unsupported PROXY protocol v2 mode 0x%x,0x%x",versionAndCommand,transportAndFamily)); - if (_length>_maxProxyHeader) - throw new IOException(String.format("Unsupported PROXY protocol v2 mode 0x%x,0x%x,0x%x",versionAndCommand,transportAndFamily,_length)); - - _buffer = _length>0?BufferUtil.allocate(_length):BufferUtil.EMPTY_BUFFER; + switch (0xf & transportAndFamily) + { + case 0: + _transport = Transport.UNSPEC; + break; + case 1: + _transport = Transport.STREAM; + break; + case 2: + _transport = Transport.DGRAM; + break; + default: + throw new IOException("Bad PROXY protocol v2 family"); + } + + _length = buffer.getChar(); + + if (!_local && (_family == Family.UNSPEC || _family == Family.UNIX || _transport != Transport.STREAM)) + throw new IOException(String.format("Unsupported PROXY protocol v2 mode 0x%x,0x%x", versionAndCommand, transportAndFamily)); + + if (_length > getMaxProxyHeader()) + throw new IOException(String.format("Unsupported PROXY protocol v2 mode 0x%x,0x%x,0x%x", versionAndCommand, transportAndFamily, _length)); + + _buffer = _length > 0 ? BufferUtil.allocate(_length) : BufferUtil.EMPTY_BUFFER; } @Override public void onOpen() { super.onOpen(); - if (_buffer.remaining()==_length) + if (_buffer.remaining() == _length) next(); else fillInterested(); } - + @Override public void onFillable() { try { - while(_buffer.remaining()<_length) + while (_buffer.remaining() < _length) { // Read data - int fill=getEndPoint().fill(_buffer); - if (fill<0) + int fill = getEndPoint().fill(_buffer); + if (fill < 0) { getEndPoint().shutdownOutput(); return; } - if (fill==0) + if (fill == 0) { fillInterested(); return; } - } + } + next(); } catch (Throwable x) { - LOG.warn("PROXY error for "+getEndPoint(),x); + LOG.warn("PROXY error for " + getEndPoint(), x); close(); - return; } - - next(); } - + private void next() { if (LOG.isDebugEnabled()) - LOG.debug("PROXYv2 next {} from {} for {}",_next,BufferUtil.toHexSummary(_buffer),this); - + LOG.debug("PROXYv2 next {} from {} for {}", _next, BufferUtil.toHexSummary(_buffer), this); + // Create the next protocol ConnectionFactory connectionFactory = _connector.getConnectionFactory(_next); if (connectionFactory == null) { - LOG.info("Next protocol '{}' for {}",_next,getEndPoint()); + LOG.info("Next protocol '{}' for {}", _next, getEndPoint()); close(); return; - } - + } + // Do we need to wrap the endpoint? - EndPoint endPoint=getEndPoint(); + EndPoint endPoint = getEndPoint(); if (!_local) { try @@ -461,84 +477,80 @@ public class ProxyConnectionFactory extends AbstractConnectionFactory int sp; int dp; - switch(_family) + switch (_family) { case INET: { - byte[] addr=new byte[4]; + byte[] addr = new byte[4]; _buffer.get(addr); src = Inet4Address.getByAddress(addr); _buffer.get(addr); dst = Inet4Address.getByAddress(addr); sp = _buffer.getChar(); dp = _buffer.getChar(); - break; } - + case INET6: { - byte[] addr=new byte[16]; + byte[] addr = new byte[16]; _buffer.get(addr); src = Inet6Address.getByAddress(addr); _buffer.get(addr); dst = Inet6Address.getByAddress(addr); sp = _buffer.getChar(); dp = _buffer.getChar(); - break; + break; } default: throw new IllegalStateException(); } - // Extract Addresses - InetSocketAddress remote=new InetSocketAddress(src,sp); - InetSocketAddress local =new InetSocketAddress(dst,dp); - ProxyEndPoint proxyEndPoint = new ProxyEndPoint(endPoint,remote,local); + InetSocketAddress remote = new InetSocketAddress(src, sp); + InetSocketAddress local = new InetSocketAddress(dst, dp); + ProxyEndPoint proxyEndPoint = new ProxyEndPoint(endPoint, remote, local); endPoint = proxyEndPoint; - - + // Any additional info? - while(_buffer.hasRemaining()) + while (_buffer.hasRemaining()) { int type = 0xff & _buffer.get(); int length = _buffer.getShort(); byte[] value = new byte[length]; _buffer.get(value); - + if (LOG.isDebugEnabled()) - LOG.debug(String.format("T=%x L=%d V=%s for %s",type,length,TypeUtil.toHexString(value),this)); - + LOG.debug(String.format("T=%x L=%d V=%s for %s", type, length, TypeUtil.toHexString(value), this)); + // TODO interpret these values - switch(type) + switch (type) { case 0x01: // PP2_TYPE_ALPN break; case 0x02: // PP2_TYPE_AUTHORITY break; case 0x20: // PP2_TYPE_SSL - { - int i=0; + { + int i = 0; int client = 0xff & value[i++]; - int verify = ((0xff & value[i++])<<24) + ((0xff & value[i++])<<16) + ((0xff & value[i++])<<8) + (0xff&value[i++]); - while(i