mirror of https://github.com/apache/cloudstack.git
fix normalizing dns record values for mx, srv and other type
This commit is contained in:
parent
883dc32abf
commit
3ae9834325
|
|
@ -50,10 +50,10 @@ public class CreateDnsRecordCmd extends BaseAsyncCmd {
|
|||
description = "ID of the DNS zone")
|
||||
private Long dnsZoneId;
|
||||
|
||||
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "Record name")
|
||||
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "DNS record name")
|
||||
private String name;
|
||||
|
||||
@Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, required = true, description = "Record type (A, CNAME)")
|
||||
@Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, required = true, description = "DNS record type (e.g., A, AAAA, CNAME, MX, TXT, etc.)")
|
||||
private String type;
|
||||
|
||||
@Parameter(name = ApiConstants.CONTENTS, type = CommandType.LIST, collectionType = CommandType.STRING, required = true,
|
||||
|
|
|
|||
|
|
@ -27,11 +27,4 @@
|
|||
<version>4.23.0.0-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
package org.apache.cloudstack.dns;
|
||||
|
||||
import static org.apache.cloudstack.dns.DnsProviderUtil.appendPublicSuffixToZone;
|
||||
import static org.apache.cloudstack.dns.DnsProviderUtil.normalizeDomain;
|
||||
import static org.apache.cloudstack.dns.DnsProviderUtil.normalizeDomainForDb;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
|
|
@ -89,13 +89,13 @@ public class DnsProviderUtilTest {
|
|||
if (Strings.isNotBlank(publicSuffix)) {
|
||||
result = executeAppendSuffixTest(userZoneName, publicSuffix);
|
||||
} else {
|
||||
result = appendPublicSuffixToZone(normalizeDomain(userZoneName), publicSuffix);
|
||||
result = appendPublicSuffixToZone(normalizeDomainForDb(userZoneName), publicSuffix);
|
||||
}
|
||||
assertEquals(expectedResult, result);
|
||||
}
|
||||
}
|
||||
|
||||
String executeAppendSuffixTest(String zoneName, String domainSuffix) {
|
||||
return appendPublicSuffixToZone(normalizeDomain(zoneName), domainSuffix);
|
||||
return appendPublicSuffixToZone(normalizeDomainForDb(zoneName), domainSuffix);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,197 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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 org.apache.cloudstack.dns;
|
||||
|
||||
import static org.apache.cloudstack.dns.DnsRecord.RecordType.A;
|
||||
import static org.apache.cloudstack.dns.DnsRecord.RecordType.AAAA;
|
||||
import static org.apache.cloudstack.dns.DnsRecord.RecordType.CNAME;
|
||||
import static org.apache.cloudstack.dns.DnsRecord.RecordType.MX;
|
||||
import static org.apache.cloudstack.dns.DnsRecord.RecordType.NS;
|
||||
import static org.apache.cloudstack.dns.DnsRecord.RecordType.PTR;
|
||||
import static org.apache.cloudstack.dns.DnsRecord.RecordType.SRV;
|
||||
import static org.apache.cloudstack.dns.DnsRecord.RecordType.TXT;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class NormalizeDnsRecordValueTest {
|
||||
|
||||
private final String description;
|
||||
private final String input;
|
||||
private final DnsRecord.RecordType recordType;
|
||||
private final String expected;
|
||||
private final boolean expectException;
|
||||
|
||||
public NormalizeDnsRecordValueTest(String description, String input,
|
||||
DnsRecord.RecordType recordType,
|
||||
String expected, boolean expectException) {
|
||||
this.description = description;
|
||||
this.input = input;
|
||||
this.recordType = recordType;
|
||||
this.expected = expected;
|
||||
this.expectException = expectException;
|
||||
}
|
||||
|
||||
@Parameterized.Parameters(name = "{0}")
|
||||
public static Collection<Object[]> data() {
|
||||
return Arrays.asList(new Object[][] {
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Guard: blank/null value — all record types should throw
|
||||
// ----------------------------------------------------------------
|
||||
{"null value, A record", null, A, null, true},
|
||||
{"empty value, A record", "", A, null, true},
|
||||
{"blank value, A record", " ", A, null, true},
|
||||
|
||||
{"null value, AAAA record", null, AAAA, null, true},
|
||||
{"null value, CNAME record", null, CNAME, null, true},
|
||||
{"null value, MX record", null, MX, null, true},
|
||||
{"null value, TXT record", null, TXT, null, true},
|
||||
{"null value, SRV record", null, SRV, null, true},
|
||||
{"null value, NS record", null, NS, null, true},
|
||||
{"null value, PTR record", null, PTR, null, true},
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// A record
|
||||
// ----------------------------------------------------------------
|
||||
{"A: valid IPv4", "93.184.216.34", A, "93.184.216.34", false},
|
||||
{"A: valid IPv4 with whitespace", " 93.184.216.34 ", A, "93.184.216.34", false},
|
||||
{"A: loopback", "127.0.0.1", A, "127.0.0.1", false},
|
||||
{"A: all-zeros", "0.0.0.0", A, "0.0.0.0", false},
|
||||
{"A: broadcast", "255.255.255.255", A, "255.255.255.255", false},
|
||||
{"A: private 10.x", "10.0.0.1", A, "10.0.0.1", false},
|
||||
{"A: private 192.168.x", "192.168.1.1", A, "192.168.1.1", false},
|
||||
|
||||
{"A: IPv6 rejected", "2001:db8::1", A, null, true},
|
||||
{"A: domain rejected", "example.com", A, null, true},
|
||||
{"A: partial IP rejected", "192.168.1", A, null, true},
|
||||
{"A: trailing dot rejected", "93.184.216.34.", A, null, true},
|
||||
{"A: octet out of range rejected", "256.0.0.1", A, null, true},
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// AAAA record
|
||||
// ----------------------------------------------------------------
|
||||
{"AAAA: full IPv6", "2001:0db8:0000:0000:0000:0000:0000:0001", AAAA,
|
||||
"2001:0db8:0000:0000:0000:0000:0000:0001", false},
|
||||
|
||||
{"AAAA: compressed IPv6", "2001:db8::1", AAAA, "2001:db8::1", false},
|
||||
{"AAAA: loopback", "::1", AAAA, "::1", false},
|
||||
{"AAAA: all zeros", "::", AAAA, "::", false},
|
||||
{"AAAA: whitespace", " 2001:db8::1 ", AAAA, "2001:db8::1", false},
|
||||
|
||||
{"AAAA: IPv4 rejected", "93.184.216.34", AAAA, null, true},
|
||||
{"AAAA: domain rejected", "example.com", AAAA, null, true},
|
||||
{"AAAA: invalid hex rejected", "2001:db8::xyz", AAAA, null, true},
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// CNAME record
|
||||
// ----------------------------------------------------------------
|
||||
{"CNAME: basic", "target.example.com", CNAME, "target.example.com.", false},
|
||||
{"CNAME: uppercase", "TARGET.EXAMPLE.COM", CNAME, "target.example.com.", false},
|
||||
{"CNAME: trailing dot", "target.example.com.", CNAME, "target.example.com.", false},
|
||||
{"CNAME: whitespace", " target.example.com ", CNAME, "target.example.com.", false},
|
||||
{"CNAME: subdomain", "sub.target.example.com", CNAME, "sub.target.example.com.", false},
|
||||
|
||||
{"CNAME: IP rejected", "192.168.1.1", CNAME, null, true},
|
||||
{"CNAME: invalid label", "-bad.example.com", CNAME, null, true},
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// NS record
|
||||
// ----------------------------------------------------------------
|
||||
{"NS: basic", "ns1.example.com", NS, "ns1.example.com.", false},
|
||||
{"NS: uppercase", "NS1.EXAMPLE.COM", NS, "ns1.example.com.", false},
|
||||
{"NS: trailing dot", "ns1.example.com.", NS, "ns1.example.com.", false},
|
||||
{"NS: subdomain", "ns1.sub.example.com", NS, "ns1.sub.example.com.", false},
|
||||
|
||||
{"NS: IP rejected", "8.8.8.8", NS, null, true},
|
||||
{"NS: invalid label", "ns1-.example.com", NS, null, true},
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// PTR record
|
||||
// ----------------------------------------------------------------
|
||||
{"PTR: basic", "host.example.com", PTR, "host.example.com.", false},
|
||||
{"PTR: in-addr.arpa", "1.168.192.in-addr.arpa", PTR, "1.168.192.in-addr.arpa.", false},
|
||||
{"PTR: uppercase", "HOST.EXAMPLE.COM", PTR, "host.example.com.", false},
|
||||
{"PTR: trailing dot", "host.example.com.", PTR, "host.example.com.", false},
|
||||
|
||||
{"PTR: IP rejected", "192.168.1.1", PTR, null, true},
|
||||
{"PTR: invalid label", "-host.example.com", PTR, null, true},
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// MX record
|
||||
// ----------------------------------------------------------------
|
||||
{"MX: standard", "10 mail.example.com", MX, "10 mail.example.com.", false},
|
||||
{"MX: zero priority", "0 mail.example.com", MX, "0 mail.example.com.", false},
|
||||
{"MX: max priority", "65535 mail.example.com", MX, "65535 mail.example.com.", false},
|
||||
{"MX: uppercase", "10 MAIL.EXAMPLE.COM", MX, "10 mail.example.com.", false},
|
||||
{"MX: trailing dot", "10 mail.example.com.", MX, "10 mail.example.com.", false},
|
||||
{"MX: extra whitespace", "10 mail.example.com", MX, "10 mail.example.com.", false},
|
||||
|
||||
{"MX: missing domain", "10", MX, null, true},
|
||||
{"MX: priority out of range", "65536 mail.example.com", MX, null, true},
|
||||
{"MX: non-numeric priority", "abc mail.example.com", MX, null, true},
|
||||
{"MX: IP rejected", "10 192.168.1.1", MX, null, true},
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// SRV record
|
||||
// ----------------------------------------------------------------
|
||||
{"SRV: standard", "10 20 443 target.example.com", SRV, "10 20 443 target.example.com.", false},
|
||||
{"SRV: zeros", "0 0 1 target.example.com", SRV, "0 0 1 target.example.com.", false},
|
||||
{"SRV: max values", "65535 65535 65535 target.example.com", SRV, "65535 65535 65535 target.example.com.", false},
|
||||
{"SRV: uppercase", "10 20 443 TARGET.EXAMPLE.COM", SRV, "10 20 443 target.example.com.", false},
|
||||
{"SRV: trailing dot", "10 20 443 target.example.com.", SRV, "10 20 443 target.example.com.", false},
|
||||
|
||||
{"SRV: missing target", "10 20 443", SRV, null, true},
|
||||
{"SRV: port 0", "10 20 0 target.example.com", SRV, null, true},
|
||||
{"SRV: priority out of range", "65536 20 443 target.example.com", SRV, null, true},
|
||||
{"SRV: IP rejected", "10 20 443 192.168.1.1", SRV, null, true},
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// TXT record
|
||||
// ----------------------------------------------------------------
|
||||
{"TXT: trim", " hello world ", TXT, "hello world", false},
|
||||
{"TXT: already clean", "v=spf1 include:example.com ~all", TXT, "v=spf1 include:example.com ~all", false},
|
||||
{"TXT: special chars", "v=DKIM1; k=rsa; p=MIGf", TXT, "v=DKIM1; k=rsa; p=MIGf", false},
|
||||
{"TXT: unicode", "héllo wörld", TXT, "héllo wörld", false},
|
||||
{"TXT: multiple spaces", "key=value with spaces", TXT, "key=value with spaces", false},
|
||||
{"TXT: quoted", "\"quoted value\"", TXT, "\"quoted value\"", false},
|
||||
{"TXT: blank", " ", TXT, null, true},
|
||||
{"TXT: newline", "\n", TXT, null, true},
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeDnsRecordValue() {
|
||||
if (expectException) {
|
||||
try {
|
||||
DnsProviderUtil.normalizeDnsRecordValue(input, recordType);
|
||||
fail("Expected IllegalArgumentException for [" + description + "] input='" + input + "'");
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
} else {
|
||||
String result = DnsProviderUtil.normalizeDnsRecordValue(input, recordType);
|
||||
assertEquals(description, expected, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -172,7 +172,7 @@ public class DnsProviderManagerImpl extends ManagerBase implements DnsProviderMa
|
|||
}
|
||||
|
||||
if (StringUtils.isNotBlank(publicDomainSuffix)) {
|
||||
publicDomainSuffix = DnsProviderUtil.normalizeDomain(publicDomainSuffix);
|
||||
publicDomainSuffix = DnsProviderUtil.normalizeDomainForDb(publicDomainSuffix);
|
||||
}
|
||||
|
||||
DnsProviderType type = cmd.getProvider();
|
||||
|
|
@ -263,7 +263,7 @@ public class DnsProviderManagerImpl extends ManagerBase implements DnsProviderMa
|
|||
}
|
||||
|
||||
if (cmd.getPublicDomainSuffix() != null) {
|
||||
dnsServer.setPublicDomainSuffix(DnsProviderUtil.normalizeDomain(cmd.getPublicDomainSuffix()));
|
||||
dnsServer.setPublicDomainSuffix(DnsProviderUtil.normalizeDomainForDb(cmd.getPublicDomainSuffix()));
|
||||
}
|
||||
|
||||
if (cmd.getNameServers() != null) {
|
||||
|
|
@ -552,7 +552,7 @@ public class DnsProviderManagerImpl extends ManagerBase implements DnsProviderMa
|
|||
throw new InvalidParameterValueException("DNS zone name cannot be empty");
|
||||
}
|
||||
|
||||
String dnsZoneName = DnsProviderUtil.normalizeDomain(cmd.getName());
|
||||
String dnsZoneName = DnsProviderUtil.normalizeDomainForDb(cmd.getName());
|
||||
DnsServerVO server = dnsServerDao.findById(cmd.getDnsServerId());
|
||||
if (server == null) {
|
||||
throw new InvalidParameterValueException(String.format("DNS server not found for the given ID: %s", cmd.getDnsServerId()));
|
||||
|
|
|
|||
|
|
@ -17,9 +17,13 @@
|
|||
|
||||
package org.apache.cloudstack.dns;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
|
||||
import org.apache.commons.validator.routines.DomainValidator;
|
||||
|
||||
import com.cloud.utils.StringUtils;
|
||||
import com.google.common.net.InetAddresses;
|
||||
|
||||
public class DnsProviderUtil {
|
||||
static DomainValidator validator = DomainValidator.getInstance(true);
|
||||
|
|
@ -28,9 +32,9 @@ public class DnsProviderUtil {
|
|||
if (StringUtils.isBlank(suffixDomain)) {
|
||||
return zoneName;
|
||||
}
|
||||
suffixDomain = DnsProviderUtil.normalizeDomain(suffixDomain);
|
||||
suffixDomain = DnsProviderUtil.normalizeDomainForDb(suffixDomain);
|
||||
// Already suffixed → return as-is
|
||||
if (zoneName.toLowerCase().endsWith("." + suffixDomain.toLowerCase())) {
|
||||
if (zoneName.toLowerCase().endsWith("." + suffixDomain)) {
|
||||
return zoneName;
|
||||
}
|
||||
|
||||
|
|
@ -55,7 +59,8 @@ public class DnsProviderUtil {
|
|||
return labels[labels.length - 1];
|
||||
}
|
||||
|
||||
public static String normalizeDomain(String domain) {
|
||||
// lowercase, no trailing dot (used for DB storage, comparisons)
|
||||
public static String normalizeDomainForDb(String domain) {
|
||||
if (StringUtils.isBlank(domain)) {
|
||||
throw new IllegalArgumentException("Domain cannot be empty");
|
||||
}
|
||||
|
|
@ -71,32 +76,144 @@ public class DnsProviderUtil {
|
|||
return normalized;
|
||||
}
|
||||
|
||||
// DNS wire form: lowercase, validated, WITH trailing dot (used in record values)
|
||||
public static String normalizeDnsRecordValue(String value, DnsRecord.RecordType recordType) {
|
||||
if (StringUtils.isBlank(value)) {
|
||||
throw new IllegalArgumentException("DNS record value cannot be empty");
|
||||
}
|
||||
String trimmedValue = value.trim();
|
||||
switch (recordType) {
|
||||
case A:
|
||||
if (!(InetAddresses.forString(trimmedValue) instanceof Inet4Address)) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Invalid IP address for %s record: %s", recordType, value));
|
||||
}
|
||||
return trimmedValue;
|
||||
case AAAA:
|
||||
// IP addresses: trim only
|
||||
return value.trim();
|
||||
|
||||
if (!(InetAddresses.forString(trimmedValue) instanceof Inet6Address)) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Invalid IP address for %s record: %s", recordType, value));
|
||||
}
|
||||
return trimmedValue;
|
||||
case CNAME:
|
||||
case NS:
|
||||
case PTR:
|
||||
return normalizeDomainForDnsRecord(trimmedValue);
|
||||
case SRV:
|
||||
// Domain names: normalize like zones
|
||||
return normalizeDomain(value);
|
||||
return normalizeSrvRecord(trimmedValue);
|
||||
case MX:
|
||||
// PowerDNS MX: contains priority + domain, only trim and lowercase
|
||||
return value.trim().toLowerCase();
|
||||
|
||||
return normalizeMxRecord(trimmedValue);
|
||||
case TXT:
|
||||
// Free text: preserve exactly
|
||||
return value;
|
||||
|
||||
return trimmedValue;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported DNS record type: " + recordType);
|
||||
}
|
||||
}
|
||||
|
||||
static String normalizeDomainForDnsRecord(String domain) {
|
||||
if (StringUtils.isBlank(domain)) {
|
||||
throw new IllegalArgumentException("Domain name cannot be empty");
|
||||
}
|
||||
String normalized = domain.trim().toLowerCase();
|
||||
// Strip trailing dot first (normalize input)
|
||||
if (normalized.endsWith(".")) {
|
||||
normalized = normalized.substring(0, normalized.length() - 1);
|
||||
}
|
||||
|
||||
// Reject IP addresses
|
||||
if (InetAddresses.isInetAddress(normalized)) {
|
||||
throw new IllegalArgumentException("Domain cannot be an IP address: " + normalized);
|
||||
}
|
||||
|
||||
// Validate total length (max 253 chars, excluding trailing dot)
|
||||
if (normalized.length() > 253) {
|
||||
throw new IllegalArgumentException(
|
||||
"Domain name exceeds maximum length: " + normalized);
|
||||
}
|
||||
|
||||
// Validate labels
|
||||
String[] labels = normalized.split("\\.", -1);
|
||||
for (String label : labels) {
|
||||
if (label.isEmpty()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Domain contains empty label: " + normalized);
|
||||
}
|
||||
if (label.length() > 63) {
|
||||
throw new IllegalArgumentException(
|
||||
"Domain label too long: " + label);
|
||||
}
|
||||
if (!label.matches("[a-z0-9]([a-z0-9-]*[a-z0-9])?")) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid domain label: " + label);
|
||||
}
|
||||
}
|
||||
return normalized + ".";
|
||||
}
|
||||
|
||||
private static String normalizeSrvRecord(String value) {
|
||||
String trimmed = value.trim();
|
||||
String[] parts = trimmed.split("\\s+", 4);
|
||||
if (parts.length != 4) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid SRV record value (expected '<priority> <weight> <port> <target>'): " + trimmed);
|
||||
}
|
||||
|
||||
int priority;
|
||||
int weight;
|
||||
int port;
|
||||
|
||||
try {
|
||||
priority = Integer.parseInt(parts[0]);
|
||||
weight = Integer.parseInt(parts[1]);
|
||||
port = Integer.parseInt(parts[2]);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"SRV priority/weight/port must be numeric: " + trimmed);
|
||||
}
|
||||
|
||||
if (priority < 0 || priority > 65535) {
|
||||
throw new IllegalArgumentException("SRV priority out of range (0–65535): " + parts[0]);
|
||||
}
|
||||
|
||||
if (weight < 0 || weight > 65535) {
|
||||
throw new IllegalArgumentException("SRV weight out of range (0–65535): " + parts[1]);
|
||||
}
|
||||
|
||||
if (port < 1 || port > 65535) {
|
||||
throw new IllegalArgumentException("SRV port out of range (1–65535): " + parts[2]);
|
||||
}
|
||||
|
||||
String target = normalizeDomainForDnsRecord(parts[3]);
|
||||
|
||||
return priority + " " + weight + " " + port + " " + target;
|
||||
}
|
||||
|
||||
private static String normalizeMxRecord(String value) {
|
||||
String trimmed = value.trim();
|
||||
String[] parts = trimmed.split("\\s+", 2);
|
||||
|
||||
if (parts.length != 2) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid MX record value (expected '<priority> <mail-exchanger>'): " + trimmed);
|
||||
}
|
||||
|
||||
int priority;
|
||||
|
||||
try {
|
||||
priority = Integer.parseInt(parts[0]);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"MX priority must be numeric: " + parts[0]);
|
||||
}
|
||||
|
||||
if (priority < 0 || priority > 65535) {
|
||||
throw new IllegalArgumentException(
|
||||
"MX priority out of range (0–65535): " + parts[0]);
|
||||
}
|
||||
|
||||
String mailExchanger = normalizeDomainForDnsRecord(parts[1]);
|
||||
|
||||
return priority + " " + mailExchanger;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,91 +0,0 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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 org.apache.cloudstack.dns;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class DnsProviderUtilTest {
|
||||
|
||||
@Test
|
||||
public void testNormalizeDnsRecordValueA() {
|
||||
String result = DnsProviderUtil.normalizeDnsRecordValue(" 1.2.3.4 ", DnsRecord.RecordType.A);
|
||||
assertEquals("1.2.3.4", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeDnsRecordValueAAAA() {
|
||||
String result = DnsProviderUtil.normalizeDnsRecordValue(" 2001:db8::1 ", DnsRecord.RecordType.AAAA);
|
||||
assertEquals("2001:db8::1", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeDnsRecordValueCNAME() {
|
||||
// Appends dot in the process? No, normalizeDomain trims, lowercases, removes trailing dot, and checks validity.
|
||||
String result = DnsProviderUtil.normalizeDnsRecordValue(" Host.Example.Com. ", DnsRecord.RecordType.CNAME);
|
||||
assertEquals("host.example.com", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeDnsRecordValueNS() {
|
||||
String result = DnsProviderUtil.normalizeDnsRecordValue("NS1.EXAMPLE.COM", DnsRecord.RecordType.NS);
|
||||
assertEquals("ns1.example.com", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeDnsRecordValuePTR() {
|
||||
String result = DnsProviderUtil.normalizeDnsRecordValue("ptr.valid.zone.", DnsRecord.RecordType.PTR);
|
||||
assertEquals("ptr.valid.zone", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeDnsRecordValueSRV() {
|
||||
String result = DnsProviderUtil.normalizeDnsRecordValue("srv.example.com", DnsRecord.RecordType.SRV);
|
||||
assertEquals("srv.example.com", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeDnsRecordValueMX() {
|
||||
// MX records just get trimmed and lowercased
|
||||
String result = DnsProviderUtil.normalizeDnsRecordValue(" 10 MAIL.EXAMPLE.COM ", DnsRecord.RecordType.MX);
|
||||
assertEquals("10 mail.example.com", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeDnsRecordValueTXT() {
|
||||
// TXT records are preserved exactly
|
||||
String result = DnsProviderUtil.normalizeDnsRecordValue(" Exact text value. ", DnsRecord.RecordType.TXT);
|
||||
assertEquals(" Exact text value. ", result);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testNormalizeDnsRecordValueEmpty() {
|
||||
DnsProviderUtil.normalizeDnsRecordValue(" ", DnsRecord.RecordType.A);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testNormalizeDnsRecordValueNull() {
|
||||
DnsProviderUtil.normalizeDnsRecordValue(null, DnsRecord.RecordType.A);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testNormalizeDnsRecordValueInvalidDomain() {
|
||||
DnsProviderUtil.normalizeDnsRecordValue("invalid!domain", DnsRecord.RecordType.CNAME);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue