client.c

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

C
2,439
字号
	if (result == ISC_R_NOSPACE) {		client->message->flags |= DNS_MESSAGEFLAG_TC;		goto renderend;	}	if (result != ISC_R_SUCCESS)		goto done;	result = dns_message_rendersection(client->message,					   DNS_SECTION_ADDITIONAL,					   preferred_glue | dnssec_opts);	if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)		goto done; renderend:	result = dns_message_renderend(client->message);	if (result != ISC_R_SUCCESS)		goto done;	if (cleanup_cctx) {		dns_compress_invalidate(&cctx);		cleanup_cctx = ISC_FALSE;	}	if (TCP_CLIENT(client)) {		isc_buffer_usedregion(&buffer, &r);		isc_buffer_putuint16(&tcpbuffer, (isc_uint16_t) r.length);		isc_buffer_add(&tcpbuffer, r.length);		result = client_sendpkg(client, &tcpbuffer);	} else		result = client_sendpkg(client, &buffer);	if (result == ISC_R_SUCCESS)		return; done:	if (client->tcpbuf != NULL) {		isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE);		client->tcpbuf = NULL;	}	if (cleanup_cctx)		dns_compress_invalidate(&cctx);	ns_client_next(client, result);}#if NS_CLIENT_DROPPORT#define DROPPORT_NO		0#define DROPPORT_REQUEST	1#define DROPPORT_RESPONSE	2/*% * ns_client_dropport determines if certain requests / responses * should be dropped based on the port number. * * Returns: * \li	0:	Don't drop. * \li	1:	Drop request. * \li	2:	Drop (error) response. */static intns_client_dropport(in_port_t port) {	switch (port) {	case 7: /* echo */	case 13: /* daytime */	case 19: /* chargen */	case 37: /* time */		return (DROPPORT_REQUEST);	case 464: /* kpasswd */		return (DROPPORT_RESPONSE);	}	return (DROPPORT_NO);}#endifvoidns_client_error(ns_client_t *client, isc_result_t result) {	dns_rcode_t rcode;	dns_message_t *message;	REQUIRE(NS_CLIENT_VALID(client));	CTRACE("error");	message = client->message;	rcode = dns_result_torcode(result);#if NS_CLIENT_DROPPORT	/*	 * Don't send FORMERR to ports on the drop port list.	 */	if (rcode == dns_rcode_formerr &&	    ns_client_dropport(isc_sockaddr_getport(&client->peeraddr)) !=	    DROPPORT_NO) {		char buf[64];		isc_buffer_t b;		isc_buffer_init(&b, buf, sizeof(buf) - 1);		if (dns_rcode_totext(rcode, &b) != ISC_R_SUCCESS)			isc_buffer_putstr(&b, "UNKNOWN RCODE");		ns_client_log(client, DNS_LOGCATEGORY_SECURITY,			      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),			      "dropped error (%.*s) response: suspicious port",			      (int)isc_buffer_usedlength(&b), buf);		ns_client_next(client, ISC_R_SUCCESS);		return;	}#endif	/*	 * Message may be an in-progress reply that we had trouble	 * with, in which case QR will be set.  We need to clear QR before	 * calling dns_message_reply() to avoid triggering an assertion.	 */	message->flags &= ~DNS_MESSAGEFLAG_QR;	/*	 * AA and AD shouldn't be set.	 */	message->flags &= ~(DNS_MESSAGEFLAG_AA | DNS_MESSAGEFLAG_AD);	result = dns_message_reply(message, ISC_TRUE);	if (result != ISC_R_SUCCESS) {		/*		 * It could be that we've got a query with a good header,		 * but a bad question section, so we try again with		 * want_question_section set to ISC_FALSE.		 */		result = dns_message_reply(message, ISC_FALSE);		if (result != ISC_R_SUCCESS) {			ns_client_next(client, result);			return;		}	}	message->rcode = rcode;	/*	 * FORMERR loop avoidance:  If we sent a FORMERR message	 * with the same ID to the same client less than two	 * seconds ago, assume that we are in an infinite error 	 * packet dialog with a server for some protocol whose 	 * error responses look enough like DNS queries to	 * elicit a FORMERR response.  Drop a packet to break	 * the loop.	 */	if (rcode == dns_rcode_formerr) {		if (isc_sockaddr_equal(&client->peeraddr,				       &client->formerrcache.addr) &&		    message->id == client->formerrcache.id &&		    client->requesttime - client->formerrcache.time < 2) {			/* Drop packet. */			ns_client_log(client, NS_LOGCATEGORY_CLIENT,				      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),				      "possible error packet loop, "				      "FORMERR dropped");			ns_client_next(client, result);			return;		}		client->formerrcache.addr = client->peeraddr;		client->formerrcache.time = client->requesttime;		client->formerrcache.id = message->id;	}	ns_client_send(client);}static inline isc_result_tclient_addopt(ns_client_t *client) {	dns_rdataset_t *rdataset;	dns_rdatalist_t *rdatalist;	dns_rdata_t *rdata;	isc_result_t result;	dns_view_t *view;	dns_resolver_t *resolver;	isc_uint16_t udpsize;	REQUIRE(client->opt == NULL);	/* XXXRTH free old. */	rdatalist = NULL;	result = dns_message_gettemprdatalist(client->message, &rdatalist);	if (result != ISC_R_SUCCESS)		return (result);	rdata = NULL;	result = dns_message_gettemprdata(client->message, &rdata);	if (result != ISC_R_SUCCESS)		return (result);	rdataset = NULL;	result = dns_message_gettemprdataset(client->message, &rdataset);	if (result != ISC_R_SUCCESS)		return (result);	dns_rdataset_init(rdataset);	rdatalist->type = dns_rdatatype_opt;	rdatalist->covers = 0;	/*	 * Set the maximum UDP buffer size.	 */	view = client->view;	resolver = (view != NULL) ? view->resolver : NULL;	if (resolver != NULL)		udpsize = dns_resolver_getudpsize(resolver);	else		udpsize = ns_g_udpsize;	rdatalist->rdclass = udpsize;	/*	 * Set EXTENDED-RCODE, VERSION and Z to 0.	 */	rdatalist->ttl = (client->extflags & DNS_MESSAGEEXTFLAG_REPLYPRESERVE);	/*	 * No ENDS options in the default case.	 */	rdata->data = NULL;	rdata->length = 0;	rdata->rdclass = rdatalist->rdclass;	rdata->type = rdatalist->type;	rdata->flags = 0;	ISC_LIST_INIT(rdatalist->rdata);	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);	RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset)		      == ISC_R_SUCCESS);	client->opt = rdataset;	return (ISC_R_SUCCESS);}static inline isc_boolean_tallowed(isc_netaddr_t *addr, dns_name_t *signer, dns_acl_t *acl) {	int match;	isc_result_t result;	if (acl == NULL)		return (ISC_TRUE);	result = dns_acl_match(addr, signer, acl, &ns_g_server->aclenv,			       &match, NULL);	if (result == ISC_R_SUCCESS && match > 0)		return (ISC_TRUE);	return (ISC_FALSE);}/* * Callback to see if a non-recursive query coming from 'srcaddr' to * 'destaddr', with optional key 'mykey' for class 'rdclass' would be * delivered to 'myview'. * * We run this unlocked as both the view list and the interface list * are updated when the approprite task has exclusivity. */isc_boolean_tns_client_isself(dns_view_t *myview, dns_tsigkey_t *mykey,		 isc_sockaddr_t *srcaddr, isc_sockaddr_t *dstaddr,		 dns_rdataclass_t rdclass, void *arg){	dns_view_t *view;	dns_tsigkey_t *key;	isc_netaddr_t netsrc;	isc_netaddr_t netdst;	UNUSED(arg);	if (!ns_interfacemgr_listeningon(ns_g_server->interfacemgr, dstaddr))		return (ISC_FALSE);	isc_netaddr_fromsockaddr(&netsrc, srcaddr);	isc_netaddr_fromsockaddr(&netdst, dstaddr);	for (view = ISC_LIST_HEAD(ns_g_server->viewlist);	     view != NULL;	     view = ISC_LIST_NEXT(view, link)) {		dns_name_t *tsig = NULL;		if (view->matchrecursiveonly)			continue;		if (rdclass != view->rdclass)			continue;		if (mykey != NULL) {			isc_boolean_t match;			isc_result_t result;			tsig = &mykey->name;			result = dns_view_gettsig(view, tsig, &key);			if (result != ISC_R_SUCCESS)				continue;			match = dst_key_compare(mykey->key, key->key);			dns_tsigkey_detach(&key);			if (!match)				continue;		}		if (allowed(&netsrc, tsig, view->matchclients) &&		    allowed(&netdst, tsig, view->matchdestinations))			break;	}	return (ISC_TF(view == myview));}/* * Handle an incoming request event from the socket (UDP case) * or tcpmsg (TCP case). */static voidclient_request(isc_task_t *task, isc_event_t *event) {	ns_client_t *client;	isc_socketevent_t *sevent;	isc_result_t result;	isc_result_t sigresult = ISC_R_SUCCESS;	isc_buffer_t *buffer;	isc_buffer_t tbuffer;	dns_view_t *view;	dns_rdataset_t *opt;	isc_boolean_t ra; 	/* Recursion available. */	isc_netaddr_t netaddr;	isc_netaddr_t destaddr;	int match;	dns_messageid_t id;	unsigned int flags;	isc_boolean_t notimp;	REQUIRE(event != NULL);	client = event->ev_arg;	REQUIRE(NS_CLIENT_VALID(client));	REQUIRE(task == client->task);	INSIST(client->recursionquota == NULL);	INSIST(client->state ==	       TCP_CLIENT(client) ?	       NS_CLIENTSTATE_READING :	       NS_CLIENTSTATE_READY);	ns_client_requests++;	if (event->ev_type == ISC_SOCKEVENT_RECVDONE) {		INSIST(!TCP_CLIENT(client));		sevent = (isc_socketevent_t *)event;		REQUIRE(sevent == client->recvevent);		isc_buffer_init(&tbuffer, sevent->region.base, sevent->n);		isc_buffer_add(&tbuffer, sevent->n);		buffer = &tbuffer;		result = sevent->result;		if (result == ISC_R_SUCCESS) {			client->peeraddr = sevent->address;			client->peeraddr_valid = ISC_TRUE;		}		if ((sevent->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0) {			client->attributes |= NS_CLIENTATTR_PKTINFO;			client->pktinfo = sevent->pktinfo;		}		if ((sevent->attributes & ISC_SOCKEVENTATTR_MULTICAST) != 0)			client->attributes |= NS_CLIENTATTR_MULTICAST;		client->nrecvs--;	} else {		INSIST(TCP_CLIENT(client));		REQUIRE(event->ev_type == DNS_EVENT_TCPMSG);		REQUIRE(event->ev_sender == &client->tcpmsg);		buffer = &client->tcpmsg.buffer;		result = client->tcpmsg.result;		INSIST(client->nreads == 1);		/*		 * client->peeraddr was set when the connection was accepted.		 */		client->nreads--;	}	if (exit_check(client))		goto cleanup;	client->state = client->newstate = NS_CLIENTSTATE_WORKING;	isc_task_getcurrenttime(task, &client->requesttime);	client->now = client->requesttime;	if (result != ISC_R_SUCCESS) {		if (TCP_CLIENT(client)) {			ns_client_next(client, result);		} else {			if  (result != ISC_R_CANCELED)				isc_log_write(ns_g_lctx, NS_LOGCATEGORY_CLIENT,					      NS_LOGMODULE_CLIENT,					      ISC_LOG_ERROR,					      "UDP client handler shutting "					      "down due to fatal receive "					      "error: %s",					      isc_result_totext(result));			isc_task_shutdown(client->task);		}		goto cleanup;	}	isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);#if NS_CLIENT_DROPPORT	if (ns_client_dropport(isc_sockaddr_getport(&client->peeraddr)) ==	    DROPPORT_REQUEST) {		ns_client_log(client, DNS_LOGCATEGORY_SECURITY,			      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),			      "dropped request: suspicious port");		ns_client_next(client, ISC_R_SUCCESS);		goto cleanup;	}#endif	ns_client_log(client, NS_LOGCATEGORY_CLIENT,		      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),		      "%s request",		      TCP_CLIENT(client) ? "TCP" : "UDP");	/*	 * Check the blackhole ACL for UDP only, since TCP is done in	 * client_newconn.	 */	if (!TCP_CLIENT(client)) {		if (ns_g_server->blackholeacl != NULL &&		    dns_acl_match(&netaddr, NULL, ns_g_server->blackholeacl,				  &ns_g_server->aclenv,				  &match, NULL) == ISC_R_SUCCESS &&		    match > 0)		{			ns_client_log(client, DNS_LOGCATEGORY_SECURITY,				      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),				      "blackholed UDP datagram");			ns_client_next(client, ISC_R_SUCCESS);			goto cleanup;		}	}	/*	 * Silently drop multicast requests for the present.	 * XXXMPA look at when/if mDNS spec stabilizes.	 */	if ((client->attributes & NS_CLIENTATTR_MULTICAST) != 0) {		ns_client_log(client, NS_LOGCATEGORY_CLIENT,			      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),			      "dropping multicast request");		ns_client_next(client, DNS_R_REFUSED);		goto cleanup;	}	result = dns_message_peekheader(buffer, &id, &flags);	if (result != ISC_R_SUCCESS) {		/*		 * There isn't enough header to determine whether		 * this was a request or a response.  Drop it.		 */		ns_client_next(client, result);		goto cleanup;	}	/*	 * The client object handles requests, not responses.	 * If this is a UDP response, forward it to the dispatcher.	 * If it's a TCP response, discard it here.	 */	if ((flags & DNS_MESSAGEFLAG_QR) != 0) {		if (TCP_CLIENT(client)) {			CTRACE("unexpected response");			ns_client_next(client, DNS_R_FORMERR);			goto cleanup;		} else {			dns_dispatch_importrecv(client->dispatch, event);			ns_client_next(client, ISC_R_SUCCESS);			goto cleanup;		}	}	/*	 * It's a request.  Parse it.	 */	result = dns_message_parse(client->message, buffer, 0);	if (result != ISC_R_SUCCESS) {		/*		 * Parsing the request failed.  Send a response		 * (typically FORMERR or SERVFAIL).		 */		ns_client_error(client, result);		goto cleanup;	}	switch (client->message->opcode) {	case dns_opcode_query:	case dns_opcode_update:	case dns_opcode_notify:		notimp = ISC_FALSE;		break;	case dns_opcode_iquery:	default:		notimp = ISC_TRUE;		break;

⌨️ 快捷键说明

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