/** Send a failed DNS lookup request again. * @param[in] request Request to resend. */ static void resend_query(struct reslist *request) { if (request->resend == 0) return; switch(request->type) { case T_PTR: do_query_number(NULL, NULL, &request->addr, request); break; case T_A: do_query_name(NULL, NULL, request->name, request, request->type); break; case T_AAAA: /* didn't work, try A */ if (request->state == REQ_AAAA) do_query_name(NULL, NULL, request->name, request, T_A); default: break; } }
/* * ar_resent_query * * resends a query. */ int Resolver :: ar_resend_query(DNSSession* session) { if (!session->getResends()) return -1; switch(session->getType()) { case T_PTR: ar_reinfo.re_resends++; /* XXXMB - I think this should be: (char *)&(session->re_addr) */ return do_query_number(NULL, (char *)(session->getReaddr()), session, session->getReaddrtype()); case T_A: ar_reinfo.re_resends++; return do_query_name(NULL, session->getName(), session, T_A); case T_AAAA: ar_reinfo.re_resends++; return do_query_name(NULL, session->getName(), session, T_AAAA); default: break; } return -1; }
PRBool Resolver :: process(DNSSession* session) { PR_AtomicIncrement(&curlookups); PRBool locstatus = PR_FALSE; char host[MAXDNAME]; resinfo_t resi; resinfo_t* rp = &resi; struct hostent* hp = NULL; PRInt32 rv = 0; int querytype = 0; if (session) { session->setStatus(DNS_IN_PROCESS); if (FORWARD_LOOKUP == session->getQType ()) { PR_AtomicIncrement(&namelookups); memset((char *)rp, 0, sizeof(resi)); ar_reinfo.re_na_look++; strncpy(host, session->getName(), 64); host[64] = '\0'; locstatus = PR_TRUE; switch(session->getFamily()) { case PR_AF_INET: querytype = T_A; break; case PR_AF_INET6: querytype = T_AAAA; break; default: locstatus = PR_FALSE; } // Makes and sends the query // the session gets automatically added to the hash table if (PR_TRUE == locstatus) { if (do_query_name(rp, host, session, querytype) == -1) { PR_SetError(PR_BAD_ADDRESS_ERROR, 0); locstatus = PR_FALSE; } } } else if (REVERSE_LOOKUP == session->getQType ()) { PR_AtomicIncrement(&addrlookups); memset((char *)rp, 0, sizeof(resi)); ar_reinfo.re_na_look++; const PRNetAddr* addrp = session->getIP(); locstatus = PR_TRUE; switch(addrp->raw.family) { case PR_AF_INET: rv = do_query_number(rp, (char *) &addrp->inet.ip, session, PR_AF_INET); break; case PR_AF_INET6: rv = do_query_number(rp, (char *) &addrp->ipv6.ip, session, PR_AF_INET6); break; default: locstatus = PR_FALSE; PR_SetError(PR_BAD_ADDRESS_ERROR, 0); break; } if (-1 == rv) { locstatus = PR_FALSE; } } } if (PR_TRUE == locstatus) { locstatus = PR_FALSE; int resend; do { resend = 0; session->wait(); if (DNS_COMPLETED == session->getStatus() ) { // Process answer and return meaningful data to caller. if (FORWARD_LOOKUP == session->getQType()) { if ((hp = ar_answer(session, &resend, NULL, 0)) != NULL) { PRInt32 rv = CopyHostent(session->getHentp(), hp, session->getBuffer(), session->getBufferSize()); if (rv != PR_AR_OK) PR_SetError(rv, 0); else locstatus = PR_TRUE; } } else if (REVERSE_LOOKUP == session->getQType()) { if (hp = ar_answer(session, &resend, NULL, 0)) { PRInt32 rv = CopyHostent(session->getHentp(), hp, session->getBuffer(), session->getBufferSize()); if (rv != PR_AR_OK) PR_SetError(rv, 0); else locstatus = PR_TRUE; } } } else if (DNS_TIMED_OUT == session->getStatus()) { PR_SetError(PR_IO_TIMEOUT_ERROR, 0); } else { PR_SetError(PR_BAD_ADDRESS_ERROR, 0); } } while (resend); } PR_AtomicDecrement(&curlookups); return locstatus; }
/** Read a DNS reply from the nameserver and process it. * @param[in] ev I/O activity event for resolver socket. */ static void res_readreply(struct Event *ev) { struct irc_sockaddr lsin; struct Socket *sock; char buf[sizeof(HEADER) + MAXPACKET]; HEADER *header; struct reslist *request = NULL; unsigned int rc; int answer_count; assert((ev_socket(ev) == &res_socket_v4) || (ev_socket(ev) == &res_socket_v6)); sock = ev_socket(ev); if (IO_SUCCESS != os_recvfrom_nonb(s_fd(sock), buf, sizeof(buf), &rc, &lsin) || (rc <= sizeof(HEADER))) return; /* * check against possibly fake replies */ if (!res_ourserver(&lsin)) return; /* * convert DNS reply reader from Network byte order to CPU byte order. */ header = (HEADER *)buf; header->ancount = ntohs(header->ancount); header->qdcount = ntohs(header->qdcount); header->nscount = ntohs(header->nscount); header->arcount = ntohs(header->arcount); /* * response for an id which we have already received an answer for * just ignore this response. */ if (0 == (request = find_id(header->id))) return; if ((header->rcode != NO_ERRORS) || (header->ancount == 0)) { if (SERVFAIL == header->rcode || NXDOMAIN == header->rcode) { /* * If a bad error was returned, we stop here and don't send * send any more (no retries granted). */ Debug((DEBUG_DNS, "Request %p has bad response (state %d type %d rcode %d)", request, request->state, request->type, header->rcode)); (*request->callback)(request->callback_ctx, NULL, NULL); rem_request(request); } else { /* * If we haven't already tried this, and we're looking up AAAA, try A * now */ if (request->state == REQ_AAAA && request->type == T_AAAA) { request->timeout += feature_int(FEAT_IRCD_RES_TIMEOUT); resend_query(request); } else if (request->type == T_PTR && request->state != REQ_INT && !irc_in_addr_is_ipv4(&request->addr)) { request->state = REQ_INT; request->timeout += feature_int(FEAT_IRCD_RES_TIMEOUT); resend_query(request); } } return; } /* * If this fails there was an error decoding the received packet, * try it again and hope it works the next time. */ answer_count = proc_answer(request, header, buf, buf + rc); if (answer_count) { if (request->type == T_PTR) { if (request->name == NULL) { /* * got a PTR response with no name, something bogus is happening * don't bother trying again, the client address doesn't resolve */ Debug((DEBUG_DNS, "Request %p PTR had empty name", request)); (*request->callback)(request->callback_ctx, NULL, NULL); rem_request(request); return; } /* * Lookup the 'authoritative' name that we were given for the * ip#. */ #ifdef IPV6 if (!irc_in_addr_is_ipv4(&request->addr)) do_query_name(request->callback, request->callback_ctx, request->name, NULL, T_AAAA); else #endif do_query_name(request->callback, request->callback_ctx, request->name, NULL, T_A); Debug((DEBUG_DNS, "Request %p switching to forward resolution", request)); rem_request(request); } else { /* * got a name and address response, client resolved */ (*request->callback)(request->callback_ctx, &request->addr, request->name); Debug((DEBUG_DNS, "Request %p got forward resolution", request)); rem_request(request); } } else if (!request->sent) { /* XXX - we got a response for a query we didn't send with a valid id? * this should never happen, bail here and leave the client unresolved */ assert(0); /* XXX don't leak it */ Debug((DEBUG_DNS, "Request %p was unexpected(!)", request)); rem_request(request); } }
/** Try to look up address for a hostname, trying IPv6 (T_AAAA) first. * @param[in] name Hostname to look up. * @param[in] query Callback information. */ void gethost_byname(const char *name, dns_callback_f callback, void *ctx) { do_query_name(callback, ctx, name, NULL, T_AAAA); }