程序遇到DNS解析问题导致服务启动失败排查过程
2020-12-23 本文已影响0人
_火山_
前言
因为组件涉及公司信息,所以我这里就自己写个demo模拟实现当时的报错现象了。
demo代码
package dns;
import sun.security.x509.DNSName;
import java.io.IOException;
public class DNSTest {
public static void main(String[] args) {
try {
DNSName dnsName = new DNSName("hdp1.test.123.com");
System.out.println(dnsName.getName());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
错误详情:
java.io.IOException: DNSName components must begin with a letter
意思是说DNS域名的每个组成部分(组成部分以.分隔)都必须以字母开头,否则就会抛出这个异常。
根据错误堆栈跟进代码里
public DNSName(String var1, boolean var2) throws IOException {
if (var1 != null && var1.length() != 0) {
if (var1.indexOf(32) != -1) {
throw new IOException("DNS names or NameConstraints with blank components are not permitted");
} else if (var1.charAt(0) != '.' && var1.charAt(var1.length() - 1) != '.') {
int var3;
for(int var4 = 0; var4 < var1.length(); var4 = var3 + 1) {
var3 = var1.indexOf(46, var4);
if (var3 < 0) {
var3 = var1.length();
}
if (var3 - var4 < 1) {
throw new IOException("DNSName SubjectAltNames with empty components are not permitted");
}
if (!var2) {
if ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".indexOf(var1.charAt(var4)) < 0) {
throw new IOException("DNSName components must begin with a letter");
}
} else {
char var5 = var1.charAt(var4);
if ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".indexOf(var5) < 0 && !Character.isDigit(var5)) {
throw new IOException("DNSName components must begin with a letter or digit");
}
}
for(int var7 = var4 + 1; var7 < var3; ++var7) {
char var6 = var1.charAt(var7);
if ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-".indexOf(var6) < 0) {
throw new IOException("DNSName components must consist of letters, digits, and hyphens");
}
}
}
this.name = var1;
} else {
throw new IOException("DNS names or NameConstraints may not begin or end with a .");
}
} else {
throw new IOException("DNS name must not be null");
}
}
可以看到抛异常的代码
if ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".indexOf(var1.charAt(var4)) < 0) {
throw new IOException("DNSName components must begin with a letter");
}
从if判断条件里可以知道,这个比较是只跟字母进行比较的,如果不在这个字母序列内,即非字母的话就抛异常。
知道了问题的原因后,我将DNS域名的每个组成部分都换成以字母开头的,程序可以正常返回了。
这个只允许字母开头的问题后来在jdk15做了修改,组成部分允许字母、数字开头了。
看下jdk15的代码
# 定义的这个常量是包含字母数字的
private static final String alphaDigits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
public DNSName(String name, boolean allowWildcard) throws IOException {
if (name == null || name.isEmpty())
throw new IOException("DNSName must not be null or empty");
if (name.contains(" "))
throw new IOException("DNSName with blank components is not permitted");
if (name.startsWith(".") || name.endsWith("."))
throw new IOException("DNSName may not begin or end with a .");
/*
* Name will consist of label components separated by "."
* startIndex is the index of the first character of a component
* endIndex is the index of the last character of a component plus 1
*/
for (int endIndex,startIndex = 0; startIndex < name.length(); startIndex = endIndex+1) {
endIndex = name.indexOf('.', startIndex);
if (endIndex < 0) {
endIndex = name.length();
}
if (endIndex - startIndex < 1)
throw new IOException("DNSName with empty components are not permitted");
if (allowWildcard) {
// RFC 1123: DNSName components must begin with a letter or digit
// or RFC 4592: the first component of a DNSName can have only a wildcard
// character * (asterisk), i.e. *.example.com. Asterisks at other components
// will not be allowed as a wildcard.
if (alphaDigits.indexOf(name.charAt(startIndex)) < 0) {
// Checking to make sure the wildcard only appears in the first component,
// and it has to be at least 3-char long with the form of *.[alphaDigit]
if ((name.length() < 3) || (name.indexOf('*', 0) != 0) ||
(name.charAt(startIndex+1) != '.') ||
(alphaDigits.indexOf(name.charAt(startIndex+2)) < 0))
throw new IOException("DNSName components must begin with a letter, digit, "
+ "or the first component can have only a wildcard character *");
}
} else {
// RFC 1123: DNSName components must begin with a letter or digit
if (alphaDigits.indexOf(name.charAt(startIndex)) < 0)
throw new IOException("DNSName components must begin with a letter or digit");
}
//nonStartIndex: index for characters in the component beyond the first one
for (int nonStartIndex=startIndex+1; nonStartIndex < endIndex; nonStartIndex++) {
char x = name.charAt(nonStartIndex);
if ((alphaDigits).indexOf(x) < 0 && x != '-')
throw new IOException("DNSName components must consist of letters, digits, and hyphens");
}
}
this.name = name;
}
摘出检查组成元素的这部分代码
if ((name.length() < 3) || (name.indexOf('*', 0) != 0) || (name.charAt(startIndex+1) != '.') || (alphaDigits.indexOf(name.charAt(startIndex+2)) < 0))
throw new IOException("DNSName components must begin with a letter, digit, or the first component can have only a wildcard character *");
可以看到它是允许字母数字开头的了,并且只有域名的第一个组成部分允许为*。