res_findzonecut.c revision 158787
11556Srgrimes#if !defined(lint) && !defined(SABER) 21556Srgrimesstatic const char rcsid[] = "$Id: res_findzonecut.c,v 1.2.2.3.4.4 2005/10/11 00:48:16 marka Exp $"; 31556Srgrimes#endif /* not lint */ 41556Srgrimes 51556Srgrimes/* 61556Srgrimes * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 71556Srgrimes * Copyright (c) 1999 by Internet Software Consortium. 81556Srgrimes * 91556Srgrimes * Permission to use, copy, modify, and distribute this software for any 101556Srgrimes * purpose with or without fee is hereby granted, provided that the above 111556Srgrimes * copyright notice and this permission notice appear in all copies. 121556Srgrimes * 131556Srgrimes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 141556Srgrimes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 151556Srgrimes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 161556Srgrimes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 171556Srgrimes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 181556Srgrimes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 191556Srgrimes * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 201556Srgrimes */ 211556Srgrimes 221556Srgrimes#include <sys/cdefs.h> 231556Srgrimes__FBSDID("$FreeBSD: head/lib/libc/resolv/res_findzonecut.c 158787 2006-05-21 11:19:36Z ume $"); 241556Srgrimes 251556Srgrimes/* Import. */ 261556Srgrimes 271556Srgrimes#include "port_before.h" 281556Srgrimes 291556Srgrimes#include <sys/param.h> 301556Srgrimes#include <sys/socket.h> 311556Srgrimes#include <sys/time.h> 321556Srgrimes 331556Srgrimes#include <netinet/in.h> 341556Srgrimes#include <arpa/inet.h> 351556Srgrimes#include <arpa/nameser.h> 361556Srgrimes 371556Srgrimes#include <errno.h> 3836150Scharnier#include <limits.h> 3936150Scharnier#include <netdb.h> 4036150Scharnier#include <stdarg.h> 411556Srgrimes#include <stdio.h> 4299110Sobrien#include <stdlib.h> 4399110Sobrien#include <string.h> 441556Srgrimes 4517987Speter#include <isc/list.h> 4617987Speter 4717987Speter#include "port_after.h" 4899762Stjr 4917987Speter#include <resolv.h> 5017987Speter 5117987Speter/* Data structures. */ 5217987Speter 5317987Spetertypedef struct rr_a { 5417987Speter LINK(struct rr_a) link; 5569793Sobrien union res_sockaddr_union addr; 5618018Speter} rr_a; 5717987Spetertypedef LIST(rr_a) rrset_a; 581556Srgrimes 591556Srgrimestypedef struct rr_ns { 6017987Speter LINK(struct rr_ns) link; 611556Srgrimes const char * name; 621556Srgrimes unsigned int flags; 6317987Speter rrset_a addrs; 6417987Speter} rr_ns; 651556Srgrimestypedef LIST(rr_ns) rrset_ns; 661556Srgrimes 671556Srgrimes#define RR_NS_HAVE_V4 0x01 681556Srgrimes#define RR_NS_HAVE_V6 0x02 691556Srgrimes 701556Srgrimes/* Forward. */ 711556Srgrimes 721556Srgrimesstatic int satisfy(res_state, const char *, rrset_ns *, 731556Srgrimes union res_sockaddr_union *, int); 741556Srgrimesstatic int add_addrs(res_state, rr_ns *, 751556Srgrimes union res_sockaddr_union *, int); 761556Srgrimesstatic int get_soa(res_state, const char *, ns_class, int, 771556Srgrimes char *, size_t, char *, size_t, 781556Srgrimes rrset_ns *); 791556Srgrimesstatic int get_ns(res_state, const char *, ns_class, int, rrset_ns *); 801556Srgrimesstatic int get_glue(res_state, ns_class, int, rrset_ns *); 8128346Sstevestatic int save_ns(res_state, ns_msg *, ns_sect, 821556Srgrimes const char *, ns_class, int, rrset_ns *); 8397659Stjrstatic int save_a(res_state, ns_msg *, ns_sect, 84100308Stjr const char *, ns_class, int, rr_ns *); 851556Srgrimesstatic void free_nsrrset(rrset_ns *); 8638536Scracauerstatic void free_nsrr(rrset_ns *, rr_ns *); 8738950Scracauerstatic rr_ns * find_ns(rrset_ns *, const char *); 8838536Scracauerstatic int do_query(res_state, const char *, ns_class, ns_type, 8999762Stjr u_char *, ns_msg *); 901556Srgrimesstatic void res_dprintf(const char *, ...) ISC_FORMAT_PRINTF(1, 2); 9120425Ssteve 9290111Simp/* Macros. */ 9320425Ssteve 9490111Simp#define DPRINTF(x) do {\ 9590111Simp int save_errno = errno; \ 96100308Stjr if ((statp->options & RES_DEBUG) != 0U) res_dprintf x; \ 97100308Stjr errno = save_errno; \ 9890111Simp } while (0) 9990111Simp 10097659Stjr/* Public. */ 10197659Stjr 10297659Stjr/* 10397659Stjr * int 10497659Stjr * res_findzonecut(res, dname, class, zname, zsize, addrs, naddrs) 10597822Stjr * find enclosing zone for a <dname,class>, and some server addresses 1061556Srgrimes * parameters: 1071556Srgrimes * res - resolver context to work within (is modified) 1081556Srgrimes * dname - domain name whose enclosing zone is desired 1091556Srgrimes * class - class of dname (and its enclosing zone) 1101556Srgrimes * zname - found zone name 1111556Srgrimes * zsize - allocated size of zname 1121556Srgrimes * addrs - found server addresses 1131556Srgrimes * naddrs - max number of addrs 11420425Ssteve * return values: 1151556Srgrimes * < 0 - an error occurred (check errno) 11690111Simp * = 0 - zname is now valid, but addrs[] wasn't changed 11717987Speter * > 0 - zname is now valid, and return value is number of addrs[] found 11899762Stjr * notes: 1191556Srgrimes * this function calls res_nsend() which means it depends on correctly 1201556Srgrimes * functioning recursive nameservers (usually defined in /etc/resolv.conf 1211556Srgrimes * or its local equivilent). 1221556Srgrimes * 12399762Stjr * we start by asking for an SOA<dname,class>. if we get one as an 12499762Stjr * answer, that just means <dname,class> is a zone top, which is fine. 12599762Stjr * more than likely we'll be told to go pound sand, in the form of a 12699762Stjr * negative answer. 12799762Stjr * 12899762Stjr * note that we are not prepared to deal with referrals since that would 129109927Stjr * only come from authority servers and our correctly functioning local 13099762Stjr * recursive server would have followed the referral and got us something 13199762Stjr * more definite. 132109927Stjr * 133109927Stjr * if the authority section contains an SOA, this SOA should also be the 134109927Stjr * closest enclosing zone, since any intermediary zone cuts would've been 135109927Stjr * returned as referrals and dealt with by our correctly functioning local 136109927Stjr * recursive name server. but an SOA in the authority section should NOT 137109927Stjr * match our dname (since that would have been returned in the answer 138109927Stjr * section). an authority section SOA has to be "above" our dname. 139109927Stjr * 140109927Stjr * however, since authority section SOA's were once optional, it's 141109927Stjr * possible that we'll have to go hunting for the enclosing SOA by 142109927Stjr * ripping labels off the front of our dname -- this is known as "doing 143109927Stjr * it the hard way." 144109927Stjr * 145103223Snectar * ultimately we want some server addresses, which are ideally the ones 14699762Stjr * pertaining to the SOA.MNAME, but only if there is a matching NS RR. 14799762Stjr * so the second phase (after we find an SOA) is to go looking for the 14899762Stjr * NS RRset for that SOA's zone. 14999762Stjr * 1501556Srgrimes * no answer section processed by this code is allowed to contain CNAME 15199762Stjr * or DNAME RR's. for the SOA query this means we strip a label and 15220425Ssteve * keep going. for the NS and A queries this means we just give up. 15399762Stjr */ 1541556Srgrimes 1551556Srgrimes#ifndef _LIBC 1561556Srgrimesint 1571556Srgrimesres_findzonecut(res_state statp, const char *dname, ns_class class, int opts, 15817987Speter char *zname, size_t zsize, struct in_addr *addrs, int naddrs) 15917987Speter{ 16099762Stjr int result, i; 1611556Srgrimes union res_sockaddr_union *u; 1621556Srgrimes 1631556Srgrimes 1641556Srgrimes opts |= RES_IPV4ONLY; 1651556Srgrimes opts &= ~RES_IPV6ONLY; 1661556Srgrimes 16717987Speter u = calloc(naddrs, sizeof(*u)); 16899762Stjr if (u == NULL) 1691556Srgrimes return(-1); 17017987Speter 17199762Stjr result = res_findzonecut2(statp, dname, class, opts, zname, zsize, 17299762Stjr u, naddrs); 17399762Stjr 1741556Srgrimes for (i = 0; i < result; i++) { 1751556Srgrimes addrs[i] = u[i].sin.sin_addr; 1761556Srgrimes } 1771556Srgrimes free(u); 1781556Srgrimes return (result); 1791556Srgrimes} 18020425Ssteve#endif 1811556Srgrimes 1821556Srgrimesint 1831556Srgrimesres_findzonecut2(res_state statp, const char *dname, ns_class class, int opts, 18428346Ssteve char *zname, size_t zsize, union res_sockaddr_union *addrs, 18517987Speter int naddrs) 1861556Srgrimes{ 1871556Srgrimes char mname[NS_MAXDNAME]; 1881556Srgrimes u_long save_pfcode; 1891556Srgrimes rrset_ns nsrrs; 1901556Srgrimes int n; 1911556Srgrimes 1921556Srgrimes DPRINTF(("START dname='%s' class=%s, zsize=%ld, naddrs=%d", 1931556Srgrimes dname, p_class(class), (long)zsize, naddrs)); 1941556Srgrimes save_pfcode = statp->pfcode; 1951556Srgrimes statp->pfcode |= RES_PRF_HEAD2 | RES_PRF_HEAD1 | RES_PRF_HEADX | 1961556Srgrimes RES_PRF_QUES | RES_PRF_ANS | 1971556Srgrimes RES_PRF_AUTH | RES_PRF_ADD; 1981556Srgrimes INIT_LIST(nsrrs); 19917987Speter 20090111Simp DPRINTF(("get the soa, and see if it has enough glue")); 20117987Speter if ((n = get_soa(statp, dname, class, opts, zname, zsize, 2021556Srgrimes mname, sizeof mname, &nsrrs)) < 0 || 203100308Stjr ((opts & RES_EXHAUSTIVE) == 0 && 2041556Srgrimes (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0)) 2051556Srgrimes goto done; 2061556Srgrimes 2071556Srgrimes DPRINTF(("get the ns rrset and see if it has enough glue")); 2081556Srgrimes if ((n = get_ns(statp, zname, class, opts, &nsrrs)) < 0 || 20996933Stjr ((opts & RES_EXHAUSTIVE) == 0 && 21096933Stjr (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0)) 21196933Stjr goto done; 2121556Srgrimes 21399762Stjr DPRINTF(("get the missing glue and see if it's finally enough")); 2141556Srgrimes if ((n = get_glue(statp, class, opts, &nsrrs)) >= 0) 215100305Stjr n = satisfy(statp, mname, &nsrrs, addrs, naddrs); 2161556Srgrimes 21745916Scracauer done: 2181556Srgrimes DPRINTF(("FINISH n=%d (%s)", n, (n < 0) ? strerror(errno) : "OK")); 2191556Srgrimes free_nsrrset(&nsrrs); 2201556Srgrimes statp->pfcode = save_pfcode; 2211556Srgrimes return (n); 2221556Srgrimes} 22317987Speter 22490111Simp/* Private. */ 22517987Speter 22696933Stjrstatic int 2271556Srgrimessatisfy(res_state statp, const char *mname, rrset_ns *nsrrsp, 2281556Srgrimes union res_sockaddr_union *addrs, int naddrs) 2291556Srgrimes{ 2301556Srgrimes rr_ns *nsrr; 2311556Srgrimes int n, x; 2321556Srgrimes 23396933Stjr n = 0; 23496933Stjr nsrr = find_ns(nsrrsp, mname); 2351556Srgrimes if (nsrr != NULL) { 236100305Stjr x = add_addrs(statp, nsrr, addrs, naddrs); 237104275Smux addrs += x; 23896933Stjr naddrs -= x; 23996933Stjr n += x; 24096933Stjr } 2411556Srgrimes for (nsrr = HEAD(*nsrrsp); 2421556Srgrimes nsrr != NULL && naddrs > 0; 2431556Srgrimes nsrr = NEXT(nsrr, link)) 2441556Srgrimes if (ns_samename(nsrr->name, mname) != 1) { 2451556Srgrimes x = add_addrs(statp, nsrr, addrs, naddrs); 2461556Srgrimes addrs += x; 24790111Simp naddrs -= x; 24817987Speter n += x; 2491556Srgrimes } 2501556Srgrimes DPRINTF(("satisfy(%s): %d", mname, n)); 2511556Srgrimes return (n); 2521556Srgrimes} 2531556Srgrimes 25497660Stjrstatic int 2551556Srgrimesadd_addrs(res_state statp, rr_ns *nsrr, 2561556Srgrimes union res_sockaddr_union *addrs, int naddrs) 2571556Srgrimes{ 25826104Ssteve rr_a *arr; 2591556Srgrimes int n = 0; 2601556Srgrimes 2611556Srgrimes for (arr = HEAD(nsrr->addrs); arr != NULL; arr = NEXT(arr, link)) { 2621556Srgrimes if (naddrs <= 0) 2631556Srgrimes return (0); 2641556Srgrimes *addrs++ = arr->addr; 2651556Srgrimes naddrs--; 2661556Srgrimes n++; 2671556Srgrimes } 2681556Srgrimes DPRINTF(("add_addrs: %d", n)); 26997669Stjr return (n); 27017987Speter} 27197669Stjr 27297669Stjrstatic int 27397669Stjrget_soa(res_state statp, const char *dname, ns_class class, int opts, 27497669Stjr char *zname, size_t zsize, char *mname, size_t msize, 275100663Stjr rrset_ns *nsrrsp) 27697669Stjr{ 27797669Stjr char tname[NS_MAXDNAME]; 27897669Stjr u_char *resp = NULL; 27997669Stjr int n, i, ancount, nscount; 28097669Stjr ns_sect sect; 28197669Stjr ns_msg msg; 28297669Stjr u_int rcode; 28397669Stjr 28497669Stjr /* 28597669Stjr * Find closest enclosing SOA, even if it's for the root zone. 28697669Stjr */ 28797669Stjr 28897669Stjr /* First canonicalize dname (exactly one unescaped trailing "."). */ 28997669Stjr if (ns_makecanon(dname, tname, sizeof tname) < 0) 29097669Stjr goto cleanup; 29197669Stjr dname = tname; 29297669Stjr 29397669Stjr resp = malloc(NS_MAXMSG); 29497669Stjr if (resp == NULL) 29597669Stjr goto cleanup; 29697669Stjr 29797822Stjr /* Now grovel the subdomains, hunting for an SOA answer or auth. */ 29897669Stjr for (;;) { 29997669Stjr /* Leading or inter-label '.' are skipped here. */ 3001556Srgrimes while (*dname == '.') 3011556Srgrimes dname++; 30297663Stjr 30397822Stjr /* Is there an SOA? */ 30497663Stjr n = do_query(statp, dname, class, ns_t_soa, resp, &msg); 30597663Stjr if (n < 0) { 30697663Stjr DPRINTF(("get_soa: do_query('%s', %s) failed (%d)", 30797669Stjr dname, p_class(class), n)); 30897669Stjr goto cleanup; 30997669Stjr } 3101556Srgrimes if (n > 0) { 31197663Stjr DPRINTF(("get_soa: CNAME or DNAME found")); 31297663Stjr sect = ns_s_max, n = 0; 31397669Stjr } else { 31497669Stjr rcode = ns_msg_getflag(msg, ns_f_rcode); 31597669Stjr ancount = ns_msg_count(msg, ns_s_an); 31697669Stjr nscount = ns_msg_count(msg, ns_s_ns); 31797669Stjr if (ancount > 0 && rcode == ns_r_noerror) 31897669Stjr sect = ns_s_an, n = ancount; 31997669Stjr else if (nscount > 0) 32097669Stjr sect = ns_s_ns, n = nscount; 32197663Stjr else 32297669Stjr sect = ns_s_max, n = 0; 323100308Stjr } 32497669Stjr for (i = 0; i < n; i++) { 32597669Stjr const char *t; 32697822Stjr const u_char *rdata; 32797669Stjr ns_rr rr; 32897822Stjr 32997822Stjr if (ns_parserr(&msg, sect, i, &rr) < 0) { 33097819Stjr DPRINTF(("get_soa: ns_parserr(%s, %d) failed", 33197669Stjr p_section(sect, ns_o_query), i)); 33297819Stjr goto cleanup; 33397669Stjr } 33497669Stjr if (ns_rr_type(rr) == ns_t_cname || 33597669Stjr ns_rr_type(rr) == ns_t_dname) 33697663Stjr break; 33797669Stjr if (ns_rr_type(rr) != ns_t_soa || 33897663Stjr ns_rr_class(rr) != class) 33997816Stjr continue; 34097663Stjr t = ns_rr_name(rr); 34197663Stjr switch (sect) { 34297669Stjr case ns_s_an: 343100308Stjr if (ns_samedomain(dname, t) == 0) { 34497669Stjr DPRINTF( 34597669Stjr ("get_soa: ns_samedomain('%s', '%s') == 0", 34697669Stjr dname, t) 34797663Stjr ); 34897819Stjr errno = EPROTOTYPE; 34997819Stjr goto cleanup; 35097819Stjr } 35197669Stjr break; 35297663Stjr case ns_s_ns: 35397820Stjr if (ns_samename(dname, t) == 1 || 35497820Stjr ns_samedomain(dname, t) == 0) { 35597820Stjr DPRINTF( 35697820Stjr ("get_soa: ns_samename() || !ns_samedomain('%s', '%s')", 35797820Stjr dname, t) 35897663Stjr ); 35997663Stjr errno = EPROTOTYPE; 36097663Stjr goto cleanup; 36197663Stjr } 36297663Stjr break; 36397663Stjr default: 36497663Stjr abort(); 36597663Stjr } 36697663Stjr if (strlen(t) + 1 > zsize) { 36797663Stjr DPRINTF(("get_soa: zname(%lu) too small (%lu)", 36897663Stjr (unsigned long)zsize, 36997663Stjr (unsigned long)strlen(t) + 1)); 37097663Stjr errno = EMSGSIZE; 37197663Stjr goto cleanup; 37297663Stjr } 37397663Stjr strcpy(zname, t); 37497663Stjr rdata = ns_rr_rdata(rr); 37597663Stjr if (ns_name_uncompress(resp, ns_msg_end(msg), rdata, 37697663Stjr mname, msize) < 0) { 37797663Stjr DPRINTF(("get_soa: ns_name_uncompress failed") 37897663Stjr ); 37997663Stjr goto cleanup; 38097669Stjr } 38197663Stjr if (save_ns(statp, &msg, ns_s_ns, 38297663Stjr zname, class, opts, nsrrsp) < 0) { 38397663Stjr DPRINTF(("get_soa: save_ns failed")); 38497663Stjr goto cleanup; 3851556Srgrimes } 3861556Srgrimes free(resp); 3871556Srgrimes return (0); 3881556Srgrimes } 3891556Srgrimes 3901556Srgrimes /* If we're out of labels, then not even "." has an SOA! */ 3911556Srgrimes if (*dname == '\0') 3921556Srgrimes break; 3931556Srgrimes 3941556Srgrimes /* Find label-terminating "."; top of loop will skip it. */ 39597669Stjr while (*dname != '.') { 39617987Speter if (*dname == '\\') 3971556Srgrimes if (*++dname == '\0') { 3981556Srgrimes errno = EMSGSIZE; 3991556Srgrimes goto cleanup; 4001556Srgrimes } 4011556Srgrimes dname++; 4021556Srgrimes } 4031556Srgrimes } 4041556Srgrimes DPRINTF(("get_soa: out of labels")); 4051556Srgrimes errno = EDESTADDRREQ; 4061556Srgrimes cleanup: 4071556Srgrimes if (resp != NULL) 4081556Srgrimes free(resp); 4091556Srgrimes return (-1); 4101556Srgrimes} 41197822Stjr 4121556Srgrimesstatic int 4131556Srgrimesget_ns(res_state statp, const char *zname, ns_class class, int opts, 4141556Srgrimes rrset_ns *nsrrsp) 4151556Srgrimes{ 4161556Srgrimes u_char *resp; 4171556Srgrimes ns_msg msg; 4181556Srgrimes int n; 4191556Srgrimes 4201556Srgrimes resp = malloc(NS_MAXMSG); 4211556Srgrimes if (resp == NULL) 4221556Srgrimes return (-1); 4231556Srgrimes 4241556Srgrimes /* Go and get the NS RRs for this zone. */ 42590111Simp n = do_query(statp, zname, class, ns_t_ns, resp, &msg); 42690111Simp if (n != 0) { 4271556Srgrimes DPRINTF(("get_ns: do_query('%s', %s) failed (%d)", 4281556Srgrimes zname, p_class(class), n)); 4291556Srgrimes free(resp); 4301556Srgrimes return (-1); 4311556Srgrimes } 4321556Srgrimes 4331556Srgrimes /* Remember the NS RRs and associated A RRs that came back. */ 4341556Srgrimes if (save_ns(statp, &msg, ns_s_an, zname, class, opts, nsrrsp) < 0) { 4351556Srgrimes DPRINTF(("get_ns save_ns('%s', %s) failed", 4361556Srgrimes zname, p_class(class))); 4371556Srgrimes free(resp); 4381556Srgrimes return (-1); 43997659Stjr } 4401556Srgrimes 4411556Srgrimes free(resp); 4421556Srgrimes return (0); 4431556Srgrimes} 4441556Srgrimes 4451556Srgrimesstatic int 4461556Srgrimesget_glue(res_state statp, ns_class class, int opts, rrset_ns *nsrrsp) { 44790111Simp rr_ns *nsrr, *nsrr_n; 44817987Speter u_char *resp; 4491556Srgrimes 45026104Ssteve resp = malloc(NS_MAXMSG); 4511556Srgrimes if (resp == NULL) 4521556Srgrimes return(-1); 4531556Srgrimes 4541556Srgrimes /* Go and get the A RRs for each empty NS RR on our list. */ 4551556Srgrimes for (nsrr = HEAD(*nsrrsp); nsrr != NULL; nsrr = nsrr_n) { 4561556Srgrimes ns_msg msg; 4571556Srgrimes int n; 45838536Scracauer 45938536Scracauer nsrr_n = NEXT(nsrr, link); 46038536Scracauer 46138536Scracauer if ((nsrr->flags & RR_NS_HAVE_V4) == 0) { 46238536Scracauer n = do_query(statp, nsrr->name, class, ns_t_a, 46338536Scracauer resp, &msg); 46438521Scracauer if (n < 0) { 46538536Scracauer DPRINTF( 4661556Srgrimes ("get_glue: do_query('%s', %s') failed", 4671556Srgrimes nsrr->name, p_class(class))); 4681556Srgrimes goto cleanup; 46926104Ssteve } 47026104Ssteve if (n > 0) { 4711556Srgrimes DPRINTF(( 47226104Ssteve "get_glue: do_query('%s', %s') CNAME or DNAME found", 47326104Ssteve nsrr->name, p_class(class))); 4741556Srgrimes } 4751556Srgrimes if (save_a(statp, &msg, ns_s_an, nsrr->name, class, 47626104Ssteve opts, nsrr) < 0) { 4771556Srgrimes DPRINTF(("get_glue: save_r('%s', %s) failed", 4781556Srgrimes nsrr->name, p_class(class))); 47938536Scracauer goto cleanup; 48026104Ssteve } 4811556Srgrimes } 4821556Srgrimes 4831556Srgrimes if ((nsrr->flags & RR_NS_HAVE_V6) == 0) { 4841556Srgrimes n = do_query(statp, nsrr->name, class, ns_t_aaaa, 48538536Scracauer resp, &msg); 4861556Srgrimes if (n < 0) { 4871556Srgrimes DPRINTF( 4881556Srgrimes ("get_glue: do_query('%s', %s') failed", 4891556Srgrimes nsrr->name, p_class(class))); 4901556Srgrimes goto cleanup; 4911556Srgrimes } 49238521Scracauer if (n > 0) { 49338521Scracauer DPRINTF(( 49438521Scracauer "get_glue: do_query('%s', %s') CNAME or DNAME found", 49538521Scracauer nsrr->name, p_class(class))); 4961556Srgrimes } 4971556Srgrimes if (save_a(statp, &msg, ns_s_an, nsrr->name, class, 4981556Srgrimes opts, nsrr) < 0) { 4991556Srgrimes DPRINTF(("get_glue: save_r('%s', %s) failed", 50017987Speter nsrr->name, p_class(class))); 50190111Simp goto cleanup; 50217987Speter } 5031556Srgrimes } 5041556Srgrimes 5051556Srgrimes /* If it's still empty, it's just chaff. */ 5061556Srgrimes if (EMPTY(nsrr->addrs)) { 5071556Srgrimes DPRINTF(("get_glue: removing empty '%s' NS", 508100308Stjr nsrr->name)); 5091556Srgrimes free_nsrr(nsrrsp, nsrr); 5101556Srgrimes } 5111556Srgrimes } 5121556Srgrimes free(resp); 5131556Srgrimes return (0); 5141556Srgrimes 5151556Srgrimes cleanup: 5161556Srgrimes free(resp); 5171556Srgrimes return (-1); 5181556Srgrimes} 5191556Srgrimes 5201556Srgrimesstatic int 52190111Simpsave_ns(res_state statp, ns_msg *msg, ns_sect sect, 52290111Simp const char *owner, ns_class class, int opts, 5231556Srgrimes rrset_ns *nsrrsp) 52497688Stjr{ 525100308Stjr int i; 5261556Srgrimes 5271556Srgrimes for (i = 0; i < ns_msg_count(*msg, sect); i++) { 5281556Srgrimes char tname[MAXDNAME]; 5291556Srgrimes const u_char *rdata; 53097659Stjr rr_ns *nsrr; 5311556Srgrimes ns_rr rr; 53297659Stjr 5331556Srgrimes if (ns_parserr(msg, sect, i, &rr) < 0) { 5341556Srgrimes DPRINTF(("save_ns: ns_parserr(%s, %d) failed", 5351556Srgrimes p_section(sect, ns_o_query), i)); 5361556Srgrimes return (-1); 5371556Srgrimes } 5381556Srgrimes if (ns_rr_type(rr) != ns_t_ns || 5391556Srgrimes ns_rr_class(rr) != class || 5401556Srgrimes ns_samename(ns_rr_name(rr), owner) != 1) 5411556Srgrimes continue; 5421556Srgrimes nsrr = find_ns(nsrrsp, ns_rr_name(rr)); 5431556Srgrimes if (nsrr == NULL) { 5441556Srgrimes nsrr = malloc(sizeof *nsrr); 54597688Stjr if (nsrr == NULL) { 54697688Stjr DPRINTF(("save_ns: malloc failed")); 54797688Stjr return (-1); 54897688Stjr } 54997688Stjr rdata = ns_rr_rdata(rr); 55097688Stjr if (ns_name_uncompress(ns_msg_base(*msg), 55197688Stjr ns_msg_end(*msg), rdata, 5521556Srgrimes tname, sizeof tname) < 0) { 55397688Stjr DPRINTF(("save_ns: ns_name_uncompress failed") 55497688Stjr ); 55597688Stjr free(nsrr); 55697688Stjr return (-1); 55797688Stjr } 55897688Stjr nsrr->name = strdup(tname); 55997688Stjr if (nsrr->name == NULL) { 56097688Stjr DPRINTF(("save_ns: strdup failed")); 56197688Stjr free(nsrr); 56297688Stjr return (-1); 56397688Stjr } 56497688Stjr INIT_LINK(nsrr, link); 5651556Srgrimes INIT_LIST(nsrr->addrs); 56697688Stjr nsrr->flags = 0; 5671556Srgrimes APPEND(*nsrrsp, nsrr, link); 5681556Srgrimes } 5691556Srgrimes if (save_a(statp, msg, ns_s_ar, 5701556Srgrimes nsrr->name, class, opts, nsrr) < 0) { 5711556Srgrimes DPRINTF(("save_ns: save_r('%s', %s) failed", 5721556Srgrimes nsrr->name, p_class(class))); 5731556Srgrimes return (-1); 5741556Srgrimes } 5751556Srgrimes } 5761556Srgrimes return (0); 5771556Srgrimes} 5781556Srgrimes 579100308Stjrstatic int 5801556Srgrimessave_a(res_state statp, ns_msg *msg, ns_sect sect, 5811556Srgrimes const char *owner, ns_class class, int opts, 5821556Srgrimes rr_ns *nsrr) 5831556Srgrimes{ 5841556Srgrimes int i; 5851556Srgrimes 5861556Srgrimes for (i = 0; i < ns_msg_count(*msg, sect); i++) { 58717987Speter ns_rr rr; 58817987Speter rr_a *arr; 5891556Srgrimes 5901556Srgrimes if (ns_parserr(msg, sect, i, &rr) < 0) { 5911556Srgrimes DPRINTF(("save_a: ns_parserr(%s, %d) failed", 5921556Srgrimes p_section(sect, ns_o_query), i)); 5931556Srgrimes return (-1); 5941556Srgrimes } 5951556Srgrimes if ((ns_rr_type(rr) != ns_t_a && 5961556Srgrimes ns_rr_type(rr) != ns_t_aaaa) || 5971556Srgrimes ns_rr_class(rr) != class || 59890111Simp ns_samename(ns_rr_name(rr), owner) != 1 || 59917987Speter ns_rr_rdlen(rr) != NS_INADDRSZ) 6001556Srgrimes continue; 6011556Srgrimes if ((opts & RES_IPV6ONLY) != 0 && ns_rr_type(rr) != ns_t_aaaa) 6021556Srgrimes continue; 6031556Srgrimes if ((opts & RES_IPV4ONLY) != 0 && ns_rr_type(rr) != ns_t_a) 6041556Srgrimes continue; 6051556Srgrimes arr = malloc(sizeof *arr); 6061556Srgrimes if (arr == NULL) { 6071556Srgrimes DPRINTF(("save_a: malloc failed")); 60897664Stjr return (-1); 60997659Stjr } 61097664Stjr INIT_LINK(arr, link); 6111556Srgrimes memset(&arr->addr, 0, sizeof(arr->addr)); 6121556Srgrimes switch (ns_rr_type(rr)) { 61317987Speter case ns_t_a: 61497659Stjr arr->addr.sin.sin_family = AF_INET; 61597659Stjr#ifdef HAVE_SA_LEN 61699760Stjr arr->addr.sin.sin_len = sizeof(arr->addr.sin); 61799760Stjr#endif 61897659Stjr memcpy(&arr->addr.sin.sin_addr, ns_rr_rdata(rr), 61997659Stjr NS_INADDRSZ); 62097659Stjr arr->addr.sin.sin_port = htons(NAMESERVER_PORT); 62197659Stjr nsrr->flags |= RR_NS_HAVE_V4; 62297659Stjr break; 62320425Ssteve case ns_t_aaaa: 62420425Ssteve arr->addr.sin6.sin6_family = AF_INET6; 62520425Ssteve#ifdef HAVE_SA_LEN 62620425Ssteve arr->addr.sin6.sin6_len = sizeof(arr->addr.sin6); 6271556Srgrimes#endif 6281556Srgrimes memcpy(&arr->addr.sin6.sin6_addr, ns_rr_rdata(rr), 16); 6291556Srgrimes arr->addr.sin.sin_port = htons(NAMESERVER_PORT); 6301556Srgrimes nsrr->flags |= RR_NS_HAVE_V6; 6311556Srgrimes break; 6321556Srgrimes default: 6331556Srgrimes abort(); 6341556Srgrimes } 6351556Srgrimes APPEND(nsrr->addrs, arr, link); 6361556Srgrimes } 6371556Srgrimes return (0); 6381556Srgrimes} 6391556Srgrimes 6401556Srgrimesstatic void 6411556Srgrimesfree_nsrrset(rrset_ns *nsrrsp) { 6421556Srgrimes rr_ns *nsrr; 643100305Stjr 6441556Srgrimes while ((nsrr = HEAD(*nsrrsp)) != NULL) 6451556Srgrimes free_nsrr(nsrrsp, nsrr); 64697659Stjr} 6471556Srgrimes 6481556Srgrimesstatic void 6491556Srgrimesfree_nsrr(rrset_ns *nsrrsp, rr_ns *nsrr) { 6501556Srgrimes rr_a *arr; 6511556Srgrimes char *tmp; 6521556Srgrimes 6531556Srgrimes while ((arr = HEAD(nsrr->addrs)) != NULL) { 65417987Speter UNLINK(nsrr->addrs, arr, link); 65517987Speter free(arr); 6561556Srgrimes } 6578855Srgrimes DE_CONST(nsrr->name, tmp); 6581556Srgrimes free(tmp); 65997659Stjr UNLINK(*nsrrsp, nsrr, link); 66097659Stjr free(nsrr); 66197659Stjr} 66297659Stjr 66397659Stjrstatic rr_ns * 6641556Srgrimesfind_ns(rrset_ns *nsrrsp, const char *dname) { 66597659Stjr rr_ns *nsrr; 66697659Stjr 66797659Stjr for (nsrr = HEAD(*nsrrsp); nsrr != NULL; nsrr = NEXT(nsrr, link)) 66897659Stjr if (ns_samename(nsrr->name, dname) == 1) 66997659Stjr return (nsrr); 67097659Stjr return (NULL); 67197659Stjr} 67297659Stjr 67397659Stjrstatic int 67497659Stjrdo_query(res_state statp, const char *dname, ns_class class, ns_type qtype, 67597659Stjr u_char *resp, ns_msg *msg) 67697659Stjr{ 67797659Stjr u_char req[NS_PACKETSZ]; 67897659Stjr int i, n; 67997659Stjr 68097659Stjr n = res_nmkquery(statp, ns_o_query, dname, class, qtype, 68197659Stjr NULL, 0, NULL, req, NS_PACKETSZ); 68297659Stjr if (n < 0) { 68397659Stjr DPRINTF(("do_query: res_nmkquery failed")); 68497659Stjr return (-1); 68597659Stjr } 68697659Stjr n = res_nsend(statp, req, n, resp, NS_MAXMSG); 68797659Stjr if (n < 0) { 68897659Stjr DPRINTF(("do_query: res_nsend failed")); 68997659Stjr return (-1); 69097659Stjr } 69197659Stjr if (n == 0) { 69297659Stjr DPRINTF(("do_query: res_nsend returned 0")); 69397659Stjr errno = EMSGSIZE; 69497659Stjr return (-1); 69597659Stjr } 6961556Srgrimes if (ns_initparse(resp, n, msg) < 0) { 69797659Stjr DPRINTF(("do_query: ns_initparse failed")); 69897659Stjr return (-1); 69997659Stjr } 70097659Stjr n = 0; 70197659Stjr for (i = 0; i < ns_msg_count(*msg, ns_s_an); i++) { 70297659Stjr ns_rr rr; 70397659Stjr 70497659Stjr if (ns_parserr(msg, ns_s_an, i, &rr) < 0) { 70597659Stjr DPRINTF(("do_query: ns_parserr failed")); 70697659Stjr return (-1); 70797659Stjr } 70897659Stjr n += (ns_rr_class(rr) == class && 70997659Stjr (ns_rr_type(rr) == ns_t_cname || 71097659Stjr ns_rr_type(rr) == ns_t_dname)); 71197659Stjr } 71297659Stjr return (n); 71397659Stjr} 71497659Stjr 71597659Stjrstatic void 71697659Stjrres_dprintf(const char *fmt, ...) { 71797659Stjr va_list ap; 71897659Stjr 71997659Stjr va_start(ap, fmt); 7201556Srgrimes fputs(";; res_findzonecut: ", stderr); 7211556Srgrimes vfprintf(stderr, fmt, ap); 7221556Srgrimes fputc('\n', stderr); 7231556Srgrimes va_end(ap); 7241556Srgrimes} 7251556Srgrimes