removed tabs and trailing whitespace from source
[platform/upstream/c-ares.git] / ares_mkquery.c
1 /* Copyright 1998 by the Massachusetts Institute of Technology.
2  *
3  * Permission to use, copy, modify, and distribute this
4  * software and its documentation for any purpose and without
5  * fee is hereby granted, provided that the above copyright
6  * notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting
8  * documentation, and that the name of M.I.T. not be used in
9  * advertising or publicity pertaining to distribution of the
10  * software without specific, written prior permission.
11  * M.I.T. makes no representations about the suitability of
12  * this software for any purpose.  It is provided "as is"
13  * without express or implied warranty.
14  */
15
16 #include "setup.h"
17 #include <sys/types.h>
18
19 #if defined(WIN32) && !defined(WATT32)
20 #include "nameser.h"
21 #else
22 #include <netinet/in.h>
23 #include <arpa/nameser.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include "ares.h"
29 #include "ares_dns.h"
30
31 /* Header format, from RFC 1035:
32  *                                  1  1  1  1  1  1
33  *    0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
34  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
35  *  |                      ID                       |
36  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
37  *  |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
38  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
39  *  |                    QDCOUNT                    |
40  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
41  *  |                    ANCOUNT                    |
42  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
43  *  |                    NSCOUNT                    |
44  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
45  *  |                    ARCOUNT                    |
46  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
47  *
48  * AA, TC, RA, and RCODE are only set in responses.  Brief description
49  * of the remaining fields:
50  *      ID      Identifier to match responses with queries
51  *      QR      Query (0) or response (1)
52  *      Opcode  For our purposes, always QUERY
53  *      RD      Recursion desired
54  *      Z       Reserved (zero)
55  *      QDCOUNT Number of queries
56  *      ANCOUNT Number of answers
57  *      NSCOUNT Number of name server records
58  *      ARCOUNT Number of additional records
59  *
60  * Question format, from RFC 1035:
61  *                                  1  1  1  1  1  1
62  *    0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
63  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
64  *  |                                               |
65  *  /                     QNAME                     /
66  *  /                                               /
67  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
68  *  |                     QTYPE                     |
69  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
70  *  |                     QCLASS                    |
71  *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
72  *
73  * The query name is encoded as a series of labels, each represented
74  * as a one-byte length (maximum 63) followed by the text of the
75  * label.  The list is terminated by a label of length zero (which can
76  * be thought of as the root domain).
77  */
78
79 int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id,
80                  int rd, unsigned char **buf, int *buflen)
81 {
82   int len;
83   unsigned char *q;
84   const char *p;
85
86   /* Compute the length of the encoded name so we can check buflen.
87    * Start counting at 1 for the zero-length label at the end. */
88   len = 1;
89   for (p = name; *p; p++)
90     {
91       if (*p == '\\' && *(p + 1) != 0)
92         p++;
93       len++;
94     }
95   /* If there are n periods in the name, there are n + 1 labels, and
96    * thus n + 1 length fields, unless the name is empty or ends with a
97    * period.  So add 1 unless name is empty or ends with a period.
98    */
99   if (*name && *(p - 1) != '.')
100     len++;
101
102   *buflen = len + HFIXEDSZ + QFIXEDSZ;
103   *buf = malloc(*buflen);
104   if (!*buf)
105       return ARES_ENOMEM;
106
107   /* Set up the header. */
108   q = *buf;
109   memset(q, 0, HFIXEDSZ);
110   DNS_HEADER_SET_QID(q, id);
111   DNS_HEADER_SET_OPCODE(q, QUERY);
112   DNS_HEADER_SET_RD(q, (rd) ? 1 : 0);
113   DNS_HEADER_SET_QDCOUNT(q, 1);
114
115   /* A name of "." is a screw case for the loop below, so adjust it. */
116   if (strcmp(name, ".") == 0)
117     name++;
118
119   /* Start writing out the name after the header. */
120   q += HFIXEDSZ;
121   while (*name)
122     {
123       if (*name == '.')
124         return ARES_EBADNAME;
125
126       /* Count the number of bytes in this label. */
127       len = 0;
128       for (p = name; *p && *p != '.'; p++)
129         {
130           if (*p == '\\' && *(p + 1) != 0)
131             p++;
132           len++;
133         }
134       if (len > MAXLABEL)
135         return ARES_EBADNAME;
136
137       /* Encode the length and copy the data. */
138       *q++ = len;
139       for (p = name; *p && *p != '.'; p++)
140         {
141           if (*p == '\\' && *(p + 1) != 0)
142             p++;
143           *q++ = *p;
144         }
145
146       /* Go to the next label and repeat, unless we hit the end. */
147       if (!*p)
148         break;
149       name = p + 1;
150     }
151
152   /* Add the zero-length label at the end. */
153   *q++ = 0;
154
155   /* Finish off the question with the type and class. */
156   DNS_QUESTION_SET_TYPE(q, type);
157   DNS_QUESTION_SET_CLASS(q, dnsclass);
158
159   return ARES_SUCCESS;
160 }