⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dns_client_reply.c

📁 DNS 的实现代码
💻 C
📖 第 1 页 / 共 4 页
字号:
        }        /*          * nothing in the cache, so we need to construct a new query for the         * CNAME.  cache any useful information, it could come in handy when         * the new query creates its name server list.  if we already have         * an active query outstanding, clean up and exit.  we only want one         * outstanding query at a time.         */        dns_add_AA2cache(dnsmsg, 0);         if ( query->nxquery != NULL ) {            dnsmsg_cleanup(dnsmsg);    	    return;        }        /*          * we also have a limit on how many queries we allow for a particular         * request.  if a new query will exceed that limit, then we don't do         * it.         */        if ( (query->nquerys + 1) > MAXQUERYDEPTH ) {            dnsmsg_cleanup(dnsmsg);	    dns_response_timeout(query);	    return;        }        /*          * so, looks like we're going to do the new query.  get a dns_hostent         * structure and an ATMOS_MESSAGE.  fill in the necessary information         * to indicate its a query for a cname and kick off the query.         */        if ((hp = dns_hent_alloc()) == NULL) {            dprintf("%C no free dns_hostent structures for internal query\n");#ifdef DNS_DEBUG            print_resource_pool();#endif	    dnsmsg_cleanup(dnsmsg);	    dns_response_timeout(query);	    return;        }	hp->hent.h_numaddrs = ENTADDRS;   /* this is a set amount */	qinfo.qtype = addr_t;	strcpy(hp->name, cRR->r_data);	qinfo.hostname = hp->name;	qinfo.cache_flag = query->use_cache;	qinfo.qcnt = ++query->nquerys;	qinfo.amsg = &hp->amsg;	qinfo.hptr = &hp->hent;	if ( start_new_query(&qinfo) < 0 ) {	    dprintf("%C: attempt to start internal query failed\n");	    dns_hent_free(hp);	    dnsmsg_cleanup(dnsmsg);	    dns_response_timeout(query);            return;        }	query->nxquery = &hp->amsg;      /* we use this to find this query later */	query->qstate = wf_cqaddr;	query->dns_qreply = cname_reply;	dnsmsg_cleanup(dnsmsg);          /* clean up */	return;    }    /* we have at least one matching record.  so we've got our answer.  handle     * formating and such.     */    fmt_cname_answer(query, &query->dnsreply);#ifdef DNS_DEBUG    if ( dns_verbosity > 0 ) {        print_responding_server(query);        print_dns_message(&query->dnsreply);    }#endif    dns_update_resolver_cache(&query->dnsreply);    sendreply(query->reply);    dnsmsg_cleanup(&query->dnsreply);    /* be sure to clean up */    free_querystate(query);              /* and to free the query state structure */}   /* end dns_cname_reply() *//* * dns_ns_reply() * * this routine is called when the name server sent us a reply that suggests we * use a different name server for our query.  if the name server sent us the  * address of the name server it suggests we try, then all is simple.  we check  * to see if the new name server is better than the ones we already have in our * list and if so we add it to our list and continue as if we had timed out  * waiting for a reply.  name servers can send other name servers to try in the * authority (or NS) records.  we need to check through those also. * * first we try to get a list of name servers from the DNS message.  if we do,  * we add that to our current list or replace elements of the current list.  if  * that's not successful, it means either we don't have addresses for the new  * servers or they're not good servers to use.  rather than just go and try to  * get an address for a server we see if we've already tried all in the current  * list.  if we haven't, we forget the whole thing.  one of the servers in our  * current list my be able to give us the results we want so we don't just go  * and start another query to get a name server address. if we have, then we find  * the first good new name server and start a query to get its address.  *  * this routine is expensive.  worst case not including any cache search: * find_ns_list() is O(n*N) where n = all the records in both answer and * NS and N is all the records in the additional section.  since n ~ N * the routine is O(n**2).  but normally the name server will send us the * addresses of the name servers it thinks we should try so it won't be a * problem.  */static voiddns_ns_reply(QueryState *query){    Dcmp         domain;    Dcmp         new_ns;    NS_t         nslist[MAXNS];    DnsRRec      *RR;    int          i, index, nums;    Qinfo_t      qinfo;    nslook_t     *hp;    DNSC_DEBUG("entry\n");    /*      * try to construct a list of name servers to try.  note that we don't just     * look at the name server suggested in the answer records, we also look at     * the NS records if there are any.     */    domain.dname = query->domain;    domain.dparts = count_domain_parts(query->domain);    if ((nums = find_ns_list(query, nslist, MAXNS)) > 0) {        for ( i = 0; i < nums; i++ ) {	    new_ns.dname = nslist[i].ns_name;	    new_ns.dparts = count_domain_parts(nslist[i].ns_name);	    if ((index = find_replaceable_ns(query, &domain, &new_ns)) >= 0) {	        strcpy(query->ns_addrs[index].ns_name, nslist[i].ns_name);		query->ns_addrs[index].ns_addr = nslist[i].ns_addr;		query->ns_addrs[index].ns_error = 0;		query->ns_addrs[index].ns_recursion = 0;		query->ns_addrs[index].ns_try = 0;		if ( index >= query->num_ns )		    query->num_ns = index + 1;	    }	}	/* since we know there are name servers and addresses, we update the	 * cache with this information.	 */	dns_update_resolver_cache(&query->dnsreply);	dnsmsg_cleanup(&query->dnsreply);        /* don't need this any more */	dns_response_timeout(query);             /* do query with next server */        DNSC_DEBUG("exit\n");	return;    }    /*      * if we get here then there may be some name servers suggested in the      * DNS response but the server wasn't kind enough to send us the addresses     * along with them.  so, if we haven't already tried all of the name servers     * in our current list at least once, we ignore the "delegation".     */    if ( ns_list_complete(query->ns_addrs, query->num_ns) == FALSE ) {	dnsmsg_cleanup(&query->dnsreply);        /* don't need this any more */	dns_response_timeout(query);             /* do query with next server */        DNSC_DEBUG("exit\n");	return;    }       /*      * if we've already tried all the servers in our current list then we have     * to try to acquire the address of a suggested name server, that is if any     * of them are worth trying.  we get the first one that is valid and set up     * a query attempt for it.     */    if ((RR = find_ns_record(query, &domain, &query->dnsreply)) == NULL) {	dnsmsg_cleanup(&query->dnsreply);        /* don't need this any more */	dns_response_timeout(query);             /* do query with next server */        DNSC_DEBUG("exit\n");	return;    }    /*      * okay, let's try to start a new query for the address of the suggessted     * name server.  first we have to do a couple of checks.  if we already     * have a outstanding internal query, we don't start another.  and we have     * a limit on the number of queries that can be done for a particular host.     * if these tests pass we get a dns_hostent structure and set up for the new     * query.     */    if ( query->nxquery != NULL ) {        dnsmsg_cleanup(&query->dnsreply);	return;    }    if ( (query->nquerys + 1) > MAXQUERYDEPTH ) {        dnsmsg_cleanup(&query->dnsreply);	dns_response_timeout(query);	return;    }    /* okay we've verified its okay to start another query, we get a dns_hostent     * structure and an ATMOS_MESSAGE.     */    /*      * pab: here we must first ask an IPv6 address of NS     */    if ((hp = dns_hent_alloc()) == NULL) {        DNSC_TRACE("no free dns_hostent structures for internal NS query\n");#ifdef DNS_DEBUG        print_resource_pool();#endif        dnsmsg_cleanup(&query->dnsreply);        dns_response_timeout(query);        DNSC_DEBUG("exit - dns_hent_alloc failed\n");        return;    }    /* fill in the structure and kick off the new query. */#ifdef DNS_HAVE_IP6STACK    qinfo.qtype = aaaa_t;    qinfo.cache_flag = TRUE;#else    hp->hent.h_numaddrs = ENTADDRS;   /* set for the max amount */    qinfo.qtype = addr_t;    qinfo.hptr = &hp->hent;#endif /* DNS_HAVE_IP6STACK */    strcpy(hp->name, RR->r_data);    qinfo.hostname = hp->name;    qinfo.qcnt = ++query->nquerys;    qinfo.amsg = &hp->amsg;    if ( start_new_query(&qinfo) < 0 ) {        dprintf("%C; attempt to start internal NS query failed\n");	dns_hent_free(hp);        dnsmsg_cleanup(&query->dnsreply);	dns_response_timeout(query);        DNSC_DEBUG("exit - start_new_query failed\n");	return;    }    query->nxquery = &hp->amsg;        /* we use this to find this query later */#ifdef DNS_HAVE_IP6STACK    query->qstate = wf_nsaddr6;    query->dns_qreply = ns6_reply;      /* set the handler */#else    query->qstate = wf_nsaddr;    query->dns_qreply = ns_reply;      /* set the handler */#endif /* DNS_HAVE_IP6STACK */    dnsmsg_cleanup(&query->dnsreply);    DNSC_DEBUG("exit - start_new_query passed\n");    return;}   /* end dns_ns_reply() *//* * find_replaceable_ns() * * each query maintains a list of NS to use.  if an NS reply indicates another  * to use, we have to see which one in our current list should be replaced. * if the current NS list is not full, then we can just add the new name server * to the end of the list.  if there is a member of the current list that does * not have a name, which indicates its a default server, we assume the new one * is better and will replace the first default name server in the list.  otherwise * we need to compare the domains. * * return:  NS list index of the name server to replace, or *         -1 if none should be replaced. */static intfind_replaceable_ns(QueryState *qstate, Dcmp *domain, Dcmp *new_ns){    NS_t  *nlist;    Dcmp  current;    int   i;    DNSC_DEBUG("entry\n");    /* if the list of servers is not full, just stick the new server     * at the end of the list.     */    if ( qstate->num_ns < MAXNS )        return qstate->num_ns;    /*      * loop through the list.  if a name server entry doesn't have a name     * then its a default name server and we assume the new name server     * is better.     */    nlist = qstate->ns_addrs;    for ( i = 0; i < qstate->num_ns; i++ ) {        if ( nlist[i].ns_name[0] == '\0' )      /* no name indicates a default server */	    return i;	current.dname = nlist[i].ns_name;	current.dparts = count_domain_parts(nlist[i].ns_name);	if ( domain_compare(domain, &current, new_ns) == 1 )	    return i;    }    return -1;}   /* end find_replaceable_ns() *//* * validate_domain() * * this routine is used to see if a domain name from an NS record is the same as  * the domain for the host name we're doing our search for.  what we do here is to * look at the last so many parts of the domain names.  if MINMATCHDOMAIN is 2 then * we just check the last two parts.  for example if the host name we're searching * for is host.domain.com we just compare domain.com.  this is just verifying the * suggested NS is reasonable, not that its the best choice, (see RFC 1035). * * return:  0 is a domain match, *         -1 will indicate an error or not a match. */static intvalidate_domain(Dcmp *dm, Dcmp *nsdm){    const char *dptr;     /* pointer to just the domain part of our domain name */    const char *nptr;     /* pointer to the same number parts of the NS name */    DNSC_DEBUG("entry\n");    if ( nsdm->dparts < MINMATCHDOMAIN )   /* must match at least this many */        return -1;    if ((dptr = get_last_domain_parts(dm->dname, dm->dparts, MINMATCHDOMAIN)) == NULL) {	dprintf("%C: bad domain format %s and %s\n", dm->dname, nsdm->dname);	return -1;    }    if ((nptr = get_last_domain_parts(nsdm->dname, nsdm->dparts, MINMATCHDOMAIN)) == NULL) {	dprintf("%C: bad domain format %s and %s\n", dm->dname, nsdm->dname);	return -1;    }    if ( strcmp(dptr, nptr) == 0 )        return 0;    return -1;}   /* end validate_domain() *//* * find_ns_list() * * this routine will try to construct a list of name servers and their addresses. * we attempt to find the number requested and return the number we actually find. * * return: the number of name server address pairs. */static intfind_ns_list(QueryState *qstate, NS_t *ns, int numns){    DnsRRec  *RR, *addrr, *ans;    DnsMsg   *dnsmsg;    Dcmp     dcmp, nscmp;    int      cnt = 0;    DNSC_DEBUG("entry\n");    dnsmsg = &qstate->dnsreply;    dcmp.dname = qstate->domain;    dcmp.dparts = count_domain_parts(qstate->domain);    ans = RR = dnsmsg->m_answers;    addrr = dnsmsg->m_additionals;    while ( RR != NULL && RR->r_type == QT_NS && cnt < numns ) {        nscmp.dname = RR->r_data;	nscmp.dparts = count_domain_parts(RR->r_data);        if ( validate_domain(&dcmp, &nscmp) < 0 ) {	    RR = RR->r_next;	    continue;	}	if ( find_replaceable_ns(qstate, &dcmp, &nscmp) < 0 ) {	    RR = RR->r_next;	    continue;	}	/* check both the answer records and the additional records for the address */	if ( find_ns_address(RR->r_data, ans, &ns[cnt], qstate->use_cache) == 0 ) 	    ++cnt;          else if ( find_ns_address(RR->r_data, addrr, &ns[cnt], qstate->use_cache) == 0 )	    ++cnt;	RR = RR->r_next;    }    RR = dnsmsg->m_authoritys;    while ( RR != NULL && RR->r_type == QT_NS && cnt < numns ) {        nscmp.dname = RR->r_data;	nscmp.dparts = count_domain_parts(RR->r_data);        if ( validate_domain(&dcmp, &nscmp) < 0 ) {	    RR = RR->r_next;	    continue;	}	if ( find_replaceable_ns(qstate, &dcmp, &nscmp) < 0 ) {	    RR = RR->r_next;	    continue;	}	if ( find_ns_address(RR->r_data, addrr, &ns[cnt], qstate->use_cache) == 0 ) 	    ++cnt;	RR = RR->r_next;    }    return cnt;}   /* end find_ns_list() */    /* * find_ns_address() * * this routine takes the name of a name server and trys to find the matching * address record is the list passed in.  if not in the list and its okay, we'll * try the cache.  if we find the address, we fill in the NS_address structure * if not we leave the structure unchanged. * * return: 0 means we found the address, *         -1 otherwise. */static intfind_ns_address(const char *name, DnsRRec *rlist, NS_t *ns, BOOL cache){    DnsRRec  *RR;    DNSC_DEBUG("entry\n");    if (((RR = find_match_rrecord(name, rlist, QT_AAAA)) != NULL) ||        ((RR = find_match_rrecord(name, rlist, QT_A6)) != NULL))    {        strcpy(ns->ns_name, name);        data2sock(&ns->ns_addr, RR->r_data);        return 0;    }    if ((RR = find_match_rrecord(name, rlist, QT_A)) != NULL) {        strcpy(ns->ns_name, name);	long2sock(&ns->ns_addr, *(U32 *)RR->r_data);	return 0;    }    if ( TRUE == cache && dns_query_cache_ns(name, ns) == 0 )        return 0;        return -1;}   /* end find_ns_address() */      /* * find_ns_record() * * this routine will look through the answer records and the authority (NS) records * and return the first NS record that is valid and that is better than something * in our current list. * * return: pointer to the first NS record that meets our criteria, or *         NULL if there isn't any. */static DnsRRec *

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -