Home | History | Annotate | Download | only in c-ares
      1 
      2 /* Copyright 1998 by the Massachusetts Institute of Technology.
      3  *
      4  * Permission to use, copy, modify, and distribute this
      5  * software and its documentation for any purpose and without
      6  * fee is hereby granted, provided that the above copyright
      7  * notice appear in all copies and that both that copyright
      8  * notice and this permission notice appear in supporting
      9  * documentation, and that the name of M.I.T. not be used in
     10  * advertising or publicity pertaining to distribution of the
     11  * software without specific, written prior permission.
     12  * M.I.T. makes no representations about the suitability of
     13  * this software for any purpose.  It is provided "as is"
     14  * without express or implied warranty.
     15  */
     16 
     17 #include "ares_setup.h"
     18 
     19 #ifdef HAVE_SYS_SOCKET_H
     20 #  include <sys/socket.h>
     21 #endif
     22 #ifdef HAVE_NETINET_IN_H
     23 #  include <netinet/in.h>
     24 #endif
     25 #ifdef HAVE_ARPA_NAMESER_H
     26 #  include <arpa/nameser.h>
     27 #else
     28 #  include "nameser.h"
     29 #endif
     30 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
     31 #  include <arpa/nameser_compat.h>
     32 #endif
     33 
     34 #include <stdlib.h>
     35 #include "ares.h"
     36 #include "ares_dns.h"
     37 #include "ares_private.h"
     38 
     39 struct qquery {
     40   ares_callback callback;
     41   void *arg;
     42 };
     43 
     44 static void qcallback(void *arg, int status, int timeouts, unsigned char *abuf, int alen);
     45 
     46 void ares__rc4(rc4_key* key, unsigned char *buffer_ptr, int buffer_len)
     47 {
     48   unsigned char x;
     49   unsigned char y;
     50   unsigned char* state;
     51   unsigned char xorIndex;
     52   short counter;
     53 
     54   x = key->x;
     55   y = key->y;
     56 
     57   state = &key->state[0];
     58   for(counter = 0; counter < buffer_len; counter ++)
     59   {
     60     x = (unsigned char)((x + 1) % 256);
     61     y = (unsigned char)((state[x] + y) % 256);
     62     ARES_SWAP_BYTE(&state[x], &state[y]);
     63 
     64     xorIndex = (unsigned char)((state[x] + state[y]) % 256);
     65 
     66     buffer_ptr[counter] = (unsigned char)(buffer_ptr[counter]^state[xorIndex]);
     67   }
     68   key->x = x;
     69   key->y = y;
     70 }
     71 
     72 static struct query* find_query_by_id(ares_channel channel, unsigned short id)
     73 {
     74   unsigned short qid;
     75   struct list_node* list_head;
     76   struct list_node* list_node;
     77   DNS_HEADER_SET_QID(((unsigned char*)&qid), id);
     78 
     79   /* Find the query corresponding to this packet. */
     80   list_head = &(channel->queries_by_qid[qid % ARES_QID_TABLE_SIZE]);
     81   for (list_node = list_head->next; list_node != list_head;
     82        list_node = list_node->next)
     83     {
     84        struct query *q = list_node->data;
     85        if (q->qid == qid)
     86 	  return q;
     87     }
     88   return NULL;
     89 }
     90 
     91 
     92 /* a unique query id is generated using an rc4 key. Since the id may already
     93    be used by a running query (as infrequent as it may be), a lookup is
     94    performed per id generation. In practice this search should happen only
     95    once per newly generated id
     96 */
     97 static unsigned short generate_unique_id(ares_channel channel)
     98 {
     99   unsigned short id;
    100 
    101   do {
    102     id = ares__generate_new_id(&channel->id_key);
    103   } while (find_query_by_id(channel, id));
    104 
    105   return (unsigned short)id;
    106 }
    107 
    108 void ares_query(ares_channel channel, const char *name, int dnsclass,
    109                 int type, ares_callback callback, void *arg)
    110 {
    111   struct qquery *qquery;
    112   unsigned char *qbuf;
    113   int qlen, rd, status;
    114 
    115   /* Compose the query. */
    116   rd = !(channel->flags & ARES_FLAG_NORECURSE);
    117   status = ares_mkquery(name, dnsclass, type, channel->next_id, rd, &qbuf,
    118                         &qlen);
    119   if (status != ARES_SUCCESS)
    120     {
    121       if (qbuf != NULL) free(qbuf);
    122       callback(arg, status, 0, NULL, 0);
    123       return;
    124     }
    125 
    126   channel->next_id = generate_unique_id(channel);
    127 
    128   /* Allocate and fill in the query structure. */
    129   qquery = malloc(sizeof(struct qquery));
    130   if (!qquery)
    131     {
    132       ares_free_string(qbuf);
    133       callback(arg, ARES_ENOMEM, 0, NULL, 0);
    134       return;
    135     }
    136   qquery->callback = callback;
    137   qquery->arg = arg;
    138 
    139   /* Send it off.  qcallback will be called when we get an answer. */
    140   ares_send(channel, qbuf, qlen, qcallback, qquery);
    141   ares_free_string(qbuf);
    142 }
    143 
    144 static void qcallback(void *arg, int status, int timeouts, unsigned char *abuf, int alen)
    145 {
    146   struct qquery *qquery = (struct qquery *) arg;
    147   unsigned int ancount;
    148   int rcode;
    149 
    150   if (status != ARES_SUCCESS)
    151     qquery->callback(qquery->arg, status, timeouts, abuf, alen);
    152   else
    153     {
    154       /* Pull the response code and answer count from the packet. */
    155       rcode = DNS_HEADER_RCODE(abuf);
    156       ancount = DNS_HEADER_ANCOUNT(abuf);
    157 
    158       /* Convert errors. */
    159       switch (rcode)
    160         {
    161         case NOERROR:
    162           status = (ancount > 0) ? ARES_SUCCESS : ARES_ENODATA;
    163           break;
    164         case FORMERR:
    165           status = ARES_EFORMERR;
    166           break;
    167         case SERVFAIL:
    168           status = ARES_ESERVFAIL;
    169           break;
    170         case NXDOMAIN:
    171           status = ARES_ENOTFOUND;
    172           break;
    173         case NOTIMP:
    174           status = ARES_ENOTIMP;
    175           break;
    176         case REFUSED:
    177           status = ARES_EREFUSED;
    178           break;
    179         }
    180       qquery->callback(qquery->arg, status, timeouts, abuf, alen);
    181     }
    182   free(qquery);
    183 }
    184