Skip to content

Commit bc96864

Browse files
lorbansbordet
andauthored
Fix Request.isSecure() when proxy offloads TLS and then sends PROXY-V2 information to the backend (#14194)
* Fixed Request.isSecure() when proxy offloads TLS and then sends PROXY-V2 information to the backend * Refactored V2.Tag generation into method V2.Tag.from(). * Added test to show how to forward V2.Tag information in ProxyHandler.Reverse. Signed-off-by: Ludovic Orban <[email protected]> Signed-off-by: Simone Bordet <[email protected]> Co-authored-by: Simone Bordet <[email protected]>
1 parent d5cec2b commit bc96864

File tree

4 files changed

+296
-66
lines changed

4 files changed

+296
-66
lines changed

jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyProtocolClientConnectionFactory.java

Lines changed: 142 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import java.net.InetAddress;
1818
import java.net.InetSocketAddress;
1919
import java.net.SocketAddress;
20+
import java.net.UnixDomainSocketAddress;
2021
import java.nio.ByteBuffer;
2122
import java.nio.charset.StandardCharsets;
2223
import java.util.Arrays;
@@ -31,6 +32,7 @@
3132
import org.eclipse.jetty.io.ClientConnectionFactory;
3233
import org.eclipse.jetty.io.Connection;
3334
import org.eclipse.jetty.io.EndPoint;
35+
import org.eclipse.jetty.util.BufferUtil;
3436
import org.eclipse.jetty.util.Callback;
3537
import org.eclipse.jetty.util.Promise;
3638
import org.slf4j.Logger;
@@ -207,23 +209,7 @@ protected ProxyProtocolConnection newProxyProtocolConnection(EndPoint endPoint,
207209
Executor executor = destination.getHttpClient().getExecutor();
208210
Tag tag = (Tag)destination.getOrigin().getTag();
209211
if (tag == null)
210-
{
211-
SocketAddress local = endPoint.getLocalSocketAddress();
212-
InetSocketAddress inetLocal = local instanceof InetSocketAddress ? (InetSocketAddress)local : null;
213-
InetAddress localAddress = inetLocal == null ? null : inetLocal.getAddress();
214-
SocketAddress remote = endPoint.getRemoteSocketAddress();
215-
InetSocketAddress inetRemote = remote instanceof InetSocketAddress ? (InetSocketAddress)remote : null;
216-
InetAddress remoteAddress = inetRemote == null ? null : inetRemote.getAddress();
217-
Tag.Family family = local == null || inetLocal == null ? Tag.Family.UNSPEC : localAddress instanceof Inet4Address ? Tag.Family.INET4 : Tag.Family.INET6;
218-
tag = new Tag(Tag.Command.PROXY,
219-
family,
220-
Tag.Protocol.STREAM,
221-
localAddress == null ? null : localAddress.getHostAddress(),
222-
inetLocal == null ? 0 : inetLocal.getPort(),
223-
remoteAddress == null ? null : remoteAddress.getHostAddress(),
224-
inetRemote == null ? 0 : inetRemote.getPort(),
225-
null);
226-
}
212+
tag = Tag.from(endPoint, true);
227213
return new ProxyProtocolConnectionV2(endPoint, executor, getWrapped(), context, tag);
228214
}
229215

@@ -241,6 +227,72 @@ public static class Tag implements ClientConnectionFactory.Decorator
241227
*/
242228
public static final Tag LOCAL = new Tag(Command.LOCAL, Family.UNSPEC, Protocol.UNSPEC, null, 0, null, 0, null);
243229

230+
/**
231+
* <p>Creates a {@code Tag} from the given {@link EndPoint}.</p>
232+
* <p>The {@code source} parameter indicates whether the {@code EndPoint}
233+
* is the local {@code EndPoint} (typical for clients), or the
234+
* remote {@code EndPoint} (typical for proxies).
235+
* In the latter case, the proxy wants to forward to the server the
236+
* information about the remote client so the {@code EndPoint} must
237+
* be that connected to the remote client (not to the server).</p>
238+
*
239+
* @param endPoint the {@code EndPoint} to create the {@code Tag} from
240+
* @param local whether the {@code EndPoint} is local or remote
241+
* @return a new {@code Tag} from the given {@code EndPoint}
242+
*/
243+
public static Tag from(EndPoint endPoint, boolean local)
244+
{
245+
SocketAddress src = local ? endPoint.getLocalSocketAddress() : endPoint.getRemoteSocketAddress();
246+
UnixDomainSocketAddress unixSrc = src instanceof UnixDomainSocketAddress ? (UnixDomainSocketAddress)src : null;
247+
InetSocketAddress inetSrc = src instanceof InetSocketAddress ? (InetSocketAddress)src : null;
248+
InetAddress srcAddress = inetSrc == null ? null : inetSrc.getAddress();
249+
String srcAddr = unixSrc != null ? unixSrc.getPath().toString()
250+
: srcAddress != null ? srcAddress.getHostAddress() : null;
251+
252+
int srcPort = inetSrc != null ? inetSrc.getPort() : 0;
253+
254+
Family family = Family.UNSPEC;
255+
if (unixSrc != null)
256+
family = Family.UNIX;
257+
else if (inetSrc != null)
258+
family = srcAddress instanceof Inet4Address ? V2.Tag.Family.INET4 : V2.Tag.Family.INET6;
259+
260+
Protocol protocol = src == null ? Protocol.UNSPEC : Protocol.STREAM;
261+
262+
SocketAddress dst = local ? endPoint.getRemoteSocketAddress() : endPoint.getLocalSocketAddress();
263+
UnixDomainSocketAddress unixDst = dst instanceof UnixDomainSocketAddress ? (UnixDomainSocketAddress)dst : null;
264+
InetSocketAddress inetDst = dst instanceof InetSocketAddress ? (InetSocketAddress)dst : null;
265+
InetAddress dstAddress = inetDst == null ? null : inetDst.getAddress();
266+
String dstAddr = unixDst != null ? unixDst.getPath().toString()
267+
: dstAddress != null ? dstAddress.getHostAddress() : null;
268+
269+
int dstPort = inetDst != null ? inetDst.getPort() : 0;
270+
271+
List<TLV> tlvs = null;
272+
EndPoint.SslSessionData sslSessionData = endPoint.getSslSessionData();
273+
int length;
274+
if (sslSessionData != null)
275+
{
276+
length = 5;
277+
String cipherSuite = sslSessionData.cipherSuite();
278+
byte[] cipherBytes = cipherSuite == null ? BufferUtil.EMPTY_BYTES : cipherSuite.getBytes(StandardCharsets.US_ASCII);
279+
length += 1 + 2 + cipherBytes.length;
280+
byte[] value = new byte[length];
281+
ByteBuffer byteBuffer = ByteBuffer.wrap(value);
282+
byteBuffer.put((byte)TLV.PP2_CLIENT_SSL);
283+
byteBuffer.putInt(1); // Verify.
284+
if (cipherSuite != null)
285+
{
286+
byteBuffer.put((byte)TLV.PP2_SUBTYPE_SSL_CIPHER);
287+
byteBuffer.putShort((short)cipherBytes.length);
288+
byteBuffer.put(cipherBytes);
289+
}
290+
tlvs = List.of(new TLV(TLV.PP2_TYPE_SSL, value));
291+
}
292+
293+
return new Tag(Command.PROXY, family, protocol, srcAddr, srcPort, dstAddr, dstPort, tlvs);
294+
}
295+
244296
private final Command command;
245297
private final Family family;
246298
private final Protocol protocol;
@@ -285,6 +337,7 @@ public Tag(String srcIP, int srcPort, List<TLV> tlvs)
285337

286338
/**
287339
* <p>Creates a Tag with the given metadata.</p>
340+
* <p>Missing metadata will be derived from the underlying EndPoint.</p>
288341
*
289342
* @param command the LOCAL or PROXY command
290343
* @param family the protocol family
@@ -394,6 +447,11 @@ public enum Protocol
394447

395448
public static class TLV
396449
{
450+
public static final int PP2_TYPE_SSL = 0x20;
451+
public static final int PP2_CLIENT_SSL = 0x01;
452+
public static final int PP2_SUBTYPE_SSL_VERSION = 0x21;
453+
public static final int PP2_SUBTYPE_SSL_CIPHER = 0x23;
454+
397455
private final int type;
398456
private final byte[] value;
399457

@@ -571,6 +629,7 @@ protected void writePROXYBytes(EndPoint endPoint, Callback callback)
571629
private static class ProxyProtocolConnectionV2 extends ProxyProtocolConnection
572630
{
573631
private static final byte[] MAGIC = {0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A};
632+
private static final int UNIX_ADDRESS_MAX_LENGTH = 108;
574633

575634
private final V2.Tag tag;
576635

@@ -589,87 +648,116 @@ protected void writePROXYBytes(EndPoint endPoint, Callback callback)
589648
capacity += 1; // version and command
590649
capacity += 1; // family and protocol
591650
capacity += 2; // length
592-
capacity += 216; // max address length
651+
capacity += 2 * UNIX_ADDRESS_MAX_LENGTH; // max address length
593652
List<V2.Tag.TLV> tlvs = tag.getTLVs();
594653
int vectorsLength = tlvs == null ? 0 : tlvs.stream()
595654
.mapToInt(tlv -> 1 + 2 + tlv.getValue().length)
596655
.sum();
597656
capacity += vectorsLength;
598657
ByteBuffer buffer = ByteBuffer.allocateDirect(capacity);
658+
599659
buffer.put(MAGIC);
660+
600661
V2.Tag.Command command = tag.getCommand();
601662
int versionAndCommand = (2 << 4) | (command.ordinal() & 0x0F);
602663
buffer.put((byte)versionAndCommand);
603-
V2.Tag.Family family = tag.getFamily();
664+
604665
String srcAddr = tag.getSourceAddress();
605666
SocketAddress local = endPoint.getLocalSocketAddress();
667+
UnixDomainSocketAddress unixLocal = local instanceof UnixDomainSocketAddress ? (UnixDomainSocketAddress)local : null;
606668
InetSocketAddress inetLocal = local instanceof InetSocketAddress ? (InetSocketAddress)local : null;
607669
InetAddress localAddress = inetLocal == null ? null : inetLocal.getAddress();
608-
if (srcAddr == null && localAddress != null)
609-
srcAddr = localAddress.getHostAddress();
670+
if (srcAddr == null)
671+
{
672+
if (unixLocal != null)
673+
srcAddr = unixLocal.getPath().toString();
674+
else if (localAddress != null)
675+
srcAddr = localAddress.getHostAddress();
676+
}
677+
610678
int srcPort = tag.getSourcePort();
611679
if (srcPort <= 0 && inetLocal != null)
612680
srcPort = inetLocal.getPort();
681+
682+
V2.Tag.Family family = tag.getFamily();
613683
if (family == null)
614-
family = local == null || inetLocal == null ? V2.Tag.Family.UNSPEC : localAddress instanceof Inet4Address ? V2.Tag.Family.INET4 : V2.Tag.Family.INET6;
684+
{
685+
if (unixLocal != null)
686+
family = V2.Tag.Family.UNIX;
687+
else if (inetLocal != null)
688+
family = localAddress instanceof Inet4Address ? V2.Tag.Family.INET4 : V2.Tag.Family.INET6;
689+
else
690+
family = V2.Tag.Family.UNSPEC;
691+
}
692+
615693
V2.Tag.Protocol protocol = tag.getProtocol();
616694
if (protocol == null)
617695
protocol = local == null ? V2.Tag.Protocol.UNSPEC : V2.Tag.Protocol.STREAM;
696+
618697
int familyAndProtocol = (family.ordinal() << 4) | protocol.ordinal();
619698
buffer.put((byte)familyAndProtocol);
620-
int length = 0;
621-
switch (family)
699+
700+
int length = switch (family)
622701
{
623-
case UNSPEC:
624-
break;
625-
case INET4:
626-
length = 12;
627-
break;
628-
case INET6:
629-
length = 36;
630-
break;
631-
case UNIX:
632-
length = 216;
633-
break;
634-
default:
635-
throw new IllegalStateException();
636-
}
702+
case UNSPEC -> 0;
703+
case INET4 -> 12;
704+
case INET6 -> 36;
705+
case UNIX -> 2 * UNIX_ADDRESS_MAX_LENGTH;
706+
};
637707
length += vectorsLength;
638708
buffer.putShort((short)length);
709+
639710
String dstAddr = tag.getDestinationAddress();
640711
SocketAddress remote = endPoint.getRemoteSocketAddress();
712+
UnixDomainSocketAddress unixRemote = remote instanceof UnixDomainSocketAddress ? (UnixDomainSocketAddress)remote : null;
641713
InetSocketAddress inetRemote = remote instanceof InetSocketAddress ? (InetSocketAddress)remote : null;
642714
InetAddress remoteAddress = inetRemote == null ? null : inetRemote.getAddress();
643-
if (dstAddr == null && remoteAddress != null)
644-
dstAddr = remoteAddress.getHostAddress();
715+
if (dstAddr == null)
716+
{
717+
if (unixRemote != null)
718+
dstAddr = unixRemote.getPath().toString();
719+
else if (remoteAddress != null)
720+
dstAddr = remoteAddress.getHostAddress();
721+
}
722+
645723
int dstPort = tag.getDestinationPort();
646724
if (dstPort <= 0 && inetRemote != null)
647725
dstPort = inetRemote.getPort();
726+
648727
switch (family)
649728
{
650-
case UNSPEC:
651-
break;
652-
case INET4:
653-
case INET6:
729+
case UNSPEC ->
730+
{
731+
// Nothing to do.
732+
}
733+
case INET4, INET6 ->
734+
{
654735
buffer.put(InetAddress.getByName(srcAddr).getAddress());
655736
buffer.put(InetAddress.getByName(dstAddr).getAddress());
656737
buffer.putShort((short)srcPort);
657738
buffer.putShort((short)dstPort);
658-
break;
659-
case UNIX:
739+
}
740+
case UNIX ->
741+
{
660742
int position = buffer.position();
661743
if (srcAddr != null)
662-
buffer.put(srcAddr.getBytes(StandardCharsets.US_ASCII));
663-
position = position + 108;
744+
{
745+
byte[] bytes = srcAddr.getBytes(StandardCharsets.US_ASCII);
746+
buffer.put(bytes, 0, Math.min(bytes.length, UNIX_ADDRESS_MAX_LENGTH));
747+
}
748+
position = position + UNIX_ADDRESS_MAX_LENGTH;
664749
buffer.position(position);
665750
if (dstAddr != null)
666-
buffer.put(dstAddr.getBytes(StandardCharsets.US_ASCII));
667-
position = position + 108;
751+
{
752+
byte[] bytes = dstAddr.getBytes(StandardCharsets.US_ASCII);
753+
buffer.put(bytes, 0, Math.min(bytes.length, UNIX_ADDRESS_MAX_LENGTH));
754+
}
755+
position = position + UNIX_ADDRESS_MAX_LENGTH;
668756
buffer.position(position);
669-
break;
670-
default:
671-
throw new IllegalStateException();
757+
}
758+
default -> throw new IllegalStateException();
672759
}
760+
673761
if (tlvs != null)
674762
{
675763
for (V2.Tag.TLV tlv : tlvs)
@@ -680,6 +768,7 @@ protected void writePROXYBytes(EndPoint endPoint, Callback callback)
680768
buffer.put(data);
681769
}
682770
}
771+
683772
buffer.flip();
684773
endPoint.write(callback, buffer);
685774
}

0 commit comments

Comments
 (0)