| 
									
										
										
										
											2015-04-09 14:58:02 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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 | 
					
						
							| 
									
										
										
										
											2021-11-27 20:11:37 +01:00
										 |  |  |  * \return The number of bytes written to the buffer | 
					
						
							| 
									
										
										
										
											2015-04-09 14:58:02 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 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 | 
					
						
							| 
									
										
										
										
											2021-11-27 20:11:37 +01:00
										 |  |  |  * \return The number of bytes written to the buffer | 
					
						
							| 
									
										
										
										
											2015-04-09 14:58:02 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 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. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-11-27 20:11:37 +01:00
										 |  |  |  * \param ttl Time to live | 
					
						
							| 
									
										
										
										
											2015-04-09 14:58:02 +00:00
										 |  |  |  * \param buf The buffer to write the answer into | 
					
						
							| 
									
										
										
										
											2021-11-27 20:11:37 +01:00
										 |  |  |  * \return The number of bytes written to the buffer | 
					
						
							| 
									
										
										
										
											2015-04-09 14:58:02 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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(©, "."); | 
					
						
							|  |  |  | 		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 */
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-10 13:32:24 +00:00
										 |  |  | int ast_dns_test_write_string(const struct ast_dns_test_string *string, char *buf) | 
					
						
							| 
									
										
										
										
											2015-04-09 14:58:02 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	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
 |