[mdns] service implementation for public key
Bug: 317946010 Bug: 333232582 Change-Id: Iab66bf0a1af14878c7b18a7a3015c2de7a6514c8
This commit is contained in:
parent
364aa570e2
commit
52497d66cc
9 changed files with 695 additions and 49 deletions
|
|
@ -201,6 +201,7 @@ public class NsdService extends INsdManager.Stub {
|
|||
private static final int NO_SENT_QUERY_COUNT = 0;
|
||||
private static final int DISCOVERY_QUERY_SENT_CALLBACK = 1000;
|
||||
private static final int MAX_SUBTYPE_COUNT = 100;
|
||||
private static final int DNSSEC_PROTOCOL = 3;
|
||||
private static final SharedLog LOGGER = new SharedLog("serviceDiscovery");
|
||||
|
||||
private final Context mContext;
|
||||
|
|
@ -1009,6 +1010,17 @@ public class NsdService extends INsdManager.Stub {
|
|||
break;
|
||||
}
|
||||
|
||||
if (!checkPublicKey(serviceInfo.getPublicKey())) {
|
||||
Log.e(TAG,
|
||||
"Invalid public key: "
|
||||
+ Arrays.toString(serviceInfo.getPublicKey()));
|
||||
clientInfo.onRegisterServiceFailedImmediately(
|
||||
clientRequestId,
|
||||
NsdManager.FAILURE_BAD_PARAMETERS,
|
||||
false /* isLegacy */);
|
||||
break;
|
||||
}
|
||||
|
||||
Set<String> subtypes = new ArraySet<>(serviceInfo.getSubtypes());
|
||||
if (typeSubtype != null && typeSubtype.second != null) {
|
||||
for (String subType : typeSubtype.second) {
|
||||
|
|
@ -1842,6 +1854,25 @@ public class NsdService extends INsdManager.Stub {
|
|||
return Pattern.compile(HOSTNAME_REGEX).matcher(hostname).matches();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the public key is valid.
|
||||
*
|
||||
* <p>For simplicity, it only checks if the protocol is DNSSEC and the RDATA is not fewer than 4
|
||||
* bytes. See RFC 3445 Section 3.
|
||||
*
|
||||
* <p>Message format: flags (2 bytes), protocol (1 byte), algorithm (1 byte), public key.
|
||||
*/
|
||||
private static boolean checkPublicKey(@Nullable byte[] publicKey) {
|
||||
if (publicKey == null) {
|
||||
return true;
|
||||
}
|
||||
if (publicKey.length < 4) {
|
||||
return false;
|
||||
}
|
||||
int protocol = publicKey[2];
|
||||
return protocol == DNSSEC_PROTOCOL;
|
||||
}
|
||||
|
||||
/** Returns {@code true} if {@code subtype} is a valid DNS-SD subtype label. */
|
||||
private static boolean checkSubtypeLabel(String subtype) {
|
||||
return Pattern.compile("^" + SUBTYPE_LABEL_REGEX + "$").matcher(subtype).matches();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.connectivity.mdns;
|
||||
|
||||
import static com.android.net.module.util.HexDump.toHexString;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/** An mDNS "KEY" record, which contains a public key for a name. See RFC 2535. */
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
|
||||
public class MdnsKeyRecord extends MdnsRecord {
|
||||
@Nullable private byte[] rData;
|
||||
|
||||
public MdnsKeyRecord(@NonNull String[] name, @NonNull MdnsPacketReader reader)
|
||||
throws IOException {
|
||||
this(name, reader, false);
|
||||
}
|
||||
|
||||
public MdnsKeyRecord(@NonNull String[] name, @NonNull MdnsPacketReader reader,
|
||||
boolean isQuestion) throws IOException {
|
||||
super(name, TYPE_KEY, reader, isQuestion);
|
||||
}
|
||||
|
||||
public MdnsKeyRecord(@NonNull String[] name, boolean isUnicast) {
|
||||
super(name, TYPE_KEY,
|
||||
MdnsConstants.QCLASS_INTERNET | (isUnicast ? MdnsConstants.QCLASS_UNICAST : 0),
|
||||
0L /* receiptTimeMillis */, false /* cacheFlush */, 0L /* ttlMillis */);
|
||||
}
|
||||
|
||||
public MdnsKeyRecord(@NonNull String[] name, long receiptTimeMillis, boolean cacheFlush,
|
||||
long ttlMillis, @Nullable byte[] rData) {
|
||||
super(name, TYPE_KEY, MdnsConstants.QCLASS_INTERNET, receiptTimeMillis, cacheFlush,
|
||||
ttlMillis);
|
||||
if (rData != null) {
|
||||
this.rData = Arrays.copyOf(rData, rData.length);
|
||||
}
|
||||
}
|
||||
/** Returns the KEY RDATA in bytes **/
|
||||
public byte[] getRData() {
|
||||
if (rData == null) {
|
||||
return null;
|
||||
}
|
||||
return Arrays.copyOf(rData, rData.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readData(MdnsPacketReader reader) throws IOException {
|
||||
rData = new byte[reader.getRemaining()];
|
||||
reader.readBytes(rData);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeData(MdnsPacketWriter writer) throws IOException {
|
||||
if (rData != null) {
|
||||
writer.writeBytes(rData);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "KEY: " + toHexString(rData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (super.hashCode() * 31) + Arrays.hashCode(rData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof MdnsKeyRecord)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return super.equals(other) && Arrays.equals(rData, ((MdnsKeyRecord) other).rData);
|
||||
}
|
||||
}
|
||||
|
|
@ -196,6 +196,15 @@ public class MdnsPacket {
|
|||
}
|
||||
}
|
||||
|
||||
case MdnsRecord.TYPE_KEY: {
|
||||
try {
|
||||
return new MdnsKeyRecord(name, reader, isQuestion);
|
||||
} catch (IOException e) {
|
||||
throw new ParseException(MdnsResponseErrorCode.ERROR_READING_KEY_RDATA,
|
||||
"Failed to read KEY record from mDNS response.", e);
|
||||
}
|
||||
}
|
||||
|
||||
case MdnsRecord.TYPE_NSEC: {
|
||||
try {
|
||||
return new MdnsNsecRecord(name, reader, isQuestion);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ public abstract class MdnsRecord {
|
|||
public static final int TYPE_PTR = 0x000C;
|
||||
public static final int TYPE_SRV = 0x0021;
|
||||
public static final int TYPE_TXT = 0x0010;
|
||||
public static final int TYPE_KEY = 0x0019;
|
||||
public static final int TYPE_NSEC = 0x002f;
|
||||
public static final int TYPE_ANY = 0x00ff;
|
||||
|
||||
|
|
|
|||
|
|
@ -184,6 +184,10 @@ public class MdnsRecordRepository {
|
|||
public final RecordInfo<MdnsServiceRecord> srvRecord;
|
||||
@Nullable
|
||||
public final RecordInfo<MdnsTextRecord> txtRecord;
|
||||
@Nullable
|
||||
public final RecordInfo<MdnsKeyRecord> serviceKeyRecord;
|
||||
@Nullable
|
||||
public final RecordInfo<MdnsKeyRecord> hostKeyRecord;
|
||||
@NonNull
|
||||
public final List<RecordInfo<MdnsInetAddressRecord>> addressRecords;
|
||||
@NonNull
|
||||
|
|
@ -245,7 +249,6 @@ public class MdnsRecordRepository {
|
|||
nameRecordsTtlMillis = DEFAULT_NAME_RECORDS_TTL_MILLIS;
|
||||
}
|
||||
|
||||
final boolean hasService = !TextUtils.isEmpty(serviceInfo.getServiceType());
|
||||
final boolean hasCustomHost = !TextUtils.isEmpty(serviceInfo.getHostname());
|
||||
final String[] hostname =
|
||||
hasCustomHost
|
||||
|
|
@ -253,9 +256,11 @@ public class MdnsRecordRepository {
|
|||
: deviceHostname;
|
||||
final ArrayList<RecordInfo<?>> allRecords = new ArrayList<>(5);
|
||||
|
||||
if (hasService) {
|
||||
final String[] serviceType = splitServiceType(serviceInfo);
|
||||
final String[] serviceName = splitFullyQualifiedName(serviceInfo, serviceType);
|
||||
final boolean hasService = !TextUtils.isEmpty(serviceInfo.getServiceType());
|
||||
final String[] serviceType = hasService ? splitServiceType(serviceInfo) : null;
|
||||
final String[] serviceName =
|
||||
hasService ? splitFullyQualifiedName(serviceInfo, serviceType) : null;
|
||||
if (hasService && hasSrvRecord(serviceInfo)) {
|
||||
// Service PTR records
|
||||
ptrRecords = new ArrayList<>(serviceInfo.getSubtypes().size() + 1);
|
||||
ptrRecords.add(new RecordInfo<>(
|
||||
|
|
@ -336,6 +341,36 @@ public class MdnsRecordRepository {
|
|||
addressRecords = Collections.emptyList();
|
||||
}
|
||||
|
||||
final boolean hasKey = hasKeyRecord(serviceInfo);
|
||||
if (hasKey && hasService) {
|
||||
this.serviceKeyRecord = new RecordInfo<>(
|
||||
serviceInfo,
|
||||
new MdnsKeyRecord(
|
||||
serviceName,
|
||||
0L /*receiptTimeMillis */,
|
||||
true /* cacheFlush */,
|
||||
nameRecordsTtlMillis,
|
||||
serviceInfo.getPublicKey()),
|
||||
false /* sharedName */);
|
||||
allRecords.add(this.serviceKeyRecord);
|
||||
} else {
|
||||
this.serviceKeyRecord = null;
|
||||
}
|
||||
if (hasKey && hasCustomHost) {
|
||||
this.hostKeyRecord = new RecordInfo<>(
|
||||
serviceInfo,
|
||||
new MdnsKeyRecord(
|
||||
hostname,
|
||||
0L /*receiptTimeMillis */,
|
||||
true /* cacheFlush */,
|
||||
nameRecordsTtlMillis,
|
||||
serviceInfo.getPublicKey()),
|
||||
false /* sharedName */);
|
||||
allRecords.add(this.hostKeyRecord);
|
||||
} else {
|
||||
this.hostKeyRecord = null;
|
||||
}
|
||||
|
||||
this.allRecords = Collections.unmodifiableList(allRecords);
|
||||
this.repliedServiceCount = repliedServiceCount;
|
||||
this.sentPacketCount = sentPacketCount;
|
||||
|
|
@ -486,6 +521,22 @@ public class MdnsRecordRepository {
|
|||
? inetAddressRecord.getInet6Address()
|
||||
: inetAddressRecord.getInet4Address()));
|
||||
}
|
||||
|
||||
List<MdnsKeyRecord> keyRecords = new ArrayList<>();
|
||||
if (registration.serviceKeyRecord != null) {
|
||||
keyRecords.add(registration.serviceKeyRecord.record);
|
||||
}
|
||||
if (registration.hostKeyRecord != null) {
|
||||
keyRecords.add(registration.hostKeyRecord.record);
|
||||
}
|
||||
for (MdnsKeyRecord keyRecord : keyRecords) {
|
||||
probingRecords.add(new MdnsKeyRecord(
|
||||
keyRecord.getName(),
|
||||
0L /* receiptTimeMillis */,
|
||||
false /* cacheFlush */,
|
||||
keyRecord.getTtl(),
|
||||
keyRecord.getRData()));
|
||||
}
|
||||
return new MdnsProber.ProbingInfo(serviceId, probingRecords);
|
||||
}
|
||||
|
||||
|
|
@ -1101,18 +1152,15 @@ public class MdnsRecordRepository {
|
|||
Collections.emptyList() /* additionalRecords */);
|
||||
}
|
||||
|
||||
/** Check if the record is in any service registration */
|
||||
private boolean hasInetAddressRecord(@NonNull MdnsInetAddressRecord record) {
|
||||
for (int i = 0; i < mServices.size(); i++) {
|
||||
final ServiceRegistration registration = mServices.valueAt(i);
|
||||
if (registration.exiting) continue;
|
||||
|
||||
for (RecordInfo<MdnsInetAddressRecord> localRecord : registration.addressRecords) {
|
||||
if (Objects.equals(localRecord.record, record)) {
|
||||
return true;
|
||||
}
|
||||
/** Check if the record is in a registration */
|
||||
private static boolean hasInetAddressRecord(
|
||||
@NonNull ServiceRegistration registration, @NonNull MdnsInetAddressRecord record) {
|
||||
for (RecordInfo<MdnsInetAddressRecord> localRecord : registration.addressRecords) {
|
||||
if (Objects.equals(localRecord.record, record)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1155,36 +1203,33 @@ public class MdnsRecordRepository {
|
|||
return conflicting;
|
||||
}
|
||||
|
||||
|
||||
private static boolean conflictForService(
|
||||
@NonNull MdnsRecord record, @NonNull ServiceRegistration registration) {
|
||||
if (registration.srvRecord == null) {
|
||||
String[] fullServiceName;
|
||||
if (registration.srvRecord != null) {
|
||||
fullServiceName = registration.srvRecord.record.getName();
|
||||
} else if (registration.serviceKeyRecord != null) {
|
||||
fullServiceName = registration.serviceKeyRecord.record.getName();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
final RecordInfo<MdnsServiceRecord> srvRecord = registration.srvRecord;
|
||||
if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase(record.getName(), srvRecord.record.getName())) {
|
||||
if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase(record.getName(), fullServiceName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// As per RFC6762 9., it's fine if the "conflict" is an identical record with same
|
||||
// data.
|
||||
if (record instanceof MdnsServiceRecord) {
|
||||
final MdnsServiceRecord local = srvRecord.record;
|
||||
final MdnsServiceRecord other = (MdnsServiceRecord) record;
|
||||
// Note "equals" does not consider TTL or receipt time, as intended here
|
||||
if (Objects.equals(local, other)) {
|
||||
return false;
|
||||
}
|
||||
if (record instanceof MdnsServiceRecord && equals(record, registration.srvRecord)) {
|
||||
return false;
|
||||
}
|
||||
if (record instanceof MdnsTextRecord && equals(record, registration.txtRecord)) {
|
||||
return false;
|
||||
}
|
||||
if (record instanceof MdnsKeyRecord && equals(record, registration.serviceKeyRecord)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (record instanceof MdnsTextRecord) {
|
||||
final MdnsTextRecord local = registration.txtRecord.record;
|
||||
final MdnsTextRecord other = (MdnsTextRecord) record;
|
||||
if (Objects.equals(local, other)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1196,6 +1241,11 @@ public class MdnsRecordRepository {
|
|||
return false;
|
||||
}
|
||||
|
||||
// It cannot be a hostname conflict because not record is registered with the hostname.
|
||||
if (registration.addressRecords.isEmpty() && registration.hostKeyRecord == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The record's name cannot be registered by NsdManager so it's not a conflict.
|
||||
if (record.getName().length != 2 || !record.getName()[1].equals(LOCAL_TLD)) {
|
||||
return false;
|
||||
|
|
@ -1207,13 +1257,26 @@ public class MdnsRecordRepository {
|
|||
return false;
|
||||
}
|
||||
|
||||
// If this registration has any address record and there's no identical record in the
|
||||
// repository, it's a conflict. There will be no conflict if no registration has addresses
|
||||
// for that hostname.
|
||||
if (record instanceof MdnsInetAddressRecord) {
|
||||
if (!registration.addressRecords.isEmpty()) {
|
||||
return !hasInetAddressRecord((MdnsInetAddressRecord) record);
|
||||
}
|
||||
// As per RFC6762 9., it's fine if the "conflict" is an identical record with same
|
||||
// data.
|
||||
if (record instanceof MdnsInetAddressRecord
|
||||
&& hasInetAddressRecord(registration, (MdnsInetAddressRecord) record)) {
|
||||
return false;
|
||||
}
|
||||
if (record instanceof MdnsKeyRecord && equals(record, registration.hostKeyRecord)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Per RFC 6762 8.1, when a record is being probed, any answer containing a record with that
|
||||
// name, of any type, MUST be considered a conflicting response.
|
||||
if (registration.isProbing) {
|
||||
return true;
|
||||
}
|
||||
if (record instanceof MdnsInetAddressRecord && !registration.addressRecords.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (record instanceof MdnsKeyRecord && registration.hostKeyRecord != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -1402,4 +1465,21 @@ public class MdnsRecordRepository {
|
|||
|
||||
return type;
|
||||
}
|
||||
|
||||
/** Returns whether there will be an SRV record when registering the {@code info}. */
|
||||
private static boolean hasSrvRecord(@NonNull NsdServiceInfo info) {
|
||||
return info.getPort() > 0;
|
||||
}
|
||||
|
||||
/** Returns whether there will be KEY record(s) when registering the {@code info}. */
|
||||
private static boolean hasKeyRecord(@NonNull NsdServiceInfo info) {
|
||||
return info.getPublicKey() != null;
|
||||
}
|
||||
|
||||
private static boolean equals(@NonNull MdnsRecord record, @Nullable RecordInfo<?> recordInfo) {
|
||||
if (recordInfo == null) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(record, recordInfo.record);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,4 +37,5 @@ public class MdnsResponseErrorCode {
|
|||
public static final int ERROR_END_OF_FILE = 12;
|
||||
public static final int ERROR_READING_NSEC_RDATA = 13;
|
||||
public static final int ERROR_READING_ANY_RDATA = 14;
|
||||
public static final int ERROR_READING_KEY_RDATA = 15;
|
||||
}
|
||||
|
|
@ -1463,10 +1463,8 @@ class NsdManagerTest {
|
|||
handlerThread.waitForIdle(TIMEOUT_MS)
|
||||
|
||||
tryTest {
|
||||
repeat(3) {
|
||||
assertNotNull(packetReader.pollForAdvertisement(serviceName, serviceType),
|
||||
"Expect 3 announcements sent after initial probing")
|
||||
}
|
||||
assertNotNull(packetReader.pollForAdvertisement(serviceName, serviceType),
|
||||
"No announcements sent after initial probing")
|
||||
|
||||
assertEquals(si.serviceName, registeredService.serviceName)
|
||||
assertEquals(si.hostname, registeredService.hostname)
|
||||
|
|
|
|||
|
|
@ -21,11 +21,13 @@ import android.net.LinkAddress
|
|||
import android.net.nsd.NsdServiceInfo
|
||||
import android.os.Build
|
||||
import android.os.HandlerThread
|
||||
import com.android.net.module.util.HexDump.hexStringToByteArray
|
||||
import com.android.server.connectivity.mdns.MdnsAnnouncer.AnnouncementInfo
|
||||
import com.android.server.connectivity.mdns.MdnsInterfaceAdvertiser.CONFLICT_HOST
|
||||
import com.android.server.connectivity.mdns.MdnsInterfaceAdvertiser.CONFLICT_SERVICE
|
||||
import com.android.server.connectivity.mdns.MdnsRecord.TYPE_A
|
||||
import com.android.server.connectivity.mdns.MdnsRecord.TYPE_AAAA
|
||||
import com.android.server.connectivity.mdns.MdnsRecord.TYPE_KEY
|
||||
import com.android.server.connectivity.mdns.MdnsRecord.TYPE_PTR
|
||||
import com.android.server.connectivity.mdns.MdnsRecord.TYPE_SRV
|
||||
import com.android.server.connectivity.mdns.MdnsRecord.TYPE_TXT
|
||||
|
|
@ -120,6 +122,20 @@ private val TEST_SERVICE_CUSTOM_HOST_NO_ADDRESSES = NsdServiceInfo().apply {
|
|||
port = TEST_PORT
|
||||
}
|
||||
|
||||
private val TEST_PUBLIC_KEY = hexStringToByteArray(
|
||||
"0201030dc141d0637960b98cbc12cfca"
|
||||
+ "221d2879dac26ee5b460e9007c992e19"
|
||||
+ "02d897c391b03764d448f7d0c772fdb0"
|
||||
+ "3b1d9d6d52ff8886769e8e2362513565"
|
||||
+ "270962d3")
|
||||
|
||||
private val TEST_PUBLIC_KEY_2 = hexStringToByteArray(
|
||||
"0201030dc141d0637960b98cbc12cfca"
|
||||
+ "221d2879dac26ee5b460e9007c992e19"
|
||||
+ "02d897c391b03764d448f7d0c772fdb0"
|
||||
+ "3b1d9d6d52ff8886769e8e2362513565"
|
||||
+ "270962d4")
|
||||
|
||||
@RunWith(DevSdkIgnoreRunner::class)
|
||||
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||
class MdnsRecordRepositoryTest {
|
||||
|
|
@ -581,6 +597,7 @@ class MdnsRecordRepositoryTest {
|
|||
TYPE_PTR -> return MdnsPointerRecord(name, false /* isUnicast */)
|
||||
TYPE_SRV -> return MdnsServiceRecord(name, false /* isUnicast */)
|
||||
TYPE_TXT -> return MdnsTextRecord(name, false /* isUnicast */)
|
||||
TYPE_KEY -> return MdnsKeyRecord(name, false /* isUnicast */)
|
||||
TYPE_A, TYPE_AAAA -> return MdnsInetAddressRecord(name, type, false /* isUnicast */)
|
||||
else -> fail("Unexpected question type: $type")
|
||||
}
|
||||
|
|
@ -907,6 +924,159 @@ class MdnsRecordRepositoryTest {
|
|||
reply.additionalAnswers)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetReply_keyQuestionForServiceName_returnsKeyRecord() {
|
||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
|
||||
|
||||
repository.addServiceAndFinishProbing(TEST_SERVICE_ID_1, NsdServiceInfo().apply {
|
||||
serviceType = "_testservice._tcp"
|
||||
serviceName = "MyTestService1"
|
||||
port = TEST_PORT
|
||||
publicKey = TEST_PUBLIC_KEY
|
||||
})
|
||||
repository.addServiceAndFinishProbing(TEST_SERVICE_ID_2, NsdServiceInfo().apply {
|
||||
serviceType = "_testservice._tcp"
|
||||
serviceName = "MyTestService2"
|
||||
port = 0 // No SRV RR
|
||||
publicKey = TEST_PUBLIC_KEY
|
||||
})
|
||||
val src = InetSocketAddress(parseNumericAddress("fe80::123"), 5353)
|
||||
val serviceName1 = arrayOf("MyTestService1", "_testservice", "_tcp", "local")
|
||||
val serviceName2 = arrayOf("MyTestService2", "_testservice", "_tcp", "local")
|
||||
|
||||
val query1 = makeQuery(TYPE_KEY to serviceName1)
|
||||
val reply1 = repository.getReply(query1, src)
|
||||
|
||||
assertNotNull(reply1)
|
||||
assertEquals(listOf(MdnsKeyRecord(serviceName1,
|
||||
0, false, LONG_TTL, TEST_PUBLIC_KEY)),
|
||||
reply1.answers)
|
||||
assertEquals(listOf(),
|
||||
reply1.additionalAnswers)
|
||||
|
||||
val query2 = makeQuery(TYPE_KEY to serviceName2)
|
||||
val reply2 = repository.getReply(query2, src)
|
||||
|
||||
assertNotNull(reply2)
|
||||
assertEquals(listOf(MdnsKeyRecord(serviceName2,
|
||||
0, false, LONG_TTL, TEST_PUBLIC_KEY)),
|
||||
reply2.answers)
|
||||
assertEquals(listOf(MdnsNsecRecord(serviceName2,
|
||||
0L, true, SHORT_TTL,
|
||||
serviceName2 /* nextDomain */,
|
||||
intArrayOf(TYPE_KEY))),
|
||||
reply2.additionalAnswers)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetReply_keyQuestionForHostname_returnsKeyRecord() {
|
||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
|
||||
|
||||
repository.addServiceAndFinishProbing(TEST_SERVICE_ID_1, NsdServiceInfo().apply {
|
||||
hostname = "MyHost1"
|
||||
hostAddresses = listOf(
|
||||
parseNumericAddress("2001:db8::1"),
|
||||
parseNumericAddress("2001:db8::2"))
|
||||
publicKey = TEST_PUBLIC_KEY
|
||||
})
|
||||
repository.addServiceAndFinishProbing(TEST_SERVICE_ID_2, NsdServiceInfo().apply {
|
||||
hostname = "MyHost2"
|
||||
hostAddresses = listOf() // No address records
|
||||
publicKey = TEST_PUBLIC_KEY
|
||||
})
|
||||
val src = InetSocketAddress(parseNumericAddress("fe80::123"), 5353)
|
||||
val hostname1 = arrayOf("MyHost1", "local")
|
||||
val hostname2 = arrayOf("MyHost2", "local")
|
||||
|
||||
val query1 = makeQuery(TYPE_KEY to hostname1)
|
||||
val reply1 = repository.getReply(query1, src)
|
||||
|
||||
assertNotNull(reply1)
|
||||
assertEquals(listOf(MdnsKeyRecord(hostname1,
|
||||
0, false, LONG_TTL, TEST_PUBLIC_KEY)),
|
||||
reply1.answers)
|
||||
assertEquals(listOf(),
|
||||
reply1.additionalAnswers)
|
||||
|
||||
val query2 = makeQuery(TYPE_KEY to hostname2)
|
||||
val reply2 = repository.getReply(query2, src)
|
||||
|
||||
assertNotNull(reply2)
|
||||
assertEquals(listOf(MdnsKeyRecord(hostname2,
|
||||
0, false, LONG_TTL, TEST_PUBLIC_KEY)),
|
||||
reply2.answers)
|
||||
assertEquals(listOf(MdnsNsecRecord(hostname2, 0L, true, SHORT_TTL,
|
||||
hostname2 /* nextDomain */,
|
||||
intArrayOf(TYPE_KEY))),
|
||||
reply2.additionalAnswers)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetReply_keyRecordForHostRemoved_noAnswertoKeyQuestion() {
|
||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
|
||||
|
||||
repository.addServiceAndFinishProbing(TEST_SERVICE_ID_1, NsdServiceInfo().apply {
|
||||
hostname = "MyHost1"
|
||||
hostAddresses = listOf(
|
||||
parseNumericAddress("2001:db8::1"),
|
||||
parseNumericAddress("2001:db8::2"))
|
||||
publicKey = TEST_PUBLIC_KEY
|
||||
})
|
||||
repository.addServiceAndFinishProbing(TEST_SERVICE_ID_2, NsdServiceInfo().apply {
|
||||
hostname = "MyHost2"
|
||||
hostAddresses = listOf() // No address records
|
||||
publicKey = TEST_PUBLIC_KEY
|
||||
})
|
||||
repository.removeService(TEST_SERVICE_ID_1)
|
||||
repository.removeService(TEST_SERVICE_ID_2)
|
||||
val src = InetSocketAddress(parseNumericAddress("fe80::123"), 5353)
|
||||
val hostname1 = arrayOf("MyHost1", "local")
|
||||
val hostname2 = arrayOf("MyHost2", "local")
|
||||
|
||||
val query1 = makeQuery(TYPE_KEY to hostname1)
|
||||
val reply1 = repository.getReply(query1, src)
|
||||
|
||||
assertNull(reply1)
|
||||
|
||||
val query2 = makeQuery(TYPE_KEY to hostname2)
|
||||
val reply2 = repository.getReply(query2, src)
|
||||
|
||||
assertNull(reply2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetReply_keyRecordForServiceRemoved_noAnswertoKeyQuestion() {
|
||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
|
||||
|
||||
repository.addServiceAndFinishProbing(TEST_SERVICE_ID_1, NsdServiceInfo().apply {
|
||||
serviceType = "_testservice._tcp"
|
||||
serviceName = "MyTestService1"
|
||||
port = TEST_PORT
|
||||
publicKey = TEST_PUBLIC_KEY
|
||||
})
|
||||
repository.addServiceAndFinishProbing(TEST_SERVICE_ID_2, NsdServiceInfo().apply {
|
||||
serviceType = "_testservice._tcp"
|
||||
serviceName = "MyTestService2"
|
||||
port = 0 // No SRV RR
|
||||
publicKey = TEST_PUBLIC_KEY
|
||||
})
|
||||
repository.removeService(TEST_SERVICE_ID_1)
|
||||
repository.removeService(TEST_SERVICE_ID_2)
|
||||
val src = InetSocketAddress(parseNumericAddress("fe80::123"), 5353)
|
||||
val serviceName1 = arrayOf("MyTestService1", "_testservice", "_tcp", "local")
|
||||
val serviceName2 = arrayOf("MyTestService2", "_testservice", "_tcp", "local")
|
||||
|
||||
val query1 = makeQuery(TYPE_KEY to serviceName1)
|
||||
val reply1 = repository.getReply(query1, src)
|
||||
|
||||
assertNull(reply1)
|
||||
|
||||
val query2 = makeQuery(TYPE_KEY to serviceName2)
|
||||
val reply2 = repository.getReply(query2, src)
|
||||
|
||||
assertNull(reply2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetReply_customHostRemoved_noAnswerToAAAAQuestion() {
|
||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
|
||||
|
|
@ -1221,8 +1391,8 @@ class MdnsRecordRepositoryTest {
|
|||
@Test
|
||||
fun testGetConflictingServices_customHostsReplyHasFewerAddressesThanUs_noConflict() {
|
||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
|
||||
repository.addService(TEST_CUSTOM_HOST_ID_1, TEST_CUSTOM_HOST_1, null /* ttl */)
|
||||
repository.addService(TEST_CUSTOM_HOST_ID_2, TEST_CUSTOM_HOST_2, null /* ttl */)
|
||||
repository.addServiceAndFinishProbing(TEST_CUSTOM_HOST_ID_1, TEST_CUSTOM_HOST_1)
|
||||
repository.addServiceAndFinishProbing(TEST_CUSTOM_HOST_ID_2, TEST_CUSTOM_HOST_2)
|
||||
|
||||
val packet = MdnsPacket(
|
||||
0, /* flags */
|
||||
|
|
@ -1240,10 +1410,30 @@ class MdnsRecordRepositoryTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun testGetConflictingServices_customHostsReplyHasIdenticalHosts_noConflict() {
|
||||
fun testGetConflictingServices_customHostsReplyHasSameNameRecord_conflictDuringProbing() {
|
||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
|
||||
repository.addService(TEST_CUSTOM_HOST_ID_1, TEST_CUSTOM_HOST_1, null /* ttl */)
|
||||
repository.addService(TEST_CUSTOM_HOST_ID_2, TEST_CUSTOM_HOST_2, null /* ttl */)
|
||||
repository.addServiceAndFinishProbing(TEST_CUSTOM_HOST_ID_2, TEST_CUSTOM_HOST_2)
|
||||
|
||||
val packet = MdnsPacket(
|
||||
0, /* flags */
|
||||
emptyList(), /* questions */
|
||||
listOf(MdnsKeyRecord(arrayOf("TestHost", "local"),
|
||||
0L /* receiptTimeMillis */, true /* cacheFlush */,
|
||||
0L /* ttlMillis */, TEST_PUBLIC_KEY),
|
||||
) /* answers */,
|
||||
emptyList() /* authorityRecords */,
|
||||
emptyList() /* additionalRecords */)
|
||||
|
||||
assertEquals(mapOf(TEST_CUSTOM_HOST_ID_1 to CONFLICT_HOST),
|
||||
repository.getConflictingServices(packet))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetConflictingServices_customHostsReplyHasIdenticalHosts_noConflict() {
|
||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
|
||||
repository.addServiceAndFinishProbing(TEST_CUSTOM_HOST_ID_1, TEST_CUSTOM_HOST_1)
|
||||
repository.addServiceAndFinishProbing(TEST_CUSTOM_HOST_ID_2, TEST_CUSTOM_HOST_2)
|
||||
|
||||
val packet = MdnsPacket(
|
||||
0, /* flags */
|
||||
|
|
@ -1267,8 +1457,8 @@ class MdnsRecordRepositoryTest {
|
|||
@Test
|
||||
fun testGetConflictingServices_customHostsCaseInsensitiveReplyHasIdenticalHosts_noConflict() {
|
||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
|
||||
repository.addService(TEST_CUSTOM_HOST_ID_1, TEST_CUSTOM_HOST_1, null /* ttl */)
|
||||
repository.addService(TEST_CUSTOM_HOST_ID_2, TEST_CUSTOM_HOST_2, null /* ttl */)
|
||||
repository.addServiceAndFinishProbing(TEST_CUSTOM_HOST_ID_1, TEST_CUSTOM_HOST_1)
|
||||
repository.addServiceAndFinishProbing(TEST_CUSTOM_HOST_ID_2, TEST_CUSTOM_HOST_2)
|
||||
|
||||
val packet = MdnsPacket(
|
||||
0, /* flags */
|
||||
|
|
@ -1288,6 +1478,152 @@ class MdnsRecordRepositoryTest {
|
|||
repository.getConflictingServices(packet))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetConflictingServices_identicalKeyRecordsForService_noConflict() {
|
||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
|
||||
|
||||
repository.addService(TEST_SERVICE_ID_1, NsdServiceInfo().apply {
|
||||
serviceType = "_testservice._tcp"
|
||||
serviceName = "MyTestService"
|
||||
port = TEST_PORT
|
||||
publicKey = TEST_PUBLIC_KEY
|
||||
}, null /* ttl */)
|
||||
|
||||
val otherTtlMillis = 1234L
|
||||
val packet = MdnsPacket(
|
||||
0 /* flags */,
|
||||
emptyList() /* questions */,
|
||||
listOf(
|
||||
MdnsKeyRecord(
|
||||
arrayOf("MyTestService", "_testservice", "_tcp", "local"),
|
||||
0L /* receiptTimeMillis */, true /* cacheFlush */,
|
||||
otherTtlMillis,
|
||||
TEST_PUBLIC_KEY)
|
||||
) /* answers */,
|
||||
emptyList() /* authorityRecords */,
|
||||
emptyList() /* additionalRecords */)
|
||||
|
||||
assertEquals(emptyMap(),
|
||||
repository.getConflictingServices(packet))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetConflictingServices_differentKeyRecordsForService_conflict() {
|
||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
|
||||
|
||||
repository.addService(TEST_SERVICE_ID_1, NsdServiceInfo().apply {
|
||||
serviceType = "_testservice._tcp"
|
||||
serviceName = "MyTestService"
|
||||
port = TEST_PORT
|
||||
publicKey = TEST_PUBLIC_KEY
|
||||
}, null /* null */)
|
||||
|
||||
val otherTtlMillis = 1234L
|
||||
val packet = MdnsPacket(
|
||||
0 /* flags */,
|
||||
emptyList() /* questions */,
|
||||
listOf(
|
||||
MdnsKeyRecord(
|
||||
arrayOf("MyTestService", "_testservice", "_tcp", "local"),
|
||||
0L /* receiptTimeMillis */, true /* cacheFlush */,
|
||||
otherTtlMillis,
|
||||
TEST_PUBLIC_KEY_2)
|
||||
) /* answers */,
|
||||
emptyList() /* authorityRecords */,
|
||||
emptyList() /* additionalRecords */)
|
||||
|
||||
assertEquals(mapOf(TEST_SERVICE_ID_1 to CONFLICT_SERVICE),
|
||||
repository.getConflictingServices(packet))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetConflictingServices_identicalKeyRecordsForHost_noConflict() {
|
||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
|
||||
|
||||
repository.addServiceAndFinishProbing(TEST_SERVICE_ID_1, NsdServiceInfo().apply {
|
||||
hostname = "MyHost"
|
||||
hostAddresses = listOf(
|
||||
parseNumericAddress("2001:db8::1"),
|
||||
parseNumericAddress("2001:db8::2")
|
||||
)
|
||||
publicKey = TEST_PUBLIC_KEY
|
||||
})
|
||||
|
||||
val otherTtlMillis = 1234L
|
||||
val packet = MdnsPacket(
|
||||
0 /* flags */,
|
||||
emptyList() /* questions */,
|
||||
listOf(
|
||||
MdnsKeyRecord(
|
||||
arrayOf("MyHost", "local"),
|
||||
0L /* receiptTimeMillis */, true /* cacheFlush */,
|
||||
otherTtlMillis,
|
||||
TEST_PUBLIC_KEY)
|
||||
) /* answers */,
|
||||
emptyList() /* authorityRecords */,
|
||||
emptyList() /* additionalRecords */)
|
||||
|
||||
assertEquals(emptyMap(),
|
||||
repository.getConflictingServices(packet))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetConflictingServices_keyForCustomHostReplySameRecordName_conflictDuringProbing() {
|
||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
|
||||
|
||||
repository.addService(TEST_SERVICE_ID_1, NsdServiceInfo().apply {
|
||||
hostname = "MyHost"
|
||||
publicKey = TEST_PUBLIC_KEY
|
||||
}, null /* ttl */)
|
||||
|
||||
val otherTtlMillis = 1234L
|
||||
val packet = MdnsPacket(
|
||||
0 /* flags */,
|
||||
emptyList() /* questions */,
|
||||
listOf(MdnsInetAddressRecord(arrayOf("MyHost", "local"),
|
||||
0L /* receiptTimeMillis */,
|
||||
true /* cacheFlush */,
|
||||
otherTtlMillis,
|
||||
parseNumericAddress("192.168.2.111"))
|
||||
) /* answers */,
|
||||
emptyList() /* authorityRecords */,
|
||||
emptyList() /* additionalRecords */
|
||||
)
|
||||
|
||||
assertEquals(mapOf(TEST_SERVICE_ID_1 to CONFLICT_HOST),
|
||||
repository.getConflictingServices(packet))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetConflictingServices_differentKeyRecordsForHost_conflict() {
|
||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
|
||||
|
||||
repository.addService(TEST_SERVICE_ID_1, NsdServiceInfo().apply {
|
||||
hostname = "MyHost"
|
||||
hostAddresses = listOf(
|
||||
parseNumericAddress("2001:db8::1"),
|
||||
parseNumericAddress("2001:db8::2"))
|
||||
publicKey = TEST_PUBLIC_KEY
|
||||
}, null /* ttl */)
|
||||
|
||||
val otherTtlMillis = 1234L
|
||||
val packet = MdnsPacket(
|
||||
0 /* flags */,
|
||||
emptyList() /* questions */,
|
||||
listOf(
|
||||
MdnsKeyRecord(
|
||||
arrayOf("MyHost", "local"),
|
||||
0L /* receiptTimeMillis */, true /* cacheFlush */,
|
||||
otherTtlMillis,
|
||||
TEST_PUBLIC_KEY_2)
|
||||
) /* answers */,
|
||||
emptyList() /* authorityRecords */,
|
||||
emptyList() /* additionalRecords */)
|
||||
|
||||
assertEquals(mapOf(TEST_SERVICE_ID_1 to CONFLICT_HOST),
|
||||
repository.getConflictingServices(packet))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetConflictingServices_IdenticalService() {
|
||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME, makeFlags())
|
||||
|
|
|
|||
|
|
@ -16,11 +16,13 @@
|
|||
|
||||
package com.android.server.connectivity.mdns;
|
||||
|
||||
import static com.android.server.connectivity.mdns.MdnsConstants.QCLASS_INTERNET;
|
||||
import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
|
@ -424,4 +426,92 @@ public class MdnsRecordTests {
|
|||
assertEquals(new TextEntry("xyz", HexDump.hexStringToByteArray("FFEFDFCF")),
|
||||
entries.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeyRecord() throws IOException {
|
||||
final byte[] dataIn =
|
||||
HexDump.hexStringToByteArray(
|
||||
"09746573742d686f7374056c6f63616c"
|
||||
+ "00001980010000000a00440201030dc1"
|
||||
+ "41d0637960b98cbc12cfca221d2879da"
|
||||
+ "c26ee5b460e9007c992e1902d897c391"
|
||||
+ "b03764d448f7d0c772fdb03b1d9d6d52"
|
||||
+ "ff8886769e8e2362513565270962d3");
|
||||
final byte[] rData =
|
||||
HexDump.hexStringToByteArray(
|
||||
"0201030dc141d0637960b98cbc12cfca"
|
||||
+ "221d2879dac26ee5b460e9007c992e19"
|
||||
+ "02d897c391b03764d448f7d0c772fdb0"
|
||||
+ "3b1d9d6d52ff8886769e8e2362513565"
|
||||
+ "270962d3");
|
||||
assertNotNull(dataIn);
|
||||
String dataInText = HexDump.dumpHexString(dataIn, 0, dataIn.length);
|
||||
|
||||
// Decode
|
||||
DatagramPacket packet = new DatagramPacket(dataIn, dataIn.length);
|
||||
MdnsPacketReader reader = new MdnsPacketReader(packet);
|
||||
|
||||
String[] name = reader.readLabels();
|
||||
assertNotNull(name);
|
||||
assertEquals(2, name.length);
|
||||
String fqdn = MdnsRecord.labelsToString(name);
|
||||
assertEquals("test-host.local", fqdn);
|
||||
|
||||
int type = reader.readUInt16();
|
||||
assertEquals(MdnsRecord.TYPE_KEY, type);
|
||||
|
||||
MdnsKeyRecord keyRecord;
|
||||
|
||||
// MdnsKeyRecord(String[] name, MdnsPacketReader reader)
|
||||
reader = new MdnsPacketReader(packet);
|
||||
reader.readLabels(); // Skip labels
|
||||
reader.readUInt16(); // Skip type
|
||||
keyRecord = new MdnsKeyRecord(name, reader);
|
||||
assertEquals(MdnsRecord.TYPE_KEY, keyRecord.getType());
|
||||
assertTrue(keyRecord.getTtl() > 0); // Not a question so the TTL is greater than 0
|
||||
assertTrue(keyRecord.getCacheFlush());
|
||||
assertArrayEquals(new String[] {"test-host", "local"}, keyRecord.getName());
|
||||
assertArrayEquals(rData, keyRecord.getRData());
|
||||
assertNotEquals(rData, keyRecord.getRData()); // Uses a copy of the original RDATA
|
||||
assertEquals(dataInText, toHex(keyRecord));
|
||||
|
||||
// MdnsKeyRecord(String[] name, MdnsPacketReader reader, boolean isQuestion)
|
||||
reader = new MdnsPacketReader(packet);
|
||||
reader.readLabels(); // Skip labels
|
||||
reader.readUInt16(); // Skip type
|
||||
keyRecord = new MdnsKeyRecord(name, reader, false /* isQuestion */);
|
||||
assertEquals(MdnsRecord.TYPE_KEY, keyRecord.getType());
|
||||
assertTrue(keyRecord.getTtl() > 0); // Not a question, so the TTL is greater than 0
|
||||
assertTrue(keyRecord.getCacheFlush());
|
||||
assertArrayEquals(new String[] {"test-host", "local"}, keyRecord.getName());
|
||||
assertArrayEquals(rData, keyRecord.getRData());
|
||||
assertNotEquals(rData, keyRecord.getRData()); // Uses a copy of the original RDATA
|
||||
|
||||
// MdnsKeyRecord(String[] name, boolean isUnicast)
|
||||
keyRecord = new MdnsKeyRecord(name, false /* isUnicast */);
|
||||
assertEquals(MdnsRecord.TYPE_KEY, keyRecord.getType());
|
||||
assertEquals(0, keyRecord.getTtl());
|
||||
assertEquals(QCLASS_INTERNET, keyRecord.getRecordClass());
|
||||
assertFalse(keyRecord.getCacheFlush());
|
||||
assertArrayEquals(new String[] {"test-host", "local"}, keyRecord.getName());
|
||||
assertArrayEquals(null, keyRecord.getRData());
|
||||
|
||||
// MdnsKeyRecord(String[] name, long receiptTimeMillis, boolean cacheFlush, long ttlMillis,
|
||||
// byte[] rData)
|
||||
keyRecord =
|
||||
new MdnsKeyRecord(
|
||||
name,
|
||||
10 /* receiptTimeMillis */,
|
||||
true /* cacheFlush */,
|
||||
20_000 /* ttlMillis */,
|
||||
rData);
|
||||
assertEquals(MdnsRecord.TYPE_KEY, keyRecord.getType());
|
||||
assertEquals(10, keyRecord.getReceiptTime());
|
||||
assertTrue(keyRecord.getCacheFlush());
|
||||
assertEquals(20_000, keyRecord.getTtl());
|
||||
assertEquals(QCLASS_INTERNET, keyRecord.getRecordClass());
|
||||
assertArrayEquals(new String[] {"test-host", "local"}, keyRecord.getName());
|
||||
assertArrayEquals(rData, keyRecord.getRData());
|
||||
assertNotEquals(rData, keyRecord.getRData()); // Uses a copy of the original RDATA
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue