summaryrefslogtreecommitdiff
path: root/main/dns_test.c
blob: 5ec994aed7e6e9adbb15f9495f0d12694b79f507 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
/*
 * Asterisk -- An open source telephony toolkit.
 *
 * Copyright (C) 2015, Digium, Inc.
 *
 * Mark Michelson <mmichelson@digium.com>
 *
 * Includes code and algorithms from the Zapata library.
 *
 * See http://www.asterisk.org for more information about
 * the Asterisk project. Please do not directly contact
 * any of the maintainers of this project for assistance;
 * the project provides a web site, mailing lists and IRC
 * channels for your use.
 *
 * This program is free software, distributed under the terms of
 * the GNU General Public License Version 2. See the LICENSE file
 * at the top of the source tree.
 */

/*** MODULEINFO
	<support_level>core</support_level>
 ***/

#include "asterisk.h"
#include "asterisk/dns_core.h"
#include "asterisk/dns_test.h"
#include "asterisk/utils.h"

#ifdef TEST_FRAMEWORK

const char DNS_HEADER[] = {
	/* ID  == 0 */
	0x00, 0x00,
	/* QR == 1, Opcode == 0, AA == 1, TC == 0, RD == 1 */
	0x85,
	/* RA == 1, Z == 0, RCODE == 0 */
	0x80,
	/* QDCOUNT == 1 */
	0x00, 0x01,
	/* ANCOUNT == 1 */
	0x00, 0x00,
	/* NSCOUNT == 0 */
	0x00, 0x00,
	/* ARCOUNT == 0 */
	0x00, 0x00,
};

/*!
 * \brief Generate a DNS header and write it to a buffer
 *
 * The DNS header is the first part of a DNS request or response. In our
 * case, the only part of the header that a test can affect is the number
 * of answers. The rest of the DNS header is based on hard-coded values.
 *
 * There is no buffer size passed to this function since we provide
 * the data ourselves and have sized the buffer to be way larger
 * than necessary for the tests.
 *
 * \param num_records The number of DNS records in this DNS response
 * \param buf The buffer to write the header into
 * \retval The number of bytes written to the buffer
 */
static int generate_dns_header(unsigned short num_records, char *buf)
{
	unsigned short net_num_records = htons(num_records);

	memcpy(buf, DNS_HEADER, ARRAY_LEN(DNS_HEADER));
	/* Overwrite the ANCOUNT with the actual number of answers */
	memcpy(&buf[6], &net_num_records, sizeof(num_records));

	return ARRAY_LEN(DNS_HEADER);
}

const char DNS_QUESTION [] = {
	/* goose */
	0x05, 0x67, 0x6f, 0x6f, 0x73, 0x65,
	/* feathers */
	0x08, 0x66, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x73,
	/* end label */
	0x00,
	/* NAPTR type */
	0x00, 0x23,
	/* IN class */
	0x00, 0x01,
};

/*!
 * \brief Generate a DNS question and write it to a buffer
 *
 * The DNS question is the second part of a DNS request or response.
 * All DNS questions in this file are for the same domain and thus
 * the DNS question is a hard-coded value.
 *
 * There is no buffer size passed to this function since we provide
 * the data ourselves and have sized the buffer to be way larger
 * than necessary for the tests.
 *
 * \param buf The buffer to write the question into
 * \retval The number of bytes written to the buffer
 */
static int generate_dns_question(char *buf)
{
	memcpy(buf, DNS_QUESTION, ARRAY_LEN(DNS_QUESTION));
	return ARRAY_LEN(DNS_QUESTION);
}

const char NAPTR_ANSWER [] = {
	/* Domain points to name from question */
	0xc0, 0x0c,
	/* NAPTR type */
	0x00, 0x23,
	/* IN Class */
	0x00, 0x01,
	/* TTL (12345 by default) */
	0x00, 0x00, 0x30, 0x39,
};

/*!
 * \brief Generate a DNS answer and write it to a buffer
 *
 * The DNS answer is the third (and in our case final) part of a
 * DNS response. The DNS answer generated here is only partial.
 * The record-specific data is generated by a separate function.
 * DNS answers in our tests may have variable TTLs, but the rest
 * is hard-coded.
 *
 * There is no buffer size passed to this function since we provide
 * the data ourselves and have sized the buffer to be way larger
 * than necessary for the tests.
 *
 * \param buf The buffer to write the answer into
 * \retval The number of bytes written to the buffer
 */
static int generate_dns_answer(int ttl, char *buf)
{
	int net_ttl = htonl(ttl);

	memcpy(buf, NAPTR_ANSWER, ARRAY_LEN(NAPTR_ANSWER));
	/* Overwrite TTL if one is provided */
	if (ttl) {
		memcpy(&buf[6], &net_ttl, sizeof(int));
	}

	return ARRAY_LEN(NAPTR_ANSWER);
}

/*!
 * \brief Write a DNS string to a buffer
 *
 * This writes the DNS string to the buffer and returns the total
 * number of bytes written to the buffer.
 *
 * There is no buffer size passed to this function since we provide
 * the data ourselves and have sized the buffer to be way larger
 * than necessary for the tests.
 *
 * \param string The string to write
 * \param buf The buffer to write the string into
 * \return The number of bytes written to the buffer
 */
int ast_dns_test_write_string(const struct ast_dns_test_string *string, char *buf)
{
	uint8_t len = string->len;
	size_t actual_len = strlen(string->val);
	buf[0] = len;
	/*
	 * We use the actual length of the string instead of
	 * the stated value since sometimes we're going to lie about
	 * the length of the string
	 */
	if (actual_len) {
		memcpy(&buf[1], string->val, strlen(string->val));
	}

	return actual_len + 1;
}

/*!
 * \brief Write a DNS domain to a buffer
 *
 * A DNS domain consists of a series of labels separated
 * by dots. Each of these labels gets written as a DNS
 * string. A DNS domain ends with a NULL label, which is
 * essentially a zero-length DNS string.
 *
 *
 * There is no buffer size passed to this function since we provide
 * the data ourselves and have sized the buffer to be way larger
 * than necessary for the tests.
 *
 * \param string The DNS domain to write
 * \param buf The buffer to write the domain into
 * \return The number of bytes written to the buffer
 */
int ast_dns_test_write_domain(const char *string, char *buf)
{
	char *copy = ast_strdupa(string);
	char *part;
	char *ptr = buf;
	static const struct ast_dns_test_string null_label = {
		.len = 0,
		.val = "",
	};

	while (1) {
		struct ast_dns_test_string dns_str;
		part = strsep(&copy, ".");
		if (ast_strlen_zero(part)) {
			break;
		}
		dns_str.len = strlen(part);
		dns_str.val = part;

		ptr += ast_dns_test_write_string(&dns_str, ptr);
	}
	ptr += ast_dns_test_write_string(&null_label, ptr);

	return ptr - buf;
}

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)
{
	char *ptr = buffer;
	char *record_iter;

	ptr += generate_dns_header(num_records, ptr);
	ptr += generate_dns_question(ptr);

	for (record_iter = records; record_iter < (char *) records + num_records * record_size; record_iter += record_size) {
		unsigned short rdlength;
		unsigned short net_rdlength;

		/* XXX Do we even want to override TTL? */
		ptr += generate_dns_answer(0, ptr);
		rdlength = generate(record_iter, ptr + 2);
		net_rdlength = htons(rdlength);
		memcpy(ptr, &net_rdlength, 2);
		ptr += 2;
		ptr += rdlength;
	}

	return ptr - buffer;
}

#else /* TEST_FRAMEWORK */

int ast_dns_test_write_string(const struct ast_dns_test_string *string, char *buf)
{
	return 0;
}

int ast_dns_test_write_domain(const char *string, char *buf)
{
	return 0;
}

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)
{
	return 0;
}

#endif