Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ with QuickFIX, followed by an example.
| `EndpointIdentificationAlgorithm` | Sets the endpoint identification algorithm. If the algorithm parameter is non-null, the endpoint identification/verification procedures must be handled during SSL/TLS handshaking. See [Endpoint Identification Algorithm Names](https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#jssenames). | | |
| `UseSNI` | Enables the SSL engine to use Server Name Indication (SNI). This option is only applicable for initiators. If provided, `SNIHostName` will be used as the server name. Otherwise, `SocketConnectHost` or `SocketConnectHost<n>` will be used. Note: When this option is disabled, the JVM may still implicitly send the SSL `server_name` extension. | `Y`<br/>`N` | `N` |
| `SNIHostName` | SNI host name to be used as desired Server Name Indication (SNI) parameter. | | |
| `ReverseDNSEnabled` | Whether to perform a reverse DNS lookup to resolve the peer host name when connected directly to/from an IP address. The resolved host is used as the SSL peer host (e.g. for hostname verification). When disabled, the literal IP address is used as-is and no reverse DNS lookup is performed. Applies to both initiator and acceptor sessions. | `Y`<br/>`N` | `Y` |

---

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package quickfix.mina;

import java.net.InetSocketAddress;

@FunctionalInterface
public interface HostResolutionStrategy {
String getHost(InetSocketAddress address);

HostResolutionStrategy WITH_REVERSE_DNS = InetSocketAddress::getHostName;

HostResolutionStrategy WITHOUT_REVERSE_DNS = InetSocketAddress::getHostString;

static HostResolutionStrategy fromReverseDnsEnabled(boolean reverseDnsEnabled) {
return reverseDnsEnabled ? WITH_REVERSE_DNS : WITHOUT_REVERSE_DNS;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import quickfix.SessionSettings;
import quickfix.mina.CompositeIoFilterChainBuilder;
import quickfix.mina.EventHandlingStrategy;
import quickfix.mina.HostResolutionStrategy;
import quickfix.mina.NetworkingOptions;
import quickfix.mina.ProtocolFactory;
import quickfix.mina.SessionConnector;
Expand Down Expand Up @@ -135,7 +136,9 @@ private void installSSL(AcceptorSocketDescriptor descriptor,
log.info("Installing SSL filter for {}", descriptor.getAddress());
SSLConfig sslConfig = descriptor.getSslConfig();
SSLContext sslContext = SSLContextFactory.getInstance(sslConfig);
SslFilter sslFilter = new AcceptorSslFilter(sslContext);
HostResolutionStrategy hostResolutionStrategy = HostResolutionStrategy.fromReverseDnsEnabled(
descriptor.isReverseDnsEnabled());
SslFilter sslFilter = new AcceptorSslFilter(sslContext, hostResolutionStrategy);
sslFilter.setNeedClientAuth(sslConfig.isNeedClientAuth());
sslFilter.setEnabledCipherSuites(sslConfig.getEnabledCipherSuites() != null ? sslConfig.getEnabledCipherSuites()
: SSLSupport.getDefaultCipherSuites(sslContext));
Expand Down Expand Up @@ -188,6 +191,8 @@ && getSettings().getBool(sessionID, SSLSupport.SETTING_USE_SSL)) {
sslConfig = SSLSupport.getSslConfig(getSettings(), sessionID);
}
}
boolean reverseDnsEnabled = getSettings().getBoolOrDefault(sessionID,
SSLSupport.SETTING_REVERSE_DNS_ENABLED, true);

int acceptPort = (int) settings.getLong(sessionID, Acceptor.SETTING_SOCKET_ACCEPT_PORT);

Expand All @@ -206,7 +211,7 @@ && getSettings().getBool(sessionID, SSLSupport.SETTING_USE_SSL)) {
throw new ConfigError("Conflicting configurations of acceptor socket: " + acceptorAddress);
}
} else {
descriptor = new AcceptorSocketDescriptor(acceptorAddress, useSSL, sslConfig);
descriptor = new AcceptorSocketDescriptor(acceptorAddress, useSSL, sslConfig, reverseDnsEnabled);
socketDescriptorForAddress.put(acceptorAddress, descriptor);
}

Expand Down Expand Up @@ -281,12 +286,15 @@ private static class AcceptorSocketDescriptor {
private final SocketAddress address;
private final boolean useSSL;
private final SSLConfig sslConfig;
private final boolean reverseDnsEnabled;
private final Map<SessionID, Session> acceptedSessions = new HashMap<>();

public AcceptorSocketDescriptor(SocketAddress address, boolean useSSL, SSLConfig sslConfig) {
public AcceptorSocketDescriptor(SocketAddress address, boolean useSSL, SSLConfig sslConfig,
boolean reverseDnsEnabled) {
this.address = address;
this.useSSL = useSSL;
this.sslConfig = sslConfig;
this.reverseDnsEnabled = reverseDnsEnabled;
}

public void acceptSession(Session session) {
Expand All @@ -308,6 +316,10 @@ public boolean isUseSSL() {
public SSLConfig getSslConfig() {
return sslConfig;
}

public boolean isReverseDnsEnabled() {
return reverseDnsEnabled;
}
}

public Collection<IoAcceptor> getEndpoints() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import quickfix.SessionSettings;
import quickfix.field.converter.BooleanConverter;
import quickfix.mina.EventHandlingStrategy;
import quickfix.mina.HostResolutionStrategy;
import quickfix.mina.NetworkingOptions;
import quickfix.mina.ProtocolFactory;
import quickfix.mina.SessionConnector;
Expand Down Expand Up @@ -139,6 +140,10 @@ private void createInitiator(final Session session, final boolean continueInitOn
sslConfig = SSLSupport.getSslConfig(getSettings(), sessionID);
}

// Defaults to true for backwards compatibility
HostResolutionStrategy hostResolutionStrategy = HostResolutionStrategy.fromReverseDnsEnabled(
getSettings().getBoolOrDefault(sessionID, SSLSupport.SETTING_REVERSE_DNS_ENABLED, true));

String proxyUser = null;
String proxyPassword = null;
String proxyHost = null;
Expand Down Expand Up @@ -177,7 +182,7 @@ && getSettings().isSetting(sessionID, Initiator.SETTING_PROXY_DOMAIN)) {
ScheduledExecutorService scheduledExecutorService = (scheduledReconnectExecutor != null ? scheduledReconnectExecutor : getScheduledExecutorService());
try {
final IoSessionInitiator ioSessionInitiator = new IoSessionInitiator(session,
socketAddresses, localAddress, connectTimeout, reconnectingIntervals,
socketAddresses, localAddress, hostResolutionStrategy, connectTimeout, reconnectingIntervals,
scheduledExecutorService, settings, networkingOptions,
getEventHandlingStrategy(), getIoFilterChainBuilder(), sslEnabled, sslConfig,
proxyType, proxyVersion, proxyHost, proxyPort, proxyUser, proxyPassword, proxyDomain, proxyWorkstation);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import quickfix.SystemTime;
import quickfix.mina.CompositeIoFilterChainBuilder;
import quickfix.mina.EventHandlingStrategy;
import quickfix.mina.HostResolutionStrategy;
import quickfix.mina.NetworkingOptions;
import quickfix.mina.ProtocolFactory;
import quickfix.mina.SessionConnector;
Expand Down Expand Up @@ -64,10 +65,10 @@ public class IoSessionInitiator {

private Future<?> reconnectFuture;

public IoSessionInitiator(Session fixSession, SocketAddress[] socketAddresses,
SocketAddress localAddress, int connectTimeout, int[] reconnectIntervalInSeconds,
ScheduledExecutorService executor, SessionSettings sessionSettings, NetworkingOptions networkingOptions,
EventHandlingStrategy eventHandlingStrategy,
IoSessionInitiator(Session fixSession, SocketAddress[] socketAddresses,
SocketAddress localAddress, HostResolutionStrategy hostResolutionStrategy, int connectTimeout,
int[] reconnectIntervalInSeconds, ScheduledExecutorService executor, SessionSettings sessionSettings,
NetworkingOptions networkingOptions, EventHandlingStrategy eventHandlingStrategy,
IoFilterChainBuilder userIoFilterChainBuilder, boolean sslEnabled, SSLConfig sslConfig,
String proxyType, String proxyVersion, String proxyHost, int proxyPort,
String proxyUser, String proxyPassword, String proxyDomain, String proxyWorkstation) throws ConfigError {
Expand All @@ -83,7 +84,8 @@ public IoSessionInitiator(Session fixSession, SocketAddress[] socketAddresses,
reconnectTask = new ConnectTask(sslEnabled, socketAddresses, localAddress,
userIoFilterChainBuilder, fixSession, connectTimeoutMillis, reconnectIntervalInMillis,
sessionSettings, networkingOptions, eventHandlingStrategy, sslConfig,
proxyType, proxyVersion, proxyHost, proxyPort, proxyUser, proxyPassword, proxyDomain, proxyWorkstation, log);
proxyType, proxyVersion, proxyHost, proxyPort, proxyUser, proxyPassword, proxyDomain,
proxyWorkstation, log, hostResolutionStrategy);
Comment thread
chrjohn marked this conversation as resolved.
} catch (GeneralSecurityException e) {
throw new ConfigError(e);
}
Expand All @@ -105,6 +107,7 @@ private static class ConnectTask implements Runnable {
private final EventHandlingStrategy eventHandlingStrategy;
private final SSLConfig sslConfig;
private final Logger log;
private final HostResolutionStrategy hostResolutionStrategy;

private IoSession ioSession;
private long lastReconnectAttemptTime;
Expand All @@ -122,13 +125,13 @@ private static class ConnectTask implements Runnable {
private final String proxyDomain;
private final String proxyWorkstation;

public ConnectTask(boolean sslEnabled, SocketAddress[] socketAddresses,
ConnectTask(boolean sslEnabled, SocketAddress[] socketAddresses,
SocketAddress localAddress, IoFilterChainBuilder userIoFilterChainBuilder,
Session fixSession, long connectTimeoutMillis, long[] reconnectIntervalInMillis,
SessionSettings sessionSettings, NetworkingOptions networkingOptions, EventHandlingStrategy eventHandlingStrategy, SSLConfig sslConfig,
String proxyType, String proxyVersion, String proxyHost,
int proxyPort, String proxyUser, String proxyPassword, String proxyDomain,
String proxyWorkstation, Logger log) throws ConfigError, GeneralSecurityException {
String proxyWorkstation, Logger log, HostResolutionStrategy hostResolutionStrategy) throws ConfigError, GeneralSecurityException {
this.sslEnabled = sslEnabled;
this.socketAddresses = socketAddresses;
this.localAddress = localAddress;
Expand All @@ -141,6 +144,7 @@ public ConnectTask(boolean sslEnabled, SocketAddress[] socketAddresses,
this.eventHandlingStrategy = eventHandlingStrategy;
this.sslConfig = sslConfig;
this.log = log;
this.hostResolutionStrategy = hostResolutionStrategy;

this.proxyType = proxyType;
this.proxyVersion = proxyVersion;
Expand Down Expand Up @@ -194,7 +198,7 @@ private void setupIoConnector() throws ConfigError, GeneralSecurityException {
private void installSslFilter(CompositeIoFilterChainBuilder ioFilterChainBuilder)
throws GeneralSecurityException {
final SSLContext sslContext = SSLContextFactory.getInstance(sslConfig);
final SslFilter sslFilter = new InitiatorSslFilter(sslContext, getSniHostName(sslConfig));
final SslFilter sslFilter = new InitiatorSslFilter(sslContext, getSniHostName(sslConfig), hostResolutionStrategy);
sslFilter.setEnabledCipherSuites(sslConfig.getEnabledCipherSuites() != null ? sslConfig.getEnabledCipherSuites()
: SSLSupport.getDefaultCipherSuites(sslContext));
sslFilter.setEnabledProtocols(sslConfig.getEnabledProtocols() != null ? sslConfig.getEnabledProtocols()
Expand Down Expand Up @@ -294,7 +298,7 @@ private SocketAddress getNextSocketAddress() {
// Recreate socket address to avoid cached address resolution
if (socketAddress instanceof InetSocketAddress) {
InetSocketAddress inetAddr = (InetSocketAddress) socketAddress;
socketAddress = new InetSocketAddress(inetAddr.getHostName(), inetAddr.getPort());
socketAddress = new InetSocketAddress(hostResolutionStrategy.getHost(inetAddr), inetAddr.getPort());
socketAddresses[nextSocketAddressIndex] = socketAddress;
}
nextSocketAddressIndex = (nextSocketAddressIndex + 1) % socketAddresses.length;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,56 @@

import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.ssl.SslFilter;
import quickfix.mina.HostResolutionStrategy;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import java.net.InetSocketAddress;

public final class AcceptorSslFilter extends SslFilter {
private final HostResolutionStrategy hostResolutionStrategy;

public AcceptorSslFilter(SSLContext sslContext) {
public AcceptorSslFilter(SSLContext sslContext, HostResolutionStrategy hostResolutionStrategy) {
super(sslContext);
this.hostResolutionStrategy = hostResolutionStrategy;
}

@Override
protected SSLEngine createEngine(IoSession session, InetSocketAddress addr) {
SSLEngine sslEngine;

if (addr != null) {
sslEngine = sslContext.createSSLEngine(hostResolutionStrategy.getHost(addr), addr.getPort());
} else {
sslEngine = sslContext.createSSLEngine();
}

if (wantClientAuth) {
sslEngine.setWantClientAuth(true);
}

if (needClientAuth) {
sslEngine.setNeedClientAuth(true);
}

if (enabledCipherSuites != null) {
sslEngine.setEnabledCipherSuites(enabledCipherSuites);
}

if (enabledProtocols != null) {
sslEngine.setEnabledProtocols(enabledProtocols);
}

if (getEndpointIdentificationAlgorithm() != null) {
SSLParameters sslParameters = sslEngine.getSSLParameters();
sslParameters.setEndpointIdentificationAlgorithm(getEndpointIdentificationAlgorithm());
sslEngine.setSSLParameters(sslParameters);
}

sslEngine.setUseClientMode(!session.isServer());

return sslEngine;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.ssl.SslFilter;
import quickfix.mina.HostResolutionStrategy;

import javax.net.ssl.SNIHostName;
import javax.net.ssl.SSLContext;
Expand All @@ -10,21 +11,26 @@
import java.net.InetSocketAddress;
import java.util.Collections;

/**
* This class is not part of the public API and may be removed or changed in future releases.
*/
public final class InitiatorSslFilter extends SslFilter {

private final String sniHostName;
private final HostResolutionStrategy hostResolutionStrategy;

public InitiatorSslFilter(SSLContext sslContext, String sniHostName) {
public InitiatorSslFilter(SSLContext sslContext, String sniHostName, HostResolutionStrategy hostResolutionStrategy) {
super(sslContext, false);
this.sniHostName = sniHostName;
this.hostResolutionStrategy = hostResolutionStrategy;
}

@Override
protected SSLEngine createEngine(IoSession session, InetSocketAddress addr) {
SSLEngine sslEngine;

if (addr != null) {
sslEngine = sslContext.createSSLEngine(addr.getHostName(), addr.getPort());
sslEngine = sslContext.createSSLEngine(hostResolutionStrategy.getHost(addr), addr.getPort());
} else {
sslEngine = sslContext.createSSLEngine();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public class SSLSupport {
public static final String SETTING_NEED_CLIENT_AUTH = "NeedClientAuth";
public static final String SETTING_ENDPOINT_IDENTIFICATION_ALGORITHM = "EndpointIdentificationAlgorithm";
public static final String SETTING_USE_SNI = "UseSNI";
public static final String SETTING_REVERSE_DNS_ENABLED = "ReverseDNSEnabled";
public static final String SETTING_SNI_HOST_NAME = "SNIHostName";
public static final String SETTING_ENABLED_PROTOCOLS = "EnabledProtocols";
public static final String SETTING_CIPHER_SUITES = "CipherSuites";
Expand Down
Loading
Loading