📄 client.c
字号:
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);}voidns_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); /* * 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);}/* * 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); 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); 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); } 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; } client->message->rcode = dns_rcode_noerror; /* RFC1123 section 6.1.3.2 */ if ((client->attributes & NS_CLIENTATTR_MULTICAST) != 0) client->message->flags &= ~DNS_MESSAGEFLAG_RD; /* * Deal with EDNS. */ opt = dns_message_getopt(client->message); if (opt != NULL) { unsigned int version; /* * Set the client's UDP buffer size. */ client->udpsize = opt->rdclass; /* * If the requested UDP buffer size is less than 512, * ignore it and use 512. */ if (client->udpsize < 512) client->udpsize = 512; /* * Get the flags out of the OPT record. */ client->extflags = (isc_uint16_t)(opt->ttl & 0xFFFF); /* * Create an OPT for our reply. */ result = client_addopt(client); if (result != ISC_R_SUCCESS) { ns_client_error(client, result); goto cleanup; } /* * Do we understand this version of ENDS? * * XXXRTH need library support for this! */ version = (opt->ttl & 0x00FF0000) >> 16; if (version != 0) { ns_client_error(client, DNS_R_BADVERS); goto cleanup; } } if (client->message->rdclass == 0) { ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1), "message class could not be determined"); ns_client_dumpmessage(client, "message class could not be determined"); ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_FORMERR); goto cleanup; } /* * Determine the destination address. If the receiving interface is * bound to a specific address, we simply use it regardless of the * address family. All IPv4 queries should fall into this case. * Otherwise, if this is a TCP query, get the address from the * receiving socket (this needs a system call and can be heavy). * For IPv6 UDP queries, we get this from the pktinfo structure (if * supported). * If all the attempts fail (this can happen due to memory shortage, * etc), we regard this as an error for safety. */ if ((client->interface->flags & NS_INTERFACEFLAG_ANYADDR) == 0) isc_netaddr_fromsockaddr(&destaddr, &client->interface->addr); else { result = ISC_R_FAILURE; if (TCP_CLIENT(client)) { isc_sockaddr_t destsockaddr; result = isc_socket_getsockname(client->tcpsocket, &destsockaddr); if (result == ISC_R_SUCCESS) isc_netaddr_fromsockaddr(&destaddr, &destsockaddr); } if (result != ISC_R_SUCCESS && client->interface->addr.type.sa.sa_family == AF_INET6 && (client->attributes & NS_CLIENTATTR_PKTINFO) != 0) { isc_uint32_t zone = 0; /* * XXXJT technically, we should convert the receiving * interface ID to a proper scope zone ID. However, * due to the fact there is no standard API for this, * we only handle link-local addresses and use the * interface index as link ID. Despite the assumption, * it should cover most typical cases. */ if (IN6_IS_ADDR_LINKLOCAL(&client->pktinfo.ipi6_addr)) zone = (isc_uint32_t)client->pktinfo.ipi6_ifindex; isc_netaddr_fromin6(&destaddr, &client->pktinfo.ipi6_addr); isc_netaddr_setzone(&destaddr, zone); result = ISC_R_SUCCESS; } if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "failed to get request's " "destination: %s", isc_result_totext(result)); goto cleanup; } } /* * Find a view that matches the client's source address. */ for (view = ISC_LIST_HEAD(ns_g_server->viewlist); view != NULL; view = ISC_LIST_NEXT(view, link)) { if (client->message->rdclass == view->rdclass || client->message->rdclass == dns_rdataclass_any) { dns_name_t *tsig = NULL; sigresult = dns_message_rechecksig(client->message,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -