Exemple #1
0
/** 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;
}
Exemple #4
0
/** 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);
  }
}
Exemple #5
0
/** 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);
}