LCOV - code coverage report
Current view: top level - src - resolver.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 4 168 2.4 %
Date: 2024-02-03 11:54:46 Functions: 2 11 18.2 %

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

Generated by: LCOV version 1.14