mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 18:55:19 +00:00 
			
		
		
		
	Add missing DNS NAPTR test file.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@434154 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
		
							
								
								
									
										715
									
								
								tests/test_dns_naptr.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										715
									
								
								tests/test_dns_naptr.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,715 @@ | ||||
| /* | ||||
|  * Asterisk -- An open source telephony toolkit. | ||||
|  * | ||||
|  * Copyright (C) 2015, Mark Michelson | ||||
|  * | ||||
|  * Mark Michelson <mmichelson@digium.com> | ||||
|  * | ||||
|  * 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 | ||||
| 	<depend>TEST_FRAMEWORK</depend> | ||||
| 	<support_level>core</support_level> | ||||
|  ***/ | ||||
|  | ||||
| #include "asterisk.h" | ||||
|  | ||||
| #include <arpa/nameser.h> | ||||
|  | ||||
| #include "asterisk/test.h" | ||||
| #include "asterisk/module.h" | ||||
| #include "asterisk/dns_core.h" | ||||
| #include "asterisk/dns_resolver.h" | ||||
| #include "asterisk/dns_naptr.h" | ||||
|  | ||||
| #define DNS_HEADER_SIZE 96 | ||||
|  | ||||
| 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 Representation of a string in DNS | ||||
|  * | ||||
|  * In DNS, a string has a byte to indicate the length, | ||||
|  * followed by a series of bytes representing the string. | ||||
|  * DNS does not NULL-terminate its strings. | ||||
|  */ | ||||
| struct dns_string { | ||||
| 	uint8_t len; | ||||
| 	const char *val; | ||||
| }; | ||||
|  | ||||
| /*! | ||||
|  * \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 | ||||
|  */ | ||||
| static int write_dns_string(const struct dns_string *string, char *buf) | ||||
| { | ||||
| 	uint8_t len = string->len; | ||||
| 	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 (strlen(string->val)) { | ||||
| 		memcpy(&buf[1], string->val, strlen(string->val)); | ||||
| 	} | ||||
|  | ||||
| 	return strlen(string->val) + 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 | ||||
|  */ | ||||
| static int write_dns_domain(const char *string, char *buf) | ||||
| { | ||||
| 	char *copy = ast_strdupa(string); | ||||
| 	char *part; | ||||
| 	char *ptr = buf; | ||||
| 	static const struct dns_string null_label = { | ||||
| 		.len = 0, | ||||
| 		.val = "", | ||||
| 	}; | ||||
|  | ||||
| 	while (1) { | ||||
| 		struct dns_string dns_str; | ||||
| 		part = strsep(©, "."); | ||||
| 		if (ast_strlen_zero(part)) { | ||||
| 			break; | ||||
| 		} | ||||
| 		dns_str.len = strlen(part); | ||||
| 		dns_str.val = part; | ||||
|  | ||||
| 		ptr += write_dns_string(&dns_str, ptr); | ||||
| 	} | ||||
| 	ptr += write_dns_string(&null_label, ptr); | ||||
|  | ||||
| 	return ptr - buf; | ||||
| } | ||||
|  | ||||
| struct naptr_record { | ||||
| 	uint16_t order; | ||||
| 	uint16_t preference; | ||||
| 	struct dns_string flags; | ||||
| 	struct dns_string services; | ||||
| 	struct dns_string regexp; | ||||
| 	const char * replacement; | ||||
| }; | ||||
|  | ||||
| /*! | ||||
|  * \brief Given a NAPTR record, generate a binary form, as would appear in DNS RDATA | ||||
|  * | ||||
|  * This is part of a DNS answer, specific to NAPTR. It consists of all parts of | ||||
|  * the NAPTR record, encoded as it should be in a DNS record. | ||||
|  * | ||||
|  * 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 NAPTR record to encode | ||||
|  * \param buf The buffer to write the record into | ||||
|  * \return The number of bytes written to the buffer | ||||
|  */ | ||||
| static int generate_naptr_record(struct naptr_record *record, char *buf) | ||||
| { | ||||
| 	uint16_t net_order = htons(record->order); | ||||
| 	uint16_t net_preference = htons(record->preference); | ||||
| 	char *ptr = buf; | ||||
|  | ||||
| 	memcpy(ptr, &net_order, sizeof(net_order)); | ||||
| 	ptr += sizeof(net_order); | ||||
|  | ||||
| 	memcpy(ptr, &net_preference, sizeof(net_preference)); | ||||
| 	ptr += sizeof(net_preference); | ||||
|  | ||||
| 	ptr += write_dns_string(&record->flags, ptr); | ||||
| 	ptr += write_dns_string(&record->services, ptr); | ||||
| 	ptr += write_dns_string(&record->regexp, ptr); | ||||
| 	ptr += write_dns_domain(record->replacement, ptr); | ||||
|  | ||||
| 	return ptr - buf; | ||||
| } | ||||
|  | ||||
| /*! | ||||
|  * \brief A pointer to an array of records for a test | ||||
|  * | ||||
|  * Each test is expected to set this pointer to its local | ||||
|  * array of records and then re-set tis pointer to NULL | ||||
|  * at the end of the test | ||||
|  */ | ||||
| static struct naptr_record *test_records; | ||||
| /*! | ||||
|  * \brief The number of records in the test_records array. | ||||
|  * | ||||
|  * Each test must set this to the appropriate value at the | ||||
|  * beginning of the test and must set this back to zero at | ||||
|  * the end of the test. | ||||
|  */ | ||||
| static int num_test_records; | ||||
| /*! | ||||
|  * \brief A buffer to place raw DNS records into. | ||||
|  * | ||||
|  * This buffer is way larger than any DNS records we actually | ||||
|  * wish to create during any of the tests, but that's fine. | ||||
|  */ | ||||
| static char ans_buffer[1024]; | ||||
|  | ||||
| /*! | ||||
|  * \brief Asynchronous NAPTR resolution thread. | ||||
|  * | ||||
|  * This builds an appropriate DNS response based on the NAPTR | ||||
|  * records for a given test. Once the records have been created, | ||||
|  * the records are added to the DNS result | ||||
|  */ | ||||
| static void *naptr_thread(void *dns_query) | ||||
| { | ||||
| 	struct ast_dns_query *query = dns_query; | ||||
| 	int i; | ||||
| 	char *ptr = ans_buffer; | ||||
|  | ||||
| 	ptr += generate_dns_header(num_test_records, ptr); | ||||
| 	ptr += generate_dns_question(ptr); | ||||
|  | ||||
| 	for (i = 0; i < num_test_records; ++i) { | ||||
| 		unsigned short rdlength; | ||||
| 		unsigned short net_rdlength; | ||||
|  | ||||
| 		ptr += generate_dns_answer(0, ptr); | ||||
| 		rdlength = generate_naptr_record(&test_records[i], ptr + 2); | ||||
| 		net_rdlength = htons(rdlength); | ||||
| 		memcpy(ptr, &net_rdlength, 2); | ||||
| 		ptr += 2; | ||||
| 		ptr += rdlength; | ||||
| 	} | ||||
|  | ||||
| 	ast_dns_resolver_set_result(query, 0, 0, ns_r_noerror, "goose.feathers", ans_buffer, ptr - ans_buffer); | ||||
|  | ||||
| 	for (i = 0; i < num_test_records; ++i) { | ||||
| 		char record[128]; | ||||
| 		ptr = record; | ||||
|  | ||||
| 		ptr += generate_naptr_record(&test_records[i], ptr); | ||||
| 		ast_dns_resolver_add_record(query, ns_t_naptr, ns_c_in, 12345, record, ptr - record); | ||||
| 	} | ||||
|  | ||||
| 	ast_dns_resolver_completed(query); | ||||
|  | ||||
| 	ao2_ref(query, -1); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| /*! | ||||
|  * \brief Mock NAPTR resolution method. | ||||
|  * | ||||
|  * This spawns a thread to handle generation of the necessary NAPTR records | ||||
|  */ | ||||
| static int naptr_resolve(struct ast_dns_query *query) | ||||
| { | ||||
| 	pthread_t thread; | ||||
|  | ||||
| 	return ast_pthread_create_detached(&thread, NULL, naptr_thread, ao2_bump(query)); | ||||
| } | ||||
|  | ||||
| /*! | ||||
|  * \brief A STUB | ||||
|  */ | ||||
| static int naptr_cancel(struct ast_dns_query *query) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /*! | ||||
|  * \brief Mock NAPTR resolver | ||||
|  */ | ||||
| static struct ast_dns_resolver naptr_resolver = { | ||||
| 	.name = "naptr_test", | ||||
| 	.priority = 0, | ||||
| 	.resolve = naptr_resolve, | ||||
| 	.cancel = naptr_cancel, | ||||
| }; | ||||
|  | ||||
| AST_TEST_DEFINE(naptr_resolve_nominal) | ||||
| { | ||||
| 	RAII_VAR(struct ast_dns_result *, result, NULL, ast_dns_result_free); | ||||
| 	const struct ast_dns_record *record; | ||||
| 	struct naptr_record records[] = { | ||||
| 		/* Incredibly plain record */ | ||||
| 		{ 200, 100, {1, "A"}, {4, "BLAH"}, {0, ""}, "goose.down" }, | ||||
| 		/* Records with valid but unusual flags */ | ||||
| 		{ 300,   8, {0, ""}, {4, "BLAH"}, {0, ""}, "goose.down" }, | ||||
| 		{ 300,   6, {1, "3"}, {4, "BLAH"}, {0, ""}, "goose.down" }, | ||||
| 		{ 100,   2, {2, "32"}, {4, "BLAH"}, {0, ""}, "goose.down" }, | ||||
| 		{ 400, 100, {3, "A32"}, {4, "BLAH"}, {0, ""}, "goose.down" }, | ||||
| 		/* Records with valid but unusual services */ | ||||
| 		{ 100, 700, {0, ""}, {0, ""}, {0, ""}, "goose.down" }, | ||||
| 		//{ 500, 100, {1, "A"}, {42, "A+B12+C+D+EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"}, {0, ""}, "goose.down" }, | ||||
| 		{ 500, 100, {1, "A"}, {14, "A+B12+C+D+EEEE"}, {0, ""}, "goose.down" }, | ||||
| 		/* Records with valid regexes (regexes are always unusual) */ | ||||
| 		{ 500, 101, {1, "A"}, {4, "BLAH"}, {15, "!.*!horse.mane!"}, "" }, | ||||
| 		{ 500,  99, {1, "A"}, {4, "BLAH"}, {15, "0.*0horse.mane0"}, "" }, | ||||
| 		{  10, 100, {1, "A"}, {4, "BLAH"}, {11, "!.*!\\!\\!\\!!"}, "" }, | ||||
| 		{ 700, 999, {1, "A"}, {4, "BLAH"}, {30, "!(.)(.)(.)(.)!\\1.m.\\2.n\\3.o\\4!"}, "" }, | ||||
| 	}; | ||||
|  | ||||
| 	int naptr_record_order[] = { 9, 3, 5, 0, 2, 1, 4, 8, 6, 7, 10}; | ||||
| 	enum ast_test_result_state res = AST_TEST_PASS; | ||||
| 	int i; | ||||
|  | ||||
| 	switch (cmd) { | ||||
| 	case TEST_INIT: | ||||
| 		info->name = "naptr_resolve"; | ||||
| 		info->category = "/main/dns/naptr/"; | ||||
| 		info->summary = "Test nominal resolution of NAPTR records"; | ||||
| 		info->description = "This test defines four valid NAPTR records and\n" | ||||
| 			"performs a resolution of the domain to which they belong. The test\n" | ||||
| 			"ensures that all fields of the NAPTR records are parsed correctly\n" | ||||
| 			"and that the records are returned in sorted order\n"; | ||||
| 		return AST_TEST_NOT_RUN; | ||||
| 	case TEST_EXECUTE: | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	test_records = records; | ||||
| 	num_test_records = ARRAY_LEN(records); | ||||
| 	memset(ans_buffer, 0, sizeof(ans_buffer)); | ||||
|  | ||||
| 	ast_dns_resolver_register(&naptr_resolver); | ||||
|  | ||||
| 	if (ast_dns_resolve("goose.feathers", ns_t_naptr, ns_c_in, &result)) { | ||||
| 		ast_test_status_update(test, "DNS resolution failed\n"); | ||||
| 		res = AST_TEST_FAIL; | ||||
| 		goto cleanup; | ||||
| 	} | ||||
|  | ||||
| 	if (!result) { | ||||
| 		ast_test_status_update(test, "DNS resolution returned no result\n"); | ||||
| 		res = AST_TEST_FAIL; | ||||
| 		goto cleanup; | ||||
| 	} | ||||
|  | ||||
| 	i = 0; | ||||
| 	for (record = ast_dns_result_get_records(result); record; record = ast_dns_record_get_next(record)) { | ||||
| 		if (ast_dns_naptr_get_order(record) != records[naptr_record_order[i]].order) { | ||||
| 			ast_test_status_update(test, "Expected order %hu, got order %hu from NAPTR record\n", | ||||
| 					records[naptr_record_order[i]].order, ast_dns_naptr_get_order(record)); | ||||
| 			res = AST_TEST_FAIL; | ||||
| 		} | ||||
| 		if (ast_dns_naptr_get_preference(record) != records[naptr_record_order[i]].preference) { | ||||
| 			ast_test_status_update(test, "Expected preference %hu, got preference %hu from NAPTR record\n", | ||||
| 					records[naptr_record_order[i]].preference, ast_dns_naptr_get_preference(record)); | ||||
| 			res = AST_TEST_FAIL; | ||||
| 		} | ||||
| 		if (strcmp(ast_dns_naptr_get_flags(record), records[naptr_record_order[i]].flags.val)) { | ||||
| 			ast_test_status_update(test, "Expected flags %s, got flags %s from NAPTR record\n", | ||||
| 					records[naptr_record_order[i]].flags.val, ast_dns_naptr_get_flags(record)); | ||||
| 			res = AST_TEST_FAIL; | ||||
| 		} | ||||
| 		if (strcmp(ast_dns_naptr_get_service(record), records[naptr_record_order[i]].services.val)) { | ||||
| 			ast_test_status_update(test, "Expected services %s, got services %s from NAPTR record\n", | ||||
| 					records[naptr_record_order[i]].services.val, ast_dns_naptr_get_service(record)); | ||||
| 			res = AST_TEST_FAIL; | ||||
| 		} | ||||
| 		if (strcmp(ast_dns_naptr_get_regexp(record), records[naptr_record_order[i]].regexp.val)) { | ||||
| 			ast_test_status_update(test, "Expected regexp %s, got regexp %s from NAPTR record\n", | ||||
| 					records[naptr_record_order[i]].regexp.val, ast_dns_naptr_get_regexp(record)); | ||||
| 			res = AST_TEST_FAIL; | ||||
| 		} | ||||
| 		if (strcmp(ast_dns_naptr_get_replacement(record), records[naptr_record_order[i]].replacement)) { | ||||
| 			ast_test_status_update(test, "Expected replacement %s, got replacement %s from NAPTR record\n", | ||||
| 					records[naptr_record_order[i]].replacement, ast_dns_naptr_get_replacement(record)); | ||||
| 			res = AST_TEST_FAIL; | ||||
| 		} | ||||
| 		++i; | ||||
| 	} | ||||
|  | ||||
| 	if (i != ARRAY_LEN(records)) { | ||||
| 		ast_test_status_update(test, "Unexpected number of records returned in NAPTR lookup\n"); | ||||
| 		res = AST_TEST_FAIL; | ||||
| 	} | ||||
|  | ||||
| cleanup: | ||||
|  | ||||
| 	ast_dns_resolver_unregister(&naptr_resolver); | ||||
|  | ||||
| 	test_records = NULL; | ||||
| 	num_test_records = 0; | ||||
| 	memset(ans_buffer, 0, sizeof(ans_buffer)); | ||||
|  | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| static enum ast_test_result_state off_nominal_test(struct ast_test *test, struct naptr_record *records, int num_records) | ||||
| { | ||||
| 	RAII_VAR(struct ast_dns_result *, result, NULL, ast_dns_result_free); | ||||
| 	enum ast_test_result_state res = AST_TEST_PASS; | ||||
| 	const struct ast_dns_record *record; | ||||
|  | ||||
| 	test_records = records; | ||||
| 	num_test_records = num_records; | ||||
| 	memset(ans_buffer, 0, sizeof(ans_buffer)); | ||||
|  | ||||
| 	ast_dns_resolver_register(&naptr_resolver); | ||||
|  | ||||
| 	if (ast_dns_resolve("goose.feathers", ns_t_naptr, ns_c_in, &result)) { | ||||
| 		ast_test_status_update(test, "Failed to perform DNS resolution, despite using valid inputs\n"); | ||||
| 		res = AST_TEST_FAIL; | ||||
| 		goto cleanup; | ||||
| 	} | ||||
|  | ||||
| 	if (!result) { | ||||
| 		ast_test_status_update(test, "Synchronous DNS resolution failed to set a result\n"); | ||||
| 		res = AST_TEST_FAIL; | ||||
| 		goto cleanup; | ||||
| 	} | ||||
|  | ||||
| 	record = ast_dns_result_get_records(result); | ||||
| 	if (record) { | ||||
| 		ast_test_status_update(test, "DNS resolution returned records when it was not expected to\n"); | ||||
| 		res = AST_TEST_FAIL; | ||||
| 		goto cleanup; | ||||
| 	} | ||||
|  | ||||
| cleanup: | ||||
| 	ast_dns_resolver_unregister(&naptr_resolver); | ||||
|  | ||||
| 	test_records = NULL; | ||||
| 	num_test_records = 0; | ||||
| 	memset(ans_buffer, 0, sizeof(ans_buffer)); | ||||
|  | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| AST_TEST_DEFINE(naptr_resolve_off_nominal_length) | ||||
| { | ||||
| 	struct naptr_record records[] = { | ||||
| 		{ 100, 100, {255, "A"}, {4, "BLAH"},   {15, "!.*!horse.mane!"}, "" }, | ||||
| 		{ 100, 100, {0, "A"},   {4, "BLAH"},   {15, "!.*!horse.mane!"}, "" }, | ||||
| 		{ 100, 100, {1, "A"},   {255, "BLAH"}, {15, "!.*!horse.mane!"}, "" }, | ||||
| 		{ 100, 100, {1, "A"},   {2, "BLAH"},   {15, "!.*!horse.mane!"}, "" }, | ||||
| 		{ 100, 100, {1, "A"},   {4, "BLAH"},   {255, "!.*!horse.mane!"}, "" }, | ||||
| 		{ 100, 100, {1, "A"},   {4, "BLAH"},   {3, "!.*!horse.mane!"}, "" }, | ||||
| 		{ 100, 100, {255, "A"}, {255, "BLAH"}, {255, "!.*!horse.mane!"}, "" }, | ||||
| 		{ 100, 100, {0, "A"},   {2, "BLAH"},   {3, "!.*!horse.mane!"}, "" }, | ||||
| 	}; | ||||
|  | ||||
| 	switch (cmd) { | ||||
| 	case TEST_INIT: | ||||
| 		info->name = "naptr_resolve_off_nominal_length"; | ||||
| 		info->category = "/main/dns/naptr/"; | ||||
| 		info->summary = "Test resolution of NAPTR records with off-nominal lengths"; | ||||
| 		info->description = "This test defines a set of records where the strings provided\n" | ||||
| 			"within the record are valid, but the lengths of the strings in the record are\n" | ||||
| 			"invalid, either too large or too small. The goal of this test is to ensure that\n" | ||||
| 			"these invalid lengths result in resolution failures\n"; | ||||
| 		return AST_TEST_NOT_RUN; | ||||
| 	case TEST_EXECUTE: | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	return off_nominal_test(test, records, ARRAY_LEN(records)); | ||||
| } | ||||
|  | ||||
| AST_TEST_DEFINE(naptr_resolve_off_nominal_flags) | ||||
| { | ||||
| 	struct naptr_record records[] = { | ||||
| 		/* Non-alphanumeric flag */ | ||||
| 		{ 100, 100, {1, "!"}, {4, "BLAH"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		/* Mix of valid and non-alphanumeric */ | ||||
| 		{ 100, 100, {2, "A!"}, {4, "BLAH"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {2, "!A"}, {4, "BLAH"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		/* Invalid combinations of flags */ | ||||
| 		{ 100, 100, {2, "sa"}, {4, "BLAH"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {2, "su"}, {4, "BLAH"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {2, "sp"}, {4, "BLAH"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {2, "as"}, {4, "BLAH"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {2, "au"}, {4, "BLAH"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {2, "ap"}, {4, "BLAH"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {2, "ua"}, {4, "BLAH"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {2, "us"}, {4, "BLAH"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {2, "up"}, {4, "BLAH"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {2, "pa"}, {4, "BLAH"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {2, "ps"}, {4, "BLAH"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {2, "pu"}, {4, "BLAH"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 	}; | ||||
|  | ||||
| 	switch (cmd) { | ||||
| 	case TEST_INIT: | ||||
| 		info->name = "naptr_resolve_off_nominal_flags"; | ||||
| 		info->category = "/main/dns/naptr/"; | ||||
| 		info->summary = "Ensure that NAPTR records with invalid flags are not presented in results"; | ||||
| 		info->description = "This test defines a set of records where the flags provided are\n" | ||||
| 			"invalid in some way. This may be due to providing non-alphanumeric characters or\n" | ||||
| 			"by providing clashing flags. The result should be that none of the defined records\n" | ||||
| 			"are returned by the resolver\n"; | ||||
| 		return AST_TEST_NOT_RUN; | ||||
| 	case TEST_EXECUTE: | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	return off_nominal_test(test, records, ARRAY_LEN(records)); | ||||
| } | ||||
|  | ||||
| AST_TEST_DEFINE(naptr_resolve_off_nominal_services) | ||||
| { | ||||
| 	struct naptr_record records[] = { | ||||
| 		{ 100, 100, {1, "A"}, {5, "BLAH!"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {1, "A"}, {5, "BL!AH"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {1, "A"}, {8, "1SIP+D2U"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {1, "A"}, {8, "SIP+1D2U"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {1, "A"}, {4, "+D2U"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {1, "A"}, {4, "SIP+"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {1, "A"}, {8, "SIP++D2U"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {1, "A"}, {37, "SIPSIPSIPSIPSIPSIPSIPSIPSIPSIPSIP+D2U"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 		{ 100, 100, {1, "A"}, {37, "SIP+D2UD2UD2UD2UD2UD2UD2UD2UD2UD2UD2U"}, {15, "!.*!horse.mane!"}, ""}, | ||||
| 	}; | ||||
|  | ||||
| 	switch (cmd) { | ||||
| 	case TEST_INIT: | ||||
| 		info->name = "naptr_resolve_off_nominal_services"; | ||||
| 		info->category = "/main/dns/naptr/"; | ||||
| 		info->summary = "Ensure that NAPTR records with invalid services are not presented in results"; | ||||
| 		info->description = "This test defines a set of records where the services provided are\n" | ||||
| 			"invalid in some way. This may be due to providing non-alphanumeric characters, providing\n" | ||||
| 			"protocols or resolution services that start with a non-alphabetic character, or\n" | ||||
| 			"providing fields that are too long.\n"; | ||||
| 		return AST_TEST_NOT_RUN; | ||||
| 	case TEST_EXECUTE: | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	return off_nominal_test(test, records, ARRAY_LEN(records)); | ||||
| } | ||||
|  | ||||
| AST_TEST_DEFINE(naptr_resolve_off_nominal_regexp) | ||||
| { | ||||
| 	struct naptr_record records[] = { | ||||
| 		/* Invalid delim-char */ | ||||
| 		{ 100, 100, {1, "A"}, {4, "BLAH"}, {15, "1.*1horse.mane1"}, ""}, | ||||
| 		/* Not enough delim-chars */ | ||||
| 		{ 100, 100, {1, "A"}, {4, "BLAH"}, {14, "!.*!horse.mane"}, ""}, | ||||
| 		/* Not enough delim-chars, part 2 */ | ||||
| 		{ 100, 100, {1, "A"}, {4, "BLAH"}, {16, "!.*!horse.mane\\!"}, ""}, | ||||
| 		/* Too many delim-chars */ | ||||
| 		{ 100, 100, {1, "A"}, {4, "BLAH"}, {15, "!.*!horse!mane!"}, ""}, | ||||
| 		/* Invalid regex flag */ | ||||
| 		{ 100, 100, {1, "A"}, {4, "BLAH"}, {16, "!.*!horse.mane!o"}, ""}, | ||||
| 		/* Invalid backreference */ | ||||
| 		{ 100, 100, {1, "A"}, {4, "BLAH"}, {13, "!.*!horse.\\0!"}, ""}, | ||||
| 		/* Invalid regex */ | ||||
| 		{ 100, 100, {1, "A"}, {4, "BLAH"}, {16, "!(.*!horse.mane!"}, ""}, | ||||
| 	}; | ||||
|  | ||||
| 	switch (cmd) { | ||||
| 	case TEST_INIT: | ||||
| 		info->name = "naptr_resolve_off_nominal_regexp"; | ||||
| 		info->category = "/main/dns/naptr/"; | ||||
| 		info->summary = "Ensure that NAPTR records with invalid regexps are not presented in results"; | ||||
| 		info->description = "This test defines a set of records where the regexps provided are\n" | ||||
| 			"invalid in some way. The test ensures that none of the invalid records are returned\n" | ||||
| 			"when performing a NAPTR lookup\n"; | ||||
| 		return AST_TEST_NOT_RUN; | ||||
| 	case TEST_EXECUTE: | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	return off_nominal_test(test, records, ARRAY_LEN(records)); | ||||
| } | ||||
|  | ||||
| AST_TEST_DEFINE(naptr_resolve_off_nominal_interactions) | ||||
| { | ||||
| 	struct naptr_record records[] = { | ||||
| 		/* Both regexp and replacement are specified */ | ||||
| 		{ 100, 100, {1, "A"}, {4, "BLAH"}, {15, "!.*!horse.mane!"}, "goose.down"}, | ||||
| 		/* XXX RFC 2915 says that a service MUST be present if terminal flags are | ||||
| 		 * specified. However, RFCs 3401-3404 do not specify this behavior, so | ||||
| 		 * I am not putting in a test for it | ||||
| 		 */ | ||||
| 	}; | ||||
|  | ||||
| 	switch (cmd) { | ||||
| 	case TEST_INIT: | ||||
| 		info->name = "naptr_resolve_off_nominal_interactions"; | ||||
| 		info->category = "/main/dns/naptr/"; | ||||
| 		info->summary = "Ensure that NAPTR records with invalid interactions are not presented in results"; | ||||
| 		info->description = "This test defines a set of records where all parts are individually valid,\n" | ||||
| 			"but when combined do not make sense and are thus invalid.\n"; | ||||
| 		return AST_TEST_NOT_RUN; | ||||
| 	case TEST_EXECUTE: | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	return off_nominal_test(test, records, ARRAY_LEN(records)); | ||||
| } | ||||
|  | ||||
| static int unload_module(void) | ||||
| { | ||||
| 	AST_TEST_UNREGISTER(naptr_resolve_nominal); | ||||
| 	AST_TEST_UNREGISTER(naptr_resolve_off_nominal_length); | ||||
| 	AST_TEST_UNREGISTER(naptr_resolve_off_nominal_flags); | ||||
| 	AST_TEST_UNREGISTER(naptr_resolve_off_nominal_services); | ||||
| 	AST_TEST_UNREGISTER(naptr_resolve_off_nominal_regexp); | ||||
| 	AST_TEST_UNREGISTER(naptr_resolve_off_nominal_interactions); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int load_module(void) | ||||
| { | ||||
| 	AST_TEST_REGISTER(naptr_resolve_nominal); | ||||
| 	AST_TEST_REGISTER(naptr_resolve_off_nominal_length); | ||||
| 	AST_TEST_REGISTER(naptr_resolve_off_nominal_flags); | ||||
| 	AST_TEST_REGISTER(naptr_resolve_off_nominal_services); | ||||
| 	AST_TEST_REGISTER(naptr_resolve_off_nominal_regexp); | ||||
| 	AST_TEST_REGISTER(naptr_resolve_off_nominal_interactions); | ||||
|  | ||||
| 	return AST_MODULE_LOAD_SUCCESS; | ||||
| } | ||||
|  | ||||
| AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DNS API Tests"); | ||||
		Reference in New Issue
	
	Block a user