Skip to content

Commit 9a7cadb

Browse files
committed
feat(plc4j/opcua): Remove additional hostname resolution within connect attempts.
Closes #1897. Removed code which caused additional DNS lookups in favor of endpoint-port and endpoint-host options provided with plc4j 0.13. Signed-off-by: Łukasz Dywicki <[email protected]>
1 parent 5c73dfe commit 9a7cadb

File tree

3 files changed

+26
-52
lines changed

3 files changed

+26
-52
lines changed

plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/config/OpcuaConfiguration.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,11 @@ public class OpcuaConfiguration implements PlcConnectionConfiguration {
136136
private Limits limits;
137137

138138
@ConfigurationParameter("endpoint-host")
139-
@Description("Endpoint host used to establish secure channel.")
139+
@Description("Endpoint host used to establish secure channel connection. Used when client made connection to server which advertises different hostname than one used for network connection.")
140140
private String endpointHost;
141141

142142
@ConfigurationParameter("endpoint-port")
143-
@Description("Endpoint port used to establish secure channel")
143+
@Description("Endpoint port used to establish secure channel. Used when client made connection to server which advertises different port number than one used for network connection.")
144144
private Integer endpointPort;
145145

146146
public String getProtocolCode() {

plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/OpcuaDriverContext.java

-7
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,6 @@ public void setConfiguration(OpcuaConfiguration configuration) {
139139
port = matcher.group("transportPort");
140140
transportEndpoint = matcher.group("transportEndpoint");
141141

142-
if (configuration.getEndpointHost() != null) {
143-
host = configuration.getEndpointHost();
144-
}
145-
if (configuration.getEndpointPort() != null) {
146-
port = String.valueOf(configuration.getEndpointPort());
147-
}
148-
149142
String portAddition = port != null ? ":" + port : "";
150143
endpoint = "opc." + code + "://" + host + portAddition + transportEndpoint;
151144

plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/SecureChannel.java

+24-43
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@
2828
import java.security.cert.CertificateEncodingException;
2929
import java.security.cert.CertificateFactory;
3030
import java.security.cert.X509Certificate;
31-
import java.util.Collection;
3231
import java.util.Comparator;
33-
import java.util.HashSet;
3432
import java.util.Map.Entry;
3533
import java.util.Set;
3634
import java.util.concurrent.ScheduledExecutorService;
@@ -54,8 +52,6 @@
5452
import org.slf4j.Logger;
5553
import org.slf4j.LoggerFactory;
5654

57-
import java.net.InetAddress;
58-
import java.net.UnknownHostException;
5955
import java.nio.ByteBuffer;
6056
import java.nio.ByteOrder;
6157
import java.util.ArrayList;
@@ -95,7 +91,6 @@ public class SecureChannel {
9591
private final OpcuaDriverContext driverContext;
9692
private final Conversation conversation;
9793
private ScheduledFuture<?> keepAlive;
98-
private final Set<String> endpoints = new HashSet<>();
9994
private double sessionTimeout;
10095
private long revisedLifetime;
10196

@@ -118,17 +113,6 @@ public SecureChannel(Conversation conversation, RequestTransactionManager tm, Op
118113
this.password = configuration.getPassword();
119114
}
120115

121-
// Generate a list of endpoints we can use.
122-
try {
123-
InetAddress address = InetAddress.getByName(driverContext.getHost());
124-
this.endpoints.add("opc.tcp://" + address.getHostAddress() + ":" + driverContext.getPort() + driverContext.getTransportEndpoint());
125-
this.endpoints.add("opc.tcp://" + address.getHostName() + ":" + driverContext.getPort() + driverContext.getTransportEndpoint());
126-
this.endpoints.add("opc.tcp://" + address.getCanonicalHostName() + ":" + driverContext.getPort() + driverContext.getTransportEndpoint());
127-
} catch (UnknownHostException e) {
128-
LOGGER.warn("Unable to resolve host name. Using original host from connection string which may cause issues connecting to server");
129-
this.endpoints.add(driverContext.getHost());
130-
}
131-
132116
if (conversation.getSecurityPolicy() == SecurityPolicy.NONE) {
133117
this.localCertificateString = NULL_BYTE_STRING;
134118
this.remoteCertificateThumbprint = NULL_BYTE_STRING;
@@ -314,23 +298,10 @@ private CompletableFuture<ActivateSessionResponse> onConnectActivateSessionReque
314298
conversation.setRemoteCertificate(getX509Certificate(sessionResponse.getServerCertificate().getStringValue()));
315299
conversation.setRemoteNonce(sessionResponse.getServerNonce().getStringValue());
316300

317-
List<String> contactPoints = new ArrayList<>(3);
318-
String port = driverContext.getPort() == null ? "" : ":" + driverContext.getPort();
319-
try {
320-
InetAddress address = InetAddress.getByName(driverContext.getHost());
321-
contactPoints.add("opc.tcp://" + address.getHostAddress() + port + driverContext.getTransportEndpoint());
322-
contactPoints.add("opc.tcp://" + address.getHostName() + port + driverContext.getTransportEndpoint());
323-
contactPoints.add("opc.tcp://" + address.getCanonicalHostName() + port + driverContext.getTransportEndpoint());
324-
} catch (UnknownHostException e) {
325-
// fall back to declared host
326-
contactPoints.add("opc.tcp://" + driverContext.getHost() + port + driverContext.getTransportEndpoint());
327-
LOGGER.warn("Could not reach host {}, possible network failure", driverContext.getHost(), e);
328-
}
329-
330-
Entry<EndpointDescription, UserTokenPolicy> selectedEndpoint = selectEndpoint(sessionResponse.getServerEndpoints(), contactPoints,
301+
Entry<EndpointDescription, UserTokenPolicy> selectedEndpoint = selectEndpoint(sessionResponse.getServerEndpoints(),
331302
configuration.getSecurityPolicy(), configuration.getMessageSecurity());
332303
if (selectedEndpoint == null) {
333-
throw new PlcRuntimeException("Unable to find endpoint matching " + contactPoints.get(0));
304+
throw new PlcRuntimeException("Unable to find endpoint matching " + driverContext.getEndpoint());
334305
}
335306

336307
PascalString policyId = selectedEndpoint.getValue().getPolicyId();
@@ -421,7 +392,8 @@ public CompletableFuture<EndpointDescription> onDiscoverGetEndpointsRequest() {
421392
);
422393

423394
return conversation.submit(endpointsRequest, GetEndpointsResponse.class).thenApply(response -> {
424-
Entry<EndpointDescription, UserTokenPolicy> entry = selectEndpoint(response.getEndpoints(), this.endpoints, this.configuration.getSecurityPolicy(), this.configuration.getMessageSecurity());
395+
Entry<EndpointDescription, UserTokenPolicy> entry = selectEndpoint(response.getEndpoints(),
396+
this.configuration.getSecurityPolicy(), this.configuration.getMessageSecurity());
425397

426398
if (entry == null) {
427399
Set<String> endpointUris = response.getEndpoints().stream()
@@ -494,19 +466,18 @@ private static ReadBufferByteBased toBuffer(Supplier<Payload> supplier) {
494466
* Selects the endpoint and authentication policy based on client settings.
495467
*
496468
* @param extensionObjects Endpoint descriptions returned by the server.
497-
* @param contactPoints Contact points expected by client.
498469
* @param securityPolicy Security policy searched in endpoints.
499470
* @param messageSecurity Message security needed by client.
500471
* @return Endpoint matching given.
501472
*/
502-
private Entry<EndpointDescription, UserTokenPolicy> selectEndpoint(List<EndpointDescription> extensionObjects, Collection<String> contactPoints,
473+
private Entry<EndpointDescription, UserTokenPolicy> selectEndpoint(List<EndpointDescription> extensionObjects,
503474
SecurityPolicy securityPolicy, MessageSecurity messageSecurity) throws PlcRuntimeException {
504475
// Get a list of the endpoints which match ours.
505476
MessageSecurityMode effectiveMessageSecurity = SecurityPolicy.NONE == securityPolicy ? MessageSecurityMode.messageSecurityModeNone : messageSecurity.getMode();
506477
List<Entry<EndpointDescription, UserTokenPolicy>> serverEndpoints = new ArrayList<>();
507478

508479
for (EndpointDescription endpointDescription : extensionObjects) {
509-
if (isMatchingEndpoint(endpointDescription, contactPoints)) {
480+
if (isMatchingEndpointDescription(endpointDescription)) {
510481
boolean policyMatch = endpointDescription.getSecurityPolicyUri().getStringValue().equals(securityPolicy.getSecurityPolicyUri());
511482
boolean msgSecurityMatch = endpointDescription.getSecurityMode().equals(effectiveMessageSecurity);
512483

@@ -530,22 +501,32 @@ private Entry<EndpointDescription, UserTokenPolicy> selectEndpoint(List<Endpoint
530501
return serverEndpoints.get(0);
531502
}
532503

504+
private boolean isMatchingEndpointDescription(EndpointDescription endpointDescription) {
505+
if (isMatchingEndpoint(endpointDescription, driverContext.getHost(), driverContext.getPort(), driverContext.getTransportEndpoint())) {
506+
return true;
507+
}
508+
if (configuration.getEndpointHost() != null) {
509+
return isMatchingEndpoint(endpointDescription, configuration.getEndpointHost(), configuration.getEndpointPort() == null ? driverContext.getPort() : String.valueOf(configuration.getEndpointPort()), driverContext.getTransportEndpoint());
510+
} else if (configuration.getEndpointPort() != null) {
511+
return isMatchingEndpoint(endpointDescription, driverContext.getHost(), configuration.getEndpointPort().toString(), driverContext.getTransportEndpoint());
512+
}
513+
return false;
514+
}
515+
533516
/**
534517
* Checks each component of the return endpoint description against the connection string.
535518
* If all are correct then return true.
536519
*
537520
* @param endpoint - EndpointDescription returned from server
521+
* @param host Permitted host
522+
* @param port Permitted port
523+
* @param transportEndpoint Transport endpoint
538524
* @return true if this endpoint matches our configuration
539525
* @throws PlcRuntimeException - If the returned endpoint string doesn't match the format expected
540526
*/
541-
private static boolean isMatchingEndpoint(EndpointDescription endpoint, Collection<String> contactPoints) throws PlcRuntimeException {
542-
// Split up the connection string into it's individual segments.
543-
for (String contactPoint : contactPoints) {
544-
if (endpoint.getEndpointUrl().getStringValue().startsWith(contactPoint)) {
545-
return true;
546-
}
547-
}
548-
return false;
527+
private static boolean isMatchingEndpoint(EndpointDescription endpoint, String host, String port, String transportEndpoint) throws PlcRuntimeException {
528+
String portAddition = port == null ? "" : ":" + port;
529+
return endpoint.getEndpointUrl().getStringValue().startsWith("opc.tcp://" + host + portAddition + transportEndpoint);
549530
}
550531

551532
/**

0 commit comments

Comments
 (0)