📄 client.c
字号:
} unlock: if (locked_manager != NULL) { UNLOCK(&locked_manager->lock); locked_manager = NULL; } /* * Only now is it safe to destroy the client manager (if needed), * because we have accessed its lock for the last time. */ if (destroy_manager != NULL) clientmgr_destroy(destroy_manager); return (ISC_TRUE);}/* * The client's task has received the client's control event * as part of the startup process. */static voidclient_start(isc_task_t *task, isc_event_t *event) { ns_client_t *client = (ns_client_t *) event->ev_arg; INSIST(task == client->task); UNUSED(task); INSIST(client->nctls == 1); client->nctls--; if (exit_check(client)) return; if (TCP_CLIENT(client)) { client_accept(client); } else { client_udprecv(client); }}/* * The client's task has received a shutdown event. */static voidclient_shutdown(isc_task_t *task, isc_event_t *event) { ns_client_t *client; REQUIRE(event != NULL); REQUIRE(event->ev_type == ISC_TASKEVENT_SHUTDOWN); client = event->ev_arg; REQUIRE(NS_CLIENT_VALID(client)); REQUIRE(task == client->task); UNUSED(task); CTRACE("shutdown"); isc_event_free(&event); if (client->shutdown != NULL) { (client->shutdown)(client->shutdown_arg, ISC_R_SHUTTINGDOWN); client->shutdown = NULL; client->shutdown_arg = NULL; } client->newstate = NS_CLIENTSTATE_FREED; (void)exit_check(client);}static voidns_client_endrequest(ns_client_t *client) { INSIST(client->naccepts == 0); INSIST(client->nreads == 0); INSIST(client->nsends == 0); INSIST(client->nrecvs == 0); INSIST(client->nupdates == 0); INSIST(client->state == NS_CLIENTSTATE_WORKING); CTRACE("endrequest"); if (client->next != NULL) { (client->next)(client); client->next = NULL; } if (client->view != NULL) dns_view_detach(&client->view); if (client->opt != NULL) { INSIST(dns_rdataset_isassociated(client->opt)); dns_rdataset_disassociate(client->opt); dns_message_puttemprdataset(client->message, &client->opt); } client->udpsize = 512; client->extflags = 0; dns_message_reset(client->message, DNS_MESSAGE_INTENTPARSE); if (client->recursionquota != NULL) isc_quota_detach(&client->recursionquota); /* * Clear all client attributes that are specific to * the request; that's all except the TCP flag. */ client->attributes &= NS_CLIENTATTR_TCP;}static voidns_client_checkactive(ns_client_t *client) { if (client->mortal) { /* * This client object should normally go inactive * at this point, but if we have fewer active client * objects than desired due to earlier quota exhaustion, * keep it active to make up for the shortage. */ isc_boolean_t need_another_client = ISC_FALSE; if (TCP_CLIENT(client)) { LOCK(&client->interface->lock); if (client->interface->ntcpcurrent < client->interface->ntcptarget) need_another_client = ISC_TRUE; UNLOCK(&client->interface->lock); } else { /* * The UDP client quota is enforced by making * requests fail rather than by not listening * for new ones. Therefore, there is always a * full set of UDP clients listening. */ } if (! need_another_client) { /* * We don't need this client object. Recycle it. */ if (client->newstate >= NS_CLIENTSTATE_INACTIVE) client->newstate = NS_CLIENTSTATE_INACTIVE; } }}voidns_client_next(ns_client_t *client, isc_result_t result) { int newstate; REQUIRE(NS_CLIENT_VALID(client)); REQUIRE(client->state == NS_CLIENTSTATE_WORKING || client->state == NS_CLIENTSTATE_READING); CTRACE("next"); if (result != ISC_R_SUCCESS) ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), "request failed: %s", isc_result_totext(result)); /* * An error processing a TCP request may have left * the connection out of sync. To be safe, we always * sever the connection when result != ISC_R_SUCCESS. */ if (result == ISC_R_SUCCESS && TCP_CLIENT(client)) newstate = NS_CLIENTSTATE_READING; else newstate = NS_CLIENTSTATE_READY; if (client->newstate > newstate) client->newstate = newstate; (void)exit_check(client);}static voidclient_senddone(isc_task_t *task, isc_event_t *event) { ns_client_t *client; isc_socketevent_t *sevent = (isc_socketevent_t *) event; REQUIRE(sevent != NULL); REQUIRE(sevent->ev_type == ISC_SOCKEVENT_SENDDONE); client = sevent->ev_arg; REQUIRE(NS_CLIENT_VALID(client)); REQUIRE(task == client->task); REQUIRE(sevent == client->sendevent); UNUSED(task); CTRACE("senddone"); if (sevent->result != ISC_R_SUCCESS) ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT, ISC_LOG_WARNING, "error sending response: %s", isc_result_totext(sevent->result)); INSIST(client->nsends > 0); client->nsends--; if (client->tcpbuf != NULL) { INSIST(TCP_CLIENT(client)); isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE); client->tcpbuf = NULL; } if (exit_check(client)) return; ns_client_next(client, ISC_R_SUCCESS);}/* * We only want to fail with ISC_R_NOSPACE when called from * ns_client_sendraw() and not when called from ns_client_send(), * tcpbuffer is NULL when called from ns_client_sendraw() and * length != 0. tcpbuffer != NULL when called from ns_client_send() * and length == 0. */static isc_result_tclient_allocsendbuf(ns_client_t *client, isc_buffer_t *buffer, isc_buffer_t *tcpbuffer, isc_uint32_t length, unsigned char *sendbuf, unsigned char **datap){ unsigned char *data; isc_uint32_t bufsize; isc_result_t result; INSIST(datap != NULL); INSIST((tcpbuffer == NULL && length != 0) || (tcpbuffer != NULL && length == 0)); if (TCP_CLIENT(client)) { INSIST(client->tcpbuf == NULL); if (length + 2 > TCP_BUFFER_SIZE) { result = ISC_R_NOSPACE; goto done; } client->tcpbuf = isc_mem_get(client->mctx, TCP_BUFFER_SIZE); if (client->tcpbuf == NULL) { result = ISC_R_NOMEMORY; goto done; } data = client->tcpbuf; if (tcpbuffer != NULL) { isc_buffer_init(tcpbuffer, data, TCP_BUFFER_SIZE); isc_buffer_init(buffer, data + 2, TCP_BUFFER_SIZE - 2); } else { isc_buffer_init(buffer, data, TCP_BUFFER_SIZE); INSIST(length <= 0xffff); isc_buffer_putuint16(buffer, (isc_uint16_t)length); } } else { data = sendbuf; if (client->udpsize < SEND_BUFFER_SIZE) bufsize = client->udpsize; else bufsize = SEND_BUFFER_SIZE; if (length > bufsize) { result = ISC_R_NOSPACE; goto done; } isc_buffer_init(buffer, data, bufsize); } *datap = data; result = ISC_R_SUCCESS; done: return (result);}static isc_result_tclient_sendpkg(ns_client_t *client, isc_buffer_t *buffer) { struct in6_pktinfo *pktinfo; isc_result_t result; isc_region_t r; isc_sockaddr_t *address; isc_socket_t *socket; isc_netaddr_t netaddr; int match; unsigned int sockflags = ISC_SOCKFLAG_IMMEDIATE; if (TCP_CLIENT(client)) { socket = client->tcpsocket; address = NULL; } else { socket = client->udpsocket; address = &client->peeraddr; isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); 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) return (DNS_R_BLACKHOLED); sockflags |= ISC_SOCKFLAG_NORETRY; } if ((client->attributes & NS_CLIENTATTR_PKTINFO) != 0 && (client->attributes & NS_CLIENTATTR_MULTICAST) == 0) pktinfo = &client->pktinfo; else pktinfo = NULL; isc_buffer_usedregion(buffer, &r); CTRACE("sendto"); result = isc_socket_sendto2(socket, &r, client->task, address, pktinfo, client->sendevent, sockflags); if (result == ISC_R_SUCCESS || result == ISC_R_INPROGRESS) { client->nsends++; if (result == ISC_R_SUCCESS) client_senddone(client->task, (isc_event_t *)client->sendevent); result = ISC_R_SUCCESS; } return (result);}voidns_client_sendraw(ns_client_t *client, dns_message_t *message) { isc_result_t result; unsigned char *data; isc_buffer_t buffer; isc_region_t r; isc_region_t *mr; unsigned char sendbuf[SEND_BUFFER_SIZE]; REQUIRE(NS_CLIENT_VALID(client)); CTRACE("sendraw"); mr = dns_message_getrawmessage(message); if (mr == NULL) { result = ISC_R_UNEXPECTEDEND; goto done; } result = client_allocsendbuf(client, &buffer, NULL, mr->length, sendbuf, &data); if (result != ISC_R_SUCCESS) goto done; /* * Copy message to buffer and fixup id. */ isc_buffer_availableregion(&buffer, &r); result = isc_buffer_copyregion(&buffer, mr); if (result != ISC_R_SUCCESS) goto done; r.base[0] = (client->message->id >> 8) & 0xff; r.base[1] = client->message->id & 0xff; 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; } ns_client_next(client, result);}voidns_client_send(ns_client_t *client) { isc_result_t result; unsigned char *data; isc_buffer_t buffer; isc_buffer_t tcpbuffer; isc_region_t r; dns_compress_t cctx; isc_boolean_t cleanup_cctx = ISC_FALSE; unsigned char sendbuf[SEND_BUFFER_SIZE]; unsigned int dnssec_opts; unsigned int preferred_glue; REQUIRE(NS_CLIENT_VALID(client)); CTRACE("send"); if ((client->attributes & NS_CLIENTATTR_RA) != 0) client->message->flags |= DNS_MESSAGEFLAG_RA; if ((client->attributes & NS_CLIENTATTR_WANTDNSSEC) != 0) dnssec_opts = 0; else dnssec_opts = DNS_MESSAGERENDER_OMITDNSSEC; preferred_glue = 0; if (client->view != NULL) { if (client->view->preferred_glue == dns_rdatatype_a) preferred_glue = DNS_MESSAGERENDER_PREFER_A; else if (client->view->preferred_glue == dns_rdatatype_aaaa) preferred_glue = DNS_MESSAGERENDER_PREFER_AAAA; } /* * XXXRTH The following doesn't deal with TCP buffer resizing. */ result = client_allocsendbuf(client, &buffer, &tcpbuffer, 0, sendbuf, &data); if (result != ISC_R_SUCCESS) goto done; result = dns_compress_init(&cctx, -1, client->mctx); if (result != ISC_R_SUCCESS) goto done; cleanup_cctx = ISC_TRUE; result = dns_message_renderbegin(client->message, &cctx, &buffer); if (result != ISC_R_SUCCESS) goto done; if (client->opt != NULL) { result = dns_message_setopt(client->message, client->opt); /* * XXXRTH dns_message_setopt() should probably do this... */ client->opt = NULL; if (result != ISC_R_SUCCESS) goto done; } result = dns_message_rendersection(client->message, DNS_SECTION_QUESTION, 0); 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_ANSWER, DNS_MESSAGERENDER_PARTIAL | dnssec_opts); 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_AUTHORITY, DNS_MESSAGERENDER_PARTIAL | dnssec_opts); 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -