dighost.c

来自「非常好的dns解析软件」· C语言 代码 · 共 2,368 行 · 第 1/5 页

C
2,368
字号
	}	dns_name_format(lookup->name, store, sizeof(store));	trying(store, lookup);	INSIST(dns_name_isabsolute(lookup->name));	isc_random_get(&id);	lookup->sendmsg->id = (unsigned short)id & 0xFFFF;	lookup->sendmsg->opcode = dns_opcode_query;	lookup->msgcounter = 0;	/*	 * If this is a trace request, completely disallow recursion, since	 * it's meaningless for traces.	 */	if (lookup->trace || (lookup->ns_search_only && !lookup->trace_root))		lookup->recurse = ISC_FALSE;	if (lookup->recurse &&	    lookup->rdtype != dns_rdatatype_axfr &&	    lookup->rdtype != dns_rdatatype_ixfr) {		debug("recursive query");		lookup->sendmsg->flags |= DNS_MESSAGEFLAG_RD;	}	/* XXX aaflag */	if (lookup->aaonly) {		debug("AA query");		lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AA;	}	if (lookup->adflag) {		debug("AD query");		lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AD;	}	if (lookup->cdflag) {		debug("CD query");		lookup->sendmsg->flags |= DNS_MESSAGEFLAG_CD;	}	dns_message_addname(lookup->sendmsg, lookup->name,			    DNS_SECTION_QUESTION);	if (lookup->trace && lookup->trace_root) {		lookup->qrdtype = lookup->rdtype;		lookup->rdtype = dns_rdatatype_ns;	}	if ((lookup->rdtype == dns_rdatatype_axfr) ||	    (lookup->rdtype == dns_rdatatype_ixfr)) {		lookup->doing_xfr = ISC_TRUE;		/*		 * Force TCP mode if we're doing an xfr.		 * XXX UDP ixfr's would be useful		 */		lookup->tcp_mode = ISC_TRUE;	}	add_question(lookup->sendmsg, lookup->name, lookup->rdclass,		     lookup->rdtype);	/* add_soa */	if (lookup->rdtype == dns_rdatatype_ixfr)		insert_soa(lookup);	/* XXX Insist this? */	lookup->tsigctx = NULL;	lookup->querysig = NULL;	if (key != NULL) {		debug("initializing keys");		result = dns_message_settsigkey(lookup->sendmsg, key);		check_result(result, "dns_message_settsigkey");	}	lookup->sendspace = isc_mempool_get(commctx);	if (lookup->sendspace == NULL)		fatal("memory allocation failure");	result = dns_compress_init(&cctx, -1, mctx);	check_result(result, "dns_compress_init");	debug("starting to render the message");	isc_buffer_init(&lookup->renderbuf, lookup->sendspace, COMMSIZE);	result = dns_message_renderbegin(lookup->sendmsg, &cctx,					 &lookup->renderbuf);	check_result(result, "dns_message_renderbegin");	if (lookup->udpsize > 0 || lookup->dnssec || lookup->edns > -1) {		if (lookup->udpsize == 0)			lookup->udpsize = 4096;		if (lookup->edns < 0)			lookup->edns = 0;		add_opt(lookup->sendmsg, lookup->udpsize,			lookup->edns, lookup->dnssec);	}	result = dns_message_rendersection(lookup->sendmsg,					   DNS_SECTION_QUESTION, 0);	check_result(result, "dns_message_rendersection");	result = dns_message_rendersection(lookup->sendmsg,					   DNS_SECTION_AUTHORITY, 0);	check_result(result, "dns_message_rendersection");	result = dns_message_renderend(lookup->sendmsg);	check_result(result, "dns_message_renderend");	debug("done rendering");	dns_compress_invalidate(&cctx);	/*	 * Force TCP mode if the request is larger than 512 bytes.	 */	if (isc_buffer_usedlength(&lookup->renderbuf) > 512)		lookup->tcp_mode = ISC_TRUE;	lookup->pending = ISC_FALSE;	for (serv = ISC_LIST_HEAD(lookup->my_server_list);	     serv != NULL;	     serv = ISC_LIST_NEXT(serv, link)) {		query = isc_mem_allocate(mctx, sizeof(dig_query_t));		if (query == NULL)			fatal("memory allocation failure in %s:%d",			      __FILE__, __LINE__);		debug("create query %p linked to lookup %p",		       query, lookup);		query->lookup = lookup;		query->waiting_connect = ISC_FALSE;		query->waiting_senddone = ISC_FALSE;		query->pending_free = ISC_FALSE;		query->recv_made = ISC_FALSE;		query->first_pass = ISC_TRUE;		query->first_soa_rcvd = ISC_FALSE;		query->second_rr_rcvd = ISC_FALSE;		query->first_repeat_rcvd = ISC_FALSE;		query->warn_id = ISC_TRUE;		query->first_rr_serial = 0;		query->second_rr_serial = 0;		query->servname = serv->servername;		query->userarg = serv->userarg;		query->rr_count = 0;		query->msg_count = 0;		query->byte_count = 0;		ISC_LINK_INIT(query, link);		ISC_LIST_INIT(query->recvlist);		ISC_LIST_INIT(query->lengthlist);		query->sock = NULL;		query->recvspace = isc_mempool_get(commctx);		if (query->recvspace == NULL)			fatal("memory allocation failure");		isc_buffer_init(&query->recvbuf, query->recvspace, COMMSIZE);		isc_buffer_init(&query->lengthbuf, query->lengthspace, 2);		isc_buffer_init(&query->slbuf, query->slspace, 2);		query->sendbuf = lookup->renderbuf;		ISC_LINK_INIT(query, link);		ISC_LIST_ENQUEUE(lookup->q, query, link);	}	/* XXX qrflag, print_query, etc... */	if (!ISC_LIST_EMPTY(lookup->q) && qr) {		extrabytes = 0;		printmessage(ISC_LIST_HEAD(lookup->q), lookup->sendmsg,			     ISC_TRUE);	}}/*% * Event handler for send completion.  Track send counter, and clear out * the query if the send was canceled. */static voidsend_done(isc_task_t *_task, isc_event_t *event) {	isc_socketevent_t *sevent = (isc_socketevent_t *)event;	isc_buffer_t *b = NULL;	dig_query_t *query, *next;	dig_lookup_t *l;	REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);	UNUSED(_task);	LOCK_LOOKUP;	debug("send_done()");	sendcount--;	debug("sendcount=%d", sendcount);	INSIST(sendcount >= 0);	for  (b = ISC_LIST_HEAD(sevent->bufferlist);	      b != NULL;	      b = ISC_LIST_HEAD(sevent->bufferlist)) 		ISC_LIST_DEQUEUE(sevent->bufferlist, b, link);	query = event->ev_arg;	query->waiting_senddone = ISC_FALSE;	l = query->lookup;	if (l->ns_search_only && !l->trace_root) {		debug("sending next, since searching");		next = ISC_LIST_NEXT(query, link);		if (next != NULL)			send_udp(next);	}	isc_event_free(&event);	if (query->pending_free)		isc_mem_free(mctx, query);	check_if_done();	UNLOCK_LOOKUP;}/*% * Cancel a lookup, sending isc_socket_cancel() requests to all outstanding * IO sockets.  The cancel handlers should take care of cleaning up the * query and lookup structures */static voidcancel_lookup(dig_lookup_t *lookup) {	dig_query_t *query, *next;	debug("cancel_lookup()");	query = ISC_LIST_HEAD(lookup->q);	while (query != NULL) {		next = ISC_LIST_NEXT(query, link);		if (query->sock != NULL) {			isc_socket_cancel(query->sock, global_task,					  ISC_SOCKCANCEL_ALL);			check_if_done();		} else {			clear_query(query);		}		query = next;	}	if (lookup->timer != NULL)		isc_timer_detach(&lookup->timer);	lookup->pending = ISC_FALSE;	lookup->retries = 0;}static voidbringup_timer(dig_query_t *query, unsigned int default_timeout) {	dig_lookup_t *l;	unsigned int local_timeout;	isc_result_t result;	debug("bringup_timer()");	/*	 * If the timer already exists, that means we're calling this	 * a second time (for a retry).  Don't need to recreate it,	 * just reset it.	 */	l = query->lookup;	if (ISC_LIST_NEXT(query, link) != NULL)		local_timeout = SERVER_TIMEOUT;	else {		if (timeout == 0)			local_timeout = default_timeout;		else			local_timeout = timeout;	}	debug("have local timeout of %d", local_timeout);	isc_interval_set(&l->interval, local_timeout, 0);	if (l->timer != NULL)		isc_timer_detach(&l->timer);	result = isc_timer_create(timermgr, isc_timertype_once, NULL,				  &l->interval, global_task, connect_timeout,				  l, &l->timer);	check_result(result, "isc_timer_create");}	static voidconnect_done(isc_task_t *task, isc_event_t *event);/*% * Unlike send_udp, this can't be called multiple times with the same * query.  When we retry TCP, we requeue the whole lookup, which should * start anew. */static voidsend_tcp_connect(dig_query_t *query) {	isc_result_t result;	dig_query_t *next;	dig_lookup_t *l;	debug("send_tcp_connect(%p)", query);	l = query->lookup;	query->waiting_connect = ISC_TRUE;	query->lookup->current_query = query;	get_address(query->servname, port, &query->sockaddr);		if (specified_source &&	    (isc_sockaddr_pf(&query->sockaddr) !=	     isc_sockaddr_pf(&bind_address))) {		printf(";; Skipping server %s, incompatible "		       "address family\n", query->servname);		query->waiting_connect = ISC_FALSE;		next = ISC_LIST_NEXT(query, link);		l = query->lookup;		clear_query(query);		if (next == NULL) {			printf(";; No acceptable nameservers\n");			check_next_lookup(l);			return;		}		send_tcp_connect(next);		return;	}	INSIST(query->sock == NULL);	result = isc_socket_create(socketmgr,				   isc_sockaddr_pf(&query->sockaddr),				   isc_sockettype_tcp, &query->sock);	check_result(result, "isc_socket_create");	sockcount++;	debug("sockcount=%d", sockcount);	if (specified_source)		result = isc_socket_bind(query->sock, &bind_address);	else {		if ((isc_sockaddr_pf(&query->sockaddr) == AF_INET) &&		    have_ipv4)			isc_sockaddr_any(&bind_any);		else			isc_sockaddr_any6(&bind_any);		result = isc_socket_bind(query->sock, &bind_any);	}	check_result(result, "isc_socket_bind");	bringup_timer(query, TCP_TIMEOUT);	result = isc_socket_connect(query->sock, &query->sockaddr,				    global_task, connect_done, query);	check_result(result, "isc_socket_connect");	/*	 * If we're at the endgame of a nameserver search, we need to	 * immediately bring up all the queries.  Do it here.	 */	if (l->ns_search_only && !l->trace_root) {		debug("sending next, since searching");		next = ISC_LIST_NEXT(query, link);		if (next != NULL)			send_tcp_connect(next);	}}/*% * Send a UDP packet to the remote nameserver, possible starting the * recv action as well.  Also make sure that the timer is running and * is properly reset. */static voidsend_udp(dig_query_t *query) {	dig_lookup_t *l = NULL;	isc_result_t result;	debug("send_udp(%p)", query);	l = query->lookup;	bringup_timer(query, UDP_TIMEOUT);	l->current_query = query;	debug("working on lookup %p, query %p", query->lookup, query);	if (!query->recv_made) {		/* XXX Check the sense of this, need assertion? */		query->waiting_connect = ISC_FALSE;		get_address(query->servname, port, &query->sockaddr);		result = isc_socket_create(socketmgr,					   isc_sockaddr_pf(&query->sockaddr),					   isc_sockettype_udp, &query->sock);		check_result(result, "isc_socket_create");		sockcount++;		debug("sockcount=%d", sockcount);		if (specified_source) {			result = isc_socket_bind(query->sock, &bind_address);		} else {			isc_sockaddr_anyofpf(&bind_any,					isc_sockaddr_pf(&query->sockaddr));			result = isc_socket_bind(query->sock, &bind_any);		}		check_result(result, "isc_socket_bind");		query->recv_made = ISC_TRUE;		ISC_LINK_INIT(&query->recvbuf, link);		ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf,				 link);		debug("recving with lookup=%p, query=%p, sock=%p",		      query->lookup, query, query->sock);		result = isc_socket_recvv(query->sock, &query->recvlist, 1,					  global_task, recv_done, query);		check_result(result, "isc_socket_recvv");		recvcount++;		debug("recvcount=%d", recvcount);	}	ISC_LIST_INIT(query->sendlist);	ISC_LIST_ENQUEUE(query->sendlist, &query->sendbuf, link);	debug("sending a request");	TIME_NOW(&query->time_sent);	INSIST(query->sock != NULL);	query->waiting_senddone = ISC_TRUE;	result = isc_socket_sendtov(query->sock, &query->sendlist,				    global_task, send_done, query,				    &query->sockaddr, NULL);	check_result(result, "isc_socket_sendtov");	sendcount++;}/*% * IO timeout handler, used for both connect and recv timeouts.  If * retries are still allowed, either resend the UDP packet or queue a * new TCP lookup.  Otherwise, cancel the lookup. */static voidconnect_timeout(isc_task_t *task, isc_event_t *event) {	dig_lookup_t *l = NULL;	dig_query_t *query = NULL, *cq;	UNUSED(task);	REQUIRE(event->ev_type == ISC_TIMEREVENT_IDLE);	debug("connect_timeout()");	LOCK_LOOKUP;	l = event->ev_arg;	query = l->current_query;	isc_event_free(&event);	INSIST(!free_now);	if ((query != NULL) && (query->lookup->current_query != NULL) &&	    (ISC_LIST_NEXT(query->lookup->current_query, link) != NULL)) {		debug("trying next server...");		cq = query->lookup->current_query;		if (!l->tcp_mode)			send_udp(ISC_LIST_NEXT(cq, link));		else			send_tcp_connect(ISC_LIST_NEXT(cq, link));		UNLOCK_LOOKUP;		return;	}	if (l->retries > 1) {		if (!l->tcp_mode) {			l->retries--;			debug("resending UDP request to first server");			send_udp(ISC_LIST_HEAD(l->q));		} else {			debug("making new TCP request, %d tries left",			      l->retries);			l->retries--;			requeue_lookup(l, ISC_TRUE);			cancel_lookup(l);			check_next_lookup(l);		}	} else {		fputs(l->cmdline, stdout);		printf(";; connection timed out; no servers could be "		       "reached\n");		cancel_lookup(l);		check_next_lookup(l);		if (exitcode < 9)			exitcode = 9;	}	UNLOCK_LOOKUP;}/*% * Event handler for the TCP recv which gets the length header of TCP * packets.  Start the next recv of length bytes. */static voidtcp_length_done(isc_task_t *task, isc_event_t *event) {	isc_socketevent_t *sevent;	isc_buffer_t *b = NULL;	isc_result_t result;	dig_query_t *que

⌨️ 快捷键说明

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