CI: Various updates to buildAsterisk.sh
[asterisk/asterisk.git] / main / dns_test.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2015, Digium, Inc.
5  *
6  * Mark Michelson <mmichelson@digium.com>
7  *
8  * Includes code and algorithms from the Zapata library.
9  *
10  * See http://www.asterisk.org for more information about
11  * the Asterisk project. Please do not directly contact
12  * any of the maintainers of this project for assistance;
13  * the project provides a web site, mailing lists and IRC
14  * channels for your use.
15  *
16  * This program is free software, distributed under the terms of
17  * the GNU General Public License Version 2. See the LICENSE file
18  * at the top of the source tree.
19  */
20
21 /*** MODULEINFO
22         <support_level>core</support_level>
23  ***/
24
25 #include "asterisk.h"
26 #include "asterisk/dns_core.h"
27 #include "asterisk/dns_test.h"
28 #include "asterisk/utils.h"
29
30 #ifdef TEST_FRAMEWORK
31
32 const char DNS_HEADER[] = {
33         /* ID  == 0 */
34         0x00, 0x00,
35         /* QR == 1, Opcode == 0, AA == 1, TC == 0, RD == 1 */
36         0x85,
37         /* RA == 1, Z == 0, RCODE == 0 */
38         0x80,
39         /* QDCOUNT == 1 */
40         0x00, 0x01,
41         /* ANCOUNT == 1 */
42         0x00, 0x00,
43         /* NSCOUNT == 0 */
44         0x00, 0x00,
45         /* ARCOUNT == 0 */
46         0x00, 0x00,
47 };
48
49 /*!
50  * \brief Generate a DNS header and write it to a buffer
51  *
52  * The DNS header is the first part of a DNS request or response. In our
53  * case, the only part of the header that a test can affect is the number
54  * of answers. The rest of the DNS header is based on hard-coded values.
55  *
56  * There is no buffer size passed to this function since we provide
57  * the data ourselves and have sized the buffer to be way larger
58  * than necessary for the tests.
59  *
60  * \param num_records The number of DNS records in this DNS response
61  * \param buf The buffer to write the header into
62  * \retval The number of bytes written to the buffer
63  */
64 static int generate_dns_header(unsigned short num_records, char *buf)
65 {
66         unsigned short net_num_records = htons(num_records);
67
68         memcpy(buf, DNS_HEADER, ARRAY_LEN(DNS_HEADER));
69         /* Overwrite the ANCOUNT with the actual number of answers */
70         memcpy(&buf[6], &net_num_records, sizeof(num_records));
71
72         return ARRAY_LEN(DNS_HEADER);
73 }
74
75 const char DNS_QUESTION [] = {
76         /* goose */
77         0x05, 0x67, 0x6f, 0x6f, 0x73, 0x65,
78         /* feathers */
79         0x08, 0x66, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x73,
80         /* end label */
81         0x00,
82         /* NAPTR type */
83         0x00, 0x23,
84         /* IN class */
85         0x00, 0x01,
86 };
87
88 /*!
89  * \brief Generate a DNS question and write it to a buffer
90  *
91  * The DNS question is the second part of a DNS request or response.
92  * All DNS questions in this file are for the same domain and thus
93  * the DNS question is a hard-coded value.
94  *
95  * There is no buffer size passed to this function since we provide
96  * the data ourselves and have sized the buffer to be way larger
97  * than necessary for the tests.
98  *
99  * \param buf The buffer to write the question into
100  * \retval The number of bytes written to the buffer
101  */
102 static int generate_dns_question(char *buf)
103 {
104         memcpy(buf, DNS_QUESTION, ARRAY_LEN(DNS_QUESTION));
105         return ARRAY_LEN(DNS_QUESTION);
106 }
107
108 const char NAPTR_ANSWER [] = {
109         /* Domain points to name from question */
110         0xc0, 0x0c,
111         /* NAPTR type */
112         0x00, 0x23,
113         /* IN Class */
114         0x00, 0x01,
115         /* TTL (12345 by default) */
116         0x00, 0x00, 0x30, 0x39,
117 };
118
119 /*!
120  * \brief Generate a DNS answer and write it to a buffer
121  *
122  * The DNS answer is the third (and in our case final) part of a
123  * DNS response. The DNS answer generated here is only partial.
124  * The record-specific data is generated by a separate function.
125  * DNS answers in our tests may have variable TTLs, but the rest
126  * is hard-coded.
127  *
128  * There is no buffer size passed to this function since we provide
129  * the data ourselves and have sized the buffer to be way larger
130  * than necessary for the tests.
131  *
132  * \param buf The buffer to write the answer into
133  * \retval The number of bytes written to the buffer
134  */
135 static int generate_dns_answer(int ttl, char *buf)
136 {
137         int net_ttl = htonl(ttl);
138
139         memcpy(buf, NAPTR_ANSWER, ARRAY_LEN(NAPTR_ANSWER));
140         /* Overwrite TTL if one is provided */
141         if (ttl) {
142                 memcpy(&buf[6], &net_ttl, sizeof(int));
143         }
144
145         return ARRAY_LEN(NAPTR_ANSWER);
146 }
147
148 /*!
149  * \brief Write a DNS string to a buffer
150  *
151  * This writes the DNS string to the buffer and returns the total
152  * number of bytes written to the buffer.
153  *
154  * There is no buffer size passed to this function since we provide
155  * the data ourselves and have sized the buffer to be way larger
156  * than necessary for the tests.
157  *
158  * \param string The string to write
159  * \param buf The buffer to write the string into
160  * \return The number of bytes written to the buffer
161  */
162 int ast_dns_test_write_string(const struct ast_dns_test_string *string, char *buf)
163 {
164         uint8_t len = string->len;
165         size_t actual_len = strlen(string->val);
166         buf[0] = len;
167         /*
168          * We use the actual length of the string instead of
169          * the stated value since sometimes we're going to lie about
170          * the length of the string
171          */
172         if (actual_len) {
173                 memcpy(&buf[1], string->val, strlen(string->val));
174         }
175
176         return actual_len + 1;
177 }
178
179 /*!
180  * \brief Write a DNS domain to a buffer
181  *
182  * A DNS domain consists of a series of labels separated
183  * by dots. Each of these labels gets written as a DNS
184  * string. A DNS domain ends with a NULL label, which is
185  * essentially a zero-length DNS string.
186  *
187  *
188  * There is no buffer size passed to this function since we provide
189  * the data ourselves and have sized the buffer to be way larger
190  * than necessary for the tests.
191  *
192  * \param string The DNS domain to write
193  * \param buf The buffer to write the domain into
194  * \return The number of bytes written to the buffer
195  */
196 int ast_dns_test_write_domain(const char *string, char *buf)
197 {
198         char *copy = ast_strdupa(string);
199         char *part;
200         char *ptr = buf;
201         static const struct ast_dns_test_string null_label = {
202                 .len = 0,
203                 .val = "",
204         };
205
206         while (1) {
207                 struct ast_dns_test_string dns_str;
208                 part = strsep(&copy, ".");
209                 if (ast_strlen_zero(part)) {
210                         break;
211                 }
212                 dns_str.len = strlen(part);
213                 dns_str.val = part;
214
215                 ptr += ast_dns_test_write_string(&dns_str, ptr);
216         }
217         ptr += ast_dns_test_write_string(&null_label, ptr);
218
219         return ptr - buf;
220 }
221
222 int ast_dns_test_generate_result(struct ast_dns_query *query, void *records, size_t num_records,
223                 size_t record_size, record_fn generate, char *buffer)
224 {
225         char *ptr = buffer;
226         char *record_iter;
227
228         ptr += generate_dns_header(num_records, ptr);
229         ptr += generate_dns_question(ptr);
230
231         for (record_iter = records; record_iter < (char *) records + num_records * record_size; record_iter += record_size) {
232                 unsigned short rdlength;
233                 unsigned short net_rdlength;
234
235                 /* XXX Do we even want to override TTL? */
236                 ptr += generate_dns_answer(0, ptr);
237                 rdlength = generate(record_iter, ptr + 2);
238                 net_rdlength = htons(rdlength);
239                 memcpy(ptr, &net_rdlength, 2);
240                 ptr += 2;
241                 ptr += rdlength;
242         }
243
244         return ptr - buffer;
245 }
246
247 #else /* TEST_FRAMEWORK */
248
249 int ast_dns_test_write_string(const struct ast_dns_test_string *string, char *buf)
250 {
251         return 0;
252 }
253
254 int ast_dns_test_write_domain(const char *string, char *buf)
255 {
256         return 0;
257 }
258
259 int ast_dns_test_generate_result(struct ast_dns_query *query, void *records, size_t num_records,
260                 size_t record_size, record_fn generate, char *buffer)
261 {
262         return 0;
263 }
264
265 #endif