📄 client.c
字号:
client_request, client); if (result != ISC_R_SUCCESS) goto fail; /* * Set a timeout to limit the amount of time we will wait * for a request on this TCP connection. */ ns_client_settimeout(client, 30); client->state = client->newstate = NS_CLIENTSTATE_READING; INSIST(client->nreads == 0); INSIST(client->recursionquota == NULL); client->nreads++; return; fail: ns_client_next(client, result);}static voidclient_newconn(isc_task_t *task, isc_event_t *event) { ns_client_t *client = event->ev_arg; isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event; isc_result_t result; REQUIRE(event->ev_type == ISC_SOCKEVENT_NEWCONN); REQUIRE(NS_CLIENT_VALID(client)); REQUIRE(client->task == task); UNUSED(task); INSIST(client->state == NS_CLIENTSTATE_READY); INSIST(client->naccepts == 1); client->naccepts--; LOCK(&client->interface->lock); INSIST(client->interface->ntcpcurrent > 0); client->interface->ntcpcurrent--; UNLOCK(&client->interface->lock); /* * We must take ownership of the new socket before the exit * check to make sure it gets destroyed if we decide to exit. */ if (nevent->result == ISC_R_SUCCESS) { client->tcpsocket = nevent->newsocket; client->state = NS_CLIENTSTATE_READING; INSIST(client->recursionquota == NULL); (void) isc_socket_getpeername(client->tcpsocket, &client->peeraddr); client->peeraddr_valid = ISC_TRUE; ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), "new TCP connection"); } else { /* * XXXRTH What should we do? We're trying to accept but * it didn't work. If we just give up, then TCP * service may eventually stop. * * For now, we just go idle. * * Going idle is probably the right thing if the * I/O was canceled. */ ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), "accept failed: %s", isc_result_totext(nevent->result)); } if (exit_check(client)) goto freeevent; if (nevent->result == ISC_R_SUCCESS) { int match; isc_netaddr_t netaddr; 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) { ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), "blackholed connection attempt"); client->newstate = NS_CLIENTSTATE_READY; (void)exit_check(client); goto freeevent; } INSIST(client->tcpmsg_valid == ISC_FALSE); dns_tcpmsg_init(client->mctx, client->tcpsocket, &client->tcpmsg); client->tcpmsg_valid = ISC_TRUE; /* * Let a new client take our place immediately, before * we wait for a request packet. If we don't, * telnetting to port 53 (once per CPU) will * deny service to legititmate TCP clients. */ result = isc_quota_attach(&ns_g_server->tcpquota, &client->tcpquota); if (result == ISC_R_SUCCESS) result = ns_client_replace(client); if (result != ISC_R_SUCCESS) { ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT, ISC_LOG_WARNING, "no more TCP clients: %s", isc_result_totext(result)); } client_read(client); } freeevent: isc_event_free(&event);}static voidclient_accept(ns_client_t *client) { isc_result_t result; CTRACE("accept"); result = isc_socket_accept(client->tcplistener, client->task, client_newconn, client); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_socket_accept() failed: %s", isc_result_totext(result)); /* * XXXRTH What should we do? We're trying to accept but * it didn't work. If we just give up, then TCP * service may eventually stop. * * For now, we just go idle. */ return; } INSIST(client->naccepts == 0); client->naccepts++; LOCK(&client->interface->lock); client->interface->ntcpcurrent++; UNLOCK(&client->interface->lock);}static voidclient_udprecv(ns_client_t *client) { isc_result_t result; isc_region_t r; CTRACE("udprecv"); r.base = client->recvbuf; r.length = RECV_BUFFER_SIZE; result = isc_socket_recv2(client->udpsocket, &r, 1, client->task, client->recvevent, 0); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_socket_recv() failed: %s", isc_result_totext(result)); /* * This cannot happen in the current implementation, since * isc_socket_recv2() cannot fail if flags == 0A * * If this does fail, we just go idle. */ return; } INSIST(client->nrecvs == 0); client->nrecvs++;}voidns_client_attach(ns_client_t *source, ns_client_t **targetp) { REQUIRE(NS_CLIENT_VALID(source)); REQUIRE(targetp != NULL && *targetp == NULL); source->references++; ns_client_log(source, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), "ns_client_attach: ref = %d", source->references); *targetp = source;}voidns_client_detach(ns_client_t **clientp) { ns_client_t *client = *clientp; client->references--; INSIST(client->references >= 0); *clientp = NULL; ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), "ns_client_detach: ref = %d", client->references); (void) exit_check(client);}isc_boolean_tns_client_shuttingdown(ns_client_t *client) { return (ISC_TF(client->newstate == NS_CLIENTSTATE_FREED));}isc_result_tns_client_replace(ns_client_t *client) { isc_result_t result; CTRACE("replace"); result = ns_clientmgr_createclients(client->manager, 1, client->interface, (TCP_CLIENT(client) ? ISC_TRUE : ISC_FALSE)); if (result != ISC_R_SUCCESS) return (result); /* * The responsibility for listening for new requests is hereby * transferred to the new client. Therefore, the old client * should refrain from listening for any more requests. */ client->mortal = ISC_TRUE; return (ISC_R_SUCCESS);}/*** *** Client Manager ***/static voidclientmgr_destroy(ns_clientmgr_t *manager) { REQUIRE(ISC_LIST_EMPTY(manager->active)); REQUIRE(ISC_LIST_EMPTY(manager->inactive)); MTRACE("clientmgr_destroy"); DESTROYLOCK(&manager->lock); manager->magic = 0; isc_mem_put(manager->mctx, manager, sizeof *manager);}isc_result_tns_clientmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr, ns_clientmgr_t **managerp){ ns_clientmgr_t *manager; isc_result_t result; manager = isc_mem_get(mctx, sizeof *manager); if (manager == NULL) return (ISC_R_NOMEMORY); result = isc_mutex_init(&manager->lock); if (result != ISC_R_SUCCESS) goto cleanup_manager; manager->mctx = mctx; manager->taskmgr = taskmgr; manager->timermgr = timermgr; manager->exiting = ISC_FALSE; ISC_LIST_INIT(manager->active); ISC_LIST_INIT(manager->inactive); manager->magic = MANAGER_MAGIC; MTRACE("create"); *managerp = manager; return (ISC_R_SUCCESS); cleanup_manager: isc_mem_put(manager->mctx, manager, sizeof *manager); return (result);}voidns_clientmgr_destroy(ns_clientmgr_t **managerp) { ns_clientmgr_t *manager; ns_client_t *client; isc_boolean_t need_destroy = ISC_FALSE; REQUIRE(managerp != NULL); manager = *managerp; REQUIRE(VALID_MANAGER(manager)); MTRACE("destroy"); LOCK(&manager->lock); manager->exiting = ISC_TRUE; for (client = ISC_LIST_HEAD(manager->active); client != NULL; client = ISC_LIST_NEXT(client, link)) isc_task_shutdown(client->task); for (client = ISC_LIST_HEAD(manager->inactive); client != NULL; client = ISC_LIST_NEXT(client, link)) isc_task_shutdown(client->task); if (ISC_LIST_EMPTY(manager->active) && ISC_LIST_EMPTY(manager->inactive)) need_destroy = ISC_TRUE; UNLOCK(&manager->lock); if (need_destroy) clientmgr_destroy(manager); *managerp = NULL;}isc_result_tns_clientmgr_createclients(ns_clientmgr_t *manager, unsigned int n, ns_interface_t *ifp, isc_boolean_t tcp){ isc_result_t result = ISC_R_SUCCESS; unsigned int i; ns_client_t *client; REQUIRE(VALID_MANAGER(manager)); REQUIRE(n > 0); MTRACE("createclients"); /* * We MUST lock the manager lock for the entire client creation * process. If we didn't do this, then a client could get a * shutdown event and disappear out from under us. */ LOCK(&manager->lock); for (i = 0; i < n; i++) { isc_event_t *ev; /* * Allocate a client. First try to get a recycled one; * if that fails, make a new one. */ client = ISC_LIST_HEAD(manager->inactive); if (client != NULL) { MTRACE("recycle"); ISC_LIST_UNLINK(manager->inactive, client, link); client->list = NULL; } else { MTRACE("create new"); result = client_create(manager, &client); if (result != ISC_R_SUCCESS) break; } ns_interface_attach(ifp, &client->interface); client->state = NS_CLIENTSTATE_READY; INSIST(client->recursionquota == NULL); if (tcp) { client->attributes |= NS_CLIENTATTR_TCP; isc_socket_attach(ifp->tcpsocket, &client->tcplistener); } else { isc_socket_t *sock; dns_dispatch_attach(ifp->udpdispatch, &client->dispatch); sock = dns_dispatch_getsocket(client->dispatch); isc_socket_attach(sock, &client->udpsocket); } client->manager = manager; ISC_LIST_APPEND(manager->active, client, link); client->list = &manager->active; INSIST(client->nctls == 0); client->nctls++; ev = &client->ctlevent; isc_task_send(client->task, &ev); } if (i != 0) { /* * We managed to create at least one client, so we * declare victory. */ result = ISC_R_SUCCESS; } UNLOCK(&manager->lock); return (result);}isc_sockaddr_t *ns_client_getsockaddr(ns_client_t *client) { return (&client->peeraddr);}isc_result_tns_client_checkaclsilent(ns_client_t *client, dns_acl_t *acl, isc_boolean_t default_allow){ isc_result_t result; int match; isc_netaddr_t netaddr; if (acl == NULL) { if (default_allow) goto allow; else goto deny; } isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); result = dns_acl_match(&netaddr, client->signer, acl, &ns_g_server->aclenv, &match, NULL); if (result != ISC_R_SUCCESS) goto deny; /* Internal error, already logged. */ if (match > 0) goto allow; goto deny; /* Negative match or no match. */ allow: return (ISC_R_SUCCESS); deny: return (DNS_R_REFUSED);}isc_result_tns_client_checkacl(ns_client_t *client, const char *opname, dns_acl_t *acl, isc_boolean_t default_allow, int log_level){ isc_result_t result = ns_client_checkaclsilent(client, acl, default_allow); if (result == ISC_R_SUCCESS) ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), "%s approved", opname); else ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_CLIENT, log_level, "%s denied", opname); return (result);}static voidns_client_name(ns_client_t *client, char *peerbuf, size_t len) { if (client->peeraddr_valid) isc_sockaddr_format(&client->peeraddr, peerbuf, len); else snprintf(peerbuf, len, "@%p", client);}static voidns_client_logv(ns_client_t *client, isc_logcategory_t *category, isc_logmodule_t *module, int level, const char *fmt, va_list ap) ISC_FORMAT_PRINTF(5, 0);static voidns_client_logv(ns_client_t *client, isc_logcategory_t *category, isc_logmodule_t *module, int level, const char *fmt, va_list ap){ char msgbuf[2048]; char peerbuf[ISC_SOCKADDR_FORMATSIZE]; vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); ns_client_name(client, peerbuf, sizeof peerbuf); isc_log_write(ns_g_lctx, category, module, level, "client %s: %s", peerbuf, msgbuf);}voidns_client_log(ns_client_t *client, isc_logcategory_t *category, isc_logmodule_t *module, int level, const char *fmt, ...){ va_list ap; if (! isc_log_wouldlog(ns_g_lctx, level)) return; va_start(ap, fmt); ns_client_logv(client, category, module, level, fmt, ap); va_end(ap);}voidns_client_aclmsg(const char *msg, dns_name_t *name, dns_rdataclass_t rdclass, char *buf, size_t len) { char namebuf[DNS_NAME_FORMATSIZE]; char classbuf[DNS_RDATACLASS_FORMATSIZE]; dns_name_format(name, namebuf, sizeof(namebuf)); dns_rdataclass_format(rdclass, classbuf, sizeof(classbuf)); (void)snprintf(buf, len, "%s '%s/%s'", msg, namebuf, classbuf);}static voidns_client_dumpmessage(ns_client_t *client, const char *reason) { isc_buffer_t buffer; char *buf = NULL; int len = 1024; isc_result_t result; /* * Note that these are multiline debug messages. We want a newline * to appear in the log after each message. */ do { buf = isc_mem_get(client->mctx, len); if (buf == NULL) break; isc_buffer_init(&buffer, buf, len); result = dns_message_totext(client->message, &dns_master_style_debug, 0, &buffer); if (result == ISC_R_NOSPACE) { isc_mem_put(client->mctx, buf, len); len += 1024; } else if (result == ISC_R_SUCCESS) ns_client_log(client, NS_LOGCATEGORY_UNMATCHED, NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1), "%s\n%.*s", reason, (int)isc_buffer_usedlength(&buffer), buf); } while (result == ISC_R_NOSPACE); if (buf != NULL) isc_mem_put(client->mctx, buf, len);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -