📄 dns_client_query.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# ##########################################################################*/#include "dns_resolv.h"#include "dns_client_query.h"#include "dns_client_cache.h"#include "dns_client_resource.h"#include "messages.h"#include "errno.h"#include <timelib.h>#include "dns_client_statics.h"#define DNSIDMAX (int )0xFFFFFFFF#ifdef DNS_DEBUGextern int dns_verbosity;extern void display_dnsmsghdr(U8 *);#endifextern U32 ipstring2long(const char *);static int msgid = 1;/* * dns_gethostbyname() * * this routine will handle setting up for a standard query for an address. the * routine will attempt to determine if we have a relative domain name and if so * will construct a complete domain name using the first element from the search * list. it then sets the next search list index. if a complete name it sets the * next search index to indicate its not necessary to worry about trying another * search list element should the query fail. the cache is queried only if indicated * to do so by the user. if the cache query fails or isn't attempted this routine * sets the query state up to post a message to the first name server. dns_query() * handles that part of the job. */voiddns_gethostbyname(ATMOS_MESSAGE *msg, DnsDomain *dm){ QueryState *qs; int cflag = FALSE; U32 ip; MSG_D_DNS_GET_ADDRBYNAME(dmsg, msg); DNSC_DEBUG("entry\n");#if defined(DEBUG) print_resource_pool();#endif /* * first verify that the hostname is not an IP address. if it is we'll * handle it differently. if the hostname is an IP address we copy * the hostname string (the IP address) into the host name element of * the dns_hostent structure. then, convert the string to an unsigned * long value (U32), and assign it to the first element of the host * address list. then set the number of addresses to 1. this is done * so as to be similiar to the gethostbyname() UNIX library routine. */ if ((ip = ipstring2long(dmsg->hostname)) != (U32 )-1) { strcpy(dmsg->hptr->h_name, dmsg->hostname); if ( dmsg->hptr->h_numaddrs > 0 ) { dmsg->hptr->h_addr_list[0] = ip; dmsg->hptr->h_numaddrs = 1; } dmsg->error = ESUCCESS; sendreply(msg); return; } /* if not an IP address, then verify that we were sent a valid host name. * if not just return an error without doing anything. */ if ( dns_validate_hostname(dmsg->hostname) < 0 ) { dprintf("%C bad host name\n"); dmsg->error = EHOSTNOTFOUND; sendreply(msg); DNSC_DEBUG("exit - bad host name\n"); return; } /* get a new query state */ if ((qs = dns_get_querystate()) == NULL) { dprintf("%C no free query states available\n");#ifdef DNS_DEBUG print_resource_pool();#endif dmsg->error = ENOMEM; sendreply(msg); DNSC_DEBUG("exit - no free query states available\n"); return; } /* initialize the query state structure */ qs->use_cache = dmsg->use_cache; qs->nquerys = dmsg->qcnt; qs->reply = msg; copy_domain(&qs->dm, dm); /* * if the host name ends with a dot, we assume the user wants us to try it * as a complete host name. if not, then we first just add the dot to the * name and try that then we'll add elements of the search list if that * fails. */ strcpy(qs->domain, dmsg->hostname); if ( DOT == qs->domain[strlen(qs->domain)-1] ) { /* we've got a complete host name */ dprintf("%C trying the null domain\n"); qs->next_srch = -1; } else { strcat(qs->domain, SDOT); /* add the '.' */ qs->next_srch = 0; /* set index of the first search list to try */ } /* * okay now we have a host name to try. if the user wants to use the cache * we construct a question and submit it to the cache. the cache can return * CNAME and A type resource records (RR). it is possible to have the CNAME * but not the address for it, if that's the case we have to start the query * with the offical, that is the canonical (CNAME). we can tell if we have * both the CNAME and the address for it by the number of RRs. if the user * doesn't want to use the cache we skip this and just send off a query to * the first name server. */ if ( qs->use_cache ) { DnsQuestion question; /* cache requests are in the form of a DNS question */ DnsMsg dnsmsg; /* responses are returned in a DNS message */ strcpy(question.q_name, qs->domain); question.q_type = QT_A; question.q_class = QC_IN; memset(&dnsmsg, 0, sizeof(dnsmsg)); if ( query_cache(&question, &dnsmsg) == 0 ) { /* * first check for a name error, the cache will set the flags to * indicate a name error if we know the host name doesn't exist. * no need to clean up the DnsMsg if name error, only the flag is * set. */ if ((dnsmsg.m_dnshdr.flags & DNS_RCODE) == DNS_NAMEERR) { if ( qs->next_srch > -1 ) { /* * well, we know that this domain name doesn't exist, and we * haven't tried all the domains in the search list, so, set up * as if for another query, we may have to query a name sever. * * first get a list of name server addresses. */ if ((qs->num_ns = get_ns_list(qs->domain, qs->ns_addrs, dm)) == 0) { dprintf("%C No name servers to query\n"); dmsg->error = ENONSADDRESS; free_querystate(qs); sendreply(msg); DNSC_DEBUG("exit - no name server to query\n"); return; } /* now set up the rest of the query state */ qs->dns_construct = dns_std_query; qs->dns_response = dns_response_std_query; qs->dns_qreply = NULL; qs->ntrys = 0; qs->qtype = ac_type; qs->qstate = wf_caddr; return dns_start_next_search(qs); } dmsg->error = EHOSTNOTFOUND; free_querystate(qs); sendreply(msg); DNSC_DEBUG("exit - host not found\n"); return; } /* * if the anwser RR is a CNAME and there are no additional records * then we have to construct the DNS query for the new name. otherwise * format the answer and send it back. the cache places A records for * a CNAME in the additional section. */ if ( QT_CNAME == dnsmsg.m_answers->r_type && 0 == dnsmsg.m_dnshdr.naddrr ) { strcpy(qs->cname, qs->domain); strcpy(qs->domain, dnsmsg.m_answers->r_data); dnsmsg_cleanup(&dnsmsg); cflag = TRUE; } else { fmt_cache_answer(qs, &dnsmsg); free_querystate(qs); dnsmsg_cleanup(&dnsmsg); sendreply(msg); DNSC_DEBUG("exit - reply from cache\n"); return; } } } /* * first get a list of default name servers to try, then construct the DNS * request message, send the message and start listen to network. */ if ((qs->num_ns = get_ns_list(qs->domain, qs->ns_addrs, dm)) == 0) { dprintf("%C No name servers to query\n"); dmsg->error = ENONSADDRESS; free_querystate(qs); sendreply(msg); DNSC_DEBUG("exit - no name server to query\n"); return; }#ifdef DNS_DEBUG if ( dns_verbosity > 1 ) { int j; NS_t *ns; char ipstr[INET6_ADDRSTRLEN]; ns = qs->ns_addrs; for ( j = 0; j < qs->num_ns; j++ ) { ip_string(&ns[j].ns_addr, ipstr, sizeof(ipstr)); if ( ns[j].ns_name[0] != '\0' ) dprintf("NS_list[%d]: %s, address %s\n", j, ns[j].ns_name, ipstr); else dprintf("NS_list[%d] address: %s\n", j, ipstr); } }#endif qs->dns_construct = dns_std_query; qs->dns_response = dns_response_std_query; qs->dns_qreply = NULL; qs->ntrys = 0; if ( FALSE == cflag ) { qs->qtype = a_type; qs->qstate = wf_addr; } else { qs->qtype = ac_type; qs->qstate = wf_caddr; }#if defined (DNS_DEBUG) && defined (DNS_VERBOSE) dprintf("starting query for %s\n", qs->domain);#endif if ( dns_query(qs) < 0 ) { dmsg->error = ETRYAGAIN; free_querystate(qs); sendreply(msg); DNSC_DEBUG("exit - dns_query failed\n"); return; } DNSC_DEBUG("exit\n");} /* end dns_gethostbyname() *//* * dns_gethostbyaddr() * * this routine will set up a query state to handle a PTR request. this is the * case where we have an IP address and want the domain name associated with that * host. if the user wants we first query the cache and if found there return the * cached information. if not, or if not found in the cache, we set up for a query * to the DNS name servers. */voiddns_gethostbyaddr(ATMOS_MESSAGE *msg, DnsDomain *dm){ QueryState *query; MSG_D_DNS_GET_HOSTBYADDR(dmsg, msg); DNSC_DEBUG("entry\n"); if ((query = dns_get_querystate()) == NULL) { /* get a new query state structure */ dprintf("%C no free query states available\n");#ifdef DNS_DEBUG print_resource_pool();#endif dmsg->error = ENOMEM; sendreply(msg); return; } /* initialize the query state structure */ query->use_cache = dmsg->use_cache; query->nquerys = dmsg->qcnt; query->reply = msg; copy_domain(&query->dm, dm); reverse_ip_addr(dmsg->ipaddr, query->domain); /* if alright by the user we first see if the info is in the cache */ if ( query->use_cache ) { DnsQuestion question; /* the cache wants a DNS question */ DnsMsg dnsmsg; /* our representation of the DNS message */ /* construct question, then try the cache */ strcpy(question.q_name, query->domain); question.q_type = QT_PTR; question.q_class = QC_IN; /* the cache either has a RR for this IP address or it doesn't */ memset(&dnsmsg, 0, sizeof(dnsmsg)); if ( query_cache(&question, &dnsmsg) == 0 ) { /* see if the cache knows that this address doesn't exist. we * cache name error replies. no need to clean up the DnsMsg * if name error, only the flag is set. */ if ((dnsmsg.m_dnshdr.flags & DNS_RCODE) == DNS_NAMEERR) dmsg->error = EHOSTNOTFOUND; else { fmt_ptr_answer(query, &dnsmsg); dnsmsg_cleanup(&dnsmsg); } sendreply(msg); free_querystate(query); return; } } /* * either the user didn't want to use the cache or it wasn't there. first * we need to get a list of default name servers to try. this is done by * looking to the cache for name servers that would be good to try or just * using the default list. not having a list is considered a fatal error. */ if ((query->num_ns = get_ns_list(query->domain, query->ns_addrs, dm)) == 0) { dprintf("%C No name servers to query\n"); dmsg->error = ENONSADDRESS; free_querystate(query); sendreply(msg); return; }#ifdef DNS_DEBUG if ( dns_verbosity > 1 ) { int j; NS_t *ns; char ipstr[INET6_ADDRSTRLEN]; ns = query->ns_addrs; for ( j = 0; j < query->num_ns; j++ ) { ip_string(&ns[j].ns_addr, ipstr, sizeof(ipstr)); if ( ns[j].ns_name[0] != '\0' )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -