📄 resolver.c
字号:
FCTXTRACE("query"); res = fctx->res; task = res->buckets[fctx->bucketnum].task; fctx_setretryinterval(fctx, addrinfo->srtt); result = fctx_startidletimer(fctx); if (result != ISC_R_SUCCESS) return (result); INSIST(ISC_LIST_EMPTY(fctx->validators)); dns_message_reset(fctx->rmessage, DNS_MESSAGE_INTENTPARSE); query = isc_mem_get(res->buckets[fctx->bucketnum].mctx, sizeof(*query)); if (query == NULL) { result = ISC_R_NOMEMORY; goto stop_idle_timer; } query->mctx = res->buckets[fctx->bucketnum].mctx; query->options = options; query->attributes = 0; query->sends = 0; query->connects = 0; /* * Note that the caller MUST guarantee that 'addrinfo' will remain * valid until this query is canceled. */ query->addrinfo = addrinfo; TIME_NOW(&query->start); /* * If this is a TCP query, then we need to make a socket and * a dispatch for it here. Otherwise we use the resolver's * shared dispatch. */ query->dispatchmgr = res->dispatchmgr; query->dispatch = NULL; query->tcpsocket = NULL; if (res->view->peers != NULL) { dns_peer_t *peer = NULL; isc_netaddr_t dstip; isc_netaddr_fromsockaddr(&dstip, &addrinfo->sockaddr); result = dns_peerlist_peerbyaddr(res->view->peers, &dstip, &peer); if (result == ISC_R_SUCCESS) { result = dns_peer_getquerysource(peer, &addr); if (result == ISC_R_SUCCESS) have_addr = ISC_TRUE; } } if ((query->options & DNS_FETCHOPT_TCP) != 0) { int pf; pf = isc_sockaddr_pf(&addrinfo->sockaddr); if (!have_addr) { switch (pf) { case PF_INET: result = dns_dispatch_getlocaladdress(res->dispatchv4, &addr); break; case PF_INET6: result = dns_dispatch_getlocaladdress(res->dispatchv6, &addr); break; default: result = ISC_R_NOTIMPLEMENTED; break; } if (result != ISC_R_SUCCESS) goto cleanup_query; } isc_sockaddr_setport(&addr, 0); result = isc_socket_create(res->socketmgr, pf, isc_sockettype_tcp, &query->tcpsocket); if (result != ISC_R_SUCCESS) goto cleanup_query;#ifndef BROKEN_TCP_BIND_BEFORE_CONNECT result = isc_socket_bind(query->tcpsocket, &addr); if (result != ISC_R_SUCCESS) goto cleanup_socket;#endif /* * A dispatch will be created once the connect succeeds. */ } else { if (have_addr) { unsigned int attrs, attrmask; attrs = DNS_DISPATCHATTR_UDP; switch (isc_sockaddr_pf(&addr)) { case AF_INET: attrs |= DNS_DISPATCHATTR_IPV4; break; case AF_INET6: attrs |= DNS_DISPATCHATTR_IPV6; break; default: result = ISC_R_NOTIMPLEMENTED; goto cleanup_query; } attrmask = DNS_DISPATCHATTR_UDP; attrmask |= DNS_DISPATCHATTR_TCP; attrmask |= DNS_DISPATCHATTR_IPV4; attrmask |= DNS_DISPATCHATTR_IPV6; result = dns_dispatch_getudp(res->dispatchmgr, res->socketmgr, res->taskmgr, &addr, 4096, 1000, 32768, 16411, 16433, attrs, attrmask, &query->dispatch); if (result != ISC_R_SUCCESS) goto cleanup_query; } else { switch (isc_sockaddr_pf(&addrinfo->sockaddr)) { case PF_INET: dns_dispatch_attach(res->dispatchv4, &query->dispatch); break; case PF_INET6: dns_dispatch_attach(res->dispatchv6, &query->dispatch); break; default: result = ISC_R_NOTIMPLEMENTED; goto cleanup_query; } } /* * We should always have a valid dispatcher here. If we * don't support a protocol family, then its dispatcher * will be NULL, but we shouldn't be finding addresses for * protocol types we don't support, so the dispatcher * we found should never be NULL. */ INSIST(query->dispatch != NULL); } query->dispentry = NULL; query->fctx = fctx; query->tsig = NULL; query->tsigkey = NULL; ISC_LINK_INIT(query, link); query->magic = QUERY_MAGIC; if ((query->options & DNS_FETCHOPT_TCP) != 0) { /* * Connect to the remote server. * * XXXRTH Should we attach to the socket? */ result = isc_socket_connect(query->tcpsocket, &addrinfo->sockaddr, task, resquery_connected, query); if (result != ISC_R_SUCCESS) goto cleanup_socket; query->connects++; QTRACE("connecting via TCP"); } else { result = resquery_send(query); if (result != ISC_R_SUCCESS) goto cleanup_dispatch; } ISC_LIST_APPEND(fctx->queries, query, link); query->fctx->nqueries++; return (ISC_R_SUCCESS); cleanup_socket: isc_socket_detach(&query->tcpsocket); cleanup_dispatch: if (query->dispatch != NULL) dns_dispatch_detach(&query->dispatch); cleanup_query: query->magic = 0; isc_mem_put(res->buckets[fctx->bucketnum].mctx, query, sizeof(*query)); stop_idle_timer: RUNTIME_CHECK(fctx_stopidletimer(fctx) == ISC_R_SUCCESS); return (result);}static isc_boolean_ttriededns(fetchctx_t *fctx, isc_sockaddr_t *address) { isc_sockaddr_t *sa; for (sa = ISC_LIST_HEAD(fctx->edns); sa != NULL; sa = ISC_LIST_NEXT(sa, link)) { if (isc_sockaddr_equal(sa, address)) return (ISC_TRUE); } return (ISC_FALSE);}static voidadd_triededns(fetchctx_t *fctx, isc_sockaddr_t *address) { isc_sockaddr_t *sa; if (triededns(fctx, address)) return; sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx, sizeof(*sa)); if (sa == NULL) return; *sa = *address; ISC_LIST_INITANDAPPEND(fctx->edns, sa, link);}static isc_boolean_ttriededns512(fetchctx_t *fctx, isc_sockaddr_t *address) { isc_sockaddr_t *sa; for (sa = ISC_LIST_HEAD(fctx->edns512); sa != NULL; sa = ISC_LIST_NEXT(sa, link)) { if (isc_sockaddr_equal(sa, address)) return (ISC_TRUE); } return (ISC_FALSE);}static voidadd_triededns512(fetchctx_t *fctx, isc_sockaddr_t *address) { isc_sockaddr_t *sa; if (triededns512(fctx, address)) return; sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx, sizeof(*sa)); if (sa == NULL) return; *sa = *address; ISC_LIST_INITANDAPPEND(fctx->edns512, sa, link);}static isc_result_tresquery_send(resquery_t *query) { fetchctx_t *fctx; isc_result_t result; dns_name_t *qname = NULL; dns_rdataset_t *qrdataset = NULL; isc_region_t r; dns_resolver_t *res; isc_task_t *task; isc_socket_t *socket; isc_buffer_t tcpbuffer; isc_sockaddr_t *address; isc_buffer_t *buffer; isc_netaddr_t ipaddr; dns_tsigkey_t *tsigkey = NULL; dns_peer_t *peer = NULL; isc_boolean_t useedns; dns_compress_t cctx; isc_boolean_t cleanup_cctx = ISC_FALSE; isc_boolean_t secure_domain; fctx = query->fctx; QTRACE("send"); res = fctx->res; task = res->buckets[fctx->bucketnum].task; address = NULL; if ((query->options & DNS_FETCHOPT_TCP) != 0) { /* * Reserve space for the TCP message length. */ isc_buffer_init(&tcpbuffer, query->data, sizeof(query->data)); isc_buffer_init(&query->buffer, query->data + 2, sizeof(query->data) - 2); buffer = &tcpbuffer; } else { isc_buffer_init(&query->buffer, query->data, sizeof(query->data)); buffer = &query->buffer; } result = dns_message_gettempname(fctx->qmessage, &qname); if (result != ISC_R_SUCCESS) goto cleanup_temps; result = dns_message_gettemprdataset(fctx->qmessage, &qrdataset); if (result != ISC_R_SUCCESS) goto cleanup_temps; /* * Get a query id from the dispatch. */ result = dns_dispatch_addresponse(query->dispatch, &query->addrinfo->sockaddr, task, resquery_response, query, &query->id, &query->dispentry); if (result != ISC_R_SUCCESS) goto cleanup_temps; fctx->qmessage->opcode = dns_opcode_query; /* * Set up question. */ dns_name_init(qname, NULL); dns_name_clone(&fctx->name, qname); dns_rdataset_init(qrdataset); dns_rdataset_makequestion(qrdataset, res->rdclass, fctx->type); ISC_LIST_APPEND(qname->list, qrdataset, link); dns_message_addname(fctx->qmessage, qname, DNS_SECTION_QUESTION); qname = NULL; qrdataset = NULL; /* * Set RD if the client has requested that we do a recursive query, * or if we're sending to a forwarder. */ if ((query->options & DNS_FETCHOPT_RECURSIVE) != 0 || ISFORWARDER(query->addrinfo)) fctx->qmessage->flags |= DNS_MESSAGEFLAG_RD; /* * Set CD if the client says don't validate or the question is * under a secure entry point. */ if ((query->options & DNS_FETCHOPT_NOVALIDATE) != 0) { fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD; } else if (res->view->enablevalidation) { result = dns_keytable_issecuredomain(res->view->secroots, &fctx->name, &secure_domain); if (result != ISC_R_SUCCESS) secure_domain = ISC_FALSE; if (res->view->dlv != NULL) secure_domain = ISC_TRUE; if (secure_domain) fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD; } /* * We don't have to set opcode because it defaults to query. */ fctx->qmessage->id = query->id; /* * Convert the question to wire format. */ result = dns_compress_init(&cctx, -1, fctx->res->mctx); if (result != ISC_R_SUCCESS) goto cleanup_message; cleanup_cctx = ISC_TRUE; result = dns_message_renderbegin(fctx->qmessage, &cctx, &query->buffer); if (result != ISC_R_SUCCESS) goto cleanup_message; result = dns_message_rendersection(fctx->qmessage, DNS_SECTION_QUESTION, 0); if (result != ISC_R_SUCCESS) goto cleanup_message; peer = NULL; isc_netaddr_fromsockaddr(&ipaddr, &query->addrinfo->sockaddr); (void) dns_peerlist_peerbyaddr(fctx->res->view->peers, &ipaddr, &peer); /* * The ADB does not know about servers with "edns no". Check this, * and then inform the ADB for future use. */ if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0 && peer != NULL && dns_peer_getsupportedns(peer, &useedns) == ISC_R_SUCCESS && !useedns) { query->options |= DNS_FETCHOPT_NOEDNS0; dns_adb_changeflags(fctx->adb, query->addrinfo, DNS_FETCHOPT_NOEDNS0, DNS_FETCHOPT_NOEDNS0); } /* * Use EDNS0, unless the caller doesn't want it, or we know that * the remote server doesn't like it. */ if ((triededns512(fctx, &query->addrinfo->sockaddr) || fctx->timeouts >= (MAX_EDNS0_TIMEOUTS * 2)) && (query->options & DNS_FETCHOPT_NOEDNS0) == 0) { query->options |= DNS_FETCHOPT_NOEDNS0; FCTXTRACE("too many timeouts, disabling EDNS0"); } else if ((triededns(fctx, &query->addrinfo->sockaddr) || fctx->timeouts >= MAX_EDNS0_TIMEOUTS) && (query->options & DNS_FETCHOPT_NOEDNS0) == 0) { query->options |= DNS_FETCHOPT_EDNS512; FCTXTRACE("too many timeouts, setting EDNS size to 512"); } if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) { if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0) { unsigned int version = 0; /* Default version. */ unsigned int flags; isc_uint16_t udpsize = res->udpsize; flags = query->addrinfo->flags; if ((flags & DNS_FETCHOPT_EDNSVERSIONSET) != 0) { version = flags & DNS_FETCHOPT_EDNSVERSIONMASK; version >>= DNS_FETCHOPT_EDNSVERSIONSHIFT; } if ((query->options & DNS_FETCHOPT_EDNS512) != 0) udpsize = 512; else if (peer != NULL) (void)dns_peer_getudpsize(peer, &udpsize); result = fctx_addopt(fctx->qmessage, version, udpsize); if (result != ISC_R_SUCCESS) { /* * We couldn't add the OPT, but we'll press on. * We're not using EDNS0, so set the NOEDNS0 * bit. */ query->options |= DNS_FETCHOPT_NOEDNS0; } } else { /* * We know this server doesn't like EDNS0, so we * won't use it. Set the NOEDNS0 bit since we're * not using EDNS0. */ query->options |= DNS_FETCHOPT_NOEDNS0; } } /* * If we need EDNS0 to do this query and aren't using it, we lose. */ if (NEEDEDNS0(fctx) && (query->options & DNS_FETCHOPT_NOEDNS0) != 0) { result = DNS_R_SERVFAIL; goto cleanup_message; } if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) add_triededns(fctx, &query->addrinfo->sockaddr); if ((query->options & DNS_FETCHOPT_EDNS512) != 0) add_triededns512(fctx, &query->addrinfo->sockaddr); /* * Clear CD if EDNS is not in use. */ if ((query->options & DNS_FETCHOPT_NOEDNS0) != 0) fctx->qmessage->flags &= ~DNS_MESSAGEFLAG_CD; /* * Add TSIG record tailored to the current recipient. */ result = dns_view_getpeertsig(fctx->res->view, &ipaddr, &tsigkey); if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) goto cleanup_message; if (tsigkey != NULL) { result = dns_message_settsigkey(fctx->qmessage, tsigkey); dns_tsigkey_detach(&tsigkey); if (result != ISC_R_SUCCESS) goto cleanup_message; } result = dns_message_rendersection(fctx->qmessage, DNS_SECTION_ADDITIONAL, 0); if (result != ISC_R_SUCCESS) goto cleanup_message; result = dns_message_renderend(fctx->qmessage); if (result != ISC_R_SUCCESS) goto cleanup_message; dns_compress_invalidate(&cctx); cleanup_cctx = ISC_FALSE; if (dns_message_gettsigkey(fctx->qmessage) != NULL) { dns_tsigkey_attach(dns_message_gettsigkey(fctx->qmessage), &query->tsigkey); result = dns_message_getquerytsig(fctx->qmessage, fctx->res->mctx, &query->tsig); if (result != ISC_R_SUCCESS) goto cleanup_message; } /* * If using TCP, write the length of the message at the beginning * of the buffer. */ if ((query->options & DNS_FETCHOPT_TCP) != 0) { isc_buffer_usedregion(&query->buffer, &r);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -