diff options
author | Rich Felker <dalias@aerifal.cx> | 2016-01-28 19:50:48 -0500 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2016-01-28 20:29:55 -0500 |
commit | 3d6e2e477ced37fd328870f018950b283cb7293c (patch) | |
tree | a3b2f8f623166d7e82b8749d56c4c497e4d4c27e /src/network/lookup_name.c | |
parent | 0fef7ffac114befc94ab5fa794a1754442dcd531 (diff) | |
download | musl-3d6e2e477ced37fd328870f018950b283cb7293c.tar.gz musl-3d6e2e477ced37fd328870f018950b283cb7293c.tar.bz2 musl-3d6e2e477ced37fd328870f018950b283cb7293c.tar.xz musl-3d6e2e477ced37fd328870f018950b283cb7293c.zip |
add support for search domains to dns resolver
search is only performed if the search or domain keyword is used in
resolv.conf and the queried name has fewer than ndots dots. there is
no default domain and names with >=ndots dots are never subjected to
search; failure in the root scope is final.
the (non-POSIX) res_search API presently does not honor search. this
may be added at some point in the future if needed.
resolv.conf is now parsed twice, at two different layers of the code
involved. this will be fixed in a subsequent patch.
Diffstat (limited to 'src/network/lookup_name.c')
-rw-r--r-- | src/network/lookup_name.c | 42 |
1 files changed, 41 insertions, 1 deletions
diff --git a/src/network/lookup_name.c b/src/network/lookup_name.c index fb7b5c12..09734b50 100644 --- a/src/network/lookup_name.c +++ b/src/network/lookup_name.c @@ -157,6 +157,46 @@ static int name_from_dns(struct address buf[static MAXADDRS], char canon[static return EAI_FAIL; } +static int name_from_dns_search(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family) +{ + char search[256]; + struct resolvconf conf; + size_t l, dots; + char *p, *z; + + if (__get_resolv_conf(&conf, search, sizeof search) < 0) return -1; + + /* Count dots, suppress search when >=ndots or name ends in + * a dot, which is an explicit request for global scope. */ + for (dots=l=0; name[l]; l++) if (name[l]=='.') dots++; + if (dots >= conf.ndots || name[l-1]=='.') *search = 0; + + /* This can never happen; the caller already checked length. */ + if (l >= 256) return EAI_NONAME; + + /* Name with search domain appended is setup in canon[]. This both + * provides the desired default canonical name (if the requested + * name is not a CNAME record) and serves as a buffer for passing + * the full requested name to name_from_dns. */ + memcpy(canon, name, l); + canon[l] = '.'; + + for (p=search; *p; p=z) { + for (; isspace(*p); p++); + for (z=p; *z && !isspace(*z); z++); + if (z==p) break; + if (z-p < 256 - l - 1) { + memcpy(canon+l+1, p, z-p); + canon[z-p+1+l] = 0; + int cnt = name_from_dns(buf, canon, canon, family); + if (cnt) return cnt; + } + } + + canon[l] = 0; + return name_from_dns(buf, canon, name, family); +} + static const struct policy { unsigned char addr[16]; unsigned char len, mask; @@ -257,7 +297,7 @@ int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], c if (!cnt) cnt = name_from_numeric(buf, name, family); if (!cnt && !(flags & AI_NUMERICHOST)) { cnt = name_from_hosts(buf, canon, name, family); - if (!cnt) cnt = name_from_dns(buf, canon, name, family); + if (!cnt) cnt = name_from_dns_search(buf, canon, name, family); } if (cnt<=0) return cnt ? cnt : EAI_NONAME; |