LCOV - code coverage report
Current view: top level - src - resolver.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 4 170 2.4 %
Date: 2023-08-10 00:00:00 Functions: 2 10 20.0 %

          Line data    Source code
       1             : /* resolver.c
       2             :  * strophe XMPP client library -- DNS resolver
       3             :  *
       4             :  * Copyright (C) 2015 Dmitry Podgorny <pasis.ua@gmail.com>
       5             :  *
       6             :  *  This software is provided AS-IS with no warranty, either express
       7             :  *  or implied.
       8             :  *
       9             :  *  This program is dual licensed under the MIT and GPLv3 licenses.
      10             :  */
      11             : 
      12             : /** @file
      13             :  *  DNS resolver.
      14             :  */
      15             : 
      16             : #if !defined(_WIN32) && !defined(HAVE_CARES)
      17             : #include <netinet/in.h>
      18             : #include <arpa/nameser.h>
      19             : #include <resolv.h>
      20             : #endif /* _WIN32 && HAVE_CARES */
      21             : 
      22             : #ifdef HAVE_CARES
      23             : #include <ares.h>
      24             : /* for select(2) */
      25             : #ifdef _WIN32
      26             : #include <winsock2.h>
      27             : #else /* _WIN32 */
      28             : #include <sys/time.h>
      29             : #include <sys/types.h>
      30             : #include <unistd.h>
      31             : #endif /* !_WIN32 */
      32             : #endif /* HAVE_CARES */
      33             : 
      34             : #include <string.h> /* strncpy */
      35             : 
      36             : #include "ostypes.h"
      37             : #include "snprintf.h"
      38             : #include "util.h" /* xmpp_min */
      39             : #include "resolver.h"
      40             : 
      41             : #define MESSAGE_HEADER_LEN 12
      42             : #define MESSAGE_RESPONSE 1
      43             : #define MESSAGE_T_SRV 33
      44             : #define MESSAGE_C_IN 1
      45             : 
      46             : /*******************************************************************************
      47             :  * Forward declarations.
      48             :  ******************************************************************************/
      49             : 
      50             : #ifdef HAVE_CARES
      51             : static int resolver_ares_srv_lookup_buf(xmpp_ctx_t *ctx,
      52             :                                         const unsigned char *buf,
      53             :                                         size_t len,
      54             :                                         resolver_srv_rr_t **srv_rr_list);
      55             : static int resolver_ares_srv_lookup(xmpp_ctx_t *ctx,
      56             :                                     const char *fulldomain,
      57             :                                     resolver_srv_rr_t **srv_rr_list);
      58             : #endif /* HAVE_CARES */
      59             : 
      60             : #ifndef HAVE_CARES
      61             : static int resolver_raw_srv_lookup_buf(xmpp_ctx_t *ctx,
      62             :                                        const unsigned char *buf,
      63             :                                        size_t len,
      64             :                                        resolver_srv_rr_t **srv_rr_list);
      65             : #endif /* !HAVE_CARES */
      66             : 
      67             : #if defined(_WIN32) && !defined(HAVE_CARES)
      68             : static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx,
      69             :                                      const char *fulldomain,
      70             :                                      resolver_srv_rr_t **srv_rr_list);
      71             : static int resolver_win32_srv_query(const char *fulldomain,
      72             :                                     unsigned char *buf,
      73             :                                     size_t len);
      74             : #endif /* _WIN32 && !HAVE_CARES */
      75             : 
      76             : /*******************************************************************************
      77             :  * Implementation.
      78             :  ******************************************************************************/
      79             : 
      80           2 : void resolver_initialize(void)
      81             : {
      82             : #ifdef HAVE_CARES
      83             :     ares_library_init(ARES_LIB_INIT_ALL);
      84             : #endif
      85           2 : }
      86             : 
      87           2 : void resolver_shutdown(void)
      88             : {
      89             : #ifdef HAVE_CARES
      90             :     ares_library_cleanup();
      91             : #endif
      92           2 : }
      93             : 
      94           0 : resolver_srv_rr_t *resolver_srv_rr_new(xmpp_ctx_t *ctx,
      95             :                                        const char *host,
      96             :                                        unsigned short port,
      97             :                                        unsigned short prio,
      98             :                                        unsigned short weight)
      99             : {
     100           0 :     resolver_srv_rr_t *rr = strophe_alloc(ctx, sizeof(*rr));
     101           0 :     if (rr) {
     102           0 :         memset(rr, 0, sizeof(*rr));
     103           0 :         rr->port = port;
     104           0 :         rr->priority = prio;
     105           0 :         rr->weight = weight;
     106           0 :         if (host) {
     107           0 :             snprintf(rr->target, sizeof(rr->target), "%s", host);
     108             :         }
     109             :     }
     110           0 :     return rr;
     111             : }
     112             : 
     113           0 : static void resolver_srv_list_sort(resolver_srv_rr_t **srv_rr_list)
     114             : {
     115           0 :     resolver_srv_rr_t *rr_head;
     116           0 :     resolver_srv_rr_t *rr_current;
     117           0 :     resolver_srv_rr_t *rr_next;
     118           0 :     resolver_srv_rr_t *rr_prev;
     119           0 :     int swap;
     120             : 
     121           0 :     rr_head = *srv_rr_list;
     122             : 
     123           0 :     if ((rr_head == NULL) || (rr_head->next == NULL)) {
     124             :         /* Empty or single record list */
     125             :         return;
     126             :     }
     127             : 
     128           0 :     do {
     129           0 :         rr_prev = NULL;
     130           0 :         rr_current = rr_head;
     131           0 :         rr_next = rr_head->next;
     132           0 :         swap = 0;
     133           0 :         while (rr_next != NULL) {
     134             :             /*
     135             :              * RFC2052: A client MUST attempt to contact the target host
     136             :              * with the lowest-numbered priority it can reach.
     137             :              * RFC2052: When selecting a target host among the
     138             :              * those that have the same priority, the chance of trying
     139             :              * this one first SHOULD be proportional to its weight.
     140             :              */
     141           0 :             if ((rr_current->priority > rr_next->priority) ||
     142           0 :                 (rr_current->priority == rr_next->priority &&
     143           0 :                  rr_current->weight < rr_next->weight)) {
     144             :                 /* Swap node */
     145           0 :                 swap = 1;
     146           0 :                 if (rr_prev != NULL) {
     147           0 :                     rr_prev->next = rr_next;
     148             :                 } else {
     149             :                     /* Swap head node */
     150             :                     rr_head = rr_next;
     151             :                 }
     152           0 :                 rr_current->next = rr_next->next;
     153           0 :                 rr_next->next = rr_current;
     154             : 
     155           0 :                 rr_prev = rr_next;
     156           0 :                 rr_next = rr_current->next;
     157             :             } else {
     158             :                 /* Next node */
     159           0 :                 rr_prev = rr_current;
     160           0 :                 rr_current = rr_next;
     161           0 :                 rr_next = rr_next->next;
     162             :             }
     163             :         }
     164           0 :     } while (swap != 0);
     165             : 
     166           0 :     *srv_rr_list = rr_head;
     167             : }
     168             : 
     169           0 : int resolver_srv_lookup_buf(xmpp_ctx_t *ctx,
     170             :                             const unsigned char *buf,
     171             :                             size_t len,
     172             :                             resolver_srv_rr_t **srv_rr_list)
     173             : {
     174           0 :     int set;
     175             : 
     176             : #ifdef HAVE_CARES
     177             :     set = resolver_ares_srv_lookup_buf(ctx, buf, len, srv_rr_list);
     178             : #else
     179           0 :     set = resolver_raw_srv_lookup_buf(ctx, buf, len, srv_rr_list);
     180           0 :     if (set != XMPP_DOMAIN_FOUND && *srv_rr_list != NULL) {
     181           0 :         resolver_srv_free(ctx, *srv_rr_list);
     182           0 :         *srv_rr_list = NULL;
     183             :     }
     184             : #endif
     185           0 :     resolver_srv_list_sort(srv_rr_list);
     186             : 
     187           0 :     return set;
     188             : }
     189             : 
     190           0 : int resolver_srv_lookup(xmpp_ctx_t *ctx,
     191             :                         const char *service,
     192             :                         const char *proto,
     193             :                         const char *domain,
     194             :                         resolver_srv_rr_t **srv_rr_list)
     195             : {
     196             : #define RESOLVER_BUF_MAX 65536
     197           0 :     unsigned char *buf;
     198           0 :     char fulldomain[2048];
     199           0 :     int len;
     200           0 :     int set = XMPP_DOMAIN_NOT_FOUND;
     201             : 
     202           0 :     (void)buf;
     203           0 :     (void)len;
     204             : 
     205           0 :     strophe_snprintf(fulldomain, sizeof(fulldomain), "_%s._%s.%s", service,
     206             :                      proto, domain);
     207             : 
     208           0 :     *srv_rr_list = NULL;
     209             : 
     210             : #ifdef HAVE_CARES
     211             : 
     212             :     set = resolver_ares_srv_lookup(ctx, fulldomain, srv_rr_list);
     213             : 
     214             : #else /* HAVE_CARES */
     215             : 
     216             : #ifdef _WIN32
     217             :     set = resolver_win32_srv_lookup(ctx, fulldomain, srv_rr_list);
     218             :     if (set == XMPP_DOMAIN_FOUND)
     219             :         return set;
     220             : #endif /* _WIN32 */
     221             : 
     222           0 :     buf = strophe_alloc(ctx, RESOLVER_BUF_MAX);
     223           0 :     if (buf == NULL)
     224           0 :         return XMPP_DOMAIN_NOT_FOUND;
     225             : 
     226             : #ifdef _WIN32
     227             :     len = resolver_win32_srv_query(fulldomain, buf, RESOLVER_BUF_MAX);
     228             : #else  /* _WIN32 */
     229           0 :     len = res_query(fulldomain, MESSAGE_C_IN, MESSAGE_T_SRV, buf,
     230             :                     RESOLVER_BUF_MAX);
     231             : #endif /* _WIN32 */
     232             : 
     233           0 :     if (len > 0)
     234           0 :         set = resolver_srv_lookup_buf(ctx, buf, (size_t)len, srv_rr_list);
     235             : 
     236           0 :     strophe_free(ctx, buf);
     237             : 
     238             : #endif /* HAVE_CARES */
     239             : 
     240             :     return set;
     241             : }
     242             : 
     243           0 : void resolver_srv_free(xmpp_ctx_t *ctx, resolver_srv_rr_t *srv_rr_list)
     244             : {
     245           0 :     resolver_srv_rr_t *rr;
     246             : 
     247           0 :     while (srv_rr_list != NULL) {
     248           0 :         rr = srv_rr_list->next;
     249           0 :         strophe_free(ctx, srv_rr_list);
     250           0 :         srv_rr_list = rr;
     251             :     }
     252           0 : }
     253             : 
     254             : #ifndef HAVE_CARES
     255             : /*******************************************************************************
     256             :  * Resolver raw implementation.
     257             :  *
     258             :  * This code is common for both unix and win32.
     259             :  ******************************************************************************/
     260             : 
     261             : struct message_header {
     262             :     uint16_t id;
     263             :     uint8_t octet2;
     264             :     uint8_t octet3;
     265             :     uint16_t qdcount;
     266             :     uint16_t ancount;
     267             :     uint16_t nscount;
     268             :     uint16_t arcount;
     269             : };
     270             : 
     271             : /* the same as ntohs(), but receives pointer to the value */
     272           0 : static uint16_t xmpp_ntohs_ptr(const void *ptr)
     273             : {
     274           0 :     const uint8_t *p = (const uint8_t *)ptr;
     275             : 
     276           0 :     return (uint16_t)((p[0] << 8U) + p[1]);
     277             : }
     278             : 
     279           0 : static uint8_t message_header_qr(const struct message_header *header)
     280             : {
     281           0 :     return (header->octet2 >> 7) & 1;
     282             : }
     283             : 
     284           0 : static uint8_t message_header_rcode(const struct message_header *header)
     285             : {
     286           0 :     return header->octet3 & 0x0f;
     287             : }
     288             : 
     289             : /*
     290             :  * Append a label or a dot to the target name with buffer overflow checks.
     291             :  * Returns length of the non-truncated resulting string, may be bigger than
     292             :  * name_max.
     293             :  */
     294           0 : static size_t message_name_append_safe(char *name,
     295             :                                        size_t name_len,
     296             :                                        size_t name_max,
     297             :                                        const char *tail,
     298             :                                        size_t tail_len)
     299             : {
     300           0 :     size_t copy_len;
     301             : 
     302           0 :     copy_len = name_max > name_len ? name_max - name_len : 0;
     303           0 :     copy_len = xmpp_min(tail_len, copy_len);
     304           0 :     if (copy_len > 0)
     305           0 :         memcpy(&name[name_len], tail, copy_len);
     306             : 
     307           0 :     return name_len + tail_len;
     308             : }
     309             : 
     310             : /* Returns length of the compressed name. This is NOT the same as strlen(). */
     311           0 : static unsigned message_name_get(const unsigned char *buf,
     312             :                                  size_t buf_len,
     313             :                                  unsigned buf_offset,
     314             :                                  char *name,
     315             :                                  size_t name_max)
     316             : {
     317           0 :     size_t name_len = 0;
     318           0 :     unsigned i = buf_offset;
     319           0 :     unsigned pointer;
     320           0 :     unsigned rc;
     321           0 :     unsigned char label_len;
     322             : 
     323           0 :     while (1) {
     324           0 :         if (i >= buf_len)
     325             :             return 0;
     326           0 :         label_len = buf[i++];
     327           0 :         if (label_len == 0)
     328             :             break;
     329             : 
     330             :         /* Label */
     331           0 :         if ((label_len & 0xc0) == 0) {
     332           0 :             if (i + label_len - 1 >= buf_len)
     333             :                 return 0;
     334           0 :             if (name != NULL) {
     335           0 :                 name_len = message_name_append_safe(name, name_len, name_max,
     336           0 :                                                     (char *)&buf[i], label_len);
     337           0 :                 name_len =
     338           0 :                     message_name_append_safe(name, name_len, name_max, ".", 1);
     339             :             }
     340             :             i += label_len;
     341             : 
     342             :             /* Pointer */
     343           0 :         } else if ((label_len & 0xc0) == 0xc0) {
     344           0 :             if (i >= buf_len)
     345             :                 return 0;
     346           0 :             pointer = (label_len & 0x3f) << 8 | buf[i++];
     347             :             /* Prevent infinite looping */
     348           0 :             if (pointer >= buf_offset)
     349             :                 return 0;
     350           0 :             if (name != NULL && name_len >= name_max && name_max > 0) {
     351             :                 /* We have filled the name buffer. Don't pass it recursively. */
     352           0 :                 name[name_max - 1] = '\0';
     353           0 :                 name = NULL;
     354           0 :                 name_max = 0;
     355             :             }
     356           0 :             rc = message_name_get(
     357             :                 buf, buf_len, pointer, name != NULL ? &name[name_len] : NULL,
     358             :                 name_max > name_len ? name_max - name_len : 0);
     359           0 :             if (rc == 0)
     360             :                 return 0;
     361             :             /* Pointer is always the last. */
     362             :             break;
     363             : 
     364             :             /* The 10 and 01 combinations are reserved for future use. */
     365             :         } else {
     366             :             return 0;
     367             :         }
     368             :     }
     369           0 :     if (label_len == 0) {
     370           0 :         if (name_len == 0)
     371             :             name_len = 1;
     372             :         /*
     373             :          * At this point name_len is length of the resulting name,
     374             :          * including '\0'. This value can be exported to allocate buffer
     375             :          * of precise size.
     376             :          */
     377           0 :         if (name != NULL && name_max > 0) {
     378             :             /*
     379             :              * Overwrite leading '.' with a '\0'. If the resulting name is
     380             :              * bigger than name_max it is truncated.
     381             :              */
     382           0 :             name[xmpp_min(name_len, name_max) - 1] = '\0';
     383             :         }
     384             :     }
     385             : 
     386           0 :     return i - buf_offset;
     387             : }
     388             : 
     389             : static unsigned
     390           0 : message_name_len(const unsigned char *buf, size_t buf_len, unsigned buf_offset)
     391             : {
     392           0 :     return message_name_get(buf, buf_len, buf_offset, NULL, SIZE_MAX);
     393             : }
     394             : 
     395             : #define BUF_OVERFLOW_CHECK(ptr, len)                  \
     396             :     do {                                              \
     397             :         if ((ptr) >= (len)) {                         \
     398             :             if (*srv_rr_list != NULL)                 \
     399             :                 resolver_srv_free(ctx, *srv_rr_list); \
     400             :             *srv_rr_list = NULL;                      \
     401             :             return XMPP_DOMAIN_NOT_FOUND;             \
     402             :         }                                             \
     403             :     } while (0)
     404             : 
     405           0 : static int resolver_raw_srv_lookup_buf(xmpp_ctx_t *ctx,
     406             :                                        const unsigned char *buf,
     407             :                                        size_t len,
     408             :                                        resolver_srv_rr_t **srv_rr_list)
     409             : {
     410           0 :     unsigned i;
     411           0 :     unsigned j;
     412           0 :     unsigned name_len;
     413           0 :     unsigned rdlength;
     414           0 :     uint16_t type;
     415           0 :     uint16_t class;
     416           0 :     struct message_header header;
     417           0 :     resolver_srv_rr_t *rr;
     418             : 
     419           0 :     *srv_rr_list = NULL;
     420             : 
     421           0 :     if (len < MESSAGE_HEADER_LEN)
     422             :         return XMPP_DOMAIN_NOT_FOUND;
     423             : 
     424           0 :     header.id = xmpp_ntohs_ptr(&buf[0]);
     425           0 :     header.octet2 = buf[2];
     426           0 :     header.octet3 = buf[3];
     427           0 :     header.qdcount = xmpp_ntohs_ptr(&buf[4]);
     428           0 :     header.ancount = xmpp_ntohs_ptr(&buf[6]);
     429           0 :     header.nscount = xmpp_ntohs_ptr(&buf[8]);
     430           0 :     header.arcount = xmpp_ntohs_ptr(&buf[10]);
     431           0 :     if (message_header_qr(&header) != MESSAGE_RESPONSE ||
     432           0 :         message_header_rcode(&header) != 0) {
     433             :         return XMPP_DOMAIN_NOT_FOUND;
     434             :     }
     435             :     j = MESSAGE_HEADER_LEN;
     436             : 
     437             :     /* skip question section */
     438           0 :     for (i = 0; i < header.qdcount; ++i) {
     439           0 :         BUF_OVERFLOW_CHECK(j, len);
     440           0 :         name_len = message_name_len(buf, len, j);
     441             :         /* error in name format */
     442           0 :         if (name_len == 0)
     443             :             return XMPP_DOMAIN_NOT_FOUND;
     444           0 :         j += name_len + 4;
     445             :     }
     446             : 
     447           0 :     for (i = 0; i < header.ancount; ++i) {
     448           0 :         BUF_OVERFLOW_CHECK(j, len);
     449           0 :         name_len = message_name_len(buf, len, j);
     450             :         /* error in name format */
     451           0 :         if (name_len == 0)
     452             :             return XMPP_DOMAIN_NOT_FOUND;
     453           0 :         j += name_len;
     454           0 :         BUF_OVERFLOW_CHECK(j + 16, len);
     455           0 :         type = xmpp_ntohs_ptr(&buf[j]);
     456           0 :         class = xmpp_ntohs_ptr(&buf[j + 2]);
     457           0 :         rdlength = xmpp_ntohs_ptr(&buf[j + 8]);
     458           0 :         j += 10;
     459           0 :         if (type == MESSAGE_T_SRV && class == MESSAGE_C_IN) {
     460           0 :             rr = resolver_srv_rr_new(ctx, NULL, 0, 0, 0);
     461           0 :             if (rr) {
     462           0 :                 rr->next = *srv_rr_list;
     463           0 :                 rr->priority = xmpp_ntohs_ptr(&buf[j]);
     464           0 :                 rr->weight = xmpp_ntohs_ptr(&buf[j + 2]);
     465           0 :                 rr->port = xmpp_ntohs_ptr(&buf[j + 4]);
     466           0 :                 name_len = message_name_get(buf, len, j + 6, rr->target,
     467             :                                             sizeof(rr->target));
     468           0 :                 if (name_len > 0)
     469           0 :                     *srv_rr_list = rr;
     470             :                 else
     471           0 :                     strophe_free(ctx, rr); /* skip broken record */
     472             :             }
     473             :         }
     474           0 :         j += rdlength;
     475             :     }
     476             : 
     477           0 :     return *srv_rr_list != NULL ? XMPP_DOMAIN_FOUND : XMPP_DOMAIN_NOT_FOUND;
     478             : }
     479             : 
     480             : #endif /* !HAVE_CARES */
     481             : 
     482             : #ifdef HAVE_CARES
     483             : /*******************************************************************************
     484             :  * Resolver implementation using c-ares library.
     485             :  ******************************************************************************/
     486             : 
     487             : struct resolver_ares_ctx {
     488             :     xmpp_ctx_t *ctx;
     489             :     int result;
     490             :     resolver_srv_rr_t *srv_rr_list;
     491             : };
     492             : 
     493             : static int resolver_ares_srv_lookup_buf(xmpp_ctx_t *ctx,
     494             :                                         const unsigned char *buf,
     495             :                                         size_t len,
     496             :                                         resolver_srv_rr_t **srv_rr_list)
     497             : {
     498             :     struct ares_srv_reply *srv;
     499             :     struct ares_srv_reply *item;
     500             :     resolver_srv_rr_t *rr;
     501             :     int rc;
     502             : 
     503             :     *srv_rr_list = NULL;
     504             : 
     505             :     rc = ares_parse_srv_reply(buf, len, &srv);
     506             :     if (rc != ARES_SUCCESS)
     507             :         return XMPP_DOMAIN_NOT_FOUND;
     508             : 
     509             :     item = srv;
     510             :     while (item != NULL) {
     511             :         rr = strophe_alloc(ctx, sizeof(*rr));
     512             :         if (rr == NULL)
     513             :             break;
     514             :         rr->next = *srv_rr_list;
     515             :         rr->priority = item->priority;
     516             :         rr->weight = item->weight;
     517             :         rr->port = item->port;
     518             :         strncpy(rr->target, item->host, sizeof(rr->target) - 1);
     519             :         rr->target[sizeof(rr->target) - 1] = '\0';
     520             :         *srv_rr_list = rr;
     521             :         item = item->next;
     522             :     }
     523             :     ares_free_data(srv);
     524             : 
     525             :     return *srv_rr_list == NULL ? XMPP_DOMAIN_NOT_FOUND : XMPP_DOMAIN_FOUND;
     526             : }
     527             : 
     528             : static void ares_srv_lookup_callback(
     529             :     void *arg, int status, int timeouts, unsigned char *buf, int len)
     530             : {
     531             :     struct resolver_ares_ctx *actx = arg;
     532             : 
     533             :     (void)timeouts;
     534             : 
     535             :     if (status != ARES_SUCCESS)
     536             :         actx->result = XMPP_DOMAIN_NOT_FOUND;
     537             :     else
     538             :         actx->result = resolver_ares_srv_lookup_buf(actx->ctx, buf, len,
     539             :                                                     &actx->srv_rr_list);
     540             : }
     541             : 
     542             : static int resolver_ares_srv_lookup(xmpp_ctx_t *ctx,
     543             :                                     const char *fulldomain,
     544             :                                     resolver_srv_rr_t **srv_rr_list)
     545             : {
     546             :     struct resolver_ares_ctx actx;
     547             :     ares_channel chan;
     548             :     struct timeval tv;
     549             :     struct timeval *tvp;
     550             :     fd_set rfds;
     551             :     fd_set wfds;
     552             :     int nfds;
     553             :     int rc;
     554             : 
     555             :     actx.ctx = ctx;
     556             :     actx.result = XMPP_DOMAIN_NOT_FOUND;
     557             :     actx.srv_rr_list = NULL;
     558             : 
     559             :     rc = ares_init(&chan);
     560             :     if (rc == ARES_SUCCESS) {
     561             :         ares_query(chan, fulldomain, MESSAGE_C_IN, MESSAGE_T_SRV,
     562             :                    ares_srv_lookup_callback, &actx);
     563             :         while (1) {
     564             :             FD_ZERO(&rfds);
     565             :             FD_ZERO(&wfds);
     566             :             nfds = ares_fds(chan, &rfds, &wfds);
     567             :             if (nfds == 0)
     568             :                 break;
     569             :             tvp = ares_timeout(chan, NULL, &tv);
     570             :             select(nfds, &rfds, &wfds, NULL, tvp);
     571             :             ares_process(chan, &rfds, &wfds);
     572             :         }
     573             :         ares_destroy(chan);
     574             :     }
     575             : 
     576             :     *srv_rr_list = actx.srv_rr_list;
     577             :     return actx.result;
     578             : }
     579             : 
     580             : #endif /* HAVE_CARES */
     581             : 
     582             : #if defined(_WIN32) && !defined(HAVE_CARES)
     583             : /*******************************************************************************
     584             :  * Next part was copied from sock.c and contains old win32 code.
     585             :  *
     586             :  * The idea is to get raw response from a name server and pass it to
     587             :  * resolver_srv_lookup_buf(). In fact, resolver_win32_srv_query() replaces
     588             :  * the call of res_query().
     589             :  * Dnsapi code is moved to a separated function resolver_srv_win32_lookup() and
     590             :  * changed to meet new API.
     591             :  *
     592             :  * XXX If the code is compiled it should work like before.
     593             :  ******************************************************************************/
     594             : 
     595             : #include <winsock2.h>
     596             : #include <ws2tcpip.h>
     597             : #include <windns.h>
     598             : #include <iphlpapi.h>
     599             : 
     600             : struct dnsquery_header {
     601             :     unsigned short id;
     602             :     unsigned char qr;
     603             :     unsigned char opcode;
     604             :     unsigned char aa;
     605             :     unsigned char tc;
     606             :     unsigned char rd;
     607             :     unsigned char ra;
     608             :     unsigned char z;
     609             :     unsigned char rcode;
     610             :     unsigned short qdcount;
     611             :     unsigned short ancount;
     612             :     unsigned short nscount;
     613             :     unsigned short arcount;
     614             : };
     615             : 
     616             : struct dnsquery_question {
     617             :     char qname[1024];
     618             :     unsigned short qtype;
     619             :     unsigned short qclass;
     620             : };
     621             : 
     622             : static void netbuf_add_16bitnum(unsigned char *buf,
     623             :                                 int buflen,
     624             :                                 int *offset,
     625             :                                 unsigned short num)
     626             : {
     627             :     unsigned char *start = buf + *offset;
     628             :     unsigned char *p = start;
     629             : 
     630             :     /* assuming big endian */
     631             :     *p++ = (num >> 8) & 0xff;
     632             :     *p++ = (num)&0xff;
     633             : 
     634             :     *offset += 2;
     635             : }
     636             : 
     637             : static void
     638             : netbuf_add_domain_name(unsigned char *buf, int buflen, int *offset, char *name)
     639             : {
     640             :     unsigned char *start = buf + *offset;
     641             :     unsigned char *p = start;
     642             :     unsigned char *wordstart, *wordend;
     643             : 
     644             :     wordstart = (unsigned char *)name;
     645             : 
     646             :     while (*wordstart) {
     647             :         int len;
     648             :         wordend = wordstart;
     649             :         while (*wordend && *wordend != '.') {
     650             :             wordend++;
     651             :         }
     652             : 
     653             :         len = (int)(wordend - wordstart);
     654             : 
     655             :         if (len > 0x3F) {
     656             :             len = 0x3F;
     657             :         }
     658             : 
     659             :         *p++ = len;
     660             : 
     661             :         while (wordstart != wordend) {
     662             :             *p++ = *wordstart++;
     663             :         }
     664             : 
     665             :         if (*wordstart == '.') {
     666             :             wordstart++;
     667             :         }
     668             :     }
     669             : 
     670             :     *p++ = '\0';
     671             : 
     672             :     *offset += (int)(p - start);
     673             : }
     674             : 
     675             : static void netbuf_add_dnsquery_header(unsigned char *buf,
     676             :                                        int buflen,
     677             :                                        int *offset,
     678             :                                        struct dnsquery_header *header)
     679             : {
     680             :     unsigned char *p;
     681             : 
     682             :     netbuf_add_16bitnum(buf, buflen, offset, header->id);
     683             : 
     684             :     p = buf + *offset;
     685             :     *p++ = ((header->qr & 0x01) << 7) | ((header->opcode & 0x0F) << 3) |
     686             :            ((header->aa & 0x01) << 2) | ((header->tc & 0x01) << 1) |
     687             :            ((header->rd & 0x01));
     688             :     *p++ = ((header->ra & 0x01) << 7) | ((header->z & 0x07) << 4) |
     689             :            ((header->rcode & 0x0F));
     690             :     *offset += 2;
     691             : 
     692             :     netbuf_add_16bitnum(buf, buflen, offset, header->qdcount);
     693             :     netbuf_add_16bitnum(buf, buflen, offset, header->ancount);
     694             :     netbuf_add_16bitnum(buf, buflen, offset, header->nscount);
     695             :     netbuf_add_16bitnum(buf, buflen, offset, header->arcount);
     696             : }
     697             : 
     698             : static void netbuf_add_dnsquery_question(unsigned char *buf,
     699             :                                          int buflen,
     700             :                                          int *offset,
     701             :                                          struct dnsquery_question *question)
     702             : {
     703             :     netbuf_add_domain_name(buf, buflen, offset, question->qname);
     704             :     netbuf_add_16bitnum(buf, buflen, offset, question->qtype);
     705             :     netbuf_add_16bitnum(buf, buflen, offset, question->qclass);
     706             : }
     707             : 
     708             : static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx,
     709             :                                      const char *fulldomain,
     710             :                                      resolver_srv_rr_t **srv_rr_list)
     711             : {
     712             :     resolver_srv_rr_t *rr;
     713             :     HINSTANCE hdnsapi = NULL;
     714             : 
     715             :     DNS_STATUS(WINAPI * pDnsQuery_A)
     716             :     (PCSTR, WORD, DWORD, PIP4_ARRAY, DNS_RECORDA **, PVOID *);
     717             :     void(WINAPI * pDnsRecordListFree)(DNS_RECORDA *, DNS_FREE_TYPE);
     718             : 
     719             :     if (hdnsapi = LoadLibrary("dnsapi.dll")) {
     720             :         pDnsQuery_A = (void *)GetProcAddress(hdnsapi, "DnsQuery_A");
     721             :         pDnsRecordListFree =
     722             :             (void *)GetProcAddress(hdnsapi, "DnsRecordListFree");
     723             : 
     724             :         if (pDnsQuery_A && pDnsRecordListFree) {
     725             :             DNS_RECORDA *dnsrecords = NULL;
     726             :             DNS_STATUS error;
     727             : 
     728             :             error = pDnsQuery_A(fulldomain, DNS_TYPE_SRV, DNS_QUERY_STANDARD,
     729             :                                 NULL, &dnsrecords, NULL);
     730             : 
     731             :             if (error == 0) {
     732             :                 DNS_RECORDA *current = dnsrecords;
     733             : 
     734             :                 while (current) {
     735             :                     if (current->wType == DNS_TYPE_SRV) {
     736             :                         rr = strophe_alloc(ctx, sizeof(*rr));
     737             :                         if (rr == NULL)
     738             :                             break;
     739             :                         rr->next = *srv_rr_list;
     740             :                         rr->port = current->Data.Srv.wPort;
     741             :                         rr->priority = current->Data.Srv.wPriority;
     742             :                         rr->weight = current->Data.Srv.wWeight;
     743             :                         strophe_snprintf(rr->target, sizeof(rr->target), "%s",
     744             :                                          current->Data.Srv.pNameTarget);
     745             :                         *srv_rr_list = rr;
     746             :                     }
     747             :                     current = current->pNext;
     748             :                 }
     749             :             }
     750             : 
     751             :             pDnsRecordListFree(dnsrecords, DnsFreeRecordList);
     752             :         }
     753             : 
     754             :         FreeLibrary(hdnsapi);
     755             :     }
     756             :     resolver_srv_list_sort(srv_rr_list);
     757             : 
     758             :     return *srv_rr_list != NULL ? XMPP_DOMAIN_FOUND : XMPP_DOMAIN_NOT_FOUND;
     759             : }
     760             : 
     761             : static int
     762             : resolver_win32_srv_query(const char *fulldomain, unsigned char *buf, size_t len)
     763             : {
     764             :     int set = 0;
     765             :     int insize = 0;
     766             : 
     767             :     /* if dnsapi didn't work/isn't there, try querying the dns server manually
     768             :      */
     769             :     if (!set) {
     770             :         struct dnsquery_header header;
     771             :         struct dnsquery_question question;
     772             :         int offset = 0;
     773             :         int addrlen;
     774             :         sock_t sock;
     775             :         struct sockaddr_in dnsaddr;
     776             :         char dnsserverips[16][256];
     777             :         int numdnsservers = 0;
     778             :         int j;
     779             : 
     780             :         /* Try getting the DNS server ips from GetNetworkParams() in iphlpapi
     781             :          * first */
     782             :         if (!numdnsservers) {
     783             :             HINSTANCE hiphlpapi = NULL;
     784             :             DWORD(WINAPI * pGetNetworkParams)(PFIXED_INFO, PULONG);
     785             : 
     786             :             if (hiphlpapi = LoadLibrary("Iphlpapi.dll")) {
     787             :                 pGetNetworkParams =
     788             :                     (void *)GetProcAddress(hiphlpapi, "GetNetworkParams");
     789             : 
     790             :                 if (pGetNetworkParams) {
     791             :                     FIXED_INFO *fi;
     792             :                     ULONG len;
     793             :                     DWORD error;
     794             :                     char buffer[65535];
     795             : 
     796             :                     len = 65535;
     797             :                     fi = (FIXED_INFO *)buffer;
     798             : 
     799             :                     if ((error = pGetNetworkParams(fi, &len)) ==
     800             :                         ERROR_SUCCESS) {
     801             :                         IP_ADDR_STRING *pias = &(fi->DnsServerList);
     802             : 
     803             :                         while (pias && numdnsservers < 16) {
     804             :                             strcpy(dnsserverips[numdnsservers++],
     805             :                                    pias->IpAddress.String);
     806             :                             pias = pias->Next;
     807             :                         }
     808             :                     }
     809             :                 }
     810             :             }
     811             :             FreeLibrary(hiphlpapi);
     812             :         }
     813             : 
     814             :         /* Next, try getting the DNS server ips from the registry */
     815             :         if (!numdnsservers) {
     816             :             HKEY search;
     817             :             LONG error;
     818             : 
     819             :             error = RegOpenKeyEx(
     820             :                 HKEY_LOCAL_MACHINE,
     821             :                 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0,
     822             :                 KEY_READ, &search);
     823             : 
     824             :             if (error != ERROR_SUCCESS) {
     825             :                 error = RegOpenKeyEx(
     826             :                     HKEY_LOCAL_MACHINE,
     827             :                     "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0,
     828             :                     KEY_READ, &search);
     829             :             }
     830             : 
     831             :             if (error == ERROR_SUCCESS) {
     832             :                 char name[512];
     833             :                 DWORD len = 512;
     834             : 
     835             :                 error = RegQueryValueEx(search, "NameServer", NULL, NULL,
     836             :                                         (LPBYTE)name, &len);
     837             : 
     838             :                 if (error != ERROR_SUCCESS) {
     839             :                     error = RegQueryValueEx(search, "DhcpNameServer", NULL,
     840             :                                             NULL, (LPBYTE)name, &len);
     841             :                 }
     842             : 
     843             :                 if (error == ERROR_SUCCESS) {
     844             :                     char *parse = "0123456789.", *start, *end;
     845             :                     start = name;
     846             :                     end = name;
     847             :                     name[len] = '\0';
     848             : 
     849             :                     while (*start && numdnsservers < 16) {
     850             :                         while (strchr(parse, *end)) {
     851             :                             end++;
     852             :                         }
     853             : 
     854             :                         strncpy(dnsserverips[numdnsservers++], start,
     855             :                                 end - start);
     856             : 
     857             :                         while (*end && !strchr(parse, *end)) {
     858             :                             end++;
     859             :                         }
     860             : 
     861             :                         start = end;
     862             :                     }
     863             :                 }
     864             :             }
     865             : 
     866             :             RegCloseKey(search);
     867             :         }
     868             : 
     869             :         if (!numdnsservers) {
     870             :             HKEY searchlist;
     871             :             LONG error;
     872             : 
     873             :             error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
     874             :                                  "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\P"
     875             :                                  "arameters\\Interfaces",
     876             :                                  0, KEY_READ, &searchlist);
     877             : 
     878             :             if (error == ERROR_SUCCESS) {
     879             :                 unsigned int i;
     880             :                 DWORD numinterfaces = 0;
     881             : 
     882             :                 RegQueryInfoKey(searchlist, NULL, NULL, NULL, &numinterfaces,
     883             :                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
     884             : 
     885             :                 for (i = 0; i < numinterfaces; i++) {
     886             :                     char name[512];
     887             :                     DWORD len = 512;
     888             :                     HKEY searchentry;
     889             : 
     890             :                     RegEnumKeyEx(searchlist, i, (LPTSTR)name, &len, NULL, NULL,
     891             :                                  NULL, NULL);
     892             : 
     893             :                     if (RegOpenKeyEx(searchlist, name, 0, KEY_READ,
     894             :                                      &searchentry) == ERROR_SUCCESS) {
     895             :                         if (RegQueryValueEx(searchentry, "DhcpNameServer", NULL,
     896             :                                             NULL, (LPBYTE)name,
     897             :                                             &len) == ERROR_SUCCESS) {
     898             :                             char *parse = "0123456789.", *start, *end;
     899             :                             start = name;
     900             :                             end = name;
     901             :                             name[len] = '\0';
     902             : 
     903             :                             while (*start && numdnsservers < 16) {
     904             :                                 while (strchr(parse, *end)) {
     905             :                                     end++;
     906             :                                 }
     907             : 
     908             :                                 strncpy(dnsserverips[numdnsservers++], start,
     909             :                                         end - start);
     910             : 
     911             :                                 while (*end && !strchr(parse, *end)) {
     912             :                                     end++;
     913             :                                 }
     914             : 
     915             :                                 start = end;
     916             :                             }
     917             :                         } else if (RegQueryValueEx(searchentry, "NameServer",
     918             :                                                    NULL, NULL, (LPBYTE)name,
     919             :                                                    &len) == ERROR_SUCCESS) {
     920             :                             char *parse = "0123456789.", *start, *end;
     921             :                             start = name;
     922             :                             end = name;
     923             :                             name[len] = '\0';
     924             : 
     925             :                             while (*start && numdnsservers < 16) {
     926             :                                 while (strchr(parse, *end)) {
     927             :                                     end++;
     928             :                                 }
     929             : 
     930             :                                 strncpy(dnsserverips[numdnsservers++], start,
     931             :                                         end - start);
     932             : 
     933             :                                 while (*end && !strchr(parse, *end)) {
     934             :                                     end++;
     935             :                                 }
     936             : 
     937             :                                 start = end;
     938             :                             }
     939             :                         }
     940             :                         RegCloseKey(searchentry);
     941             :                     }
     942             :                 }
     943             :                 RegCloseKey(searchlist);
     944             :             }
     945             :         }
     946             : 
     947             :         /* If we have a DNS server, use it */
     948             :         if (numdnsservers) {
     949             :             ULONG nonblocking = 1;
     950             :             int i;
     951             : 
     952             :             memset(&header, 0, sizeof(header));
     953             :             header.id = 12345; /* FIXME: Get a better id here */
     954             :             header.rd = 1;
     955             :             header.qdcount = 1;
     956             : 
     957             :             netbuf_add_dnsquery_header(buf, (int)len, &offset, &header);
     958             : 
     959             :             memset(&question, 0, sizeof(question));
     960             :             strncpy(question.qname, fulldomain, 1024);
     961             :             question.qtype = MESSAGE_T_SRV; /* SRV */
     962             :             question.qclass = MESSAGE_C_IN; /* INTERNET! */
     963             : 
     964             :             netbuf_add_dnsquery_question(buf, (int)len, &offset, &question);
     965             : 
     966             :             insize = 0;
     967             :             for (i = 0; i < numdnsservers && insize <= 0; i++) {
     968             :                 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
     969             :                 ioctlsocket(sock, FIONBIO, &nonblocking);
     970             : 
     971             :                 memset(&dnsaddr, 0, sizeof(dnsaddr));
     972             : 
     973             :                 dnsaddr.sin_family = AF_INET;
     974             :                 dnsaddr.sin_port = htons(53);
     975             :                 dnsaddr.sin_addr.s_addr = inet_addr(dnsserverips[i]);
     976             : 
     977             :                 addrlen = sizeof(dnsaddr);
     978             :                 sendto(sock, (char *)buf, offset, 0,
     979             :                        (struct sockaddr *)&dnsaddr, addrlen);
     980             :                 for (j = 0; j < 50; j++) {
     981             :                     insize = recvfrom(sock, (char *)buf, (int)len, 0,
     982             :                                       (struct sockaddr *)&dnsaddr, &addrlen);
     983             :                     if (insize == SOCKET_ERROR) {
     984             :                         if (sock_error() == WSAEWOULDBLOCK) {
     985             :                             Sleep(100);
     986             :                         } else {
     987             :                             break;
     988             :                         }
     989             :                     } else {
     990             :                         break;
     991             :                     }
     992             :                 }
     993             : 
     994             :                 closesocket(sock);
     995             :             }
     996             :             set = insize > 0;
     997             :         }
     998             :     }
     999             : 
    1000             :     return set ? insize : -1;
    1001             : }
    1002             : 
    1003             : #endif /* _WIN32 && !HAVE_CARES */

Generated by: LCOV version 1.14