diff --git a/core/src/main/java/google/registry/flows/host/HostCreateFlow.java b/core/src/main/java/google/registry/flows/host/HostCreateFlow.java index fc99a8287..aba7acb6d 100644 --- a/core/src/main/java/google/registry/flows/host/HostCreateFlow.java +++ b/core/src/main/java/google/registry/flows/host/HostCreateFlow.java @@ -116,6 +116,7 @@ public final class HostCreateFlow implements MutatingFlow { ? new SubordinateHostMustHaveIpException() : new UnexpectedExternalHostIpException(); } + HostFlowUtils.validateInetAddresses(command.getInetAddresses()); Host newHost = new Host.Builder() .setCreationRegistrarId(registrarId) diff --git a/core/src/main/java/google/registry/flows/host/HostFlowUtils.java b/core/src/main/java/google/registry/flows/host/HostFlowUtils.java index 1c1d32f8c..c780701dc 100644 --- a/core/src/main/java/google/registry/flows/host/HostFlowUtils.java +++ b/core/src/main/java/google/registry/flows/host/HostFlowUtils.java @@ -22,6 +22,7 @@ import static java.util.stream.Collectors.joining; import com.google.common.base.Ascii; import com.google.common.base.CharMatcher; +import com.google.common.collect.ImmutableSet; import com.google.common.net.InternetDomainName; import google.registry.flows.EppException; import google.registry.flows.EppException.AuthorizationErrorException; @@ -34,6 +35,7 @@ import google.registry.model.ForeignKeyUtils; import google.registry.model.domain.Domain; import google.registry.model.eppcommon.StatusValue; import google.registry.util.Idn; +import java.net.InetAddress; import java.util.Optional; import org.joda.time.DateTime; @@ -108,6 +110,24 @@ public class HostFlowUtils { return superordinateDomain; } + /** Makes sure that no provided IP addresses are local / loopback addresses. */ + public static void validateInetAddresses(ImmutableSet inetAddresses) + throws EppException { + if (inetAddresses == null) { + return; + } + if (inetAddresses.stream().anyMatch(InetAddress::isLoopbackAddress)) { + throw new LoopbackIpNotValidForHostException(); + } + } + + /** Loopback IPs are not valid for hosts. */ + static class LoopbackIpNotValidForHostException extends ParameterValuePolicyErrorException { + public LoopbackIpNotValidForHostException() { + super("Loopback IPs are not valid for hosts"); + } + } + /** Superordinate domain for this hostname does not exist. */ static class SuperordinateDomainDoesNotExistException extends ObjectDoesNotExistException { public SuperordinateDomainDoesNotExistException(String domainName) { diff --git a/core/src/main/java/google/registry/flows/host/HostUpdateFlow.java b/core/src/main/java/google/registry/flows/host/HostUpdateFlow.java index 0a553df9b..0c1fc51be 100644 --- a/core/src/main/java/google/registry/flows/host/HostUpdateFlow.java +++ b/core/src/main/java/google/registry/flows/host/HostUpdateFlow.java @@ -161,6 +161,7 @@ public final class HostUpdateFlow implements MutatingFlow { AddRemove remove = command.getInnerRemove(); checkSameValuesNotAddedAndRemoved(add.getStatusValues(), remove.getStatusValues()); checkSameValuesNotAddedAndRemoved(add.getInetAddresses(), remove.getInetAddresses()); + HostFlowUtils.validateInetAddresses(add.getInetAddresses()); VKey newSuperordinateDomainKey = newSuperordinateDomain.map(Domain::createVKey).orElse(null); // If the superordinateDomain field is changing, set the lastSuperordinateChange to now. diff --git a/core/src/test/java/google/registry/flows/host/HostCreateFlowTest.java b/core/src/test/java/google/registry/flows/host/HostCreateFlowTest.java index f466db2ec..d1b682676 100644 --- a/core/src/test/java/google/registry/flows/host/HostCreateFlowTest.java +++ b/core/src/test/java/google/registry/flows/host/HostCreateFlowTest.java @@ -45,6 +45,7 @@ import google.registry.flows.host.HostFlowUtils.HostNameNotNormalizedException; import google.registry.flows.host.HostFlowUtils.HostNameNotPunyCodedException; import google.registry.flows.host.HostFlowUtils.HostNameTooLongException; import google.registry.flows.host.HostFlowUtils.HostNameTooShallowException; +import google.registry.flows.host.HostFlowUtils.LoopbackIpNotValidForHostException; import google.registry.flows.host.HostFlowUtils.SuperordinateDomainDoesNotExistException; import google.registry.flows.host.HostFlowUtils.SuperordinateDomainInPendingDeleteException; import google.registry.model.ForeignKeyUtils; @@ -322,6 +323,26 @@ class HostCreateFlowTest extends ResourceFlowTestCase { assertAboutEppExceptions().that(thrown).marshalsToXml(); } + @Test + void testFailure_localhostInetAddress_ipv4() { + createTld("tld"); + persistActiveDomain("example.tld"); + setEppHostCreateInput("ns1.example.tld", "127.0.0.1"); + assertAboutEppExceptions() + .that(assertThrows(LoopbackIpNotValidForHostException.class, this::runFlow)) + .marshalsToXml(); + } + + @Test + void testFailure_localhostInetAddress_ipv6() { + createTld("tld"); + persistActiveDomain("example.tld"); + setEppHostCreateInput("ns1.example.tld", "::1"); + assertAboutEppExceptions() + .that(assertThrows(LoopbackIpNotValidForHostException.class, this::runFlow)) + .marshalsToXml(); + } + @Test void testIcannActivityReportField_getsLogged() throws Exception { runFlow(); diff --git a/core/src/test/java/google/registry/flows/host/HostUpdateFlowTest.java b/core/src/test/java/google/registry/flows/host/HostUpdateFlowTest.java index 84b7bf8f4..2387bfcc4 100644 --- a/core/src/test/java/google/registry/flows/host/HostUpdateFlowTest.java +++ b/core/src/test/java/google/registry/flows/host/HostUpdateFlowTest.java @@ -61,6 +61,7 @@ import google.registry.flows.host.HostFlowUtils.HostNameNotNormalizedException; import google.registry.flows.host.HostFlowUtils.HostNameNotPunyCodedException; import google.registry.flows.host.HostFlowUtils.HostNameTooLongException; import google.registry.flows.host.HostFlowUtils.HostNameTooShallowException; +import google.registry.flows.host.HostFlowUtils.LoopbackIpNotValidForHostException; import google.registry.flows.host.HostFlowUtils.SuperordinateDomainDoesNotExistException; import google.registry.flows.host.HostFlowUtils.SuperordinateDomainInPendingDeleteException; import google.registry.flows.host.HostUpdateFlow.CannotAddIpToExternalHostException; @@ -1306,6 +1307,28 @@ class HostUpdateFlowTest extends ResourceFlowTestCase { doFailingHostNameTest("foo.co.uk", HostNameTooShallowException.class); } + @Test + void testFailure_localhostInetAddress_ipv4() throws Exception { + createTld("tld"); + persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld")); + setEppHostUpdateInput( + "ns1.example.tld", "ns2.example.tld", "127.0.0.1", null); + assertAboutEppExceptions() + .that(assertThrows(LoopbackIpNotValidForHostException.class, this::runFlow)) + .marshalsToXml(); + } + + @Test + void testFailure_localhostInetAddress_ipv6() throws Exception { + createTld("tld"); + persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld")); + setEppHostUpdateInput( + "ns1.example.tld", "ns2.example.tld", "::1", null); + assertAboutEppExceptions() + .that(assertThrows(LoopbackIpNotValidForHostException.class, this::runFlow)) + .marshalsToXml(); + } + @Test void testSuccess_metadata() throws Exception { createTld("tld");