• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /* Copyright 1998 by the Massachusetts Institute of Technology.
3  *
4  * Permission to use, copy, modify, and distribute this
5  * software and its documentation for any purpose and without
6  * fee is hereby granted, provided that the above copyright
7  * notice appear in all copies and that both that copyright
8  * notice and this permission notice appear in supporting
9  * documentation, and that the name of M.I.T. not be used in
10  * advertising or publicity pertaining to distribution of the
11  * software without specific, written prior permission.
12  * M.I.T. makes no representations about the suitability of
13  * this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  */
16 
17 #include "ares_setup.h"
18 
19 #ifdef HAVE_NETINET_IN_H
20 #  include <netinet/in.h>
21 #endif
22 #ifdef HAVE_ARPA_NAMESER_H
23 #  include <arpa/nameser.h>
24 #else
25 #  include "nameser.h"
26 #endif
27 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
28 #  include <arpa/nameser_compat.h>
29 #endif
30 
31 #include "ares.h"
32 #include "ares_dns.h"
33 #include "ares_private.h"
34 
35 #ifndef T_OPT
36 #  define T_OPT  41 /* EDNS0 option (meta-RR) */
37 #endif
38 
39 /* Header format, from RFC 1035:
40  *                                  1  1  1  1  1  1
41  *    0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
42  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
43  *  |                      ID                       |
44  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
45  *  |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
46  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
47  *  |                    QDCOUNT                    |
48  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
49  *  |                    ANCOUNT                    |
50  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
51  *  |                    NSCOUNT                    |
52  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
53  *  |                    ARCOUNT                    |
54  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
55  *
56  * AA, TC, RA, and RCODE are only set in responses.  Brief description
57  * of the remaining fields:
58  *      ID      Identifier to match responses with queries
59  *      QR      Query (0) or response (1)
60  *      Opcode  For our purposes, always QUERY
61  *      RD      Recursion desired
62  *      Z       Reserved (zero)
63  *      QDCOUNT Number of queries
64  *      ANCOUNT Number of answers
65  *      NSCOUNT Number of name server records
66  *      ARCOUNT Number of additional records
67  *
68  * Question format, from RFC 1035:
69  *                                  1  1  1  1  1  1
70  *    0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
71  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
72  *  |                                               |
73  *  /                     QNAME                     /
74  *  /                                               /
75  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
76  *  |                     QTYPE                     |
77  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
78  *  |                     QCLASS                    |
79  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
80  *
81  * The query name is encoded as a series of labels, each represented
82  * as a one-byte length (maximum 63) followed by the text of the
83  * label.  The list is terminated by a label of length zero (which can
84  * be thought of as the root domain).
85  */
86 
ares_create_query(const char * name,int dnsclass,int type,unsigned short id,int rd,unsigned char ** bufp,int * buflenp,int max_udp_size)87 int ares_create_query(const char *name, int dnsclass, int type,
88                       unsigned short id, int rd, unsigned char **bufp,
89                       int *buflenp, int max_udp_size)
90 {
91   size_t len;
92   unsigned char *q;
93   const char *p;
94   size_t buflen;
95   unsigned char *buf;
96 
97   /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */
98   if (ares__is_onion_domain(name))
99     return ARES_ENOTFOUND;
100 
101   /* Set our results early, in case we bail out early with an error. */
102   *buflenp = 0;
103   *bufp = NULL;
104 
105   /* Allocate a memory area for the maximum size this packet might need. +2
106    * is for the length byte and zero termination if no dots or ecscaping is
107    * used.
108    */
109   len = strlen(name) + 2 + HFIXEDSZ + QFIXEDSZ +
110     (max_udp_size ? EDNSFIXEDSZ : 0);
111   buf = ares_malloc(len);
112   if (!buf)
113     return ARES_ENOMEM;
114 
115   /* Set up the header. */
116   q = buf;
117   memset(q, 0, HFIXEDSZ);
118   DNS_HEADER_SET_QID(q, id);
119   DNS_HEADER_SET_OPCODE(q, QUERY);
120   if (rd) {
121     DNS_HEADER_SET_RD(q, 1);
122   }
123   else {
124     DNS_HEADER_SET_RD(q, 0);
125   }
126   DNS_HEADER_SET_QDCOUNT(q, 1);
127 
128   if (max_udp_size) {
129       DNS_HEADER_SET_ARCOUNT(q, 1);
130   }
131 
132   /* A name of "." is a screw case for the loop below, so adjust it. */
133   if (strcmp(name, ".") == 0)
134     name++;
135 
136   /* Start writing out the name after the header. */
137   q += HFIXEDSZ;
138   while (*name)
139     {
140       if (*name == '.') {
141         ares_free (buf);
142         return ARES_EBADNAME;
143       }
144 
145       /* Count the number of bytes in this label. */
146       len = 0;
147       for (p = name; *p && *p != '.'; p++)
148         {
149           if (*p == '\\' && *(p + 1) != 0)
150             p++;
151           len++;
152         }
153       if (len > MAXLABEL) {
154         ares_free (buf);
155         return ARES_EBADNAME;
156       }
157 
158       /* Encode the length and copy the data. */
159       *q++ = (unsigned char)len;
160       for (p = name; *p && *p != '.'; p++)
161         {
162           if (*p == '\\' && *(p + 1) != 0)
163             p++;
164           *q++ = *p;
165         }
166 
167       /* Go to the next label and repeat, unless we hit the end. */
168       if (!*p)
169         break;
170       name = p + 1;
171     }
172 
173   /* Add the zero-length label at the end. */
174   *q++ = 0;
175 
176   /* Finish off the question with the type and class. */
177   DNS_QUESTION_SET_TYPE(q, type);
178   DNS_QUESTION_SET_CLASS(q, dnsclass);
179 
180   q += QFIXEDSZ;
181   if (max_udp_size)
182   {
183       memset(q, 0, EDNSFIXEDSZ);
184       q++;
185       DNS_RR_SET_TYPE(q, T_OPT);
186       DNS_RR_SET_CLASS(q, max_udp_size);
187       q += (EDNSFIXEDSZ-1);
188   }
189   buflen = (q - buf);
190 
191   /* Reject names that are longer than the maximum of 255 bytes that's
192    * specified in RFC 1035 ("To simplify implementations, the total length of
193    * a domain name (i.e., label octets and label length octets) is restricted
194    * to 255 octets or less."). */
195   if (buflen > (size_t)(MAXCDNAME + HFIXEDSZ + QFIXEDSZ +
196                 (max_udp_size ? EDNSFIXEDSZ : 0))) {
197     ares_free (buf);
198     return ARES_EBADNAME;
199   }
200 
201   /* we know this fits in an int at this point */
202   *buflenp = (int) buflen;
203   *bufp = buf;
204 
205   return ARES_SUCCESS;
206 }
207