mirror of
https://github.com/google/nomulus.git
synced 2025-05-13 16:07:15 +02:00
Minor fixes to dnsupdate writer
This commit is contained in:
parent
1a0c282cf8
commit
030d6b92ab
8 changed files with 92 additions and 37 deletions
|
@ -41,9 +41,9 @@ public interface DnsWriter extends AutoCloseable {
|
||||||
/**
|
/**
|
||||||
* Loads {@code hostName} from datastore and publishes its A/AAAA glue records to the DNS server.
|
* Loads {@code hostName} from datastore and publishes its A/AAAA glue records to the DNS server.
|
||||||
* Replaces existing records for the exact name supplied, with an A or AAAA record (as
|
* Replaces existing records for the exact name supplied, with an A or AAAA record (as
|
||||||
* appropriate) for each address stored in the registry, for the supplied host name. If the host is
|
* appropriate) for each address stored in the registry, for the supplied host name. If the host
|
||||||
* deleted then the existing records are deleted. Assumes that this method will only be called for
|
* is deleted then the existing records are deleted. Assumes that this method will only be called
|
||||||
* in-bailiwick hosts. The registry does not have addresses for other hosts.
|
* for in-bailiwick hosts. The registry does not have addresses for other hosts.
|
||||||
*
|
*
|
||||||
* @param hostName the fully qualified host name, with no trailing dot
|
* @param hostName the fully qualified host name, with no trailing dot
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2,6 +2,8 @@ package(
|
||||||
default_visibility = ["//java/google/registry:registry_project"],
|
default_visibility = ["//java/google/registry:registry_project"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
licenses(["notice"]) # Apache 2.0
|
||||||
|
|
||||||
|
|
||||||
java_library(
|
java_library(
|
||||||
name = "dnsupdate",
|
name = "dnsupdate",
|
||||||
|
@ -13,14 +15,14 @@ java_library(
|
||||||
"//java/com/google/common/io",
|
"//java/com/google/common/io",
|
||||||
"//java/com/google/common/net",
|
"//java/com/google/common/net",
|
||||||
"//java/com/google/common/primitives",
|
"//java/com/google/common/primitives",
|
||||||
"//java/google/registry/config",
|
|
||||||
"//java/google/registry/dns/writer/api",
|
|
||||||
"//java/google/registry/model",
|
|
||||||
"//java/google/registry/util",
|
|
||||||
"//third_party/java/dagger",
|
"//third_party/java/dagger",
|
||||||
"//third_party/java/dnsjava",
|
"//third_party/java/dnsjava",
|
||||||
"//third_party/java/joda_time",
|
"//third_party/java/joda_time",
|
||||||
"//third_party/java/jsr305_annotations",
|
"//third_party/java/jsr305_annotations",
|
||||||
"//third_party/java/jsr330_inject",
|
"//third_party/java/jsr330_inject",
|
||||||
|
"//java/google/registry/config",
|
||||||
|
"//java/google/registry/dns/writer/api",
|
||||||
|
"//java/google/registry/model",
|
||||||
|
"//java/google/registry/util",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -25,6 +25,7 @@ import google.registry.config.ConfigModule.Config;
|
||||||
import org.joda.time.Duration;
|
import org.joda.time.Duration;
|
||||||
import org.xbill.DNS.Message;
|
import org.xbill.DNS.Message;
|
||||||
import org.xbill.DNS.Opcode;
|
import org.xbill.DNS.Opcode;
|
||||||
|
import org.xbill.DNS.SimpleResolver;
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -33,6 +34,7 @@ import java.io.OutputStream;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.net.SocketFactory;
|
import javax.net.SocketFactory;
|
||||||
|
|
|
@ -21,6 +21,7 @@ import google.registry.config.ConfigModule.Config;
|
||||||
|
|
||||||
import org.joda.time.Duration;
|
import org.joda.time.Duration;
|
||||||
|
|
||||||
|
/** Dagger module that provides DNS configuration settings. */
|
||||||
@Module
|
@Module
|
||||||
public class DnsUpdateConfigModule {
|
public class DnsUpdateConfigModule {
|
||||||
|
|
||||||
|
|
|
@ -66,8 +66,8 @@ import javax.inject.Inject;
|
||||||
* <p>Only NS, DS, A, and AAAA records are published, and in particular no DNSSEC signing is done
|
* <p>Only NS, DS, A, and AAAA records are published, and in particular no DNSSEC signing is done
|
||||||
* assuming that this will be done by a third party DNS provider.
|
* assuming that this will be done by a third party DNS provider.
|
||||||
*
|
*
|
||||||
* <p>Each publish call is treated as an atomic update to the DNS. If an update fails an exception is
|
* <p>Each publish call is treated as an atomic update to the DNS. If an update fails an exception
|
||||||
* thrown, expecting the caller to retry the update later. The SOA record serial number is
|
* is thrown, expecting the caller to retry the update later. The SOA record serial number is
|
||||||
* implicitly incremented by the server on each UPDATE message, as required by RFC 2136. Care must
|
* implicitly incremented by the server on each UPDATE message, as required by RFC 2136. Care must
|
||||||
* be taken to make sure the SOA serial number does not go backwards if the entire TLD (zone) is
|
* be taken to make sure the SOA serial number does not go backwards if the entire TLD (zone) is
|
||||||
* "reset" to empty and republished.
|
* "reset" to empty and republished.
|
||||||
|
@ -193,13 +193,16 @@ public class DnsUpdateWriter implements DnsWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private RRset makeV6AddressSet(String hostName, Iterable<InetAddress> addresses)
|
private RRset makeV6AddressSet(String hostName, Iterable<InetAddress> addresses)
|
||||||
throws TextParseException {
|
throws TextParseException, IOException {
|
||||||
RRset addressSet = new RRset();
|
RRset addressSet = new RRset();
|
||||||
for (InetAddress address : addresses) {
|
for (InetAddress address : addresses) {
|
||||||
if (address instanceof Inet6Address) {
|
if (address instanceof Inet6Address) {
|
||||||
AAAARecord record =
|
AAAARecord record =
|
||||||
new AAAARecord(
|
new AAAARecord(
|
||||||
toAbsoluteName(hostName), DClass.IN, dnsTimeToLive.getStandardSeconds(), address);
|
toAbsoluteName(hostName),
|
||||||
|
DClass.IN,
|
||||||
|
dnsTimeToLive.getStandardSeconds(),
|
||||||
|
new org.xbill.DNS.Inet6Address(address.getAddress()));
|
||||||
addressSet.addRR(record);
|
addressSet.addRR(record);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
39
javatests/google/registry/dns/writer/dnsupdate/BUILD
Normal file
39
javatests/google/registry/dns/writer/dnsupdate/BUILD
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package(
|
||||||
|
default_testonly = 1,
|
||||||
|
default_visibility = ["//java/google/registry:registry_project"],
|
||||||
|
)
|
||||||
|
|
||||||
|
licenses(["notice"]) # Apache 2.0
|
||||||
|
|
||||||
|
load("//java/com/google/testing/builddefs:GenTestRules.bzl", "GenTestRules")
|
||||||
|
|
||||||
|
|
||||||
|
java_library(
|
||||||
|
name = "dnsupdate",
|
||||||
|
srcs = glob(["*.java"]),
|
||||||
|
deps = [
|
||||||
|
"//java/com/google/common/base",
|
||||||
|
"//java/com/google/common/collect",
|
||||||
|
"//java/com/google/common/io",
|
||||||
|
"//java/com/google/common/net",
|
||||||
|
"//third_party/java/dagger",
|
||||||
|
"//third_party/java/dnsjava",
|
||||||
|
"//third_party/java/joda_time",
|
||||||
|
"//third_party/java/jsr305_annotations",
|
||||||
|
"//third_party/java/junit",
|
||||||
|
"//third_party/java/mockito",
|
||||||
|
"//third_party/java/objectify:objectify-v4_1",
|
||||||
|
"//third_party/java/re2j",
|
||||||
|
"//third_party/java/servlet/servlet_api",
|
||||||
|
"//third_party/java/truth",
|
||||||
|
"//java/google/registry/dns/writer/dnsupdate",
|
||||||
|
"//java/google/registry/model",
|
||||||
|
"//javatests/google/registry/testing",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
GenTestRules(
|
||||||
|
name = "GeneratedTestRules",
|
||||||
|
test_files = glob(["*Test.java"]),
|
||||||
|
deps = [":dnsupdate"],
|
||||||
|
)
|
|
@ -22,11 +22,12 @@ import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import com.google.common.base.VerifyException;
|
import com.google.common.base.VerifyException;
|
||||||
|
|
||||||
|
import google.registry.testing.ExceptionRule;
|
||||||
|
|
||||||
import org.joda.time.Duration;
|
import org.joda.time.Duration;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.ExpectedException;
|
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.runners.MockitoJUnitRunner;
|
import org.mockito.runners.MockitoJUnitRunner;
|
||||||
|
@ -45,7 +46,6 @@ import org.xbill.DNS.utils.base16;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
@ -61,13 +61,18 @@ public class DnsMessageTransportTest {
|
||||||
|
|
||||||
private static final String UPDATE_HOST = "127.0.0.1";
|
private static final String UPDATE_HOST = "127.0.0.1";
|
||||||
|
|
||||||
@Mock private SocketFactory mockFactory;
|
@Mock
|
||||||
@Mock private Socket mockSocket;
|
private SocketFactory mockFactory;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Socket mockSocket;
|
||||||
|
|
||||||
private Message simpleQuery;
|
private Message simpleQuery;
|
||||||
private Message expectedResponse;
|
private Message expectedResponse;
|
||||||
private DnsMessageTransport resolver;
|
private DnsMessageTransport resolver;
|
||||||
|
|
||||||
@Rule public ExpectedException thrown = ExpectedException.none();
|
@Rule
|
||||||
|
public final ExceptionRule thrown = new ExceptionRule();
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void before() throws Exception {
|
public void before() throws Exception {
|
||||||
|
@ -153,8 +158,7 @@ public class DnsMessageTransportTest {
|
||||||
}
|
}
|
||||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
when(mockSocket.getOutputStream()).thenReturn(outputStream);
|
when(mockSocket.getOutputStream()).thenReturn(outputStream);
|
||||||
thrown.expect(IllegalArgumentException.class);
|
thrown.expect(IllegalArgumentException.class, "message larger than maximum");
|
||||||
thrown.expectMessage("message larger than maximum");
|
|
||||||
|
|
||||||
resolver.send(oversize);
|
resolver.send(oversize);
|
||||||
}
|
}
|
||||||
|
@ -165,8 +169,8 @@ public class DnsMessageTransportTest {
|
||||||
when(mockSocket.getInputStream())
|
when(mockSocket.getInputStream())
|
||||||
.thenReturn(new ByteArrayInputStream(messageToBytesWithLength(expectedResponse)));
|
.thenReturn(new ByteArrayInputStream(messageToBytesWithLength(expectedResponse)));
|
||||||
when(mockSocket.getOutputStream()).thenReturn(new ByteArrayOutputStream());
|
when(mockSocket.getOutputStream()).thenReturn(new ByteArrayOutputStream());
|
||||||
thrown.expect(VerifyException.class);
|
thrown.expect(
|
||||||
thrown.expectMessage(
|
VerifyException.class,
|
||||||
"response ID "
|
"response ID "
|
||||||
+ expectedResponse.getHeader().getID()
|
+ expectedResponse.getHeader().getID()
|
||||||
+ " does not match query ID "
|
+ " does not match query ID "
|
||||||
|
@ -182,8 +186,8 @@ public class DnsMessageTransportTest {
|
||||||
when(mockSocket.getInputStream())
|
when(mockSocket.getInputStream())
|
||||||
.thenReturn(new ByteArrayInputStream(messageToBytesWithLength(expectedResponse)));
|
.thenReturn(new ByteArrayInputStream(messageToBytesWithLength(expectedResponse)));
|
||||||
when(mockSocket.getOutputStream()).thenReturn(new ByteArrayOutputStream());
|
when(mockSocket.getOutputStream()).thenReturn(new ByteArrayOutputStream());
|
||||||
thrown.expect(VerifyException.class);
|
thrown.expect(
|
||||||
thrown.expectMessage("response opcode 'STATUS' does not match query opcode 'QUERY'");
|
VerifyException.class, "response opcode 'STATUS' does not match query opcode 'QUERY'");
|
||||||
|
|
||||||
resolver.send(simpleQuery);
|
resolver.send(simpleQuery);
|
||||||
}
|
}
|
||||||
|
@ -196,7 +200,7 @@ public class DnsMessageTransportTest {
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] messageToBytesWithLength(Message message) throws IOException {
|
private byte[] messageToBytesWithLength(Message message) {
|
||||||
byte[] bytes = message.toWire();
|
byte[] bytes = message.toWire();
|
||||||
ByteBuffer buffer =
|
ByteBuffer buffer =
|
||||||
ByteBuffer.allocate(bytes.length + DnsMessageTransport.MESSAGE_LENGTH_FIELD_BYTES);
|
ByteBuffer.allocate(bytes.length + DnsMessageTransport.MESSAGE_LENGTH_FIELD_BYTES);
|
||||||
|
|
|
@ -39,6 +39,7 @@ import google.registry.model.eppcommon.StatusValue;
|
||||||
import google.registry.model.host.HostResource;
|
import google.registry.model.host.HostResource;
|
||||||
import google.registry.model.ofy.Ofy;
|
import google.registry.model.ofy.Ofy;
|
||||||
import google.registry.testing.AppEngineRule;
|
import google.registry.testing.AppEngineRule;
|
||||||
|
import google.registry.testing.ExceptionRule;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
import google.registry.testing.InjectRule;
|
import google.registry.testing.InjectRule;
|
||||||
|
|
||||||
|
@ -49,7 +50,6 @@ import org.joda.time.Duration;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.ExpectedException;
|
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Captor;
|
import org.mockito.Captor;
|
||||||
|
@ -76,16 +76,20 @@ public class DnsUpdateWriterTest {
|
||||||
public final AppEngineRule appEngine =
|
public final AppEngineRule appEngine =
|
||||||
AppEngineRule.builder().withDatastore().withTaskQueue().build();
|
AppEngineRule.builder().withDatastore().withTaskQueue().build();
|
||||||
|
|
||||||
@Rule public ExpectedException thrown = ExpectedException.none();
|
@Rule
|
||||||
|
public final ExceptionRule thrown = new ExceptionRule();
|
||||||
|
|
||||||
@Rule public final InjectRule inject = new InjectRule();
|
@Rule
|
||||||
|
public final InjectRule inject = new InjectRule();
|
||||||
|
|
||||||
private final FakeClock clock = new FakeClock(DateTime.parse("1971-01-01TZ"));
|
private final FakeClock clock = new FakeClock(DateTime.parse("1971-01-01TZ"));
|
||||||
|
|
||||||
@Mock private DnsMessageTransport mockResolver;
|
@Mock
|
||||||
@Captor private ArgumentCaptor<Update> updateCaptor;
|
private DnsMessageTransport mockResolver;
|
||||||
private DelegationSignerData testSignerData =
|
|
||||||
DelegationSignerData.create(1, 3, 1, base16().decode("0123456789ABCDEF"));
|
@Captor
|
||||||
|
private ArgumentCaptor<Update> updateCaptor;
|
||||||
|
|
||||||
private DnsUpdateWriter writer;
|
private DnsUpdateWriter writer;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
|
@ -127,7 +131,9 @@ public class DnsUpdateWriterTest {
|
||||||
.asBuilder()
|
.asBuilder()
|
||||||
.setNameservers(
|
.setNameservers(
|
||||||
ImmutableSet.of(ReferenceUnion.create(persistActiveHost("ns1.example.tld"))))
|
ImmutableSet.of(ReferenceUnion.create(persistActiveHost("ns1.example.tld"))))
|
||||||
.setDsData(ImmutableSet.of(testSignerData))
|
.setDsData(
|
||||||
|
ImmutableSet.of(
|
||||||
|
DelegationSignerData.create(1, 3, 1, base16().decode("0123456789ABCDEF"))))
|
||||||
.build();
|
.build();
|
||||||
persistResource(domain);
|
persistResource(domain);
|
||||||
|
|
||||||
|
@ -184,7 +190,7 @@ public class DnsUpdateWriterTest {
|
||||||
ImmutableSet.of(
|
ImmutableSet.of(
|
||||||
InetAddresses.forString("10.0.0.1"),
|
InetAddresses.forString("10.0.0.1"),
|
||||||
InetAddresses.forString("10.1.0.1"),
|
InetAddresses.forString("10.1.0.1"),
|
||||||
InetAddresses.forString("fd0e:a5c8:6dfb:6a5e:0:0:0:1")))
|
InetAddresses.forString("fd0e:a5c8:6dfb:6a5e::1")))
|
||||||
.build();
|
.build();
|
||||||
persistResource(host);
|
persistResource(host);
|
||||||
|
|
||||||
|
@ -195,7 +201,7 @@ public class DnsUpdateWriterTest {
|
||||||
assertThatUpdatedZoneIs(update, "tld.");
|
assertThatUpdatedZoneIs(update, "tld.");
|
||||||
assertThatUpdateDeletes(update, "ns1.example.tld.", Type.ANY);
|
assertThatUpdateDeletes(update, "ns1.example.tld.", Type.ANY);
|
||||||
assertThatUpdateAdds(update, "ns1.example.tld.", Type.A, "10.0.0.1", "10.1.0.1");
|
assertThatUpdateAdds(update, "ns1.example.tld.", Type.A, "10.0.0.1", "10.1.0.1");
|
||||||
assertThatUpdateAdds(update, "ns1.example.tld.", Type.AAAA, "fd0e:a5c8:6dfb:6a5e:0:0:0:1");
|
assertThatUpdateAdds(update, "ns1.example.tld.", Type.AAAA, "fd0e:a5c8:6dfb:6a5e::1");
|
||||||
assertThatTotalUpdateSetsIs(update, 3); // The delete, the A, and AAAA sets
|
assertThatTotalUpdateSetsIs(update, 3); // The delete, the A, and AAAA sets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,8 +228,7 @@ public class DnsUpdateWriterTest {
|
||||||
.build();
|
.build();
|
||||||
persistResource(domain);
|
persistResource(domain);
|
||||||
when(mockResolver.send(any(Message.class))).thenReturn(messageWithResponseCode(Rcode.SERVFAIL));
|
when(mockResolver.send(any(Message.class))).thenReturn(messageWithResponseCode(Rcode.SERVFAIL));
|
||||||
thrown.expect(VerifyException.class);
|
thrown.expect(VerifyException.class, "SERVFAIL");
|
||||||
thrown.expectMessage("SERVFAIL");
|
|
||||||
|
|
||||||
writer.publishDomain("example.tld");
|
writer.publishDomain("example.tld");
|
||||||
}
|
}
|
||||||
|
@ -237,8 +242,7 @@ public class DnsUpdateWriterTest {
|
||||||
.build();
|
.build();
|
||||||
persistResource(host);
|
persistResource(host);
|
||||||
when(mockResolver.send(any(Message.class))).thenReturn(messageWithResponseCode(Rcode.SERVFAIL));
|
when(mockResolver.send(any(Message.class))).thenReturn(messageWithResponseCode(Rcode.SERVFAIL));
|
||||||
thrown.expect(VerifyException.class);
|
thrown.expect(VerifyException.class, "SERVFAIL");
|
||||||
thrown.expectMessage("SERVFAIL");
|
|
||||||
|
|
||||||
writer.publishHost("ns1.example.tld");
|
writer.publishHost("ns1.example.tld");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue