美文网首页
程序遇到DNS解析问题导致服务启动失败排查过程

程序遇到DNS解析问题导致服务启动失败排查过程

作者: _火山_ | 来源:发表于2020-12-23 13:43 被阅读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 *");
    

    可以看到它是允许字母数字开头的了,并且只有域名的第一个组成部分允许为*。

    相关文章

      网友评论

          本文标题:程序遇到DNS解析问题导致服务启动失败排查过程

          本文链接:https://www.haomeiwen.com/subject/jmbynktx.html