📄 dns_client_cache.c
字号:
/* ############################################################################ (c) Copyright Virata Limited 2001 ## Virata Limited Confidential and Proprietary## The following software source code ("Software") is strictly confidential and# is proprietary to Virata Limited ("Virata"). It may only be read, used,# copied, adapted, modified or otherwise dealt with by you if you have# entered into a confidentiality agreement with Virata and then subject to the# terms of that confidentiality agreement and any other applicable agreement# between you and Virata. If you are in any doubt as to whether you are # entitled to access, read, use, copy, adapt, modify or otherwise deal with# the Software or whether you are entitled to disclose the Software to any# other person you should contact Virata. If you have not entered into a# confidentiality agreement with Virata granting access to this Software you# should forthwith return all media, copies and printed listings containing# the Software to Virata. ## Virata reserves the right to take legal action against you should you breach# the above provisions.## If you are unsure, or to report violations, please contact # support@virata.com# ##########################################################################*//* * file: dns_client_cache.c * * description: this file contains routines that will implement the cache * for the resolver. * */#include "config.h"#include <stdio.h>#include <stdlib.h> /* for atoi() */#include <string.h>#include "timelib.h"#include "errno.h"#include "dns_client_cache.h"#include "dns_client_resource.h"typedef struct { int slot; /* slot or position in the list to install this element */ const char *name; /* host or domain name */ int num; /* number of elements in the list of RRs */ DnsRRec *RR; /* array of RR (resource records) */ int match; /* number of RRs in the list that match the name */ U32 ttl; /* time to live for this entry */ U16 auth; /* was the NS who sent this an authority or not */ U16 ns; /* is this entry for a NS (name server) */} MatchRec;static HostRecord *hostRR[DNS_RRMAXENTRYS];static XX_CacheEnt *Local_XX_Cache[DNS_MAX_XX_LOCAL_ENT]; static void add_host2cache(int, DnsRRec *, int);static void add_ns2cache(DnsRRec *, int, DnsRRec *);static void add_cname2cache(DnsRRec *, DnsRRec *, DnsRRec *, int);static void add_ptr2cache(DnsRRec *, int);static void add_negative2cache(DnsMsg *);static int get_slot(void);static void free_slot(int);static int search_byname(const char *);static int search_bynametype(IN const char *name, IN int type);static int search_byaddr(const char *);static int install_matching_records(MatchRec *, int type);static void print_hostrecord(HostRecord *hr);#ifdef DNS_DEBUGvoid print_cache_resource(void);void print_rlist(DnsRRec *list);#endifstatic int add2listfrommatch(const char *domain, U16 type, DnsRRec **head, DnsRRec *list);static int copy_RR(DnsRRec *to, DnsRRec *from);static DnsRRec *create_RR_list(int num, int size);#ifdef DNS_DEBUGextern void print_resource_record(DnsRRec *);#endifstatic void add_RR_to_XX_cache(int num, DnsRRec *answers, int authority) ; static int get_XX_cache_slot(void); static void free_XX_cache_slot(int i); static void print_rrdata(DnsRRec *rr);/* * dns_query_cache_byname() * * this routine will search our list using the name. if an element is found * what we do depends on what the element is. if it a CNAME type, that means * the name we searched for is just an alias. we fill in a CNAME RR. then * we need to search the cache list for the actual host name, the canonical * name. if found, we then must create additional RRs for this information. * if not a CNAME type then we will just have answer RRs. * * return: 0 for success and * -1 to indicate an error, (which will be a memory allocation error) */intdns_query_cache_byname(const char *domain, DnsMsg *reply){ int i, index; DnsRRec *answers, *additions, *rr; HostRecord *hptr; if ((index = search_bynametype(domain, QT_A)) < 0) return -1; /* * first see if the entry is for a NAME ERROR, that is does it * indicate the name doesn't exist. if so just set the flag in the * DnsMsg header and return. then we need to see if this is a CNAME * entry. if it is, then we search our list to see if we have an * entry for the actual host name. allocate space for the answer, * and fill it in. */ reply->m_dnshdr.nquest = reply->m_dnshdr.nauthrr = reply->m_dnshdr.naddrr = 0; hptr = hostRR[index]; if ( hptr->nerrflag ) { /* name error */ reply->m_dnshdr.flags = DNS_NAMEERR; return 0; } if ( hptr->cflag ) { /* cname */ if ((answers = dns_get_RR()) == NULL) { dprintf("%C allocation error cache query\n");#ifdef DNS_DEBUG print_resource_pool();#endif return -1; } strcpy(answers->r_dname, hptr->hostname); /* copy the alias, same as domain */ answers->r_datalen = strlen(hptr->cname) + 1; if ((answers->r_data = dns_dalloc(answers->r_datalen)) == NULL) { dprintf("%C allocation error cache query\n");#ifdef DNS_DEBUG print_resource_pool();#endif dns_free_RR(answers); return -1; } strcpy((char*)answers->r_data, hptr->cname); /* copy the actual host name */ answers->r_type = QT_CNAME; answers->r_class = QC_IN; answers->r_ttl = hptr->ttl; /* * search the list and see if we have any information for the actual * host name. if we do, then format that information as additional * RRs. if not, then just return the CNAME answer. */ if ((index = search_bynametype(hptr->cname, QT_A)) >= 0) { if ( hostRR[index]->cflag ) { dprintf("%C error CNAME cycle for %s\n", hptr->hostname); /* something to consider: may want to flush these entries * if there is a CNAME cycle */ dns_dfree(answers->r_data, answers->r_datalen); dns_free_RR(answers); return -1; } hptr = hostRR[index]; /* note that create_RR_list() allocates space for the r_data too. * it fails if it cannot create the entire list. */ if ((additions = create_RR_list(hptr->naddr, IPSIZE)) == NULL) { dprintf("%C allocation error cache query\n"); dns_dfree(answers->r_data, answers->r_datalen); dns_free_RR(answers); return -1; } i = 0; rr = additions; while ( rr != NULL ) { if (hptr->ipaddr[i].__ss_family == AF_INET) { memcpy(rr->r_data, &((struct sockaddr_in *) &hptr->ipaddr[i])->sin_addr, sizeof(U32)); strcpy(rr->r_dname, hptr->hostname); rr->r_type = QT_A; rr->r_class = QC_IN; rr->r_ttl = hptr->ttl; rr->r_datalen = IPSIZE; } i++; rr = rr->r_next; } reply->m_dnshdr.naddrr = hptr->naddr; reply->m_additionals = additions; } reply->m_dnshdr.nansrr = 1; reply->m_answers = answers; return 0; } /* * okay, not a CNAME, format the response. this case we just have * answer records that are of the A type. we need one for every * IP address our cache element has. remember create_RR_list() also * creates the memory space for the data part of the RR, and fails * unless it can create the entire list. */ if ((answers = create_RR_list(hptr->naddr, IPSIZE)) == NULL) { dprintf("%C allocation error cache query\n"); return -1; } i = 0; rr = answers; while ( rr != NULL ) { if (hptr->ipaddr[i].__ss_family == AF_INET) { memcpy(rr->r_data, &((struct sockaddr_in *)&hptr->ipaddr[i]) ->sin_addr, sizeof(U32)); strcpy(rr->r_dname, hptr->hostname); rr->r_type = QT_A; rr->r_class = QC_IN; rr->r_ttl = hptr->ttl; rr->r_datalen = IPSIZE; } rr = rr->r_next; i++; } reply->m_dnshdr.nansrr = hptr->naddr; reply->m_answers = answers; return 0;} /* end dns_query_cache_byname() *//* * dns_query_cache_byaddr() * * this routine searches the cache list for an entry using the address. the * address as we receive it is converted for a DNS query. for example: * 11.22.33.44 becomes 44.33.22.11.in-addr.arpa. it is converted back by * the search routine. we don't have to worry about CNAME records here because * they don't have addresses associated with them. if we find the record we're * looking for we just have to format it. * * return: 0 for success and * -1 to indicate we didn't find it, or an error, * (which will be a memory allocation error) */intdns_query_cache_byaddr(const char *addr, DnsMsg *reply){ int index; DnsRRec *answer; HostRecord *hptr; if ((index = search_byaddr(addr)) < 0) return -1; reply->m_dnshdr.nquest = reply->m_dnshdr.nauthrr = reply->m_dnshdr.naddrr = 0; hptr = hostRR[index]; /* we have to check to see if the entry is for a negative reply, if so * then set the name error bit in the flag and return. */ if ( hptr->nerrflag ) { reply->m_dnshdr.flags = DNS_NAMEERR; return 0; } if ((answer = dns_get_RR()) == NULL) { dprintf("%C allocation error acquiring new RR\n");#ifdef DNS_DEBUG print_resource_pool();#endif return -1; } answer->r_datalen = strlen(hptr->hostname) + 1; if ((answer->r_data = dns_dalloc(answer->r_datalen)) == NULL) { dprintf("%C allocation error attempting to get data space\n");#ifdef DNS_DEBUG print_resource_pool();#endif free(answer); return -1; } strcpy(answer->r_dname, addr); strcpy((char*)answer->r_data, hptr->hostname); answer->r_type = QT_PTR; answer->r_class = QC_IN; answer->r_ttl = hptr->ttl; reply->m_dnshdr.nansrr = 1; reply->m_answers = answer; return 0;} /* end dns_query_cache_byaddr() *//* * dns_query_cache_ns() * * this routine will attempt to find a name server, NS, entry matching the * domain name given. if found we check to see that its not an outdated * entry and if it isn't fill in the NS_t structure with the matching entry's * data. if the matching record is outdated we free it and return that we * didn't find anything. note that names stored in our cache list are in * lower case so we convert the domain name to lowercase. some strings returned * from a NS are in uppercase others in lowercase. comparisons are supposed * to be case insensitive, see RFC 1034. * * return: 0 for success, and * -1 to indicate an error. */intdns_query_cache_ns(const char *domain, NS_t *nsinfo){ int i; char name[NAMEMAX+1]; BITS now; lowercase_copy(name, domain); for ( i = 0; i < DNS_RRMAXENTRYS; i++ ) { if ( 0 == hostRR[i] || !hostRR[i]->nsflag ) continue; if ( strcmp(hostRR[i]->hostname, name) == 0 ) { now = timer_secs(); if ((now - hostRR[i]->init_time) > hostRR[i]->ttl) { free_slot(i); continue; } strcpy(nsinfo->ns_name, hostRR[i]->hostname); nsinfo->ns_addr = hostRR[i]->ipaddr[0]; nsinfo->ns_recursion = hostRR[i]->recursion; nsinfo->ns_error = 0; return 0; } } return -1;} /* end dns_query_cache_ns() *//* dns_query_cache_byname6 -- * find IPv6 host address information in the cache * * PARAMETERS * question - dns query to perform in cache * reply - resulting answer message * * RETURNS * -1 there is no appropriate entry in the cache * DNS_NEGATIVE cache has nothing to say * DNS_ANSWER there is a direct answer * DNS_CNAMEANSWER it is a cname, but cache returns * results in additional RRs * DNS_CNAME it is a cname, and cache does not * contain relevant IP. */intdns_query_cache_byname6(IN DnsQuestion *question, OUT DnsMsg *reply){ int i, index, ret_val; DnsRRec *answers, *additions, *rr; HostRecord *hPtr; /* The search will be performed for both QT_AAAA and QT_A6 types */ if ((index = search_bynametype(question->q_name, QT_AAAA)) < 0) { return -1; } /* * First see if the entry is for a NAME ERROR, that is does it * indicate the name doesn't exist. If so just set the flag in the * DnsMsg header and return. Then we need to see if this is a CNAME * entry. If it is, then we search our list to see if we have an * entry for the actual host name. Allocate space for the answer, * and fill it in. */ reply->m_dnshdr.nquest = reply->m_dnshdr.nauthrr = reply->m_dnshdr.naddrr = 0; hPtr = hostRR[index]; if (hPtr->nerrflag) { reply->m_dnshdr.flags = DNS_NAMEERR; return DNS_NEGATIVE; } if (hPtr->cflag) { if ((answers = dns_get_RR()) == NULL) { dprintf("%C allocation error cache query\n");#ifdef DNS_DEBUG print_resource_pool();#endif return -1; } strcpy(answers->r_dname, hPtr->hostname); /* copy the alias, same as domain */ answers->r_datalen = strlen(hPtr->cname) + 1; if ((answers->r_data = dns_dalloc(answers->r_datalen)) == NULL) { dprintf("%C allocation error cache query\n");#ifdef DNS_DEBUG print_resource_pool();#endif dns_free_RR(answers); return -1; } strcpy((char*)answers->r_data, hPtr->cname); /* copy the actual host name */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -