28 #include <arpa/nameser.h> 135 .category =
"general",
141 .
filename =
"resolver_unbound.conf",
156 .files =
ACO_FILES(&resolver_unbound_conf),
166 ub_ctx_delete(resolver->
context);
182 resolver->
context = ub_ctx_create();
189 ub_ctx_async(resolver->
context, 1);
199 ast_debug(1,
"Starting processing for unbound resolver\n");
209 ast_debug(1,
"Terminating processing for unbound resolver\n");
225 ast_debug(1,
"Starting thread for unbound resolver\n");
229 ast_debug(1,
"Could not start thread for unbound resolver\n");
245 ast_debug(1,
"Stopping processing thread for unbound resolver\n");
247 thread = resolver->
thread;
249 pthread_kill(thread, SIGURG);
250 pthread_join(thread,
NULL);
252 ast_debug(1,
"Stopped processing thread for unbound resolver\n");
265 for (i = 0; (result_data = ub_result->data[i]); i++) {
267 result_data, ub_result->len[i])) {
275 ub_resolve_free(ub_result);
294 ast_log(
LOG_ERROR,
"Failed to allocate resolver data for resolution of '%s'\n",
398 ast_log(
LOG_ERROR,
"Could not allocate unbound resolver state structure\n");
417 ast_log(
LOG_ERROR,
"Failed to set hosts file to '%s' in unbound resolver: %s\n",
431 ast_log(
LOG_ERROR,
"Failed to add nameserver '%s' to unbound resolver: %s\n",
432 nameserver, ub_strerror(res));
449 ast_log(
LOG_ERROR,
"Failed to set resolv.conf file to '%s' in unbound resolver: %s\n",
458 ast_log(
LOG_ERROR,
"Failed to set trusted anchor file to '%s' in unbound resolver: %s\n",
478 ast_log(
LOG_ERROR,
"Could not create default configuration for unbound resolver\n");
489 ast_verb(1,
"Starting unbound resolver using default configuration\n");
502 #ifdef TEST_FRAMEWORK 559 for (i = 0; i < num_records; ++i) {
571 ast_test_status_update(test,
"Successful synchronous resolution of domain %s gave NULL result\n", domain);
579 for (i = 0; i < num_records; ++i) {
709 for (i = 0; i < num_records; ++i) {
722 while (!adata->complete) {
730 return adata->failed;
748 static const size_t V4_SIZE =
sizeof(
struct in_addr);
749 static const size_t V6_SIZE =
sizeof(
struct in6_addr);
751 static const char *DOMAIN1 =
"goose.feathers";
752 static const char *DOMAIN2 =
"duck.feathers";
754 static const char *ADDR1 =
"127.0.0.2";
755 static const char *ADDR2 =
"127.0.0.3";
756 static const char *ADDR3 =
"::1";
757 static const char *ADDR4 =
"127.0.0.4";
759 char addr1_buf[V4_SIZE];
760 char addr2_buf[V4_SIZE];
761 char addr3_buf[V6_SIZE];
762 char addr4_buf[V4_SIZE];
765 {
"goose.feathers 12345 IN A 127.0.0.2", DOMAIN1, ns_t_a, ns_c_in, 12345, addr1_buf, V4_SIZE, 0 },
766 {
"goose.feathers 12345 IN A 127.0.0.3", DOMAIN1, ns_t_a, ns_c_in, 12345, addr2_buf, V4_SIZE, 0 },
767 {
"goose.feathers 12345 IN AAAA ::1", DOMAIN1, ns_t_aaaa, ns_c_in, 12345, addr3_buf, V6_SIZE, 0 },
768 {
"duck.feathers 12345 IN A 127.0.0.4", DOMAIN2, ns_t_a, ns_c_in, 12345, addr4_buf, V4_SIZE, 0 },
777 { DOMAIN1, ns_t_a, ns_c_in, { 1, 1, 0, 0 } },
778 { DOMAIN1, ns_t_aaaa, ns_c_in, { 0, 0, 1, 0 } },
779 { DOMAIN2, ns_t_a, ns_c_in, { 0, 0, 0, 1 } },
785 inet_pton(AF_INET, ADDR1, addr1_buf);
786 inet_pton(AF_INET, ADDR2, addr2_buf);
787 inet_pton(AF_INET6, ADDR3, addr3_buf);
788 inet_pton(AF_INET, ADDR4, addr4_buf);
791 resolver =
ao2_bump(cfg->global->state->resolver);
793 ub_ctx_zone_add(resolver->context, DOMAIN1,
"static");
794 ub_ctx_zone_add(resolver->context, DOMAIN2,
"static");
796 for (i = 0; i <
ARRAY_LEN(records); ++i) {
797 ub_ctx_data_add(resolver->context, records[i].
as_string);
803 if (runner(test, runs[i].
domain, runs[i].rr_type, runs[i].rr_class, records,
ARRAY_LEN(records))) {
808 for (j = 0; j <
ARRAY_LEN(records); ++j) {
809 if (records[j].visited != runs[i].visited[j]) {
818 for (i = 0; i <
ARRAY_LEN(records); ++i) {
819 ub_ctx_data_remove(resolver->context, records[i].
as_string);
821 ub_ctx_zone_remove(resolver->context, DOMAIN1);
822 ub_ctx_zone_remove(resolver->context, DOMAIN2);
832 info->name =
"resolve_sync";
833 info->category =
"/res/res_resolver_unbound/";
834 info->summary =
"Test nominal synchronous resolution using libunbound";
835 info->description =
"This test performs the following:\n" 836 "\t* Set two static A records and one static AAAA record on one domain\n" 837 "\t* Set an A record for a second domain\n" 838 "\t* Perform an A record lookup on the first domain\n" 839 "\t* Ensure that both A records are returned and no AAAA record is returned\n" 840 "\t* Perform an AAAA record lookup on the first domain\n" 841 "\t* Ensure that the AAAA record is returned and no A record is returned\n" 842 "\t* Perform an A record lookup on the second domain\n" 843 "\t* Ensure that the A record from the second domain is returned";
856 info->name =
"resolve_async";
857 info->category =
"/res/res_resolver_unbound/";
858 info->summary =
"Test nominal asynchronous resolution using libunbound";
859 info->description =
"This test performs the following:\n" 860 "\t* Set two static A records and one static AAAA record on one domain\n" 861 "\t* Set an A record for a second domain\n" 862 "\t* Perform an A record lookup on the first domain\n" 863 "\t* Ensure that both A records are returned and no AAAA record is returned\n" 864 "\t* Perform an AAAA record lookup on the first domain\n" 865 "\t* Ensure that the AAAA record is returned and no A record is returned\n" 866 "\t* Perform an A record lookup on the second domain\n" 867 "\t* Ensure that the A record from the second domain is returned";
877 int rr_class,
int expected_rcode);
880 int rr_class,
int expected_rcode)
984 int rr_class,
int expected_rcode)
1004 while (!adata->complete) {
1009 if (adata->failed) {
1012 return adata->failed;
1021 static const size_t V4_SIZE =
sizeof(
struct in_addr);
1023 static const char *DOMAIN1 =
"goose.feathers";
1024 static const char *DOMAIN2 =
"duck.feathers";
1026 static const char *ADDR1 =
"127.0.0.2";
1028 char addr1_buf[V4_SIZE];
1031 {
"goose.feathers 12345 IN A 127.0.0.2", DOMAIN1, ns_t_a, ns_c_in, 12345, addr1_buf, V4_SIZE, 0, },
1043 { DOMAIN2, ns_t_a, ns_c_in, ns_r_nxdomain },
1044 { DOMAIN1, ns_t_aaaa, ns_c_in, ns_r_noerror },
1045 { DOMAIN1, ns_t_a, ns_c_chaos, ns_r_refused },
1048 inet_pton(AF_INET, ADDR1, addr1_buf);
1051 resolver =
ao2_bump(cfg->global->state->resolver);
1053 ub_ctx_zone_add(resolver->context, DOMAIN1,
"static");
1054 ub_ctx_zone_add(resolver->context, DOMAIN2,
"static");
1056 for (i = 0; i <
ARRAY_LEN(records); ++i) {
1057 ub_ctx_data_add(resolver->context, records[i].
as_string);
1061 if (runner(test, runs[i].
domain, runs[i].rr_type, runs[i].rr_class, runs[i].rcode)) {
1073 info->name =
"resolve_sync_off_nominal";
1074 info->category =
"/res/res_resolver_unbound/";
1075 info->summary =
"Test off-nominal synchronous resolution using libunbound";
1076 info->description =
"This test performs the following:\n" 1077 "\t* Attempt a lookup of a non-existent domain\n" 1078 "\t* Attempt a lookup of a AAAA record on a domain that contains only A records\n" 1079 "\t* Attempt a lookup of an A record on Chaos-net";
1092 info->name =
"resolve_async_off_nominal";
1093 info->category =
"/res/res_resolver_unbound/";
1094 info->summary =
"Test off-nominal synchronous resolution using libunbound";
1095 info->description =
"This test performs the following:\n" 1096 "\t* Attempt a lookup of a non-existent domain\n" 1097 "\t* Attempt a lookup of a AAAA record on a domain that contains only A records\n" 1098 "\t* Attempt a lookup of an A record on Chaos-net";
1161 info->name =
"resolve_cancel_off_nominal";
1162 info->category =
"/res/res_resolver_unbound/";
1163 info->summary =
"Off nominal cancellation test using libunbound";
1164 info->description =
"This test does the following:\n" 1165 "\t* Perform an asynchronous query\n" 1166 "\t* Once the query has completed, attempt to cancel it";
1186 while (!adata->complete) {
1207 static char * DOMAIN1 =
"goose.feathers";
1212 const char *zone_entry;
1214 uint16_t preference;
1216 const char *services;
1218 const char *replacement;
1221 {
"goose.feathers 12345 IN NAPTR 100 100 A SIP+D2U \"\" goose.down", 100, 100,
"A",
"SIP+D2U",
"",
"goose.down", 0},
1222 {
"goose.feathers 12345 IN NAPTR 100 200 A SIP+D2T \"\" duck.down", 100, 200,
"A",
"SIP+D2T",
"",
"duck.down", 0},
1223 {
"goose.feathers 12345 IN NAPTR 200 100 A SIPS+D2U \"\" pheasant.down", 200, 100,
"A",
"SIPS+D2U",
"",
"pheasant.down", 0},
1224 {
"goose.feathers 12345 IN NAPTR 200 200 A SIPS+D2T \"\" platypus.fur", 200, 200,
"A",
"SIPS+D2T",
"",
"platypus.fur", 0},
1229 info->name =
"resolve_naptr";
1230 info->category =
"/res/res_resolver_unbound/";
1231 info->summary =
"Attempt resolution of NAPTR record";
1232 info->description =
"This test performs a NAPTR lookup and ensures that\n" 1233 "the returned record has the appropriate values set";
1240 resolver =
ao2_bump(cfg->global->state->resolver);
1242 ub_ctx_zone_add(resolver->context, DOMAIN1,
"static");
1244 for (i = 0; i <
ARRAY_LEN(records); ++i) {
1245 ub_ctx_data_add(resolver->context, records[i].zone_entry);
1305 for (i = 0; i <
ARRAY_LEN(records); ++i) {
1306 if (!records[i].visited) {
1322 static const char *DOMAIN1 =
"taco.bananas";
1323 static const char *DOMAIN1_SRV =
"taco.bananas 12345 IN SRV 10 20 5060 sip.taco.bananas";
1328 info->name =
"resolve_srv";
1329 info->category =
"/res/res_resolver_unbound/";
1330 info->summary =
"Test synchronous SRV resolution using libunbound";
1331 info->description =
"This test performs the following:\n" 1332 "\t* Set one SRV record on one domain\n" 1333 "\t* Perform an SRV lookup on the domain\n" 1334 "\t* Ensure that the SRV record returned matches the expected value";
1341 resolver =
ao2_bump(cfg->global->state->resolver);
1343 ub_ctx_zone_add(resolver->context, DOMAIN1,
"static");
1344 ub_ctx_data_add(resolver->context, DOMAIN1_SRV);
1378 ub_ctx_data_remove(resolver->context, DOMAIN1_SRV);
1379 ub_ctx_zone_remove(resolver->context, DOMAIN1);
int(* off_nominal_resolve_fn)(struct ast_test *test, const char *domain, int rr_type, int rr_class, int expected_rcode)
unsigned short ast_dns_srv_get_priority(const struct ast_dns_record *record)
Get the priority from an SRV record.
int ast_dns_record_get_ttl(const struct ast_dns_record *record)
Get the TTL of a DNS record.
Data required for an asynchronous callback.
static void * unbound_config_alloc(void)
Allocate a unbound_config to hold a snapshot of the complete results of parsing a config...
const struct ast_dns_record * ast_dns_record_get_next(const struct ast_dns_record *record)
Get the next DNS record.
const ast_string_field hosts
Asterisk main include file. File version handling, generic pbx functions.
const char * ast_dns_record_get_data(const struct ast_dns_record *record)
Retrieve the raw DNS record.
int ast_dns_resolve(const char *name, int rr_type, int rr_class, struct ast_dns_result **result)
Synchronously resolve a DNS query.
static void unbound_resolver_destroy(void *obj)
Destructor for unbound resolver.
void ast_dns_result_free(struct ast_dns_result *result)
Free the DNS result information.
int ast_dns_resolver_add_record(struct ast_dns_query *query, int rr_type, int rr_class, int ttl, const char *data, const size_t size)
Add a DNS record to the result of a DNS query.
const char * ast_dns_query_get_name(const struct ast_dns_query *query)
Get the name queried in a DNS query.
static void unbound_resolver_data_dtor(void *vdoomed)
static struct aco_type global
static struct off_nominal_async_data * off_nominal_async_data_alloc(int expected_rcode)
int ast_dns_query_get_rr_class(const struct ast_dns_query *query)
Get the record resource class of a DNS query.
static int unload_module(void)
A container for config related information.
#define aco_option_register_custom(info, name, matchtype, types, default_val, handler, flags)
Register a config option.
Unbound configuration state information.
const ast_string_field resolv
const ast_string_field ta_file
static int debug
Global debug status.
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
struct ast_dns_query_active * ast_dns_resolve_async(const char *name, int rr_type, int rr_class, ast_dns_resolve_callback callback, void *data)
Asynchronously resolve a DNS query.
static enum ast_test_result_state nominal_test(struct ast_test *test, resolve_fn runner)
Framework for running a nominal DNS test.
Structure for variables, used for configurations and for channel variables.
A DNS record to be used during a test.
#define AST_TEST_REGISTER(cb)
const char * ast_dns_naptr_get_regexp(const struct ast_dns_record *record)
Get the regular expression from a NAPTR record.
#define ast_cond_wait(cond, mutex)
#define ast_cond_init(cond, attr)
enum aco_process_status aco_process_config(struct aco_info *info, int reload)
Process a config info via the options registered with an aco_info.
#define ao2_global_obj_ref(holder)
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
struct unbound_resolver * resolver
The configured resolver.
#define ao2_alloc_options(data_size, destructor_fn, options)
#define ast_mutex_lock(a)
unsigned short ast_dns_naptr_get_preference(const struct ast_dns_record *record)
Get the preference from a NAPTR record.
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
static int off_nominal_async_run(struct ast_test *test, const char *domain, int rr_type, int rr_class, int expected_rcode)
static AO2_GLOBAL_OBJ_STATIC(globals)
A global object container that will contain the global_config that gets swapped out on reloads...
struct unbound_config_state * state
State information.
The representation of a single configuration file to be processed.
const char * ast_dns_naptr_get_service(const struct ast_dns_record *record)
Get the service from a NAPTR record.
void * ast_dns_resolver_get_data(const struct ast_dns_query *query)
Retrieve resolver specific data.
#define ast_cond_signal(cond)
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
struct unbound_global_config * global
#define ast_verb(level,...)
unsigned short ast_dns_srv_get_port(const struct ast_dns_record *record)
Get the port from an SRV record.
const char * ast_dns_srv_get_host(const struct ast_dns_record *record)
Get the hostname from an SRV record.
Structure for query resolver data.
int(* resolve_fn)(struct ast_test *test, const char *domain, int rr_type, int rr_class, struct dns_record *records, size_t num_records)
Resolution function for tests.
pthread_cond_t ast_cond_t
#define ast_strlen_zero(foo)
unsigned short ast_dns_srv_get_weight(const struct ast_dns_record *record)
Get the weight from an SRV record.
static int nominal_sync_run(struct ast_test *test, const char *domain, int rr_type, int rr_class, struct dns_record *records, size_t num_records)
Pluggable function for running a synchronous query and checking its results.
static int custom_nameserver_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static int nominal_async_run(struct ast_test *test, const char *domain, int rr_type, int rr_class, struct dns_record *records, size_t num_records)
Pluggable function for performing an asynchronous query during a test.
Configuration File Parser.
A structure to hold global configuration-related options.
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_config_load(filename, flags)
Load a config file.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
pthread_t thread
Thread handling the resolver.
static void off_nominal_async_data_destructor(void *obj)
User data for off-nominal async resolution test.
void * aco_pending_config(struct aco_info *info)
Get pending config changes.
struct ao2_container * ast_str_container_alloc_options(enum ao2_alloc_opts opts, int buckets)
Allocates a hash container for bare strings.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Type for default option handler for unsigned integers.
#define ast_test_status_update(a, b, c...)
void * ast_dns_query_get_data(const struct ast_dns_query *query)
Get the user specific data of a DNS query.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define AST_PTHREADT_NULL
static int reload_module(void)
int ast_dns_resolver_register(struct ast_dns_resolver *resolver)
Register a DNS resolver.
static int load_module(void)
#define AST_STRING_FIELD(name)
Declare a string field.
#define ao2_ref(o, delta)
void ast_config_destroy(struct ast_config *config)
Destroys a config.
static void unbound_global_config_destructor(void *obj)
static void unbound_resolver_callback(void *data, int err, struct ub_result *ub_result)
Callback invoked when resolution completes on a query.
static int unbound_resolver_resolve(struct ast_dns_query *query)
A set of macros to manage forward-linked lists.
static struct console_pvt globals
static void * unbound_resolver_thread(void *data)
Resolver thread which waits and handles results.
CONFIG_INFO_STANDARD(cfg_info, globals, unbound_config_alloc,.files=ACO_FILES(&resolver_unbound_conf),.pre_apply_config=unbound_config_preapply_callback,)
Register information about the configs being processed by this module.
Their was an error and no changes were applied.
The result of a DNS query.
void ast_dns_resolver_completed(struct ast_dns_query *query)
Mark a DNS query as having been completed.
static void async_callback(const struct ast_dns_query *query)
Callback for asynchronous queries.
static int unbound_resolver_cancel(struct ast_dns_query *query)
Configuration option-handling.
const char * ast_dns_naptr_get_flags(const struct ast_dns_record *record)
Get the flags from a NAPTR record.
static void unbound_config_state_destructor(void *obj)
static struct unbound_resolver * unbound_resolver_alloc(void)
Allocator for unbound resolver.
static int unbound_resolver_start(struct unbound_resolver *resolver)
Start function for the unbound resolver.
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
#define AST_TEST_UNREGISTER(cb)
#define ao2_global_obj_release(holder)
struct ast_dns_result * ast_dns_query_get_result(const struct ast_dns_query *query)
Get the result information for a DNS query.
static void async_minimal_data_destructor(void *obj)
int ast_dns_resolver_set_data(struct ast_dns_query *query, void *data)
Set resolver specific data on a query.
static void unbound_config_destructor(void *obj)
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
#define ao2_iterator_next(iter)
#define ast_cond_destroy(cond)
Minimal data required to signal the completion of an async resolve.
#define ao2_alloc(data_size, destructor_fn)
static int unbound_config_preapply(struct unbound_config *cfg)
static int off_nominal_sync_run(struct ast_test *test, const char *domain, int rr_type, int rr_class, int expected_rcode)
DNS resolver implementation.
static int unbound_config_apply_default(void)
static void off_nominal_async_callback(const struct ast_dns_query *query)
Async callback for off-nominal async test.
#define ast_pthread_create(a, b, c, d)
int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
Set all default options of obj.
static enum ast_test_result_state off_nominal_test(struct ast_test *test, off_nominal_resolve_fn runner)
struct dns_record * records
AST_TEST_DEFINE(resolve_sync)
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
Module has failed to load, may be in an inconsistent state.
const struct ast_dns_record * ast_dns_result_get_records(const struct ast_dns_result *result)
Get the first record of a DNS Result.
static void * cleanup(void *unused)
Structure used to handle boolean flags.
static int unbound_config_preapply_callback(void)
Finish initializing new configuration.
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
struct ub_ctx * context
Resolver context itself.
int id
ID for the specific query.
struct ao2_container * nameservers
List of nameservers (in order) to use for queries.
int ast_dns_query_get_rr_type(const struct ast_dns_query *query)
Get the record resource type of a DNS query.
#define ao2_global_obj_replace_unref(holder, obj)
DNS NAPTR Record Parsing API.
unsigned short ast_dns_naptr_get_order(const struct ast_dns_record *record)
Get the order from a NAPTR record.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Type information about a category-level configurable object.
static void async_data_destructor(void *obj)
int ast_dns_resolve_cancel(struct ast_dns_query_active *active)
Cancel an asynchronous DNS resolution.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
static struct async_data * async_data_alloc(struct dns_record *records, size_t num_records)
#define AST_PTHREADT_STOP
static void minimal_callback(const struct ast_dns_query *query)
Async callback for off-nominal cancellation test.
static struct async_minimal_data * async_minimal_data_alloc(void)
static void unbound_resolver_stop(struct unbound_resolver *resolver)
Stop function for the unbound resolver.
Structure for an unbound resolver.
static struct aco_type * global_options[]
const char * ast_dns_naptr_get_replacement(const struct ast_dns_record *record)
Get the replacement value from a NAPTR record.
Type for default option handler for stringfields.
static struct aco_file resolver_unbound_conf
int error(const char *format,...)
int ast_wait_for_input(int fd, int ms)
DNS SRV Record Parsing API.
#define ast_mutex_init(pmutex)
static struct aco_type global_option
An aco_type structure to link the "general" category to the unbound_global_config type...
#define ast_mutex_destroy(a)
int ast_dns_record_get_rr_class(const struct ast_dns_record *record)
Get the resource record class of a DNS record.
struct unbound_resolver * resolver
The resolver in use for the query.
int ast_dns_record_get_rr_type(const struct ast_dns_record *record)
Get the resource record type of a DNS record.
#define ASTERISK_GPL_KEY
The text the key() function should return.
unsigned int debug
Debug level for the resolver.
int ast_dns_resolver_set_result(struct ast_dns_query *query, unsigned int secure, unsigned int bogus, unsigned int rcode, const char *canonical, const char *answer, size_t answer_size)
Set result information for a DNS query.
Asterisk module definitions.
int rr_type
Resource record type.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
int ast_str_container_add(struct ao2_container *str_container, const char *add)
Adds a string to a string container allocated by ast_str_container_alloc.
unsigned int ast_dns_result_get_rcode(const struct ast_dns_result *result)
Get the error rcode of a DN result.
Structure for mutex and tracking information.
static struct ast_test * test
#define ast_mutex_unlock(a)
int rr_class
Resource record class.