Asterisk - The Open Source Telephony Project  18.5.0
dns_test.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2015, Digium, Inc.
5  *
6  * Mark Michelson <[email protected]>
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
static int records
Definition: cdr_mysql.c:84
Asterisk main include file. File version handling, generic pbx functions.
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
int ast_dns_test_generate_result(struct ast_dns_query *query, void *records, size_t num_records, size_t record_size, record_fn generate, char *buffer)
Generate a full DNS response for the given DNS records.
Definition: dns_test.c:222
Representation of a string in DNS.
Definition: dns_test.h:33
int(* record_fn)(void *record, char *buf)
Callback to write specific DNS record to an answer.
Definition: dns_test.h:85
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int copy(char *infile, char *outfile)
Utility function to copy a file.
static int generate_dns_question(char *buf)
Generate a DNS question and write it to a buffer.
Definition: dns_test.c:102
Utility functions.
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static int generate_dns_header(unsigned short num_records, char *buf)
Generate a DNS header and write it to a buffer.
Definition: dns_test.c:64
int ast_dns_test_write_domain(const char *string, char *buf)
Write a DNS domain to a buffer.
Definition: dns_test.c:196
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
A DNS query.
Definition: dns_internal.h:137
const char * val
Definition: dns_test.h:35
static int generate_dns_answer(int ttl, char *buf)
Generate a DNS answer and write it to a buffer.
Definition: dns_test.c:135
int ast_dns_test_write_string(const struct ast_dns_test_string *string, char *buf)
Write a DNS string to a buffer.
Definition: dns_test.c:162
char * strsep(char **str, const char *delims)
const char DNS_QUESTION[]
Definition: dns_test.c:75
const char NAPTR_ANSWER[]
Definition: dns_test.c:108
const char DNS_HEADER[]
Definition: dns_test.c:32
Core DNS API.