diff --git a/code/common/service-discovery/src/main/java/nu/marginalia/service/discovery/ZkServiceRegistry.java b/code/common/service-discovery/src/main/java/nu/marginalia/service/discovery/ZkServiceRegistry.java index a75d1f8d..48efc64f 100644 --- a/code/common/service-discovery/src/main/java/nu/marginalia/service/discovery/ZkServiceRegistry.java +++ b/code/common/service-discovery/src/main/java/nu/marginalia/service/discovery/ZkServiceRegistry.java @@ -192,10 +192,18 @@ public class ZkServiceRegistry implements ServiceRegistryIf { .getData() .forPath(ZKPaths.makePath(restRoot, uuid)); String hostAndPort = new String(data); - ret.add(RestEndpoint + var address = RestEndpoint .parse(hostAndPort) - .asInstance(UUID.fromString(uuid)) - ); + .asInstance(UUID.fromString(uuid)); + + // Ensure that the address is resolvable + // (this reduces the risk of exceptions when trying to connect to the service) + if (!address.endpoint().validateHost()) { + logger.warn("Omitting stale address {}, address does not resolve", address); + continue; + } + + ret.add(address); } @@ -221,11 +229,20 @@ public class ZkServiceRegistry implements ServiceRegistryIf { byte[] data = curatorFramework .getData() .forPath(ZKPaths.makePath(restRoot, uuid)); + String hostAndPort = new String(data); - ret.add(GrpcEndpoint + var address = GrpcEndpoint .parse(hostAndPort) - .asInstance(UUID.fromString(uuid)) - ); + .asInstance(UUID.fromString(uuid)); + + // Ensure that the address is resolvable + // (this reduces the risk of exceptions when trying to connect to the service) + if (!address.endpoint().validateHost()) { + logger.warn("Omitting stale address {}, address does not resolve", address); + continue; + } + + ret.add(address); } diff --git a/code/common/service-discovery/src/main/java/nu/marginalia/service/discovery/property/ServiceEndpoint.java b/code/common/service-discovery/src/main/java/nu/marginalia/service/discovery/property/ServiceEndpoint.java index e8ce621e..7763eca0 100644 --- a/code/common/service-discovery/src/main/java/nu/marginalia/service/discovery/property/ServiceEndpoint.java +++ b/code/common/service-discovery/src/main/java/nu/marginalia/service/discovery/property/ServiceEndpoint.java @@ -3,9 +3,7 @@ package nu.marginalia.service.discovery.property; import lombok.SneakyThrows; -import java.net.InetSocketAddress; -import java.net.URI; -import java.net.URL; +import java.net.*; import java.util.UUID; public sealed interface ServiceEndpoint { @@ -17,6 +15,22 @@ public sealed interface ServiceEndpoint { return new InetSocketAddress(host(), port()); } + /** Validate the host by checking if it is a valid IP address or a hostname that can be resolved. + * + * @return true if the host is a valid + */ + default boolean validateHost() { + try { + // Throws UnknownHostException if the host is not a valid IP address or hostname + // (this should not be slow since the DNS lookup should be local, and if it isn't; + // should be cached by the OS or the JVM) + InetAddress.getByName(host()); + return true; + } catch (UnknownHostException e) { + return false; + } + } + static ServiceEndpoint forSchema(ApiSchema schema, String host, int port) { return switch (schema) { case REST -> new RestEndpoint(host, port);