1968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
2968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold/* Copyright 1998 by the Massachusetts Institute of Technology.
3968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * Copyright (C) 2009 by Jakub Hrozek <jhrozek@redhat.com>
4968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold *
5968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * Permission to use, copy, modify, and distribute this
6968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * software and its documentation for any purpose and without
7968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * fee is hereby granted, provided that the above copyright
8968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * notice appear in all copies and that both that copyright
9968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * notice and this permission notice appear in supporting
10968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * documentation, and that the name of M.I.T. not be used in
11968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * advertising or publicity pertaining to distribution of the
12968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * software without specific, written prior permission.
13968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * M.I.T. makes no representations about the suitability of
14968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * this software for any purpose.  It is provided "as is"
15968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * without express or implied warranty.
16968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold */
17968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
18968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include "ares_setup.h"
19968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
20968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_SYS_SOCKET_H
21968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include <sys/socket.h>
22968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
23968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_NETINET_IN_H
24968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include <netinet/in.h>
25968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
26968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_NETDB_H
27968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include <netdb.h>
28968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
29968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_ARPA_INET_H
30968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include <arpa/inet.h>
31968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
32968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_ARPA_NAMESER_H
33968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include <arpa/nameser.h>
34968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#else
35968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include "nameser.h"
36968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
37968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_ARPA_NAMESER_COMPAT_H
38968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include <arpa/nameser_compat.h>
39968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
40968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
41968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_STRINGS_H
42968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include <strings.h>
43968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
44968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
45968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include <stdlib.h>
46968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include <string.h>
47968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
48968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include "ares.h"
49968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include "ares_dns.h"
50968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include "ares_data.h"
51968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include "ares_private.h"
52968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
53968bf19396ad404e89420f5d67900fce13f4186cGilad Arnoldint
54968bf19396ad404e89420f5d67900fce13f4186cGilad Arnoldares_parse_txt_reply (const unsigned char *abuf, int alen,
55968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                      struct ares_txt_reply **txt_out)
56968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold{
57968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  size_t substr_len, str_len;
58968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  unsigned int qdcount, ancount, i;
59968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  const unsigned char *aptr;
60968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  const unsigned char *strptr;
61968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  int status, rr_type, rr_class, rr_len;
62968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  long len;
63968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  char *hostname = NULL, *rr_name = NULL;
64968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  struct ares_txt_reply *txt_head = NULL;
65968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  struct ares_txt_reply *txt_last = NULL;
66968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  struct ares_txt_reply *txt_curr;
67968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
68968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  /* Set *txt_out to NULL for all failure cases. */
69968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  *txt_out = NULL;
70968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
71968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  /* Give up if abuf doesn't have room for a header. */
72968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (alen < HFIXEDSZ)
73968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    return ARES_EBADRESP;
74968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
75968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  /* Fetch the question and answer count from the header. */
76968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  qdcount = DNS_HEADER_QDCOUNT (abuf);
77968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  ancount = DNS_HEADER_ANCOUNT (abuf);
78968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (qdcount != 1)
79968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    return ARES_EBADRESP;
80968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (ancount == 0)
81968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    return ARES_ENODATA;
82968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
83968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  /* Expand the name from the question, and skip past the question. */
84968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  aptr = abuf + HFIXEDSZ;
85968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  status = ares_expand_name (aptr, abuf, alen, &hostname, &len);
86968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (status != ARES_SUCCESS)
87968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    return status;
88968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
89968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (aptr + len + QFIXEDSZ > abuf + alen)
90968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    {
91968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      free (hostname);
92968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      return ARES_EBADRESP;
93968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    }
94968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  aptr += len + QFIXEDSZ;
95968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
96968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  /* Examine each answer resource record (RR) in turn. */
97968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  for (i = 0; i < ancount; i++)
98968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    {
99968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      /* Decode the RR up to the data field. */
100968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      status = ares_expand_name (aptr, abuf, alen, &rr_name, &len);
101968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      if (status != ARES_SUCCESS)
102968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        {
103968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          break;
104968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        }
105968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      aptr += len;
106968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      if (aptr + RRFIXEDSZ > abuf + alen)
107968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        {
108968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          status = ARES_EBADRESP;
109968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          break;
110968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        }
111968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      rr_type = DNS_RR_TYPE (aptr);
112968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      rr_class = DNS_RR_CLASS (aptr);
113968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      rr_len = DNS_RR_LEN (aptr);
114968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      aptr += RRFIXEDSZ;
115968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
116968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      /* Check if we are really looking at a TXT record */
117968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      if (rr_class == C_IN && rr_type == T_TXT)
118968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        {
119968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          /* Allocate storage for this TXT answer appending it to the list */
120968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          txt_curr = ares_malloc_data(ARES_DATATYPE_TXT_REPLY);
121968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          if (!txt_curr)
122968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            {
123968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              status = ARES_ENOMEM;
124968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              break;
125968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            }
126968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          if (txt_last)
127968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            {
128968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              txt_last->next = txt_curr;
129968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            }
130968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          else
131968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            {
132968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              txt_head = txt_curr;
133968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            }
134968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          txt_last = txt_curr;
135968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
136968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          /*
137968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold           * There may be multiple substrings in a single TXT record. Each
138968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold           * substring may be up to 255 characters in length, with a
139968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold           * "length byte" indicating the size of the substring payload.
140968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold           * RDATA contains both the length-bytes and payloads of all
141968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold           * substrings contained therein.
142968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold           */
143968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
144968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          /* Compute total length to allow a single memory allocation */
145968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          strptr = aptr;
146968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          while (strptr < (aptr + rr_len))
147968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            {
148968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              substr_len = (unsigned char)*strptr;
149968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              txt_curr->length += substr_len;
150968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              strptr += substr_len + 1;
151968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            }
152968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
153968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          /* Including null byte */
154968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          txt_curr->txt = malloc (txt_curr->length + 1);
155968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          if (txt_curr->txt == NULL)
156968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            {
157968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              status = ARES_ENOMEM;
158968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              break;
159968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            }
160968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
161968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          /* Step through the list of substrings, concatenating them */
162968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          str_len = 0;
163968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          strptr = aptr;
164968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          while (strptr < (aptr + rr_len))
165968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            {
166968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              substr_len = (unsigned char)*strptr;
167968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              strptr++;
168968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              memcpy ((char *) txt_curr->txt + str_len, strptr, substr_len);
169968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              str_len += substr_len;
170968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              strptr += substr_len;
171968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            }
172968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          /* Make sure we NULL-terminate */
173968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          *((char *) txt_curr->txt + txt_curr->length) = '\0';
174968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        }
175968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
176968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      /* Don't lose memory in the next iteration */
177968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      free (rr_name);
178968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      rr_name = NULL;
179968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
180968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      /* Move on to the next record */
181968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      aptr += rr_len;
182968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    }
183968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
184968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (hostname)
185968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    free (hostname);
186968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (rr_name)
187968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    free (rr_name);
188968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
189968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  /* clean up on error */
190968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (status != ARES_SUCCESS)
191968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    {
192968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      if (txt_head)
193968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        ares_free_data (txt_head);
194968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      return status;
195968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    }
196968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
197968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  /* everything looks fine, return the data */
198968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  *txt_out = txt_head;
199968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
200968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  return ARES_SUCCESS;
201968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold}
202