📄 dns_client_support.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_support.c * * description: most of the routines in this file support handling messages * received by the DNS client. *//* * List of New Routines: * dns_node_query_reply() * dns_addr6_query_reply() * dns_start_next_search_common() * dns_start_next_search6() * display_node_reply() */#include <errno.h>#include <netinet/in.h>#include <netdb.h>#include "messages.h"#include "dns_resolv.h"#include "dns_client.h"#include "dns_client_query.h"#include "dns_client_resource.h"#include "dns_client_cache.h"#include "dns_client_util6.h"#include "netlib.h"#include "dns_client_statics.h"static void display_host_reply(ATMOS_MESSAGE *);static void display_node_reply(ATMOS_MESSAGE *);static void terminate_query(QueryState *);#ifdef DNS_DEBUGvoid display_dnsmsghdr(U8 *pkt);#endif/* * dns_node_query_reply -- * This routine is called when we receive a host query reply. * This could be from one of our "internal" queries or, it could be the * results of an nslookup query. We first see if the message matches * an nslookup. If so we just hand it off. * Otherwise it must be an internal query. If it doesn't match any * current query we just free up the resources. If it does match we * call the reply routine for that query. * * PARAMETERS * rmsg - DNS_GET_NODEBYNAME message * * RETURNS * n/a */voiddns_node_query_reply(IN ATMOS_MESSAGE *rmsg){ QueryState *query; DNSC_DEBUG("entry\n"); if (dns_nslkup_locate(rmsg) == TRUE) { display_node_reply(rmsg); DNSC_DEBUG("exit - positive dns_nslkup_locate\n"); return; } if ((query = search_wait_list_reply(rmsg)) == NULL) { dprintf("%C no query state in list for DNS query reply (not an error)\n"); dns_hent_msg_free(rmsg); DNSC_DEBUG("exit - no query state in list for DNS query reply\n"); return; } if (query->dns_qreply != NULL) query->dns_qreply(query); else { dprintf("%C no internal query reply handle\n"); dns_hent_msg_free(rmsg); } DNSC_DEBUG("exit\n"); } /* end dns_node_query_reply() *//* * dns_addr6_query_reply -- * This routine is called when we receive a reply from a nslookup query * for a host name. Note in this case we know it is from nslookup * since all of the internal queries are for addresses. The address that * is printed out is the one the user entered on the command line. * * PARAMETERS * rmsg - DNS_GET_HOSTBYADDR6 message * * RETURNS * n/a */voiddns_addr6_query_reply(ATMOS_MESSAGE *rmsg){ struct hostent *hent; MSG_D_DNS_GET_HOSTBYADDR6(dmsg, rmsg); DNSC_DEBUG("entry\n"); if ( ESUCCESS == dmsg->error ) { char ipaddr[INET6_ADDRSTRLEN]; hent = dmsg->hent; if (hent->h_addr_list) { inet_ntop(AF_INET6, hent->h_addr_list[0], ipaddr, sizeof(ipaddr)); } else { strcpy(ipaddr,"<unknown>"); } printf("Name: %s\n", hent->h_name); printf("Address: %s\n", ipaddr); } else print_dns_error(dmsg->error); dns_nslkup_msg_free(rmsg); DNSC_DEBUG("exit\n");} /* end dns_addr_query_reply() *//* * dns_host_query_reply() * * this routine is called when we receive a host query reply. this could be from * one of our "internal" queries or, it could be the results of an nslookup query. * we first see if the message matches an nslookup. if so we just hand it off. * otherwise it must be an internal query. if it doesn't match any current query * we just free up the resources. if it does match we call the reply routine for * that query. */voiddns_host_query_reply(ATMOS_MESSAGE *rmsg){ QueryState *query; DNSC_DEBUG("entry\n"); if ( dns_nslkup_locate(rmsg) == TRUE ) { display_host_reply(rmsg); DNSC_DEBUG("exit - positive dns_nslkup_locate\n"); return; } if ((query = search_wait_list_reply(rmsg)) == NULL) { dprintf("%C no query state in list for DNS query reply (not an error)\n"); dns_hent_msg_free(rmsg); DNSC_DEBUG("exit - no query state in list for DNS query reply\n"); return; } if ( query->dns_qreply != NULL ) query->dns_qreply(query); else { dprintf("%C no internal query reply handle\n"); dns_hent_msg_free(rmsg); } DNSC_DEBUG("exit\n"); } /* end dns_host_query_reply() *//* * dns_addr_query_reply() * * this routine is called when we receive a reply from a nslookup query for a * host name. note in this case we know it is from nslookup since all of the * internal queries are for addresses. the address that is printed out is the * one the user entered on the command line. */voiddns_addr_query_reply(ATMOS_MESSAGE *rmsg){ struct dns_hostent *hptr; MSG_D_DNS_GET_HOSTBYADDR(dmsg, rmsg); DNSC_DEBUG("entry\n"); if ( ESUCCESS == dmsg->error ) { char ipaddr[INET6_ADDRSTRLEN]; hptr = dmsg->hptr; inet_ntop(AF_INET, hptr->h_addr_list + 0, ipaddr, sizeof(ipaddr)); printf("Name: %s\n", hptr->h_name); printf("Address: %s\n", ipaddr); } else print_dns_error(dmsg->error); dns_nslkup_msg_free(rmsg); DNSC_DEBUG("exit\n");} /* end dns_addr_query_reply() *//* * dns_udp_message() * * this routine handles the case when we get a UDP message. we expect the * message is a reply to one of our query requests. we get the message and * use the message id to determine which query it matches to. if no query is * found we assume that query has already been handled and just exit. if one * is found we hand the message to it for handling. Note that if the parse * attempt fails we treat the case the same as if the message had timed out. */voiddns_udp_message(U8 *dnsmsg, int nbytes){ int msgid; QueryState *query; DNSC_DEBUG("entry\n"); /* next get the DNS message id. then use it to see if there's a QueryState * that's waiting for the message. if not we're done. if so go ahead and * parse the message. */ msgid = ntohs(((DnsHdr *)dnsmsg)->id); if ((query = search_wait_list_id((U16 )msgid)) == NULL) {#if defined(DNS_DEBUG) && defined(DNS_VERBOSE) dprintf("%C no query for DNS message id %d (this is not an error)\n", msgid);#endif DNSC_DEBUG("exit - no query for DNS message id %d\n", msgid); return; }#if defined(DNS_DEBUG) /* Copy address of server */ memcpy(&query->svripaddr, dns_client_udp_get_sourceaddr(), sizeof(query->svripaddr));#endif #if defined(DNS_DEBUG) && defined(DNS_VERBOSE) dprintf("%C dns_udp_message: got a query:\n"); dns_print_query(query);#endif if ( parse_dns_message(dnsmsg, nbytes, &query->dnsreply) < 0 ) { dprintf("%C error attempting to parse the DNS response\n"); /* since the message did match a QueryState assume it was intended as * a reply. handle it as if we had timed out waiting for a message. */ dns_response_timeout(query); DNSC_DEBUG("exit - parse_dns_message failed\n"); return; } DNSC_DEBUG("call dns_response method 0x%08x\n", query->dns_response); query->dns_response(query); /* dns_response will clean up the parsed message */ DNSC_DEBUG("exit - dns_response method finished\n");} /* end dns_udp_message() */ /* * dns_response_timeout() * * got a time out. this could be for a "main" query or a "support" query. a support * query is one that was started to deal with something from another query. an * example is when a name server response suggests another nameserver to try but * we don't have the new name server address. to get it we start another query, this * new query is a support query. (NOTE: in other places I call the support query * an internal query) * * first we check to verify we haven't already exceeded any limits before trying * to do anything else. if we have we terminate the query. next we determine the * next name server to try. if we've tried all the name servers in our list the * max number of times the query is considered done. we then check to see if we * need to try another element of the search list. this would be the case when the * user wanted the IP address of a relative host name. */voiddns_response_timeout(QueryState *query){ int i; DNSC_DEBUG("entry\n"); /* * first, verify that we haven't exceeded any limits we have on the number * of DNS requests we've made for this query or the number of query depths, * which is where we have to post a different DNS query to support this one. */ if ( query->ntrys > MAXDNSTRYS || query->nquerys > MAXQUERYDEPTH ) { dprintf("%C DNS query max exceeded\n"); dprintf("max trys allowed %d, attempted %d\n", MAXDNSTRYS, query->ntrys); dprintf("max queries allowed %d attempted %d\n", MAXQUERYDEPTH, query->nquerys); terminate_query(query); DNSC_DEBUG("finished - query terminated - too many\n"); return; } /* * okay, now see if there's another name server to try. it would seem simplier * to just keep the index of the next name server to try but that won't work * because we can get a DNS response that suggests different name servers to * try. it can be more than one and what we do with the list is to replace * name servers in our list that shouldn't be as good as the suggested ones. * so the list can be mixed with servers that have been tried already and some * that haven't been tried at all. so first we loop through to find one that * hasn't been used at all, and if there aren't any we just get one that hasn't * been tried too many times. also, since RES_RETRY typically is 2, so we won't * likely be using the same name server twice in a row. */ for ( i = 0; i < query->num_ns; i++ ) { if ( 0 == query->ns_addrs[i].ns_try ) { if ( post_query(query, i) < 0 ) {#ifdef DNS_DEBUG char strip[INET6_ADDRSTRLEN]; ip_string(&query->ns_addrs[i].ns_addr, strip, sizeof(strip)); dprintf("%C error sending DNS request to %s\n", strip);#endif terminate_query(query); /* there's an error sending message quit */ DNSC_DEBUG("finished - query terminated - post #0 error\n"); return; } else {#ifdef DNS_DEBUG char str[INET6_ADDRSTRLEN]; ip_string(&query->ns_addrs[i].ns_addr, str, sizeof(str)); dprintf("%C trying name server %s\n", str); dprintf("for query %s\n\n", query->domain);#endif DNSC_DEBUG("finished - try the first time\n"); return; } } } for ( i = 0; i < query->num_ns; i++ ) { if ( query->ns_addrs[i].ns_try < RES_RETRY ) { if ( post_query(query, i) < 0 ) {#ifdef DNS_DEBUG char str2[INET6_ADDRSTRLEN]; ip_string(&query->ns_addrs[i].ns_addr, str2, sizeof(str2)); dprintf("%C error sending DNS request to %s\n", str2);#endif terminate_query(query); /* end the query if UDP error */ DNSC_DEBUG("finished - query terminated - post #%d error\n", query->ns_addrs[i].ns_try); return; } else {#ifdef DNS_DEBUG char str3[INET6_ADDRSTRLEN]; ip_string(&query->ns_addrs[i].ns_addr, str3, sizeof(str3)); dprintf("%C trying name server %s\n", str3); dprintf("this is the %d try for this server\n", query->ns_addrs[i].ns_try); dprintf("for query %s\n\n", query->domain);#endif DNSC_DEBUG("finished - try once more\n"); return; } } } /* * if we get here, we've run out of name servers to try. we see if we need * to try another search list element. note if we terminate the query we do * it with a try again error, see RFC 1035, since we didn't get any other * error type from a name server or we wouldn't have gotten here. */ if ( query->next_srch < 0 ) /* no need to try search list */ { terminate_query(query); /* let the caller know we didn't find anything */ DNSC_DEBUG("finished - query terminated - no next search\n"); } else { dns_start_next_search_common(query); /* try the next search list */ DNSC_DEBUG("finished - start next search\n"); }} /* end dns_response_timeout() *//* * dns_start_next_search_common -- * This routine starts either 'dns_start_next_search()' or * 'dns_start_next_search6()' depending on the family. We guess the * family to be AF_INET6 for aaaa_type and a6_type queries. * * PARAMETERS * query - query state structure * * RETURNS * n/a */voiddns_start_next_search_common(QueryState *query){ DNSC_DEBUG("entry\n"); if (query->qtype == a6_type || query->qtype == aaaa_type) dns_start_next_search6(query); else dns_start_next_search(query); DNSC_DEBUG("exit\n");}/* dns_start_next_search6 -- * This routine sets up for the next attempt using a constructed name * from search list. * * PARAMETERS * query - query state structure * * RETURNS * n/a */voiddns_start_next_search6(QueryState *query){ int i; MSG_D_DNS_GET_NODEBYNAME(dmsg, query->reply); DNSC_DEBUG("entry\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -