Asterisk - The Open Source Telephony Project  21.4.1
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  * \return 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  * \return 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 ttl Time to live
133  * \param buf The buffer to write the answer into
134  * \return The number of bytes written to the buffer
135  */
136 static int generate_dns_answer(int ttl, char *buf)
137 {
138  int net_ttl = htonl(ttl);
139 
140  memcpy(buf, NAPTR_ANSWER, ARRAY_LEN(NAPTR_ANSWER));
141  /* Overwrite TTL if one is provided */
142  if (ttl) {
143  memcpy(&buf[6], &net_ttl, sizeof(int));
144  }
145 
146  return ARRAY_LEN(NAPTR_ANSWER);
147 }
148 
149 int ast_dns_test_write_string(const struct ast_dns_test_string *string, char *buf)
150 {
151  uint8_t len = string->len;
152  size_t actual_len = strlen(string->val);
153  buf[0] = len;
154  /*
155  * We use the actual length of the string instead of
156  * the stated value since sometimes we're going to lie about
157  * the length of the string
158  */
159  if (actual_len) {
160  memcpy(&buf[1], string->val, strlen(string->val));
161  }
162 
163  return actual_len + 1;
164 }
165 
166 int ast_dns_test_write_domain(const char *string, char *buf)
167 {
168  char *copy = ast_strdupa(string);
169  char *part;
170  char *ptr = buf;
171  static const struct ast_dns_test_string null_label = {
172  .len = 0,
173  .val = "",
174  };
175 
176  while (1) {
177  struct ast_dns_test_string dns_str;
178  part = strsep(&copy, ".");
179  if (ast_strlen_zero(part)) {
180  break;
181  }
182  dns_str.len = strlen(part);
183  dns_str.val = part;
184 
185  ptr += ast_dns_test_write_string(&dns_str, ptr);
186  }
187  ptr += ast_dns_test_write_string(&null_label, ptr);
188 
189  return ptr - buf;
190 }
191 
192 int ast_dns_test_generate_result(struct ast_dns_query *query, void *records, size_t num_records,
193  size_t record_size, record_fn generate, char *buffer)
194 {
195  char *ptr = buffer;
196  char *record_iter;
197 
198  ptr += generate_dns_header(num_records, ptr);
199  ptr += generate_dns_question(ptr);
200 
201  for (record_iter = records; record_iter < (char *) records + num_records * record_size; record_iter += record_size) {
202  unsigned short rdlength;
203  unsigned short net_rdlength;
204 
205  /* XXX Do we even want to override TTL? */
206  ptr += generate_dns_answer(0, ptr);
207  rdlength = generate(record_iter, ptr + 2);
208  net_rdlength = htons(rdlength);
209  memcpy(ptr, &net_rdlength, 2);
210  ptr += 2;
211  ptr += rdlength;
212  }
213 
214  return ptr - buffer;
215 }
216 
217 #else /* TEST_FRAMEWORK */
218 
219 int ast_dns_test_write_string(const struct ast_dns_test_string *string, char *buf)
220 {
221  return 0;
222 }
223 
224 int ast_dns_test_write_domain(const char *string, char *buf)
225 {
226  return 0;
227 }
228 
229 int ast_dns_test_generate_result(struct ast_dns_query *query, void *records, size_t num_records,
230  size_t record_size, record_fn generate, char *buffer)
231 {
232  return 0;
233 }
234 
235 #endif
Asterisk main include file. File version handling, generic pbx functions.
Representation of a string in DNS.
Definition: dns_test.h:33
static int copy(char *infile, char *outfile)
Utility function to copy a file.
Utility functions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
A DNS query.
Definition: dns_internal.h:137
Core DNS API.