Android 关于IPV6 DNS的问题

2023-05-16

目前在测试IPV6 DNS解析的时候发现一个问题,这里记录一下

问题是:当dhcpv6服务器分配的IPV6 dns是fe80类型的dns时,无法发送dns请求,抓包看不到有目标地址为fe80::1的dns报文

首先我这边使用dumpsys netd查看了下是否有fe80::1这个dns设置到系统中

发现是有设置到系统中的,而且可以看到dns请求的数据统计都是internal errors,那么表示错误产生在内部,并未实际发出dns报文

接下来只能查dns解析接口getaddrinfo了,看其中是否有会挡住fe80::1为目标地址的请求的地方

分析getaddrinfo流程时,发现一段代码的注释挺可疑的(注释写的好真的很有帮助),就让我锁定了目标

cp = strchr(hostname, SCOPE_DELIMITER);
if (cp == NULL)
    return explore_numeric(pai, hostname, servname, res, hostname);

/*
* Handle special case of <scoped_address><delimiter><scope id>
*/
hostname2 = strdup(hostname);
if (hostname2 == NULL)
    return EAI_MEMORY;
/* terminate at the delimiter */
hostname2[cp - hostname] = '\0';
addr = hostname2;
scope = cp + 1;

error = explore_numeric(pai, addr, servname, res, hostname);
if (error == 0) {
    u_int32_t scopeid;

    for (cur = *res; cur; cur = cur->ai_next) {
        if (cur->ai_family != AF_INET6)
             continue;
        sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
        if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) {
             free(hostname2);
             return(EAI_NODATA); /* XXX: is return OK? */
        }
        sin6->sin6_scope_id = scopeid;
    }
}

在系统设置dns的时候会对dns地址调用一次getaddrinfo(这个大家可以去追一下android 设置dns的流程),比如说getaddrinfo(fe80::1,......),这个时候走到这里我看到这么一句注释

 这里可以理解成对特殊的dns地址进行处理,这个地址由scoped_address+delimiter+scope id组成,让我比较奇怪的地址就是一串字符串,为什么还会有特殊的地址需要处理,解析来我就看看到底是什么样的地址被认为是特殊地址

cp = strchr(hostname, SCOPE_DELIMITER);
if (cp == NULL)
    return explore_numeric(pai, hostname, servname, res, hostname);

这段代码的意思就是查看hostname字符串种是否包含SCOPE_DELIMITER,不包含就会return,也就是说包含了SCOPE_DELIMITER的就是特殊dns地址

/*
 * Scope delimit character
 */
#define SCOPE_DELIMITER '%'

SCOPE_DELIMITER就是%,也就是说特殊dns地址是需要包含%的,到这里还不是知道特殊地址为什么要带%,就假设目前是特殊地址了,会怎么处理

/* terminate at the delimiter */
hostname2[cp - hostname] = '\0';
addr = hostname2;
scope = cp + 1;

通过这里的字符串处理,特殊地址被分成两部分,%前的和%后面的,addr就是%前的,scope就是%后的,%前面的就是dns地址,这里主要看下%后的是什么,有什么作用

for (cur = *res; cur; cur = cur->ai_next) {
    if (cur->ai_family != AF_INET6)
        continue;
    sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
    if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) {
        free(hostname2);
        return(EAI_NODATA); /* XXX: is return OK? */
    }
    sin6->sin6_scope_id = scopeid;
}

这里调用ip6_str2scopeid对上面的scope参数进行了处理,也就是我们说的%后面的部分,然后将scopeid赋值给了sin6->sin6_scope_id(sin6_scope_id的作用这里就不写了,可以自行研究内核)

/* convert a string to a scope identifier. XXX: IPv6 specific */
static int
ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid)
{
        u_long lscopeid;
        struct in6_addr *a6;
        char *ep;

        assert(scope != NULL);
        assert(sin6 != NULL);
        assert(scopeid != NULL);

        a6 = &sin6->sin6_addr;

        /* empty scopeid portion is invalid */
        if (*scope == '\0')
                return -1;

        if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
                /*
                 * We currently assume a one-to-one mapping between links
                 * and interfaces, so we simply use interface indices for
                 * like-local scopes.
                 */
                *scopeid = if_nametoindex(scope);
                if (*scopeid == 0)
                        goto trynumeric;
                return 0;
        }
        ......
}

这个函数的作用就是将scope转换成scopeid,看看这里的注释写的应该挺明显了,将interface转换成索引值

看到这里明白了,如果是fe80这种link local地址的dns,应该是需要携带%后面跟interface,也就是fe80::1%eth0设置到系统中,在这里进行特殊处理后确定scope id,否则内核会找不到网口索引,导致报文发不出去

至于内核对于link local地址为什么需要scope id,这里贴一段代码(net/ipv6/af_inet6.c),大家可以研究一下

if (__ipv6_addr_needs_scope_id(addr_type)) {
    if (addr_len >= sizeof(struct sockaddr_in6) &&
         addr->sin6_scope_id) {
         /* Override any existing binding, if another one
         * is supplied by user.
         */
         sk->sk_bound_dev_if = addr->sin6_scope_id;
    }

    /* Binding to link-local address requires an interface */
    if (!sk->sk_bound_dev_if) {
         err = -EINVAL;
         goto out_unlock;
    }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android 关于IPV6 DNS的问题 的相关文章

随机推荐