Skip to content

Commit

Permalink
Initial support for proxy protocol data V1 and V2. Minor changes to A…
Browse files Browse the repository at this point in the history
…PI to make protocol data available to application handlers.
  • Loading branch information
spericas committed Oct 18, 2023
1 parent 826cf87 commit 7c32ea1
Show file tree
Hide file tree
Showing 10 changed files with 413 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,15 @@ interface SocketOptionsBlueprint {
@ConfiguredOption("false")
boolean tcpNoDelay();

/**
* Enable support for proxy protocol for this socket.
* Default is {@code false}.
*
* @return proxy support status
*/
@ConfiguredOption("false")
boolean enableProxyProtocol();

/**
* Configure socket with defined socket options.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.io.InputStream;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;

Expand All @@ -38,6 +39,7 @@
import io.helidon.http.media.ReadableEntity;
import io.helidon.webserver.ConnectionContext;
import io.helidon.webserver.ListenerContext;
import io.helidon.webserver.ProxyProtocolData;
import io.helidon.webserver.http.HttpSecurity;
import io.helidon.webserver.http.RoutingRequest;

Expand Down Expand Up @@ -220,6 +222,11 @@ public void streamFilter(UnaryOperator<InputStream> filterFunction) {
this.streamFilter = it -> filterFunction.apply(current.apply(it));
}

@Override
public Optional<ProxyProtocolData> proxyProtocolData() {
return Optional.ofNullable(ctx.proxyProtocolData());
}

private UriInfo createUriInfo() {
return ctx.listenerContext().config().requestedUriDiscoveryContext().uriInfo(remotePeer().address().toString(),
localPeer().address().toString(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import io.helidon.common.buffers.DataReader;
import io.helidon.common.buffers.DataWriter;
import io.helidon.common.socket.SocketContext;
import io.helidon.common.socket.SocketOptions;

/**
* Server connection context.
Expand Down Expand Up @@ -60,4 +61,14 @@ public interface ConnectionContext extends SocketContext {
* @return rouer
*/
Router router();

/**
* Proxy protocol header data.
*
* @return header data or {@code null} if proxy protocol not enabled on socket
* @see SocketOptions#enableProxyProtocol()
*/
default ProxyProtocolData proxyProtocolData() {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import io.helidon.common.socket.HelidonSocket;
import io.helidon.common.socket.PeerInfo;
import io.helidon.common.socket.PlainSocket;
import io.helidon.common.socket.SocketOptions;
import io.helidon.common.socket.SocketWriter;
import io.helidon.common.socket.TlsSocket;
import io.helidon.common.task.InterruptableTask;
Expand Down Expand Up @@ -64,11 +65,13 @@ class ConnectionHandler implements InterruptableTask<Void>, ConnectionContext {
private final String serverChannelId;
private final Router router;
private final Tls tls;
private final SocketOptions connectionOptions;

private ServerConnection connection;
private HelidonSocket helidonSocket;
private DataReader reader;
private SocketWriter writer;
private ProxyProtocolData proxyProtocolData;

ConnectionHandler(ListenerContext listenerContext,
Semaphore connectionSemaphore,
Expand All @@ -78,7 +81,8 @@ class ConnectionHandler implements InterruptableTask<Void>, ConnectionContext {
Socket socket,
String serverChannelId,
Router router,
Tls tls) {
Tls tls,
SocketOptions connectionOptions) {
this.listenerContext = listenerContext;
this.connectionSemaphore = connectionSemaphore;
this.requestSemaphore = requestSemaphore;
Expand All @@ -89,6 +93,7 @@ class ConnectionHandler implements InterruptableTask<Void>, ConnectionContext {
this.serverChannelId = serverChannelId;
this.router = router;
this.tls = tls;
this.connectionOptions = connectionOptions;
}

@Override
Expand All @@ -100,6 +105,12 @@ public boolean canInterrupt() {
public final void run() {
String channelId = "0x" + HexFormat.of().toHexDigits(System.identityHashCode(socket));

// proxy protocol before SSL handshake
if (connectionOptions.enableProxyProtocol()) {
ProxyProtocolHandler handler = new ProxyProtocolHandler(socket, channelId);
proxyProtocolData = handler.get();
}

// handle SSL and init helidonSocket, reader and writer
try {
if (tls.enabled()) {
Expand Down Expand Up @@ -226,6 +237,11 @@ public Router router() {
return router;
}

@Override
public ProxyProtocolData proxyProtocolData() {
return proxyProtocolData;
}

private ServerConnection identifyConnection() {
try {
reader.ensureAvailable();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.helidon.webserver;

/**
* Proxy protocol data parsed by {@link ProxyProtocolHandler}.
*/
public interface ProxyProtocolData {

/**
* The protocol family options.
*/
enum ProtocolFamily {
/**
* TCP version 4.
*/
TCP4,

/**
* TCP version 6.
*/
TCP6,

/**
* Protocol family is unknown.
*/
UNKNOWN
}

/**
* Protocol family from protocol header.
*
* @return protocol family
*/
ProtocolFamily protocolFamily();

/**
* Source address that is either IPv4 or IPv6 depending on {@link #protocolFamily()}}.
*
* @return source address
*/
String sourceAddress();

/**
* Destination address that is either IPv4 or IPv6 depending on {@link #protocolFamily()}}.
*
* @return source address
*/
String destAddress();

/**
* Source port number.
*
* @return source port.
*/
int sourcePort();

/**
* Destination port number.
*
* @return port number.
*/
int destPort();
}


Loading

0 comments on commit 7c32ea1

Please sign in to comment.