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 + -
显示快捷键?