diff --git a/spec/example-all-functions.c b/spec/example-all-functions.c new file mode 100644 index 00000000..c4ad41c5 --- /dev/null +++ b/spec/example-all-functions.c @@ -0,0 +1,297 @@ +#include +#include +#include +#include +#include +#include +#include + +#define UNUSED_PARAM(x) ((void)(x)) + +/* The return values */ +getdns_return_t retregular; +char * retcharstar; + +/* The args */ +bool boolarg; +char * charstararg; +getdns_callback_t callbackarg; +uint16_t regulararg; +uint16_t *regularptrarg; +getdns_transaction_t txidarg; +getdns_transaction_t * txidptrarg; + +getdns_data_type * datatypeptrarg; +struct getdns_bindata ** bindataptrarg; +struct getdns_dict * dictarg; +struct getdns_bindata * bindataarg; +struct getdns_list * listarg; +struct getdns_dict ** dictptrarg; +struct getdns_list ** listptrarg; + +size_t sizetarg; +size_t * sizetptrarg; +getdns_context_t contextarg = NULL; +uint8_t uint8arg; +uint16_t uint16arg; +uint32_t uint32arg; +uint8_t * uint8ptrarg; +uint16_t * uint16ptrarg; +uint32_t * uint32ptrarg; +void * arrayarg; +void allocfunctionarg(size_t foo) {UNUSED_PARAM(foo);} +void deallocfunctionarg(void* foo) {UNUSED_PARAM(foo);} +void setcallbackfunctionarg(struct getdns_context_t *foo1, uint16_t foo2) + {UNUSED_PARAM(foo1);UNUSED_PARAM(foo2);} + +int main() +{ + +retregular = getdns_general( + contextarg, + charstararg, + uint16arg, + dictarg, + arrayarg, + txidptrarg, + callbackarg +); + +retregular = getdns_address( + contextarg, + charstararg, + dictarg, + arrayarg, + txidptrarg, + callbackarg +); + +retregular = getdns_hostname( + contextarg, + dictarg, + dictarg, + arrayarg, + txidptrarg, + callbackarg +); + +retregular = getdns_service( + contextarg, + charstararg, + dictarg, + arrayarg, + txidptrarg, + callbackarg +); + +retregular = getdns_context_create( + &contextarg, + boolarg +); + +getdns_context_destroy( + contextarg +); + +retregular = getdns_cancel_callback( + contextarg, + txidarg +); + +retregular = getdns_general_sync( + contextarg, + charstararg, + uint16arg, + dictarg, + uint32ptrarg, + dictarg +); + +retregular = getdns_address_sync( + contextarg, + charstararg, + dictarg, + uint32ptrarg, + dictarg +); + +retregular = getdns_hostname_sync( + contextarg, + dictarg, + dictarg, + uint32ptrarg, + dictarg +); + +retregular = getdns_service_sync( + contextarg, + charstararg, + dictarg, + uint32ptrarg, + dictarg +); + +getdns_free_sync_request_memory( + dictarg +); + +retregular = getdns_list_get_length(listarg, sizetptrarg); +retregular = getdns_list_get_data_type(listarg, sizetarg, datatypeptrarg); +retregular = getdns_list_get_dict(listarg, sizetarg, dictptrarg); +retregular = getdns_list_get_list(listarg, sizetarg, listptrarg); +retregular = getdns_list_get_bindata(listarg, sizetarg, bindataptrarg); +retregular = getdns_list_get_int(listarg, sizetarg, uint32ptrarg); + +retregular = getdns_dict_get_names(dictarg, listptrarg); +retregular = getdns_dict_get_data_type(dictarg, charstararg, datatypeptrarg); +retregular = getdns_dict_get_dict(dictarg, charstararg, dictptrarg); +retregular = getdns_dict_get_list(dictarg, charstararg, listptrarg); +retregular = getdns_dict_get_bindata(dictarg, charstararg, bindataptrarg); +retregular = getdns_dict_get_int(dictarg, charstararg, uint32ptrarg); + +listarg = getdns_list_create(); +getdns_list_destroy(listarg); +retregular = getdns_list_set_dict(listarg, sizetarg, dictarg); +retregular = getdns_list_set_list(listarg, sizetarg, listarg); +retregular = getdns_list_set_bindata(listarg, sizetarg, bindataarg); +retregular = getdns_list_set_int(listarg, sizetarg, uint32arg); + +dictarg = getdns_dict_create(); +getdns_dict_destroy(dictarg); +retregular = getdns_dict_set_dict(dictarg, charstararg, dictarg); +retregular = getdns_dict_set_list(dictarg, charstararg, listarg); +retregular = getdns_dict_set_bindata(dictarg, charstararg, bindataarg); +retregular = getdns_dict_set_int(dictarg, charstararg, uint32arg); + +retcharstar = getdns_convert_fqdn_to_dns_name( + charstararg +); + +retcharstar = getdns_convert_dns_name_to_fqdn( + charstararg +); + +retcharstar = getdns_convert_ulabel_to_alabel( + charstararg +); + +retcharstar = getdns_convert_alabel_to_ulabel( + charstararg +); + +retregular = getdns_validate_dnssec( + bindataarg, + listarg, + listarg +); + +retcharstar = getdns_pretty_print_dict( + dictarg +); + +retcharstar = getdns_display_ip_address( + bindataarg +); + +retregular = getdns_context_set_context_update_callback( + contextarg, + setcallbackfunctionarg +); + +retregular = getdns_context_set_resolution_type( + contextarg, + regulararg +); + +retregular = getdns_context_set_namespaces( + contextarg, + sizetarg, + regularptrarg +); + +retregular = getdns_context_set_dns_transport( + contextarg, + regulararg +); + +retregular = getdns_context_set_limit_outstanding_queries( + contextarg, + uint16arg +); + +retregular = getdns_context_set_timeout( + contextarg, + uint16arg +); + +retregular = getdns_context_set_follow_redirects( + contextarg, + regulararg +); + +retregular = getdns_context_set_dns_root_servers( + contextarg, + listarg +); + +retregular = getdns_context_set_append_name( + contextarg, + regulararg +); + +retregular = getdns_context_set_suffix( + contextarg, + listarg +); + +retregular = getdns_context_set_dnssec_trust_anchors( + contextarg, + listarg +); + +retregular = getdns_context_set_dnssec_allowed_skew( + contextarg, + uint16arg +); + +retregular = getdns_context_set_stub_resolution( + contextarg, + listarg +); + +retregular = getdns_context_set_edns_maximum_udp_payload_size( + contextarg, + uint16arg +); + +retregular = getdns_context_set_edns_extended_rcode( + contextarg, + uint8arg +); + +retregular = getdns_context_set_edns_version( + contextarg, + uint8arg +); + +retregular = getdns_context_set_edns_do_bit( + contextarg, + uint8arg +); + +retregular = getdns_context_set_memory_allocator( + contextarg, + allocfunctionarg +); + +retregular = getdns_context_set_memory_deallocator( + contextarg, + deallocfunctionarg +); + +retregular = getdns_context_set_memory_reallocator( + contextarg, + deallocfunctionarg +); + +return(0); } /* End of main() */ diff --git a/spec/example-simple-answers.c b/spec/example-simple-answers.c new file mode 100644 index 00000000..031af9e2 --- /dev/null +++ b/spec/example-simple-answers.c @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include +#include + +#define UNUSED_PARAM(x) ((void)(x)) + +/* Set up the callback function, which will also do the processing of the results */ +void this_callbackfn(struct getdns_context_t *this_context, + uint16_t this_callback_type, + struct getdns_dict *this_response, + void *this_userarg, + getdns_transaction_t this_transaction_id) +{ + UNUSED_PARAM(this_userarg); /* Not looking at the userarg for this example */ + UNUSED_PARAM(this_context); /* Not looking at the context for this example */ + getdns_return_t this_ret; /* Holder for all function returns */ + if (this_callback_type == GETDNS_CALLBACK_COMPLETE) /* This is a callback with data */ + { + /* Be sure the search returned something */ + uint32_t * this_error = NULL; + this_ret = getdns_dict_get_int(this_response, "status", this_error); // Ignore any error + if (*this_error != GETDNS_RESPSTATUS_GOOD) // If the search didn't return "good" + { + fprintf(stderr, "The search had no results, and a return value of %d. Exiting.", *this_error); + return; + } + struct getdns_list * just_the_addresses_ptr; + this_ret = getdns_dict_get_list(this_response, "just_address_answers", &just_the_addresses_ptr); + if (this_ret != GETDNS_RETURN_GOOD) // This check is really not needed, but prevents a compiler error under "pedantic" + { + fprintf(stderr, "Trying to get the answers failed: %d", this_ret); + return; + } + size_t * num_addresses_ptr = NULL; + this_ret = getdns_list_get_length(just_the_addresses_ptr, num_addresses_ptr); // Ignore any error + /* Go through each record */ + for ( size_t rec_count = 0; rec_count <= *num_addresses_ptr; ++rec_count ) + { + struct getdns_dict * this_address; + this_ret = getdns_list_get_dict(just_the_addresses_ptr, rec_count, &this_address); // Ignore any error + /* Just print the address */ + struct getdns_bindata * this_address_data; + this_ret = getdns_dict_get_bindata(this_address, "address_data", &this_address_data); // Ignore any error + printf("The address is %s", getdns_display_ip_address(this_address_data)); + } + } + else if (this_callback_type == GETDNS_CALLBACK_CANCEL) + fprintf(stderr, "The callback with ID %"PRIu64" was cancelled. Exiting.", this_transaction_id); + else + fprintf(stderr, "The callback got a callback_type of %d. Exiting.", this_callback_type); +} + +int main() +{ + /* Create the DNS context for this call */ + struct getdns_context_t *this_context = NULL; + getdns_return_t context_create_return = getdns_context_create(&this_context, true); + if (context_create_return != GETDNS_RETURN_GOOD) + { + fprintf(stderr, "Trying to create the context failed: %d", context_create_return); + return(GETDNS_RETURN_GENERIC_ERROR); + } + /* Create an event base and put it in the context using the unknown function name */ + struct event_base *this_event_base; + this_event_base = event_base_new(); + if (this_event_base == NULL) + { + fprintf(stderr, "Trying to create the event base failed."); + return(GETDNS_RETURN_GENERIC_ERROR); + } + (void)getdns_extension_set_libevent_base(this_context, this_event_base); + /* Set up the getdns call */ + const char * this_name = "www.example.com"; + char* this_userarg = "somestring"; // Could add things here to help identify this call + getdns_transaction_t this_transaction_id = 0; + + /* Make the call */ + getdns_return_t dns_request_return = getdns_address(this_context, this_name, + NULL, this_userarg, &this_transaction_id, this_callbackfn); + if (dns_request_return == GETDNS_RETURN_BAD_DOMAIN_NAME) + { + fprintf(stderr, "A bad domain name was used: %s. Exiting.", this_name); + return(GETDNS_RETURN_GENERIC_ERROR); + } + else + { + /* Call the event loop */ + int dispatch_return = event_base_dispatch(this_event_base); + UNUSED_PARAM(dispatch_return); + // TODO: check the return value above + } + /* Clean up */ + getdns_context_destroy(this_context); + /* Assuming we get here, leave gracefully */ + exit(EXIT_SUCCESS); +} diff --git a/spec/example-synchronous.c b/spec/example-synchronous.c new file mode 100644 index 00000000..513a3112 --- /dev/null +++ b/spec/example-synchronous.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include + +int main() +{ + getdns_return_t this_ret; /* Holder for all function returns */ + /* Create the DNS context for this call */ + struct getdns_context_t *this_context = NULL; + getdns_return_t context_create_return = getdns_context_create(&this_context, true); + if (context_create_return != GETDNS_RETURN_GOOD) + { + fprintf(stderr, "Trying to create the context failed: %d", context_create_return); + return(GETDNS_RETURN_GENERIC_ERROR); + } + /* Set up the getdns_sync_request call */ + const char * this_name = "www.example.com"; + uint8_t this_request_type = GETDNS_RRTYPE_A; + /* Get the A and AAAA records */ + struct getdns_dict * this_extensions = getdns_dict_create(); + this_ret = getdns_dict_set_int(this_extensions, "return_both_v4_and_v6", GETDNS_EXTENSION_TRUE); + if (this_ret != GETDNS_RETURN_GOOD) + { + fprintf(stderr, "Trying to set an extension do both IPv4 and IPv6 failed: %d", this_ret); + return(GETDNS_RETURN_GENERIC_ERROR); + } + uint32_t this_response_length; + struct getdns_dict * this_response = NULL; + + /* Make the call */ + getdns_return_t dns_request_return = getdns_general_sync(this_context, this_name, this_request_type, + this_extensions, &this_response_length, this_response); + if (dns_request_return == GETDNS_RETURN_BAD_DOMAIN_NAME) + { + fprintf(stderr, "A bad domain name was used: %s. Exiting.", this_name); + return(GETDNS_RETURN_GENERIC_ERROR); + } + else + { + /* Be sure the search returned something */ + uint32_t * this_error = NULL; + this_ret = getdns_dict_get_int(this_response, "status", this_error); // Ignore any error + if (*this_error != GETDNS_RESPSTATUS_GOOD) // If the search didn't return "good" + { + fprintf(stderr, "The search had no results, and a return value of %d. Exiting.", *this_error); + return(GETDNS_RETURN_GENERIC_ERROR); + } + struct getdns_list * just_the_addresses_ptr; + this_ret = getdns_dict_get_list(this_response, "just_address_answers", &just_the_addresses_ptr); // Ignore any error + size_t * num_addresses_ptr = NULL; + this_ret = getdns_list_get_length(just_the_addresses_ptr, num_addresses_ptr); // Ignore any error + /* Go through each record */ + for ( size_t rec_count = 0; rec_count <= *num_addresses_ptr; ++rec_count ) + { + struct getdns_dict * this_address; + this_ret = getdns_list_get_dict(just_the_addresses_ptr, rec_count, &this_address); // Ignore any error + /* Just print the address */ + struct getdns_bindata * this_address_data; + this_ret = getdns_dict_get_bindata(this_address, "address_data", &this_address_data); // Ignore any error + printf("The address is %s", getdns_display_ip_address(this_address_data)); + } + } + /* Clean up */ + getdns_context_destroy(this_context); + getdns_free_sync_request_memory(this_response); + /* Assuming we get here, leave gracefully */ + exit(EXIT_SUCCESS); +} diff --git a/spec/example-tree.c b/spec/example-tree.c new file mode 100644 index 00000000..9bda28ec --- /dev/null +++ b/spec/example-tree.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include +#include +#include + +#define UNUSED_PARAM(x) ((void)(x)) + +/* Set up the callback function, which will also do the processing of the results */ +void this_callbackfn(struct getdns_context_t *this_context, + getdns_return_t this_callback_type, + struct getdns_dict *this_response, + void *this_userarg, + getdns_transaction_t this_transaction_id) +{ + UNUSED_PARAM(this_userarg); /* Not looking at the userarg for this example */ + UNUSED_PARAM(this_context); /* Not looking at the context for this example */ + getdns_return_t this_ret; /* Holder for all function returns */ + if (this_callback_type == GETDNS_CALLBACK_COMPLETE) /* This is a callback with data */ + { + /* Be sure the search returned something */ + uint32_t * this_error = NULL; + this_ret = getdns_dict_get_int(this_response, "status", this_error); // Ignore any error + if (*this_error != GETDNS_RESPSTATUS_GOOD) // If the search didn't return "good" + { + fprintf(stderr, "The search had no results, and a return value of %d. Exiting.", *this_error); + return; + } + /* Find all the answers returned */ + struct getdns_list * these_answers; + this_ret = getdns_dict_get_list(this_response, "replies-tree", &these_answers); + if (this_ret == GETDNS_RETURN_NO_SUCH_DICT_NAME) + { + fprintf(stderr, "Weird: the response had no error, but also no replies-tree. Exiting."); + return; + } + size_t * num_answers_ptr = NULL; + this_ret = getdns_list_get_length(these_answers, num_answers_ptr); + /* Go through each answer */ + for ( size_t rec_count = 0; rec_count <= *num_answers_ptr; ++rec_count ) + { + struct getdns_dict * this_record; + this_ret = getdns_list_get_dict(these_answers, rec_count, &this_record); // Ignore any error + /* Get the answer section */ + struct getdns_list * this_answer; + this_ret = getdns_dict_get_list(this_record, "answer", &this_answer); // Ignore any error + /* Get each RR in the answer section */ + size_t * num_rrs_ptr = NULL; + this_ret = getdns_list_get_length(this_answer, num_rrs_ptr); + for ( size_t rr_count = 0; rr_count <= *num_rrs_ptr; ++rr_count ) + { + struct getdns_dict * this_rr = NULL; + this_ret = getdns_list_get_dict(this_answer, rr_count, &this_rr); // Ignore any error + /* Get the RDATA */ + struct getdns_dict * this_rdata = NULL; + this_ret = getdns_dict_get_dict(this_rr, "rdata", &this_rdata); // Ignore any error + /* Get the RDATA type */ + uint32_t * this_type = NULL; + this_ret = getdns_dict_get_int(this_rdata, "type", this_type); // Ignore any error + /* If it is type A or AAAA, print the value */ + if (*this_type == GETDNS_RRTYPE_A) + { + struct getdns_bindata * this_a_record = NULL; + this_ret = getdns_dict_get_bindata(this_rdata, "ipv4_address", &this_a_record); + if (this_ret == GETDNS_RETURN_NO_SUCH_DICT_NAME) + { + fprintf(stderr, "Weird: the A record at %d in record at %d had no address. Exiting.", + (int) rr_count, (int) rec_count); + return; + } + printf("The IPv4 address is %s", getdns_display_ip_address(this_a_record)); + } + else if (*this_type == GETDNS_RRTYPE_AAAA) + { + struct getdns_bindata * this_aaaa_record = NULL; + this_ret = getdns_dict_get_bindata(this_rdata, "ipv6_address", &this_aaaa_record); + if (this_ret == GETDNS_RETURN_NO_SUCH_DICT_NAME) + { + fprintf(stderr, "Weird: the AAAA record at %d in record at %d had no address. Exiting.", + (int) rr_count, (int) rec_count); + return; + } + printf("The IPv6 address is %s", getdns_display_ip_address(this_aaaa_record)); + } + } + } + } + else if (this_callback_type == GETDNS_CALLBACK_CANCEL) + fprintf(stderr, "The callback with ID %"PRIu64" was cancelled. Exiting.", this_transaction_id); + else + fprintf(stderr, "The callback got a callback_type of %d. Exiting.", this_callback_type); +} + +int main() +{ + /* Create the DNS context for this call */ + struct getdns_context_t *this_context = NULL; + getdns_return_t context_create_return = getdns_context_create(&this_context, true); + if (context_create_return != GETDNS_RETURN_GOOD) + { + fprintf(stderr, "Trying to create the context failed: %d", context_create_return); + return(GETDNS_RETURN_GENERIC_ERROR); + } + /* Create an event base and put it in the context using the unknown function name */ + struct event_base *this_event_base; + this_event_base = event_base_new(); + if (this_event_base == NULL) + { + fprintf(stderr, "Trying to create the event base failed."); + return(GETDNS_RETURN_GENERIC_ERROR); + } + (void)getdns_extension_set_libevent_base(this_context, this_event_base); + /* Set up the getdns call */ + const char * this_name = "www.example.com"; + char* this_userarg = "somestring"; // Could add things here to help identify this call + getdns_transaction_t this_transaction_id = 0; + + /* Make the call */ + getdns_return_t dns_request_return = getdns_address(this_context, this_name, + NULL, this_userarg, &this_transaction_id, this_callbackfn); + if (dns_request_return == GETDNS_RETURN_BAD_DOMAIN_NAME) + { + fprintf(stderr, "A bad domain name was used: %s. Exiting.", this_name); + return(GETDNS_RETURN_GENERIC_ERROR); + } + else + { + /* Call the event loop */ + int dispatch_return = event_base_dispatch(this_event_base); + UNUSED_PARAM(dispatch_return); + // TODO: check the return value above + } + /* Clean up */ + getdns_context_destroy(this_context); + /* Assuming we get here, leave gracefully */ + exit(EXIT_SUCCESS); +} diff --git a/spec/getdns_core_only.c b/spec/getdns_core_only.c new file mode 100644 index 00000000..60064440 --- /dev/null +++ b/spec/getdns_core_only.c @@ -0,0 +1,403 @@ +#include + +/* stuff to make it compile pedantically */ +#define UNUSED_PARAM(x) ((void)(x)) + +int main(){ return(0); } + +/* Function definitions */ + +getdns_return_t +getdns_general( + getdns_context_t context, + const char *name, + uint16_t request_type, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callback +) +{ UNUSED_PARAM(context); UNUSED_PARAM(name); UNUSED_PARAM(request_type); UNUSED_PARAM(extensions); UNUSED_PARAM(userarg); +UNUSED_PARAM(transaction_id); UNUSED_PARAM(callback); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_address( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callback +) +{ UNUSED_PARAM(context); UNUSED_PARAM(name); UNUSED_PARAM(extensions); UNUSED_PARAM(userarg); +UNUSED_PARAM(transaction_id); UNUSED_PARAM(callback); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_hostname( + getdns_context_t context, + struct getdns_dict *address, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callback +) +{ UNUSED_PARAM(context); UNUSED_PARAM(address); UNUSED_PARAM(extensions); UNUSED_PARAM(userarg); +UNUSED_PARAM(transaction_id); UNUSED_PARAM(callback); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_service( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callback +) +{ UNUSED_PARAM(context); UNUSED_PARAM(name); UNUSED_PARAM(extensions); UNUSED_PARAM(userarg); +UNUSED_PARAM(transaction_id); UNUSED_PARAM(callback); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_create( + getdns_context_t *context, + bool set_from_os +) +{ UNUSED_PARAM(context); UNUSED_PARAM(set_from_os); return GETDNS_RETURN_GOOD; } + +void +getdns_context_destroy( + getdns_context_t context +) +{ UNUSED_PARAM(context); } + +getdns_return_t +getdns_cancel_callback( + getdns_context_t context, + getdns_transaction_t transaction_id +) +{ UNUSED_PARAM(context); UNUSED_PARAM(transaction_id); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_general_sync( + getdns_context_t context, + const char *name, + uint16_t request_type, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +) +{ UNUSED_PARAM(context); UNUSED_PARAM(name); UNUSED_PARAM(request_type); UNUSED_PARAM(extensions); +UNUSED_PARAM(response_length); UNUSED_PARAM(response); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_address_sync( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +) +{ UNUSED_PARAM(context); UNUSED_PARAM(name); UNUSED_PARAM(extensions); +UNUSED_PARAM(response_length); UNUSED_PARAM(response); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_hostname_sync( + getdns_context_t context, + struct getdns_dict *address, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +) +{ UNUSED_PARAM(context); UNUSED_PARAM(address); UNUSED_PARAM(extensions); +UNUSED_PARAM(response_length); UNUSED_PARAM(response); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_service_sync( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +) +{ UNUSED_PARAM(context); UNUSED_PARAM(name); UNUSED_PARAM(extensions); +UNUSED_PARAM(response_length); UNUSED_PARAM(response); return GETDNS_RETURN_GOOD; } + +void +getdns_free_sync_request_memory( + struct getdns_dict *response +) +{ UNUSED_PARAM(response); } + +getdns_return_t getdns_list_get_length(struct getdns_list *this_list, size_t *answer) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_list_get_data_type(struct getdns_list *this_list, size_t index, getdns_data_type *answer) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(index); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_list_get_dict(struct getdns_list *this_list, size_t index, struct getdns_dict **answer) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(index); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_list_get_list(struct getdns_list *this_list, size_t index, struct getdns_list **answer) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(index); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_list_get_bindata(struct getdns_list *this_list, size_t index, struct getdns_bindata **answer) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(index); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_list_get_int(struct getdns_list *this_list, size_t index, uint32_t *answer) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(index); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_dict_get_names(struct getdns_dict *this_dict, struct getdns_list **answer) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_dict_get_data_type(struct getdns_dict *this_dict, char *name, getdns_data_type *answer) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(name); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_dict_get_dict(struct getdns_dict *this_dict, char *name, struct getdns_dict **answer) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(name); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_dict_get_list(struct getdns_dict *this_dict, char *name, struct getdns_list **answer) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(name); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_dict_get_bindata(struct getdns_dict *this_dict, char *name, struct getdns_bindata **answer) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(name); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_dict_get_int(struct getdns_dict *this_dict, char *name, uint32_t *answer) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(name); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +struct getdns_list * getdns_list_create() +{ return NULL; } + +void getdns_list_destroy(struct getdns_list *this_list) +{ UNUSED_PARAM(this_list); } + +getdns_return_t getdns_list_set_dict(struct getdns_list *this_list, size_t index, struct getdns_dict *child_dict) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(index); UNUSED_PARAM(child_dict); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_list_set_list(struct getdns_list *this_list, size_t index, struct getdns_list *child_list) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(index); UNUSED_PARAM(child_list); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_list_set_bindata(struct getdns_list *this_list, size_t index, struct getdns_bindata *child_bindata) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(index); UNUSED_PARAM(child_bindata); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_list_set_int(struct getdns_list *this_list, size_t index, uint32_t child_uint32) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(index); UNUSED_PARAM(child_uint32); return GETDNS_RETURN_GOOD; } + +struct getdns_dict * getdns_dict_create() +{ return NULL; } + +void getdns_dict_destroy(struct getdns_dict *this_dict) +{ UNUSED_PARAM(this_dict); } + +getdns_return_t getdns_dict_set_dict(struct getdns_dict *this_dict, char *name, struct getdns_dict *child_dict) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(name); UNUSED_PARAM(child_dict); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_dict_set_list(struct getdns_dict *this_dict, char *name, struct getdns_list *child_list) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(name); UNUSED_PARAM(child_list); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_dict_set_bindata(struct getdns_dict *this_dict, char *name, struct getdns_bindata *child_bindata) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(name); UNUSED_PARAM(child_bindata); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_dict_set_int(struct getdns_dict *this_dict, char *name, uint32_t child_uint32) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(name); UNUSED_PARAM(child_uint32); return GETDNS_RETURN_GOOD; } + +char * +getdns_convert_dns_name_to_fqdn( + char *name_from_dns_response +) +{ UNUSED_PARAM(name_from_dns_response); return NULL; } + +char * +getdns_convert_fqdn_to_dns_name( + char *fqdn_as_string +) +{ UNUSED_PARAM(fqdn_as_string); return NULL; } + +char * +getdns_convert_ulabel_to_alabel( + char *ulabel +) +{ UNUSED_PARAM(ulabel); return NULL; } + +char * +getdns_convert_alabel_to_ulabel( + char *alabel +) +{ UNUSED_PARAM(alabel); return NULL; } + +getdns_return_t +getdns_validate_dnssec( + struct getdns_bindata *record_to_validate, + struct getdns_list *bundle_of_support_records, + struct getdns_list *trust_anchor_rdatas +) +{ UNUSED_PARAM(record_to_validate); UNUSED_PARAM(bundle_of_support_records); UNUSED_PARAM(trust_anchor_rdatas); +return GETDNS_RETURN_GOOD; } + + +char * +getdns_pretty_print_dict( + struct getdns_dict *some_dict +) +{ UNUSED_PARAM(some_dict); return NULL; } + +char * +getdns_display_ip_address( + struct getdns_bindata *bindata_of_ipv4_or_ipv6_address +) +{ UNUSED_PARAM(bindata_of_ipv4_or_ipv6_address); return NULL; } + +getdns_return_t +getdns_context_set_context_update_callback( + getdns_context_t context, + void (*value)(getdns_context_t context, uint16_t changed_item) +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_context_update( + getdns_context_t context, + uint16_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_resolution_type( + getdns_context_t context, + uint16_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_namespaces( + getdns_context_t context, + size_t namespace_count, + uint16_t *namespaces +) +{ UNUSED_PARAM(context); UNUSED_PARAM(namespace_count); UNUSED_PARAM(namespaces); +return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_dns_transport( + getdns_context_t context, + uint16_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_limit_outstanding_queries( + getdns_context_t context, + uint16_t limit +) +{ UNUSED_PARAM(context); UNUSED_PARAM(limit); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_timeout( + getdns_context_t context, + uint16_t timeout +) +{ UNUSED_PARAM(context); UNUSED_PARAM(timeout); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_follow_redirects( + getdns_context_t context, + uint16_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_dns_root_servers( + getdns_context_t context, + struct getdns_list *addresses +) +{ UNUSED_PARAM(context); UNUSED_PARAM(addresses); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_append_name( + getdns_context_t context, + uint16_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_suffix( + getdns_context_t context, + struct getdns_list *value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_dnssec_trust_anchors( + getdns_context_t context, + struct getdns_list *value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_dnssec_allowed_skew( + getdns_context_t context, + uint16_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_stub_resolution( + getdns_context_t context, + struct getdns_list *upstream_list +) +{ UNUSED_PARAM(context); UNUSED_PARAM(upstream_list); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_edns_maximum_udp_payload_size( + getdns_context_t context, + uint16_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_edns_extended_rcode( + getdns_context_t context, + uint8_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_edns_version( + getdns_context_t context, + uint8_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_edns_do_bit( + getdns_context_t context, + uint8_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_memory_allocator( + getdns_context_t context, + void (*value)(size_t somesize) +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_memory_deallocator( + getdns_context_t context, + void (*value)(void*) +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_memory_reallocator( + getdns_context_t context, + void (*value)(void*) +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_extension_set_libevent_base( + getdns_context_t context, + struct event_base *this_event_base +) +{ UNUSED_PARAM(context); UNUSED_PARAM(this_event_base); return GETDNS_RETURN_GOOD; } + diff --git a/spec/getdns_core_only.h b/spec/getdns_core_only.h new file mode 100644 index 00000000..33d3bd32 --- /dev/null +++ b/spec/getdns_core_only.h @@ -0,0 +1,558 @@ +/* Created at 2013-04-02-16-59-04*/ +#ifndef GETDNS_H +#define GETDNS_H + +#include +#include +#include +#include + +#define GETDNS_COMPILATION_COMMENT The API implementation should fill in something here, such as a compilation version string and date, and change it each time the API is compiled. + +/* Return values */ +#define GETDNS_RETURN_GOOD 0 +#define GETDNS_RETURN_GOOD_TEXT Good +#define GETDNS_RETURN_GENERIC_ERROR 1 +#define GETDNS_RETURN_GENERIC_ERROR_TEXT Generic error +#define GETDNS_RETURN_BAD_DOMAIN_NAME 300 +#define GETDNS_RETURN_BAD_DOMAIN_NAME_TEXT Badly-formed domain name in first argument +#define GETDNS_RETURN_BAD_CONTEXT 301 +#define GETDNS_RETURN_BAD_CONTEXT_TEXT Bad value for a context type +#define GETDNS_RETURN_CONTEXT_UPDATE_FAIL 302 +#define GETDNS_RETURN_CONTEXT_UPDATE_FAIL_TEXT Did not update the context +#define GETDNS_RETURN_UNKNOWN_TRANSACTION 303 +#define GETDNS_RETURN_UNKNOWN_TRANSACTION_TEXT An attempt was made to cancel a callback with a transaction_id that is not recognized +#define GETDNS_RETURN_NO_SUCH_LIST_ITEM 304 +#define GETDNS_RETURN_NO_SUCH_LIST_ITEM_TEXT A helper function for lists had an index argument that was too high. +#define GETDNS_RETURN_NO_SUCH_DICT_NAME 305 +#define GETDNS_RETURN_NO_SUCH_DICT_NAME_TEXT A helper function for dicts had a name argument that for a name that is not in the dict. +#define GETDNS_RETURN_WRONG_TYPE_REQUESTED 306 +#define GETDNS_RETURN_WRONG_TYPE_REQUESTED_TEXT A helper function was supposed to return a certain type for an item, but the wrong type was given. +#define GETDNS_RETURN_NO_SUCH_EXTENSION 307 +#define GETDNS_RETURN_NO_SUCH_EXTENSION_TEXT A name in the extensions dict is not a valid extension. +#define GETDNS_RETURN_EXTENSION_MISFORMAT 308 +#define GETDNS_RETURN_EXTENSION_MISFORMAT_TEXT One or more of the extensions is has a bad format. +#define GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED 309 +#define GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED_TEXT A query was made with a context that is using stub resolution and a DNSSEC extension specified. + +/* DNSSEC values */ +#define GETDNS_DNSSEC_SECURE 400 +#define GETDNS_DNSSEC_SECURE_TEXT The record was determined to be secure in DNSSEC +#define GETDNS_DNSSEC_BOGUS 401 +#define GETDNS_DNSSEC_BOGUS_TEXT The record was determined to be bogus in DNSSEC +#define GETDNS_DNSSEC_INDETERMINATE 402 +#define GETDNS_DNSSEC_INDETERMINATE_TEXT The record was not determined to be any state in DNSSEC +#define GETDNS_DNSSEC_INSECURE 403 +#define GETDNS_DNSSEC_INSECURE_TEXT The record was determined to be insecure in DNSSEC +#define GETDNS_DNSSEC_NOT_PERFORMED 404 +#define GETDNS_DNSSEC_NOT_PERFORMED_TEXT DNSSEC validation was not performed (only used for debugging) + +/* Context Variables */ +#define GETDNS_CONTEXT_NAMESPACE_DNS 500 +#define GETDNS_CONTEXT_NAMESPACE_DNS_TEXT See getdns_context_set_namespaces() +#define GETDNS_CONTEXT_NAMESPACE_LOCALNAMES 501 +#define GETDNS_CONTEXT_NAMESPACE_LOCALNAMES_TEXT See getdns_context_set_namespaces() +#define GETDNS_CONTEXT_NAMESPACE_NETBIOS 502 +#define GETDNS_CONTEXT_NAMESPACE_NETBIOS_TEXT See getdns_context_set_namespaces() +#define GETDNS_CONTEXT_NAMESPACE_MDNS 503 +#define GETDNS_CONTEXT_NAMESPACE_MDNS_TEXT See getdns_context_set_namespaces() +#define GETDNS_CONTEXT_NAMESPACE_NIS 504 +#define GETDNS_CONTEXT_NAMESPACE_NIS_TEXT See getdns_context_set_namespaces() +#define GETDNS_CONTEXT_STUB 505 +#define GETDNS_CONTEXT_STUB_TEXT See getdns_context_set_resolution_type() +#define GETDNS_CONTEXT_RECURSING 506 +#define GETDNS_CONTEXT_RECURSING_TEXT See getdns_context_set_resolution_type() +#define GETDNS_CONTEXT_FOLLOW_REDIRECTS 507 +#define GETDNS_CONTEXT_FOLLOW_REDIRECTS_TEXT See getdns_context_set_follow_redirects() +#define GETDNS_CONTEXT_DO_NOT_FOLLOW_REDIRECTS 508 +#define GETDNS_CONTEXT_DO_NOT_FOLLOW_REDIRECTS_TEXT See getdns_context_set_follow_redirects() +#define GETDNS_CONTEXT_UDP_FIRST_AND_FALL_BACK_TO_TCP 509 +#define GETDNS_CONTEXT_UDP_FIRST_AND_FALL_BACK_TO_TCP_TEXT See getdns_context_set_use_udp_tcp() +#define GETDNS_CONTEXT_UDP_ONLY 510 +#define GETDNS_CONTEXT_UDP_ONLY_TEXT See getdns_context_set_use_udp_tcp() +#define GETDNS_CONTEXT_TCP_ONLY 511 +#define GETDNS_CONTEXT_TCP_ONLY_TEXT See getdns_context_set_use_udp_tcp() +#define GETDNS_CONTEXT_TCP_ONLY_KEEP_CONNECTIONS_OPEN 512 +#define GETDNS_CONTEXT_TCP_ONLY_KEEP_CONNECTIONS_OPEN_TEXT See getdns_context_set_use_udp_tcp() +#define GETDNS_CONTEXT_APPEND_NAME_ALWAYS 513 +#define GETDNS_CONTEXT_APPEND_NAME_ALWAYS_TEXT See getdns_context_set_append_name() +#define GETDNS_CONTEXT_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE 514 +#define GETDNS_CONTEXT_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE_TEXT See getdns_context_set_append_name() +#define GETDNS_CONTEXT_GETDNS_CONTEXT_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE 515 +#define GETDNS_CONTEXT_GETDNS_CONTEXT_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE_TEXT See getdns_context_set_append_name() +#define GETDNS_CONTEXT_DO_NOT_APPEND_NAMES 516 +#define GETDNS_CONTEXT_DO_NOT_APPEND_NAMES_TEXT See getdns_context_set_append_name() + +/* Context codes */ +#define GETDNS_CONTEXT_CODE_NAMESPACES 600 +#define GETDNS_CONTEXT_CODE_NAMESPACES_TEXT Change related to getdns_context_set_namespaces +#define GETDNS_CONTEXT_CODE_RESOLUTION_TYPE 601 +#define GETDNS_CONTEXT_CODE_RESOLUTION_TYPE_TEXT Change related to getdns_context_set_resolution_type +#define GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS 602 +#define GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS_TEXT Change related to getdns_context_set_follow_redirects +#define GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS 603 +#define GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS_TEXT Change related to getdns_context_set_upstream_recursive_servers +#define GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS 604 +#define GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS_TEXT Change related to getdns_context_set_dns_root_servers +#define GETDNS_CONTEXT_CODE_USE_UDP_TCP 605 +#define GETDNS_CONTEXT_CODE_USE_UDP_TCP_TEXT Change related to getdns_context_set_use_udp_tcp +#define GETDNS_CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES 606 +#define GETDNS_CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES_TEXT Change related to getdns_context_set_limit_outstanding_queries +#define GETDNS_CONTEXT_CODE_APPEND_NAME 607 +#define GETDNS_CONTEXT_CODE_APPEND_NAME_TEXT Change related to getdns_context_set_append_name +#define GETDNS_CONTEXT_CODE_SUFFIX 608 +#define GETDNS_CONTEXT_CODE_SUFFIX_TEXT Change related to getdns_context_set_suffix +#define GETDNS_CONTEXT_CODE_DNSSEC_TRUST_ANCHORS 609 +#define GETDNS_CONTEXT_CODE_DNSSEC_TRUST_ANCHORS_TEXT Change related to getdns_context_set_dnssec_trust_anchors +#define GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE 610 +#define GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE_TEXT Change related to getdns_context_set_edns_maximum_udp_payload_size +#define GETDNS_CONTEXT_CODE_EDNS_EXTENDED_RCODE 611 +#define GETDNS_CONTEXT_CODE_EDNS_EXTENDED_RCODE_TEXT Change related to getdns_context_set_edns_extended_rcode +#define GETDNS_CONTEXT_CODE_EDNS_VERSION 612 +#define GETDNS_CONTEXT_CODE_EDNS_VERSION_TEXT Change related to getdns_context_set_edns_version +#define GETDNS_CONTEXT_CODE_EDNS_DO_BIT 613 +#define GETDNS_CONTEXT_CODE_EDNS_DO_BIT_TEXT Change related to getdns_context_set_edns_do_bit +#define GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW 614 +#define GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW_TEXT Change related to getdns_context_set_dnssec_allowed_skew +#define GETDNS_CONTEXT_CODE_MEMORY_ALLOCATOR 615 +#define GETDNS_CONTEXT_CODE_MEMORY_ALLOCATOR_TEXT Change related to getdns_context_set_memory_allocator +#define GETDNS_CONTEXT_CODE_MEMORY_DEALLOCATOR 616 +#define GETDNS_CONTEXT_CODE_MEMORY_DEALLOCATOR_TEXT Change related to getdns_context_set_memory_deallocator +#define GETDNS_CONTEXT_CODE_MEMORY_REALLOCATOR 617 +#define GETDNS_CONTEXT_CODE_MEMORY_REALLOCATOR_TEXT Change related to getdns_context_set_memory_reallocator + +/* Callback Type Variables */ +#define GETDNS_CALLBACK_COMPLETE 700 +#define GETDNS_CALLBACK_COMPLETE_TEXT The response has the requested data in it +#define GETDNS_CALLBACK_CANCEL 701 +#define GETDNS_CALLBACK_CANCEL_TEXT The calling program cancelled the callback; response is NULL +#define GETDNS_CALLBACK_TIMEOUT 702 +#define GETDNS_CALLBACK_TIMEOUT_TEXT The requested action timed out; response is NULL +#define GETDNS_CALLBACK_ERROR 703 +#define GETDNS_CALLBACK_ERROR_TEXT The requested action had an error; response is NULL + +/* Type Of Name Services */ +#define GETDNS_NAMETYPE_DNS 800 +#define GETDNS_NAMETYPE_DNS_TEXT Normal DNS (RFC 1035) +#define GETDNS_NAMETYPE_WINS 801 +#define GETDNS_NAMETYPE_WINS_TEXT The WINS name service (some reference needed) + +/* Status Codes for Responses */ +#define GETDNS_RESPSTATUS_GOOD 900 +#define GETDNS_RESPSTATUS_GOOD_TEXT At least one response was returned +#define GETDNS_RESPSTATUS_NO_NAME 901 +#define GETDNS_RESPSTATUS_NO_NAME_TEXT Queries for the name yielded all negative responses +#define GETDNS_RESPSTATUS_ALL_TIMEOUT 902 +#define GETDNS_RESPSTATUS_ALL_TIMEOUT_TEXT All queries for the name timed out +#define GETDNS_RESPSTATUS_NO_SECURE_ANSWERS 903 +#define GETDNS_RESPSTATUS_NO_SECURE_ANSWERS_TEXT The context setting for getting only secure responses was specified, and at least one DNS response was received, but no DNS response was determined to be secure through DNSSEC. + +/* Values Associated With Extensions */ +#define GETDNS_EXTENSION_TRUE 1000 +#define GETDNS_EXTENSION_TRUE_TEXT Turn on the extension +#define GETDNS_EXTENSION_FALSE 1001 +#define GETDNS_EXTENSION_FALSE_TEXT Do not turn on the extension + +/* Values Associated With DNS Errors Found By The API */ +#define GETDNS_BAD_DNS_CNAME_IN_TARGET 1100 +#define GETDNS_BAD_DNS_CNAME_IN_TARGET_TEXT A DNS query type that does not allow a target to be a CNAME pointed to a CNAME +#define GETDNS_BAD_DNS_ALL_NUMERIC_LABEL 1101 +#define GETDNS_BAD_DNS_ALL_NUMERIC_LABEL_TEXT One or more labels in a returned domain name is all-numeric; this is not legal for a hostname +#define GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE 1102 +#define GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE_TEXT A DNS query for a type other than CNAME returned a CNAME response + +/* Defines for RRtypes (from 2012-12) */ + +#define GETDNS_RRTYPE_A 1 +#define GETDNS_RRTYPE_NS 2 +#define GETDNS_RRTYPE_MD 3 +#define GETDNS_RRTYPE_MF 4 +#define GETDNS_RRTYPE_CNAME 5 +#define GETDNS_RRTYPE_SOA 6 +#define GETDNS_RRTYPE_MB 7 +#define GETDNS_RRTYPE_MG 8 +#define GETDNS_RRTYPE_MR 9 +#define GETDNS_RRTYPE_NULL 10 +#define GETDNS_RRTYPE_WKS 11 +#define GETDNS_RRTYPE_PTR 12 +#define GETDNS_RRTYPE_HINFO 13 +#define GETDNS_RRTYPE_MINFO 14 +#define GETDNS_RRTYPE_MX 15 +#define GETDNS_RRTYPE_TXT 16 +#define GETDNS_RRTYPE_RP 17 +#define GETDNS_RRTYPE_AFSDB 18 +#define GETDNS_RRTYPE_X25 19 +#define GETDNS_RRTYPE_ISDN 20 +#define GETDNS_RRTYPE_RT 21 +#define GETDNS_RRTYPE_NSAP 22 +#define GETDNS_RRTYPE_SIG 24 +#define GETDNS_RRTYPE_KEY 25 +#define GETDNS_RRTYPE_PX 26 +#define GETDNS_RRTYPE_GPOS 27 +#define GETDNS_RRTYPE_AAAA 28 +#define GETDNS_RRTYPE_LOC 29 +#define GETDNS_RRTYPE_NXT 30 +#define GETDNS_RRTYPE_EID 31 +#define GETDNS_RRTYPE_NIMLOC 32 +#define GETDNS_RRTYPE_SRV 33 +#define GETDNS_RRTYPE_ATMA 34 +#define GETDNS_RRTYPE_NAPTR 35 +#define GETDNS_RRTYPE_KX 36 +#define GETDNS_RRTYPE_CERT 37 +#define GETDNS_RRTYPE_A6 38 +#define GETDNS_RRTYPE_DNAME 39 +#define GETDNS_RRTYPE_SINK 40 +#define GETDNS_RRTYPE_OPT 41 +#define GETDNS_RRTYPE_APL 42 +#define GETDNS_RRTYPE_DS 43 +#define GETDNS_RRTYPE_SSHFP 44 +#define GETDNS_RRTYPE_IPSECKEY 45 +#define GETDNS_RRTYPE_RRSIG 46 +#define GETDNS_RRTYPE_NSEC 47 +#define GETDNS_RRTYPE_DNSKEY 48 +#define GETDNS_RRTYPE_DHCID 49 +#define GETDNS_RRTYPE_NSEC3 50 +#define GETDNS_RRTYPE_NSEC3PARAM 51 +#define GETDNS_RRTYPE_TLSA 52 +#define GETDNS_RRTYPE_HIP 55 +#define GETDNS_RRTYPE_NINFO 56 +#define GETDNS_RRTYPE_RKEY 57 +#define GETDNS_RRTYPE_TALINK 58 +#define GETDNS_RRTYPE_CDS 59 +#define GETDNS_RRTYPE_SPF 99 +#define GETDNS_RRTYPE_UINFO 100 +#define GETDNS_RRTYPE_UID 101 +#define GETDNS_RRTYPE_GID 102 +#define GETDNS_RRTYPE_UNSPEC 103 +#define GETDNS_RRTYPE_NID 104 +#define GETDNS_RRTYPE_L32 105 +#define GETDNS_RRTYPE_L64 106 +#define GETDNS_RRTYPE_LP 107 +#define GETDNS_RRTYPE_TKEY 249 +#define GETDNS_RRTYPE_TSIG 250 +#define GETDNS_RRTYPE_IXFR 251 +#define GETDNS_RRTYPE_AXFR 252 +#define GETDNS_RRTYPE_MAILB 253 +#define GETDNS_RRTYPE_MAILA 254 +#define GETDNS_RRTYPE_URI 256 +#define GETDNS_RRTYPE_CAA 257 +#define GETDNS_RRTYPE_TA 32768 +#define GETDNS_RRTYPE_DLV 32769 + +/* Various typedefs */ +typedef struct getdns_context_t *getdns_context_t; +typedef uint16_t getdns_return_t; +typedef uint64_t getdns_transaction_t; +typedef enum some_data_type { + t_dict, t_list, t_int, t_bindata +} getdns_data_type; +typedef struct getdns_bindata { + size_t size; + uint8_t *binary_stuff; +} some_bindata; +typedef struct getdns_dict some_dict; +typedef struct getdns_list some_list; + +/* Helper functions for data structures */ + +/* Lists: get the length, get the data_type of the value at a given + position, and get the data at a given position */ +getdns_return_t getdns_list_get_length(struct getdns_list *this_list, size_t *answer); +getdns_return_t getdns_list_get_data_type(struct getdns_list *this_list, size_t index, getdns_data_type *answer); +getdns_return_t getdns_list_get_dict(struct getdns_list *this_list, size_t index, struct getdns_dict **answer); +getdns_return_t getdns_list_get_list(struct getdns_list *this_list, size_t index, struct getdns_list **answer); +getdns_return_t getdns_list_get_bindata(struct getdns_list *this_list, size_t index, struct getdns_bindata **answer); +getdns_return_t getdns_list_get_int(struct getdns_list *this_list, size_t index, uint32_t *answer); + +/* Dicts: get the list of names, get the data_type of the + value at a given name, and get the data at a given name */ +getdns_return_t getdns_dict_get_names(struct getdns_dict *this_dict, struct getdns_list **answer); +getdns_return_t getdns_dict_get_data_type(struct getdns_dict *this_dict, char *name, getdns_data_type *answer); +getdns_return_t getdns_dict_get_dict(struct getdns_dict *this_dict, char *name, struct getdns_dict **answer); +getdns_return_t getdns_dict_get_list(struct getdns_dict *this_dict, char *name, struct getdns_list **answer); +getdns_return_t getdns_dict_get_bindata(struct getdns_dict *this_dict, char *name, struct getdns_bindata **answer); +getdns_return_t getdns_dict_get_int(struct getdns_dict *this_dict, char *name, uint32_t *answer); + + +/* Lists: create, destroy, and set the data at a given position */ +struct getdns_list * getdns_list_create(); +void getdns_list_destroy(struct getdns_list *this_list); +getdns_return_t getdns_list_set_dict(struct getdns_list *this_list, size_t index, struct getdns_dict *child_dict); +getdns_return_t getdns_list_set_list(struct getdns_list *this_list, size_t index, struct getdns_list *child_list); +getdns_return_t getdns_list_set_bindata(struct getdns_list *this_list, size_t index, struct getdns_bindata *child_bindata); +getdns_return_t getdns_list_set_int(struct getdns_list *this_list, size_t index, uint32_t child_uint32); + +/* Dicts: create, destroy, and set the data at a given name */ +struct getdns_dict * getdns_dict_create(); +void getdns_dict_destroy(struct getdns_dict *this_dict); +getdns_return_t getdns_dict_set_dict(struct getdns_dict *this_dict, char *name, struct getdns_dict *child_dict); +getdns_return_t getdns_dict_set_list(struct getdns_dict *this_dict, char *name, struct getdns_list *child_list); +getdns_return_t getdns_dict_set_bindata(struct getdns_dict *this_dict, char *name, struct getdns_bindata *child_bindata); +getdns_return_t getdns_dict_set_int(struct getdns_dict *this_dict, char *name, uint32_t child_uint32); + +/* Callback arguments */ +typedef void (*getdns_callback_t)( + getdns_context_t context, + uint16_t callback_type, + struct getdns_dict *response, + void *userarg, + getdns_transaction_t transaction_id); + +/* Function definitions */ + +getdns_return_t +getdns_general( + getdns_context_t context, + const char *name, + uint16_t request_type, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn +); +getdns_return_t +getdns_address( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn +); +getdns_return_t +getdns_hostname( + getdns_context_t context, + struct getdns_dict *address, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn +); +getdns_return_t +getdns_service( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn +); + +getdns_return_t +getdns_context_create( + getdns_context_t *context, + bool set_from_os +); + +void +getdns_context_destroy( + getdns_context_t context +); + +getdns_return_t +getdns_cancel_callback( + getdns_context_t context, + getdns_transaction_t transaction_id +); + +getdns_return_t +getdns_general_sync( + getdns_context_t context, + const char *name, + uint16_t request_type, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +); + +getdns_return_t +getdns_address_sync( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +); + +getdns_return_t +getdns_hostname_sync( + getdns_context_t context, + struct getdns_dict *address, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +); + +getdns_return_t +getdns_service_sync( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +); + +void +getdns_free_sync_request_memory( + struct getdns_dict *response +); + +char * +getdns_convert_dns_name_to_fqdn( + char *name_from_dns_response +); + +char * +getdns_convert_fqdn_to_dns_name( + char *fqdn_as_string +); + +char * +getdns_convert_ulabel_to_alabel( + char *ulabel +); + +char * +getdns_convert_alabel_to_ulabel( + char *alabel +); + +getdns_return_t +getdns_validate_dnssec( + struct getdns_bindata *record_to_validate, + struct getdns_list *bundle_of_support_records, + struct getdns_list *trust_anchor_rdatas +); + +char * +getdns_pretty_print_dict( + struct getdns_dict *some_dict +); + +char * +getdns_display_ip_address( + struct getdns_bindata *bindata_of_ipv4_or_ipv6_address +); + +getdns_return_t +getdns_context_set_context_update_callback( + getdns_context_t context, + void (*value)(getdns_context_t context, uint16_t changed_item) +); + +getdns_return_t +getdns_context_set_resolution_type( + getdns_context_t context, + uint16_t value +); + +getdns_return_t +getdns_context_set_namespaces( + getdns_context_t context, + size_t namespace_count, + uint16_t *namespaces +); + +getdns_return_t +getdns_context_set_dns_transport( + getdns_context_t context, + uint16_t value +); + +getdns_return_t +getdns_context_set_limit_outstanding_queries( + getdns_context_t context, + uint16_t limit +); + +getdns_return_t +getdns_context_set_timeout( + getdns_context_t context, + uint16_t timeout +); + +getdns_return_t +getdns_context_set_follow_redirects( + getdns_context_t context, + uint16_t value +); + +getdns_return_t +getdns_context_set_dns_root_servers( + getdns_context_t context, + struct getdns_list *addresses +); + +getdns_return_t +getdns_context_set_append_name( + getdns_context_t context, + uint16_t value +); + +getdns_return_t +getdns_context_set_suffix( + getdns_context_t context, + struct getdns_list *value +); + +getdns_return_t +getdns_context_set_dnssec_trust_anchors( + getdns_context_t context, + struct getdns_list *value +); + +getdns_return_t +getdns_context_set_dnssec_allowed_skew( + getdns_context_t context, + uint16_t value +); + +getdns_return_t +getdns_context_set_stub_resolution( + getdns_context_t context, + struct getdns_list *upstream_list +); + +getdns_return_t +getdns_context_set_edns_maximum_udp_payload_size( + getdns_context_t context, + uint16_t value +); + +getdns_return_t +getdns_context_set_edns_extended_rcode( + getdns_context_t context, + uint8_t value +); + +getdns_return_t +getdns_context_set_edns_version( + getdns_context_t context, + uint8_t value +); + +getdns_return_t +getdns_context_set_edns_do_bit( + getdns_context_t context, + uint8_t value +); + +getdns_return_t +getdns_context_set_memory_allocator( + getdns_context_t context, + void (*value)(size_t somesize) +); + +getdns_return_t +getdns_context_set_memory_deallocator( + getdns_context_t context, + void (*value)(void*) +); + +getdns_return_t +getdns_context_set_memory_reallocator( + getdns_context_t context, + void (*value)(void*) +); + +#endif /* GETDNS_H */ diff --git a/spec/getdns_libevent.h b/spec/getdns_libevent.h new file mode 100644 index 00000000..fd9effce --- /dev/null +++ b/spec/getdns_libevent.h @@ -0,0 +1,9 @@ +#include +#include + +/* For libevent, which we are using for these examples */ +getdns_return_t +getdns_extension_set_libevent_base( + getdns_context_t context, + struct event_base *this_event_base +); diff --git a/spec/index.html b/spec/index.html new file mode 100644 index 00000000..99c6218c --- /dev/null +++ b/spec/index.html @@ -0,0 +1,2182 @@ + +DNS API Description + + + + + +

Description of the getdns API

+

Paul Hoffman, Editor

+

Document version: "getdns April 2013"

+ +

This document describes a modern asynchronous DNS API. This new API is intended to be useful to +application developers and operating system distributors as a way of making +all types of DNS information easily available in many types of programs. The major features +of this new API are:

+ +
    +
  • Full support for event-driven programming
  • +
  • Supports DNSSEC in multiple ways
  • +
  • Mirroring of the resolution in getaddrinfo()
  • +
  • Easily supports all RRtypes, even those yet to be defined
  • +
+ +

There is more background into the design and future goals of this API +later in this document.

+ +

This document was discussed on the +getdns-api mailing list; future versions of the API might be discussed there as well. +(If you +want to contact the editor off-list, please send mail to paul.hoffman@vpnc.org.)

+ +

1. The getdns Async Functions

+ +

The API has four async functions:

+ +
    + +
  • getdns_address for doing getaddrinfo()-like address lookups
  • + +
  • getdns_hostname for doing getnameinfo()-like name lookups
  • + +
  • getdns_service for getting results from SRV lookups
  • + +
  • getdns_general for looking up any type of DNS record
  • + +
+ +

1.1 getdns_general()

+ +
getdns_return_t +getdns_general( + getdns_context_t context, + const char *name, + uint16_t request_type, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn +); +
+ +

context

+

A pointer to the DNS context that is to be used with this call. DNS contexts are +described later in this document. Note that a context must be created +before calling the function.

+ +

*name

+

The ASCII-based domain name to be looked up as a string. This can also be +an IPv4 or IPv6 address for request types that take addresses instead of domain names, +such as PTR. The values here follow the rules in section 2.1 of RFC 4343 +to allow non-ASCII octets and special characters in labels.

+ +

request_type

+

Specifies the RRtype for the query; the RRtype numbers are listed in the IANA +registry. For example, to get the NS records, request_type would be 2. The API also has +defined macros for most of the RRtypes by name; the definition names all start with +"GETDNS_RRTYPE_". For example, to get the NS records, you can also set the +request_type to GETDNS_RRTYPE_NS. +(The full list of request types is always +here.)

+ +

*extensions

+

Specifies the extensions for this request; the value may be NULL if there are no +extensions. See the section below for information on how to specify +the extensions used for a request.

+ +

*userarg

+

A void* that is passed to the function, which the funciton +returns to the callback function untouched. userarg can be used by the callback +function for any user-specific data needed. This can be NULL.

+ +

*transaction_id

+

A pointer to a value that is filled in by the +function to identify the callback being made. +This pointer can be NULL, in which case it is ignored and no value is assigned. +The getdns_cancel_callback() function uses the +transaction_id to determine which callback is to be cancelled. +If the function fails, +transaction_id is set to 0.

+ +

*callbackfn

+

A pointer to a callback function that is defined by the application. +Typically, the callback function will do all the processing on the results from +the API. The parameters of the callback are defined below. This really needs +to be a pointer to a function (and not something like NULL); otherwise, the +results are unpredictable.

+ +

The async getdns functions return GETDNS_RETURN_GOOD if the call was properly formatted. +It returns GETDNS_RETURN_BAD_DOMAIN_NAME if the API determines that the name passed to +the function was bad, GETDNS_RETURN_BAD_CONTEXT if the context pointer is bad, +GETDNS_RETURN_NO_SUCH_EXTENSION if one or more extensions do not exist, or +GETDNS_RETURN_EXTENSION_MISFORMAT if the contents of one or more of the +extensions is incorrect. All of the return values are given later in this document.

+ +

1.2 getdns_address()

+ +
getdns_return_t +getdns_address( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn +); +
+ +

There are three critical differences between getdns_address() and +getdns_general() beyond the missing request_type argument:

+ +
    + +
  • In getdns_address(), the name argument can only take a host name.
  • + +
  • You do not need to include a return_both_v4_and_v6 extension with the call in +getdns_address(): it will always return both IPv4 and IPv6 addresses.
  • + +
  • getdns_address() always uses all of namespaces from the context (to better emulate +getaddrinfo()), while getdns_general() only uses the DNS namespace.
  • + +
+ +

1.3 getdns_hostname()

+ +
getdns_return_t +getdns_hostname( + getdns_context_t context, + struct getdns_dict *address, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn +); +
+ +

The address is given as a getdns_dict data structure (defined below). The list must +have two names: address_type (whose value is a bindata; it is currently either "IPv4" +or "IPv6") and address_data (whose value is a bindata).

+ +

1.4 getdns_service()

+ +
getdns_return_t +getdns_service( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn +); +
+ +

name must be a domain name for an SRV lookup; the call returns the +relevant SRV information for the name.

+ +

1.5 Callback Functions for getdns

+ +

A call to the async getdns functions typically returns before any network or file I/O occurs. After +the API marshalls all the needed information, it calls the callback function that was passed by the +application. The callback function might be called at any time, even before the calling function +has returned. The API guarantees that the callback will be called exactly once unless the calling function +returned an error, in which case the callback function is never called.

+ +

The getdns calling function calls the callback with the parameters defined +as follows:

+
+typedef void (*getdns_callback_t)( + getdns_context_t context, + uint16_t callback_type, + struct getdns_dict *response, + void *userarg, + getdns_transaction_t transaction_id); +
+ +

context

+

The DNS context that was used in the calling function. See below for a description of the basic use of contexts, and later for more advanced use.

+ +

callback_type

+

Supplies the reason for the callback. See below for the codes and reasons.

+ +

*response

+

A response object with the response data. This is described below. The response +object is part of the API's memory space, and will be freed by the API with the callback returns.

+ +

*userarg

+

Identical to the *userarg passed to the calling function.

+ +

transaction_id

+

The transaction identifier that was assigned by the calling function.

+ +

The following are the values for callback_type.

+ +

GETDNS_CALLBACK_COMPLETE

+

The response has the requested data in it

+

GETDNS_CALLBACK_CANCEL

+

The calling program cancelled the callback; response is NULL

+

GETDNS_CALLBACK_TIMEOUT

+

The requested action timed out; response is NULL

+

GETDNS_CALLBACK_ERROR

+

The requested action had an error; response is NULL

+ + +

1.6 Setting Up The DNS Context

+ +

Calls to getdns functions require a DNS context, which is a group of API settings +that affect how DNS calls are made. For most applications, a default context is sufficient.

+ +

To create a new DNS context, use the function:

+ +
getdns_return_t +getdns_context_create( + getdns_context_t *context, + bool set_from_os +); +
+ +

The call to getdns_context_create immediately returns a context that can +be used with other API calls; that context contains the API's default values. Most applications will +want set_from_os set to true.

+ +

To clean up the context, including cleaning up all outstanding transactions that were called +using this context, use the function:

+ +
void +getdns_context_destroy( + getdns_context_t context +); +
+ +

When getdns_context_destroy() returns, the +application knows that all outstanding transactions associated with this +context will have been called; callbacks that had not been called before +getdns_context_destroy() was called will be called with a callback_type of +GETDNS_CALLBACK_CANCEL. getdns_context_destroy() returns after +all of the needed cleanup is done and callbacks are made.

+ +

1.7 Canceling a Callback

+ +

To cancel an outstanding callback, use the following function.

+ +
getdns_return_t +getdns_cancel_callback( + getdns_context_t context, + getdns_transaction_t transaction_id +); +
+ +

This causes the API to call the callback with a callback_type of +GETDNS_CALLBACK_CANCEL if the callback for this transaction_id has not +already been called. The callback code for cancellation should clean up any memory related to the +identified call, such as to deallocate the memory for the userarg. +getdns_cancel_callback() may return immediately, even before the callback finishes its +work and returns. Calling getdns_cancel_callback() with a transaction_id +of a callback that has already been called or an unknown transaction_id returns +GETDNS_RETURN_UNKNOWN_TRANSACTION; otherwise, getdns_cancel_callback() +returns GETDNS_RETURN_GOOD.

+ +

1.8 Event-driven Programs

+ +

Event-driven programs (sometimes called "async programs") require an event +base and event loop (among other things). Different event libraries have +different structures or the event base. Because of this, there is no standard +method to set the event base in the DNS API: those are all added as +extensions. The API is distributed as a core package and one or more sets of +extensions to align with event libraries. It is mandatory to use one of the extension +functions to set the event base in the DNS context; this is required before +calling any event-driven calls like the getdns functions.

+ +

Each implementation of the DNS API will specify an extension function that +tells the DNS context which event base is being used. For example, one +implementation of this API that uses the libevent event library might name +this function "getdns_extension_set_libevent_base()" while +another might name it +"getdns_extension_set_eventbase_for_libevent()"; the two +extension functions could have very different calling patterns and return +values. Thus, the application developer must read the API documentation +(not just this design document) in order to determine what extension function +to use to tell the API the event base to use.

+ +

The structure of a typical event-driven application might look like the following pseudocode. +The code in italics is specific to the event mechanism.

+ +
+Includes for one or more regular C libraries
+An include for the getdns library specific to the event library you use
+Definition of your callback function
+    Get the DNS data from the allocated pointer
+    Process that data
+    Check for errors
+Definition of main()
+    Create context
+    Set up your event base
+    Point the context to your event base
+    Set up the getdns call arguments
+    Make the getdns call
+    Check if the getdns return is good
+    Destroy the context
+    Exit
+
+ +

The API does not have direct support for a polling interface. Instead, the callback interface is +specifically designed to allow an application that wants to process results in polling instead of in +callbacks to be able to create its own polling interface fairly trivially. Such a program would +create a data structure for the calls, including their transaction_id and +userag. The userarg could be the polling data structure or have a pointer to it. +The application would have just +one callback function for all requests, and that function would copy the response into +application memory, update the data structure based on the transaction_id index, +and return from the callback. The polling code could then check the data structure for any updates +at its leisure.

+ +

1.9 Calling the API Synchronously (Without Events)

+ +

Thare are functions parallel to the four getdns async functions, +except that there is no callback. That is, when an application calls one of these +synchronous functions, the +API gathers all the required information and then returns the result. The value returned is exactly the +same as the response returned in the callback if you had used the async version of the function.

+ +
getdns_return_t +getdns_general_sync( + getdns_context_t context, + const char *name, + uint16_t request_type, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +); +
+ +
getdns_return_t +getdns_address_sync( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +); +
+ +
getdns_return_t +getdns_hostname_sync( + getdns_context_t context, + struct getdns_dict *address, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +); +
+ +
getdns_return_t +getdns_service_sync( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +); +
+ +

When you are done with the data in the response, use the following function so that the API can +free the memory from its internal pool.

+ +
void +getdns_free_sync_request_memory( + struct getdns_dict *response +); +
+ +

2. Data structures in the API

+ +

The API returns data structures. The data structure is not a representational language like JSON: +it is really just a data structure. Data structures can have four types of members:

+ +
    + +
  • list is an ordered list, like JSON and Python lists. +The members of the list can be any of the four data types.
  • + +
  • dict is a name-value pair, like a JSON object or Python dict. The +name is a string literal, and the value can be any of the four data types. The order of the +name-value pairs in a dict is not important.
  • + +
  • int is an integer compatible with uint32_t.
  • + +
  • bindata is a struct to hold binary data. It is defined as +{ size_t size; uint8_t *binary_stuff; }.
  • + +
+ +

The API comes with helper functions to get data from the list and dict data types:

+ +
+/* Lists: get the length, get the data_type of the value at a given + position, and get the data at a given position */ +getdns_return_t getdns_list_get_length(struct getdns_list *this_list, size_t *answer); +getdns_return_t getdns_list_get_data_type(struct getdns_list *this_list, size_t index, getdns_data_type *answer); +getdns_return_t getdns_list_get_dict(struct getdns_list *this_list, size_t index, struct getdns_dict **answer); +getdns_return_t getdns_list_get_list(struct getdns_list *this_list, size_t index, struct getdns_list **answer); +getdns_return_t getdns_list_get_bindata(struct getdns_list *this_list, size_t index, struct getdns_bindata **answer); +getdns_return_t getdns_list_get_int(struct getdns_list *this_list, size_t index, uint32_t *answer); + +/* Dicts: get the list of names, get the data_type of the + value at a given name, and get the data at a given name */ +getdns_return_t getdns_dict_get_names(struct getdns_dict *this_dict, struct getdns_list **answer); +getdns_return_t getdns_dict_get_data_type(struct getdns_dict *this_dict, char *name, getdns_data_type *answer); +getdns_return_t getdns_dict_get_dict(struct getdns_dict *this_dict, char *name, struct getdns_dict **answer); +getdns_return_t getdns_dict_get_list(struct getdns_dict *this_dict, char *name, struct getdns_list **answer); +getdns_return_t getdns_dict_get_bindata(struct getdns_dict *this_dict, char *name, struct getdns_bindata **answer); +getdns_return_t getdns_dict_get_int(struct getdns_dict *this_dict, char *name, uint32_t *answer); +
+ +

All of these helper getter functions return GETDNS_RETURN_GOOD if the call is successful. +The list functions will return GETDNS_RETURN_NO_SUCH_LIST_ITEM if the index argument is +out of range; the dict functions will return GETDNS_RETURN_NO_SUCH_DICT_NAME if the name +argument doesn't exist in the dict. The functions also return GETDNS_RETURN_WRONG_TYPE_REQUESTED +if the requested data type doesn't match the contents of the indexed argument or name.

+ +

This document uses graphical representations of data structures. It is important to note that +this is only a graphical representation; the brackets, commas, quotation marks, comments, and so on +are not part of the data. Also, this document uses macro names instead of some of the int +arguments; of course, the data structures have the actual int in them.

+ +

2.1 Creating Data Structures

+ +

Some of the features of the API require that you create your own data structures to be used in +arguments passed to the API. For example, if you want to use any extensions for the calling functions, +you need to create a dict. The requisite functions are:

+ +
+/* Lists: create, destroy, and set the data at a given position */ +struct getdns_list * getdns_list_create(); +void getdns_list_destroy(struct getdns_list *this_list); +getdns_return_t getdns_list_set_dict(struct getdns_list *this_list, size_t index, struct getdns_dict *child_dict); +getdns_return_t getdns_list_set_list(struct getdns_list *this_list, size_t index, struct getdns_list *child_list); +getdns_return_t getdns_list_set_bindata(struct getdns_list *this_list, size_t index, struct getdns_bindata *child_bindata); +getdns_return_t getdns_list_set_int(struct getdns_list *this_list, size_t index, uint32_t child_uint32); + +/* Dicts: create, destroy, and set the data at a given name */ +struct getdns_dict * getdns_dict_create(); +void getdns_dict_destroy(struct getdns_dict *this_dict); +getdns_return_t getdns_dict_set_dict(struct getdns_dict *this_dict, char *name, struct getdns_dict *child_dict); +getdns_return_t getdns_dict_set_list(struct getdns_dict *this_dict, char *name, struct getdns_list *child_list); +getdns_return_t getdns_dict_set_bindata(struct getdns_dict *this_dict, char *name, struct getdns_bindata *child_bindata); +getdns_return_t getdns_dict_set_int(struct getdns_dict *this_dict, char *name, uint32_t child_uint32); +
+ +

These helper setter functions return GETDNS_RETURN_GOOD if the call is successful. +The list functions will return GETDNS_RETURN_NO_SUCH_LIST_ITEM if the index argument is +out of range; the dict functions will return GETDNS_RETURN_NO_SUCH_DICT_NAME if the name +argument doesn't exist in the dict. The functions also return GETDNS_RETURN_WRONG_TYPE_REQUESTED +if the requested data type doesn't match the contents of the indexed argument or name.

+ +

3. Extensions

+ +

Extensions are dict data structures. The names in the dict are the names of the extensions. +The definition of each extension describes the value associated with the name. For most extensions, +it is an on-off boolean, and the value is GETDNS_EXTENSION_TRUE. (There is +not currently a good reason to specify an extension name and give it a value of GETDNS_EXTENSION_FALSE, +but that is allowed by the API.)

+ +

For example, to create a dict for extensions and specify the extension to only return +results that have been validated with DNSSEC, you might use:

+ +
+/* . . . */
+struct getdns_dict * this_extensions = getdns_dict_create();
+this_ret = getdns_dict_set_int(this_extensions, "dnssec_return_only_secure", GETDNS_EXTENSION_TRUE);
+/* . . . Do some processing with the extensions and results . . . */
+/* Remember to clean up memory*/
+getdns_dict_destroy(this_extensions);
+
+ +

The extensions described in this section are are: + +

    + +
  • dnssec_return_status
  • + +
  • dnssec_return_only_secure
  • + +
  • dnssec_return_supporting_responses
  • + +
  • return_both_v4_and_v6
  • + +
  • add_opt_parameters
  • + +
  • add_warning_for_bad_dns
  • + +
  • specify_class
  • + +
  • return_api_information
  • + +
  • return_call_debugging
  • + +
+ +

3.1 Extensions for DNSSEC

+ +

If an application wants the API to do DNSSEC validation for a request, it must set one or more +DNSSEC-related extensions. Note that the default is for none of these extensions to be set and +the API will not perform DNSSEC, and thus will return results sooner.

+ +

To return the DNSSEC status for each DNS record in the replies_tree list, use the +dnssec_return_status extension. The extension's value (an int) is set to +GETDNS_EXTENSION_TRUE to cause the returned status to have the name +dnssec_status (an int) added to the other names in the record's dict ("header", +"question", and so on). The values for that name are GETDNS_DNSSEC_SECURE, +GETDNS_DNSSEC_BOGUS, GETDNS_DNSSEC_INDETERMINATE, and +GETDNS_DNSSEC_INSECURE. Thus, a reply might look like:

+ +
+    {     # This is the first reply
+      "dnssec_status": GETDNS_DNSSEC_INDETERMINATE,
+      "header": { "id": 23456, "qr": 1, "opcode": 0, ... },
+      . . .
+
+ +

If instead of returning the status, you want to only see secure results, use the +dnssec_return_only_secure extension. The extension's value (an int) is set to +GETDNS_EXTENSION_TRUE to cause only records that the API can validate as secure with +DNSSEC to be returned in the replies_tree and replies_full lists. No +additional names are added to the dict of the record; the change is that some records might not +appear in the results. When this context option is set, if the API receives DNS replies but none +are determined to be secure, the error code at the top level of the response object is +GETDNS_RESPSTATUS_NO_SECURE_ANSWERS.

+ +

Applications that want to do their own validation will want to have the DNSSEC-related records +for a particular response. Use the dnssec_return_supporting_responses extension. The +extension's value (an int) is set to GETDNS_EXTENSION_TRUE to cause a set +of additional DNSSEC-related records needed for validation to be returned in the response object. +This set comes as additional_dnssec (a list) at the top level of the response object. +This list includes any trust anchors needed for the validation. Thus, a reply might look like:

+ +
+{     # This is the response object
+  "additional_dnssec": [ <bindata of the first DNSSEC record>, <bindata of the second DNSSEC record> ... ],
+  "replies_tree":
+  [
+  . . .
+
+ +

If a request is using a context in which stub resolution is set, and that request also has +any of the dnssec_return_status, dnssec_return_only_secure, or +dnssec_return_supporting_responses extensions specified, the API will not perform +the request and will instead return an error of GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED.

+ +

3.2 Returning Both IPv4 and IPv6 Responses

+ +

Many applications want to get both IPv4 and IPv6 addresses in a single call so that the results +can be processed together. The getdns_address and getdns_address_sync +functions are able to do this automatically. If you are using the getdns_general or +getdns_general_sync function, you can enable this with the +return_both_v4_and_v6 extension. The extension's value (an int) is set to +GETDNS_EXTENSION_TRUE to cause the results to be the lookup of either A or AAAA records +to include any A and AAAA records for the queried name (otherwise, the extension does nothing). +These results are expected to be used with Happy Eyeballs systems that will find the best socket for +an application.

+ +

3.3 Setting Up OPT Resource Records

+ +

For lookups that need an OPT resource record in the Additional Data section, use the +add_opt_parameters extension. The extension's value (a dict) contains the +parameters; these are described in more detail in RFC 2671. They are:

+ +
    + +
  • maximum_udp_payload_size (an int), a value between 512 and 65535; if not specified, +this defaults to those from the DNS context
  • + +
  • extended_rcode (an int), a value between 0 and 255; if not specified, +this defaults to those from the DNS context
  • + +
  • version (an int), a value between 0 and 255; if not specified, this +defaults to 0
  • + +
  • do_bit (an int), a value between 0 and 1; if not specified, this defaults +to those from the DNS context
  • + +
  • options (a list) contains dicts for each option to be specified. +Each list time contains two names: option_code (an int) and option_data +(a bindata). The API marshalls the entire set of options into a properly-formatted RDATA +for the resource record.
  • + +
+ +

It is very important to note that the OPT resource record specified in the +add_opt_parameters extension might not be the same the one that the API sends in the +query. For example, if the application also includes any of the DNSSEC extensions, the API will make +sure that the OPT resource record sets the resource record appropriately, making the needed changes +to the settings from the add_opt_parameters extension.

+ +

The use of this extension can conflict with the values in the DNS context. For example, +the default for an OS might be a maximum payload size of 65535, but the extension might specify +1550. In such a case, the API will honor the values stated in the extension, but will honor the +values from the DNS context if values are not given in the extension.

+ +

3.4 Getting Warnings for Responses that Violate the DNS Standard

+ +

To receive a warning if a particular response violates some parts of the DNS standard, use +the add_warning_for_bad_dns extension. The extension's value (an int) is set to +GETDNS_EXTENSION_TRUE to cause each reply in the replies_tree +to contain an additional name, bad_dns (a list). The list is zero or more +ints that indicate types of bad DNS found in that reply. The list of values is: + +

GETDNS_BAD_DNS_CNAME_IN_TARGET

+

A DNS query type that does not allow a target to be a CNAME pointed to a CNAME

+

GETDNS_BAD_DNS_ALL_NUMERIC_LABEL

+

One or more labels in a returned domain name is all-numeric; this is not legal for a hostname

+

GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE

+

A DNS query for a type other than CNAME returned a CNAME response

+ + +

3.5 Using Other Class Types

+ +

The vast majority of DNS requests are made with the Internet (IN) class. To make a request in a +different DNS class, use, the specify_class extension. The extension's value (an int) +contains the class number. Few applications will ever use this extension.

+ +

3.6 Extensions Relating to the API

+ +

An application might want to see information about the API itself. Use the +return_api_information extension. An application that wants to get this information +before a "real" query is issued can add this extension to a PTR query for 127.0.0.1. +The extension's value (an int) is set to +GETDNS_EXTENSION_TRUE to add the following to the top level of the response object:

+ +
    + +
  • version_string (a bindata) represents the version string for this version of the DNS +API.
  • + +
  • implementation_string (a bindata) is a string set by the API implementer. It might +be human-readable, and it might have information in it useful to an application developer (but it doesn't +have to).
  • + +
  • resolver_type (an int) is the type of resolver that the API is acting as in this context: +GETDNS_CONTEXT_RECURSING or GETDNS_CONTEXT_STUB (it will be +a recursing resolver unless the application changed this in a context.
  • + +
  • all_context (a dict) with names for all the types of context. This can be used with +getdns_pretty_print_dict() for debugging.
  • + +
+ +

An application might want to see debugging information for queries such as the length of time it +takes for each query to return to the API. Use the return_call_debugging extension. The +extension's value (an int) is set to GETDNS_EXTENSION_TRUE to add the name +call_debugging (a list) to the top level of the response object. Each member of the +list is a dict that represents one call made for the call to the API. Each member has the following +names:

+ +
    +
  • query_name (a bindata) is the name that was sent
  • +
  • query_type (an int) is the type that was queried for
  • +
  • query_to (a bindata) is the address to which the query was sent
  • +
  • start_time (a bindata) is the time the query started in milliseconds since the epoch, +represented as a uint64_t
  • +
  • end_time (a bindata) is the time the query was received in milliseconds since the epoch, +represented as a uint64_t
  • +
  • entire_reply (a bindata) is the entire response received
  • +
  • dnssec_result (an int) is the DNSSEC status, or GETDNS_DNSSEC_NOT_PERFORMED +if DNSSEC validation was not performed
  • +
+ +

4. Response Data from Queries

+ +

The callback function contains a pointer to a response object. +A response object is always a dict. The response +object always contains at least three names: replies_full (a list) and +replies_tree (a list), and status (an int). +replies_full is a list of DNS replies (each is bindata) as they appear on the wire. +replies_tree is a list of DNS replies (each is a dict) with the various part of the +reply parsed out. status is a status code for the query.

+ +

Because the API might be extended in the future, a response object might also contain names other +than replies_full, replies_tree, and status. Similarly, any +of the dicts described here might be extended in later versions of the API. Thus, an application +using the API must not assume that it knows all possible names in a dict.

+ +

The following lists the status codes for response objects. Note that, if the status is that there +are no responses for the query, the lists in replies_full and replies_tree +will have zero length.

+ +

GETDNS_RESPSTATUS_GOOD

+

At least one response was returned

+

GETDNS_RESPSTATUS_NO_NAME

+

Queries for the name yielded all negative responses

+

GETDNS_RESPSTATUS_ALL_TIMEOUT

+

All queries for the name timed out

+

GETDNS_RESPSTATUS_NO_SECURE_ANSWERS

+

The context setting for getting only secure responses was specified, and at least one DNS response was received, but no DNS response was determined to be secure through DNSSEC.

+ + +

The top level of replies_tree can optionally have the following names: canonical_name (a +bindata), intermediate_aliases (a list), answer_ipv4_address (a bindata), +answer_ipv6_address (a bindata), and answer_type (an int).

+ +
    + +
  • The value of canonical_name is the name that the API used for its lookup. It is in +FQDN presentation format.
  • + +
  • The values in the intermediate_aliases list are domain names from any CNAME or +unsynthesized DNAME found when resolving the original query. The list might have zero entries +if there were no CNAMEs in the path. These may be useful, for example, for name comparisons +when following the rules in RFC 6125.
  • + +
  • The value of answer_ipv4_address and answer_ipv6_address are +the addresses of the server from which the answer was received.
  • + +
  • The value of answer_type is the type of name service that generated the response. +The values are:
  • + +
+ +

GETDNS_NAMETYPE_DNS

+

Normal DNS (RFC 1035)

+

GETDNS_NAMETYPE_WINS

+

The WINS name service (some reference needed)

+ + +

If the call was getdns_address or getdns_address_sync, the top level +of replies_tree has an additional name, just_address_answers (a list). +The value of just_address_answers is a list that contains all of the A and AAAA +records from the answer sections of any of the replies, in the order they appear in the replies. +Each item in the list is a dict with at least two names: address_type (whose value is +a bindata; it is currently either "IPv4" or "IPv6") and address_data (whose value is a bindata). +Note that the dnssec_return_only_secure extension affects +what will appear in the just_address_answers list. Also note if later versions of the +DNS return other address types, those types will appear in this list as well.

+ +

The API can make service discovery through SRV records easier. If +the call was getdns_service or getdns_service_sync, +the top level of replies_tree has an additional name, +srv_addresses (a list). +The list is ordered by priority and weight based on the weighting +algorithm in RFC 2782, lowest priority value first. Each element +of the list is dict has at least two names: port and domain_name. If the +API was able to determine the address of the target domain name (such as from its cache or from the +Additional section of responses), the dict for an element will also contain +address_type (whose value is a bindata; it is currently either "IPv4" or "IPv6") and +address_data (whose value is a bindata). Note that the +dnssec_return_only_secure extension affects what will appear in the +srv_addresses list.

+ +

4.1 Structure of DNS replies_tree

+ +

The names in each entry in the the replies_tree list for DNS responses include +header (a dict), question (a dict), answer (a list), +authority (a list), and additional (a list), corresponding to the sections +in the DNS message format. The answer, authority, and additional lists each contain zero or more +dicts, with each dict in each list representing a resource record.

+ +

The names in the header dict are all the fields from Section 4.1.1. of RFC 1035. +They are: id, qr, opcode, aa, tc, +rd, ra, z, rcode, qdcount, +ancount, nscount, and arcount. All are ints.

+ +

The names in the question dict are the three fields from Section 4.1.2. of RFC 1035: +qname (a bindata), qtype (an int), and qclass (an int).

+ +

Resource records are a bit different than headers and question sections in that the RDATA portion +often has its own structure. The other names in the resource record dicts are name (a +bindata), type (an int), class (an int), ttl (an int) and +rdata (a dict); there is no name equivalent to the RDLENGTH field.

+ +

The rdata dict has different names for each response type. There is a complete list of the types defined in the API. For names that end in +"-obsolete" or "-unknown", the bindata is the entire RDATA field. For example, the +rdata for an A record has a name ipv4_address (a bindata); the +rdata for an SRV record has the names priority (an int), +weight (an int), port (an int), and target (a bindata).

+ +

Each rdata dict also has a rdata_raw field (a bindata). This is useful +for types not defined in this version of the API. It also might be of value if a later version of +the API allows for additional parsers. Thus, doing a query for types not known by the API still will +return a result: an rdata with just a rdata_raw.

+ +

It is expected that later extensions to the API will give some DNS types different names. It is +also possible that later extensions will change the names for some of the DNS types listed above.

+ +

For example, a response to a getdns_address() call for www.example.com would +look something like this:

+ +
+{     # This is the response object
+  "replies_full": [ <bindata of the first response>, <bindata of the second response> ],
+  "just_address_answers": [ <bindata of 0x0a0b0c01>, <bindata of 0x33445566334455663344556633445566> ],
+  "canonical_name": <bindata for "www.example.com">,
+  "answer_type": GETDNS_NAMETYPE_DNS,
+  "intermediate_aliases": [],
+  "replies_tree":
+  [
+    {     # This is the first reply
+      "header": { "id": 23456, "qr": 1, "opcode": 0, ... },
+      "question": { "qname": <bindata for "www.example.com">, "qtype": 1, "qclass": 1 },
+      "answer":
+      [
+        {
+          "name": <bindata for "www.example.com">,
+          "type": 1,
+          "class": 1,
+          "ttl": 33000,
+          "rdata":
+          {
+            "ipv4_address": <bindata of 0x0a0b0c01>
+            "rdata_raw": <bindata of 0x0a0b0c01>
+          }
+        }
+      ],
+      "authority":
+      [
+        {
+          "name": <bindata for "ns1.example.com">,
+          "type": 1,
+          "class": 1,
+          "ttl": 600,
+          "rdata":
+          {
+            "ipv4_address": <bindata of 0x65439876>
+            "rdata_raw": <bindata of 0x65439876>
+          }
+        }
+      ]
+      "additional": [],
+      "canonical_name": <bindata for "www.example.com">,
+      "answer_type": GETDNS_NAMETYPE_DNS
+    },
+    {     # This is the second reply
+      "header": { "id": 47809, "qr": 1, "opcode": 0, ... },
+      "question": { "qname": <bindata for "www.example.com">, "qtype": 28, "qclass": 1 },
+      "answer":
+      [
+        {
+          "name": <bindata for "www.example.com">,
+          "type": 28,
+          "class": 1,
+          "ttl": 1000,
+          "rdata":
+          {
+            "ipv6_address": <bindata of 0x33445566334455663344556633445566>
+            "rdata_raw": <bindata of 0x33445566334455663344556633445566>
+          }
+       }
+      ],
+      "authority": [  # Same as for other record... ]
+      "additional": [],
+    },
+  ]
+}
+
+ +

In DNS responses, domain names are treated special. RFC 1035 describes a form of name compression +that requires that the entire record be available for analysis. The API deals with this by +converting compressed names into full names when returning names in the replies_tree. +This conversion happens for qname in question; name in the +answer, authority, and additional; and in domain names in the +data in names under rdata where the response type is AFSDB, CNAME, MX, NS, PTR, RP, RT, and SOA.

+ +

4.2 Converting Domain Names

+ +

Names in DNS fields are stored in a fashion very different from the normal presentation format +normally used in applications. The DNS format is described in the first paragraph in Section 3.1 of +RFC 1035; the presentation format here is a null-terminated string with interior dots. These helper +functions only work with names in the DNS format that are not compressed. They are useful for +converting domain names in the replies_tree to and from the FQDN presentation +format.

+ +

getdns_convert_dns_name_to_fqdn() converts a domain name in DNS format to the +presentation format. For example, the hex sequence 03 77 77 77 07 65 78 61 6d 70 6c 65 03 63 +6f 6d 00 would be converted to "www.example.com". +getdns_convert_fqdn_to_dns_name() does the reverse: it converts a null-terminated +string in FQDN format to bytes in DNS format.

+ +
+char * +getdns_convert_dns_name_to_fqdn( + char *name_from_dns_response +); + +char * +getdns_convert_fqdn_to_dns_name( + char *fqdn_as_string +); +
+ +

5. Additional Definitions and Descriptions

+ +

5.1 A Few Needed Definitions

+ +
typedef struct getdns_context_t *getdns_context_t; +typedef uint16_t getdns_return_t; +typedef uint64_t getdns_transaction_t; +typedef enum some_data_type { + t_dict, t_list, t_int, t_bindata +} getdns_data_type; +typedef struct getdns_bindata { + size_t size; + uint8_t *binary_stuff; +} some_bindata; +typedef struct getdns_dict some_dict; +typedef struct getdns_list some_list; +
+ +

5.2 Return Codes

+ +

The return codes for all the functions are:

+ +

GETDNS_RETURN_GOOD

+

Good

+

GETDNS_RETURN_GENERIC_ERROR

+

Generic error

+

GETDNS_RETURN_BAD_DOMAIN_NAME

+

Badly-formed domain name in first argument

+

GETDNS_RETURN_BAD_CONTEXT

+

Bad value for a context type

+

GETDNS_RETURN_CONTEXT_UPDATE_FAIL

+

Did not update the context

+

GETDNS_RETURN_UNKNOWN_TRANSACTION

+

An attempt was made to cancel a callback with a transaction_id that is not recognized

+

GETDNS_RETURN_NO_SUCH_LIST_ITEM

+

A helper function for lists had an index argument that was too high.

+

GETDNS_RETURN_NO_SUCH_DICT_NAME

+

A helper function for dicts had a name argument that for a name that is not in the dict.

+

GETDNS_RETURN_WRONG_TYPE_REQUESTED

+

A helper function was supposed to return a certain type for an item, but the wrong type was given.

+

GETDNS_RETURN_NO_SUCH_EXTENSION

+

A name in the extensions dict is not a valid extension.

+

GETDNS_RETURN_EXTENSION_MISFORMAT

+

One or more of the extensions is has a bad format.

+

GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED

+

A query was made with a context that is using stub resolution and a DNSSEC extension specified.

+ + +

5.3 Types of RDATA Returned in the API

+ +

The names in the rdata dicts in replies are:

+ + +

A (1)

+

ipv4_address (a bindata)

+ +

NS (2)

+

nsdname (a bindata)

+ +

MD (3)

+

madname (a bindata)

+ +

MF (4)

+

madname (a bindata)

+ +

CNAME (5)

+

cname (a bindata)

+ +

SOA (6)

+

mname (a bindata), rname (a bindata), +serial (an int), refresh (an int), refresh (an int), +retry (an int), and expire (an int)

+ +

MB (7)

+

madname (a bindata)

+ +

MG (8)

+

mgmname (a bindata)

+ +

MR (9)

+

newname (a bindata)

+ +

NULL (10)

+

anything (a bindata)

+ +

WKS (11)

+

address (a bindata), protocol (an int), +and bitmap (a bindata)

+ +

PTR (12)

+

ptrdname (a bindata)

+ +

HINFO (13)

+

cpu (a bindata) and os (a bindata)

+ +

MINFO (14)

+

rmailbx (a bindata) and emailbx (a bindata)

+ +

MX (15)

+

preference (an int) and exchange (a bindata)

+ +

TXT (16)

+

txt_strings (a list) which contains zero or more bindata elements +that are text strings

+ +

RP (17)

+

mbox_dname (a bindata) and txt_dname (a bindata)

+ +

AFSDB (18)

+

subtype (an int) and hostname (a bindata)

+ +

X25 (19)

+

psdn_address (a bindata)

+ +

ISDN (20)

+

isdn_address (a bindata) and sa (a bindata)

+ +

RT (21)

+

preference (an int) and intermediate_host (a bindata)

+ +

NSAP (22)

+

nsap (a bindata)

+ +

SIG (24)

+

sig_obsolete (a bindata)

+ +

KEY (25)

+

key_obsolete (a bindata)

+ +

PX (26)

+

preference (an int), map822 (a bindata), and mapx400 (a bindata)

+ +

GPOS (27)

+

longitude (a bindata), latitude (a bindata), and altitude (a bindata)

+ +

AAAA (28)

+

ipv6_address (a bindata)

+ +

LOC (29)

+

loc_obsolete (a bindata)

+ +

NXT (30)

+

nxt_obsolete (a bindata)

+ +

EID (31)

+

eid_unknown (a bindata)

+ +

NIMLOC (32)

+

nimloc_unknown (a bindata)

+ +

SRV (33)

+

priority (an int), weight (an int), +port (an int), and target (a bindata)

+ +

ATMA (34)

+

format (an int) and address (a bindata)

+ +

NAPTR (35)

+

order (an int), preference (an int), flags +(a bindata), service (a bindata), regexp (a bindata), and +replacement (a bindata).

+ +

KX (36)

+

preference (an int) and exchanger (a bindata)

+ +

CERT (37)

+

type (an int), key_tag (an int), algorithm (an int), +and certificate_or_crl (a bindata)

+ +

A6 (38)

+

a6_obsolete (a bindata)

+ +

DNAME (39)

+

target (a bindata)

+ +

SINK (40)

+

sink_unknown (a bindata)

+ +

OPT (41)

+

options (a list). Each element of the options list is a +dict with two names: option_code (an int) and option_data (a bindata).

+ +

APL (42)

+

address_family (an int), prefix (an int), +n (an int), and afdpart (a bindata)

+ +

DS (43)

+

key_tag (an int), algorithm (an int), digest_type (an int), +and digest (a bindata)

+ +

SSHFP (44)

+

algorithm (an int), fp_type (an int), +and fingerprint (a bindata)

+ +

IPSECKEY (45)

+

algorithm (an int), gateway_type (an int), precedence (an int), +gateway, and public_key (a bindata)

+ +

RRSIG (46)

+

type_covered (an int), algorithm (an int), +labels (an int), original_ttl (an int), signature_expiration +(an int), signature_inception (an int), key_tag (an int), +signers_name (a bindata), and signature (a bindata)

+ +

NSEC (47)

+

next_domain_name (a bindata) and type_bit_maps (a bindata)

+ +

DNSKEY (48)

+

flags (an int), protocol (an int), algorithm (an int), +and public_key (a bindata)

+ +

DHCID (49)

+

dhcid_opaque (a bindata)

+ +

NSEC3 (50)

+

hash_algorithm (an int), flags (an int), +iterations (an int), salt_length (an int), salt (a bindata), +hash_length (an int), next_hashed_owner_name (a bindata), and +type_bit_maps (a bindata)

+ +

NSEC3PARAM (51)

+

hash_algorithm (an int), flags (an int), +iterations (an int), salt_length (an int), and +salt (a bindata)

+ +

TLSA (52)

+

certificate_usage (an int), selector (an int), +matching_type (an int), and certificate_association_data (a +bindata).

+ +

HIP (55)

+

hit_length (an int), pk_algorithm (an int), +pk_length (an int), hit (a bindata), public_key +(a bindata), and rendezvous_servers (a bindata)

+ +

NINFO (56)

+

ninfo_unknown (a bindata)

+ +

RKEY (57)

+

rkey_unknown (a bindata)

+ +

TALINK (58)

+

talink_unknown (a bindata)

+ +

CDS (59)

+

cds_unknown (a bindata)

+ +

SPF (99)

+

text (a bindata)

+ +

UINFO (100)

+

uinfo_unknown (a bindata)

+ +

UID (101)

+

uid_unknown (a bindata)

+ +

GID (102)

+

gid_unknown (a bindata)

+ +

UNSPEC (103)

+

unspec_unknown (a bindata)

+ +

NID (104)

+

preference (an int) and +node_id (a bindata)

+ +

L32 (105)

+

preference (an int), locator32_msbs (a bindata), +and locator64_lsbs (a bindata)

+ +

L64 (106)

+

preference (an int) and locator64 (a bindata)

+ +

LP (107)

+

preference (an int) and fqdn (a bindata)

+ +

TKEY (249)

+

algorithm (a bindata), inception (an int), +expiration (an int), mode (an int), error (an int), +key_data (a bindata), and other_data (a bindata)

+ +

TSIG (250)

+

algorithm (a bindata), time_signed (a bindata), +fudge (an int), mac (a bindata), original_id (an int), +error (an int), and other_data (a bindata)

+ +

IXFR (251)

+

zones (a bindata)

+ +

AXFR (252)

+

zones (a bindata)

+ +

MAILB (253)

+

mailb-unknown (a bindata)

+ +

MAILA (254)

+

maila-unknown (a bindata)

+ +

URI (256)

+

priority (an int), weight (an int), +and target (a bindata)

+ +

CAA (257)

+

flags (an int), tag (a bindata), and value (a bindata)

+ +

TA (32768)

+

ta_unknown (a bindata)

+ +

DLV (32769)

+

Identical to DS (43)

+ + +

6. Examples

+ +

This section gives examples of code that calls the API to do many common tasks. +The purpose of the code here is to give application developers a quick hands-on +demo of using the API.

+ +

Note that the examples here all use getdns_libevent.h as the include that will call in the API +code as well as calling in libevent as the event library. They also use +getdns_context_set_libevent_base() as the name of the function to set the event base in +the DNS context. If you are using a different event library, you will of course use a different +#include at the beginning of your code, and a different name for the event base +function.

+ +

6.1 Get Both IPv4 and IPv6 Addresses for a Domain Name Using Quick Results

+ +

This is an example of a common call to getdns_address().

+ +
#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <getdns_libevent.h>
+
+#define UNUSED_PARAM(x) ((void)(x))
+
+/* Set up the callback function, which will also do the processing of the results */
+void this_callbackfn(struct getdns_context_t *this_context,
+                     uint16_t     this_callback_type,
+                     struct getdns_dict *this_response, 
+                     void *this_userarg,
+                     getdns_transaction_t this_transaction_id)
+{
+    UNUSED_PARAM(this_userarg);  /* Not looking at the userarg for this example */
+    UNUSED_PARAM(this_context);  /* Not looking at the context for this example */
+    getdns_return_t this_ret;  /* Holder for all function returns */
+    if (this_callback_type == GETDNS_CALLBACK_COMPLETE)  /* This is a callback with data */
+    {
+        /* Be sure the search returned something */
+        uint32_t * this_error = NULL;
+        this_ret = getdns_dict_get_int(this_response, "status", this_error);  // Ignore any error
+        if (*this_error != GETDNS_RESPSTATUS_GOOD)  // If the search didn't return "good"
+        {
+            fprintf(stderr, "The search had no results, and a return value of %d. Exiting.", *this_error);
+            return;
+        }
+        struct getdns_list * just_the_addresses_ptr;
+        this_ret = getdns_dict_get_list(this_response, "just_address_answers", &just_the_addresses_ptr);
+        if (this_ret != GETDNS_RETURN_GOOD)  // This check is really not needed, but prevents a compiler error under "pedantic"
+        {
+            fprintf(stderr, "Trying to get the answers failed: %d", this_ret);
+            return;
+        }
+        size_t * num_addresses_ptr = NULL;
+        this_ret = getdns_list_get_length(just_the_addresses_ptr, num_addresses_ptr);  // Ignore any error
+        /* Go through each record */
+        for ( size_t rec_count = 0; rec_count <= *num_addresses_ptr; ++rec_count )
+        {
+            struct getdns_dict * this_address;
+            this_ret = getdns_list_get_dict(just_the_addresses_ptr, rec_count, &this_address);  // Ignore any error
+            /* Just print the address */
+            struct getdns_bindata * this_address_data;
+            this_ret = getdns_dict_get_bindata(this_address, "address_data", &this_address_data); // Ignore any error
+            printf("The address is %s", getdns_display_ip_address(this_address_data));
+        }
+    }
+    else if (this_callback_type == GETDNS_CALLBACK_CANCEL)
+        fprintf(stderr, "The callback with ID %"PRIu64" was cancelled. Exiting.", this_transaction_id);
+    else
+        fprintf(stderr, "The callback got a callback_type of %d. Exiting.", this_callback_type);
+}
+
+int main()
+{
+    /* Create the DNS context for this call */
+    struct getdns_context_t *this_context = NULL;
+    getdns_return_t context_create_return = getdns_context_create(&this_context, true);
+    if (context_create_return != GETDNS_RETURN_GOOD)
+    {
+        fprintf(stderr, "Trying to create the context failed: %d", context_create_return);
+        return(GETDNS_RETURN_GENERIC_ERROR);
+    }
+    /* Create an event base and put it in the context using the unknown function name */
+    struct event_base *this_event_base;
+    this_event_base = event_base_new();
+    if (this_event_base == NULL)
+    {
+        fprintf(stderr, "Trying to create the event base failed.");
+        return(GETDNS_RETURN_GENERIC_ERROR);
+    }
+    (void)getdns_extension_set_libevent_base(this_context, this_event_base);
+    /* Set up the getdns call */
+    const char * this_name  = "www.example.com";
+    char* this_userarg = "somestring"; // Could add things here to help identify this call
+    getdns_transaction_t this_transaction_id = 0;
+
+    /* Make the call */
+    getdns_return_t dns_request_return = getdns_address(this_context, this_name,
+        NULL, this_userarg, &this_transaction_id, this_callbackfn);
+    if (dns_request_return == GETDNS_RETURN_BAD_DOMAIN_NAME)
+    {
+        fprintf(stderr, "A bad domain name was used: %s. Exiting.", this_name);
+        return(GETDNS_RETURN_GENERIC_ERROR);
+    }
+    else
+    {
+        /* Call the event loop */
+        int dispatch_return = event_base_dispatch(this_event_base);
+        UNUSED_PARAM(dispatch_return);
+        // TODO: check the return value above
+    }
+    /* Clean up */
+    getdns_context_destroy(this_context);
+    /* Assuming we get here, leave gracefully */
+    exit(EXIT_SUCCESS);
+}
+
+ + + +

6.2 Get IPv4 and IPv6 Addresses for a Domain Name

+ +

This example is similar to the previous one, except that it retrieves more information than just +the addresses, so it traverses the replies_tree. In this case, it gets both the addresses and +their TTLs.

+ +
#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <getdns_libevent.h>
+
+#define UNUSED_PARAM(x) ((void)(x))
+
+/* Set up the callback function, which will also do the processing of the results */
+void this_callbackfn(struct getdns_context_t *this_context,
+                     getdns_return_t this_callback_type,
+                     struct getdns_dict *this_response, 
+                     void *this_userarg,
+                     getdns_transaction_t this_transaction_id)
+{
+    UNUSED_PARAM(this_userarg);  /* Not looking at the userarg for this example */
+    UNUSED_PARAM(this_context);  /* Not looking at the context for this example */
+    getdns_return_t this_ret;  /* Holder for all function returns */
+    if (this_callback_type == GETDNS_CALLBACK_COMPLETE)  /* This is a callback with data */
+    {
+        /* Be sure the search returned something */
+        uint32_t * this_error = NULL;
+        this_ret = getdns_dict_get_int(this_response, "status", this_error);  // Ignore any error
+        if (*this_error != GETDNS_RESPSTATUS_GOOD)  // If the search didn't return "good"
+        {
+            fprintf(stderr, "The search had no results, and a return value of %d. Exiting.", *this_error);
+            return;
+        }
+        /* Find all the answers returned */
+        struct getdns_list * these_answers;
+        this_ret = getdns_dict_get_list(this_response, "replies-tree", &these_answers);
+        if (this_ret == GETDNS_RETURN_NO_SUCH_DICT_NAME)
+        {
+            fprintf(stderr, "Weird: the response had no error, but also no replies-tree. Exiting.");
+            return;
+        }
+        size_t * num_answers_ptr = NULL;
+        this_ret = getdns_list_get_length(these_answers, num_answers_ptr);
+        /* Go through each answer */
+        for ( size_t rec_count = 0; rec_count <= *num_answers_ptr; ++rec_count )
+        {
+            struct getdns_dict * this_record;
+            this_ret = getdns_list_get_dict(these_answers, rec_count, &this_record);  // Ignore any error
+            /* Get the answer section */
+            struct getdns_list * this_answer;
+            this_ret = getdns_dict_get_list(this_record, "answer", &this_answer);  // Ignore any error
+            /* Get each RR in the answer section */
+            size_t * num_rrs_ptr = NULL;
+            this_ret = getdns_list_get_length(this_answer, num_rrs_ptr);
+            for ( size_t rr_count = 0; rr_count <= *num_rrs_ptr; ++rr_count )
+            {
+                struct getdns_dict * this_rr = NULL;
+                this_ret = getdns_list_get_dict(this_answer, rr_count, &this_rr);  // Ignore any error
+                /* Get the RDATA */
+                struct getdns_dict * this_rdata = NULL;
+                this_ret = getdns_dict_get_dict(this_rr, "rdata", &this_rdata);  // Ignore any error
+                /* Get the RDATA type */
+                uint32_t * this_type = NULL;
+                this_ret = getdns_dict_get_int(this_rdata, "type", this_type);  // Ignore any error
+                /* If it is type A or AAAA, print the value */
+                if (*this_type == GETDNS_RRTYPE_A)
+                {
+                    struct getdns_bindata * this_a_record = NULL;
+                    this_ret = getdns_dict_get_bindata(this_rdata, "ipv4_address", &this_a_record);
+                    if (this_ret == GETDNS_RETURN_NO_SUCH_DICT_NAME)
+                    {
+                        fprintf(stderr, "Weird: the A record at %d in record at %d had no address. Exiting.",
+                            (int) rr_count, (int) rec_count);
+                        return;
+                    }
+                    printf("The IPv4 address is %s", getdns_display_ip_address(this_a_record));
+                }
+                else if (*this_type == GETDNS_RRTYPE_AAAA)
+                {
+                    struct getdns_bindata * this_aaaa_record = NULL;
+                    this_ret = getdns_dict_get_bindata(this_rdata, "ipv6_address", &this_aaaa_record);
+                    if (this_ret == GETDNS_RETURN_NO_SUCH_DICT_NAME)
+                    {
+                        fprintf(stderr, "Weird: the AAAA record at %d in record at %d had no address. Exiting.",
+                            (int) rr_count, (int) rec_count);
+                        return;
+                    }
+                    printf("The IPv6 address is %s", getdns_display_ip_address(this_aaaa_record));
+                }
+            }
+        }
+    }
+    else if (this_callback_type == GETDNS_CALLBACK_CANCEL)
+        fprintf(stderr, "The callback with ID %"PRIu64" was cancelled. Exiting.", this_transaction_id);
+    else
+        fprintf(stderr, "The callback got a callback_type of %d. Exiting.", this_callback_type);
+}
+
+int main()
+{
+    /* Create the DNS context for this call */
+    struct getdns_context_t *this_context = NULL;
+    getdns_return_t context_create_return = getdns_context_create(&this_context, true);
+    if (context_create_return != GETDNS_RETURN_GOOD)
+    {
+        fprintf(stderr, "Trying to create the context failed: %d", context_create_return);
+        return(GETDNS_RETURN_GENERIC_ERROR);
+    }
+    /* Create an event base and put it in the context using the unknown function name */
+    struct event_base *this_event_base;
+    this_event_base = event_base_new();
+    if (this_event_base == NULL)
+    {
+        fprintf(stderr, "Trying to create the event base failed.");
+        return(GETDNS_RETURN_GENERIC_ERROR);
+    }
+    (void)getdns_extension_set_libevent_base(this_context, this_event_base);
+    /* Set up the getdns call */
+    const char * this_name  = "www.example.com";
+    char* this_userarg = "somestring"; // Could add things here to help identify this call
+    getdns_transaction_t this_transaction_id = 0;
+
+    /* Make the call */
+    getdns_return_t dns_request_return = getdns_address(this_context, this_name,
+        NULL, this_userarg, &this_transaction_id, this_callbackfn);
+    if (dns_request_return == GETDNS_RETURN_BAD_DOMAIN_NAME)
+    {
+        fprintf(stderr, "A bad domain name was used: %s. Exiting.", this_name);
+        return(GETDNS_RETURN_GENERIC_ERROR);
+    }
+    else
+    {
+        /* Call the event loop */
+        int dispatch_return = event_base_dispatch(this_event_base);
+        UNUSED_PARAM(dispatch_return);
+        // TODO: check the return value above
+    }
+    /* Clean up */
+    getdns_context_destroy(this_context);
+    /* Assuming we get here, leave gracefully */
+    exit(EXIT_SUCCESS);
+}
+
+ + + +

6.3 Get Addresses for a Domain Name And Their Associated DNSSEC Validation Status

+ +

This example shows how to check for secure DNSSEC results using the +dnssec_return_status extension. In the innermost loop of the +callback function, add a check for the DNSSEC status. It shows how to add two +extensions to the extensions argument of the call.

+ +
+struct getdns_dict * this_extensions = getdns_dict_create();
+this_ret = getdns_dict_set_int(this_extensions, "return_both_v4_and_v6", GETDNS_EXTENSION_TRUE);
+this_ret = getdns_dict_set_int(this_extensions, "dnssec_return_status", GETDNS_EXTENSION_TRUE);
+. . .
+if (*this_type == GETDNS_RRTYPE_A)
+{
+    uint32_t * this_dnssec_status;
+    this_ret = getdns_dict_get_int(this_rdata, "dnssec_status", this_dnssec_status);
+    if (&this_dnssec_status != GETDNS_DNSSEC_SECURE)
+    {
+        // Log the DNSSEC status somewhere
+    }
+    else
+    {
+        // Deal with the record however you were going to
+    }
+}
+. . .
+
+ +

You can put the DNSSEC status check outside the check for the particular type of record you care about, but +you will then get log messages for bad status on records you might not care about as well.

+ +

6.4 Using the API Synchronously with getdns_sync_request()

+ +

This example is the same as the earlier examples, but uses getdns_general_sync() +and thus does not use the async code. Note that the processing of the answers is essentially the same +as it is for the synchronous example, it is just done in main().

+ +
#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <getdns_core_only.h>
+
+int main()
+{
+    getdns_return_t this_ret;  /* Holder for all function returns */
+    /* Create the DNS context for this call */
+    struct getdns_context_t *this_context = NULL;
+    getdns_return_t context_create_return = getdns_context_create(&this_context, true);
+    if (context_create_return != GETDNS_RETURN_GOOD)
+    {
+        fprintf(stderr, "Trying to create the context failed: %d", context_create_return);
+        return(GETDNS_RETURN_GENERIC_ERROR);
+    }
+    /* Set up the getdns_sync_request call */
+    const char * this_name  = "www.example.com";
+    uint8_t this_request_type = GETDNS_RRTYPE_A;
+    /* Get the A and AAAA records */
+    struct getdns_dict * this_extensions = getdns_dict_create();
+    this_ret = getdns_dict_set_int(this_extensions, "return_both_v4_and_v6", GETDNS_EXTENSION_TRUE);
+    if (this_ret != GETDNS_RETURN_GOOD)
+    {
+        fprintf(stderr, "Trying to set an extension do both IPv4 and IPv6 failed: %d", this_ret);
+        return(GETDNS_RETURN_GENERIC_ERROR);
+    }
+    uint32_t this_response_length;
+    struct getdns_dict * this_response = NULL;
+
+    /* Make the call */
+    getdns_return_t dns_request_return = getdns_general_sync(this_context, this_name, this_request_type,
+        this_extensions, &this_response_length, this_response);
+    if (dns_request_return == GETDNS_RETURN_BAD_DOMAIN_NAME)
+    {
+        fprintf(stderr, "A bad domain name was used: %s. Exiting.", this_name);
+        return(GETDNS_RETURN_GENERIC_ERROR);
+    }
+    else
+    {
+        /* Be sure the search returned something */
+        uint32_t * this_error = NULL;
+        this_ret = getdns_dict_get_int(this_response, "status", this_error);  // Ignore any error
+        if (*this_error != GETDNS_RESPSTATUS_GOOD)  // If the search didn't return "good"
+        {
+            fprintf(stderr, "The search had no results, and a return value of %d. Exiting.", *this_error);
+            return(GETDNS_RETURN_GENERIC_ERROR);
+        }
+        struct getdns_list * just_the_addresses_ptr;
+        this_ret = getdns_dict_get_list(this_response, "just_address_answers", &just_the_addresses_ptr);  // Ignore any error
+        size_t * num_addresses_ptr = NULL;
+        this_ret = getdns_list_get_length(just_the_addresses_ptr, num_addresses_ptr);  // Ignore any error
+        /* Go through each record */
+        for ( size_t rec_count = 0; rec_count <= *num_addresses_ptr; ++rec_count )
+        {
+            struct getdns_dict * this_address;
+            this_ret = getdns_list_get_dict(just_the_addresses_ptr, rec_count, &this_address);  // Ignore any error
+            /* Just print the address */
+            struct getdns_bindata * this_address_data;
+            this_ret = getdns_dict_get_bindata(this_address, "address_data", &this_address_data); // Ignore any error
+            printf("The address is %s", getdns_display_ip_address(this_address_data));
+        }
+    }
+    /* Clean up */
+    getdns_context_destroy(this_context);
+    getdns_free_sync_request_memory(this_response); 
+    /* Assuming we get here, leave gracefully */
+    exit(EXIT_SUCCESS);
+}
+
+ + + +

7. More Helper Functions

+ +

The following two functions convert individual labels of IDNs between their Unicode +encoding and their ASCII encoding. They follow the rules for IDNA 2008 described in +RFC 5890-5892.

+
char * +getdns_convert_ulabel_to_alabel( + char *ulabel +); +
+
char * +getdns_convert_alabel_to_ulabel( + char *alabel +); +
+ +

If an application wants the API do perform DNSSEC validation without using the extensions, it +can use the getdns_validate_dnssec() helper function.

+
getdns_return_t +getdns_validate_dnssec( + struct getdns_bindata *record_to_validate, + struct getdns_list *bundle_of_support_records, + struct getdns_list *trust_anchor_rdatas +); +
+

The record_to_validate is the resource record being validated. The API +will use the resource records in bundle_of_support_records and the RDATAs in the +trust_ancor_rdatas as trust anchors. The function returns one of +GETDNS_DNSSEC_SECURE, GETDNS_DNSSEC_BOGUS, +GETDNS_DNSSEC_INDETERMINATE, or GETDNS_DNSSEC_INSECURE.

+ +

There are two functions that help process data:

+ +
+char * +getdns_pretty_print_dict( + struct getdns_dict *some_dict +); +
+

This returns a string that is the nicely-formatted version +of the dict and all of the named elements in it.

+ +
+char * +getdns_display_ip_address( + struct getdns_bindata *bindata_of_ipv4_or_ipv6_address +); +
+

This returns a string that is the nicely-formatted version +of the IPv4 or IPv6 address in it. The API determines they type of address +by the length given in the bindata.

+ +

8. DNS Contexts

+ +

Many calls in the DNS API require a DNS context. A DNS +context contains the information that the API needs in order to process DNS calls, such as the +locations of upstream DNS servers, DNSSEC trust anchors, and so on. The internal structure of the +DNS context is opaque, and might be different on each OS. When a context is passed to any function, +it must be an allocated context; the context must not be NULL.

+ +

A typical application using this API doesn't need to know anything about contexts. Basically, +the application creates a default context, uses it in the functions that require a context, and +then deallocates it when done. Context manipulation is available for more DNS-aware programs, +but is unlikely to be of interest to applications that just want the results of lookups for +A, AAAA, SRV, and PTR records.

+ +

It is expected that contexts in implementations of the API will not necessarily be thread-safe, +but they will not be thread-hostile. A context should not be used by multiple threads: create a new +context for use on a different thread. It is just fine for an application to have many contexts, +and some DNS-heavy applications will certainly want to have many even if the application uses +a single thread.

+ +

See above for the method for creating and destroying +contexts. When the context is used in the API for the first time and set_from_os is +true, the API starts replacing some of the values with values from the OS, such as +those that would be found in res_query(3), /etc/resolv.conf, and so on, then proceeds with the new +function. Some advanced users will not want the API to change the values to the OS's defaults; if +set_from_os is false, the API will not do any updates to the initial +values based on changes in the OS. For example, this might be useful if the API is acting +as a stub resolver that is using a specific upstream recursive resolver chosen by the +application, not the one that might come back from DHCP.

+ +

8.1 Updating the Context Automatically

+ +

The context returned by getdns_context_create() is updated by the API by default, +such as when changes are made to /etc/resolv.conf. When there is a change, the callback function +that is set in getdns_context_set_context_update_callback() (described below) is +called.

+ +

Many of the defaults for a context come from the operating system under which the API is running. +In specific, it is important that the implementation should try to replicate as best as possible the +logic of a local getaddrinfo() when creating a new context. This includes making +lookups in WINS for NetBIOS, mDNS lookups, nis names, and any other name lookup that +getaddrinfo() normally does automatically. The API should look at nsswitch, the Windows +resolver, and so on.

+ +

In the function definitions below, the choice listed in bold is the one used +for the API default context.

+ +

8.2 Updating the Context Manually

+ +

Setting specific values in a context are done with value-specific +functions shown here. The setting functions all return either GETDNS_RETURN_GOOD for +success, GETDNS_RETURN_BAD_CONTEXT for trying to set a type with a value that +is not allowed, or GETDNS_RETURN_CONTEXT_UPDATE_FAIL for a failure to update the context.

+ +

An application can be notified when the context is changed.

+ +
+getdns_return_t +getdns_context_set_context_update_callback( + getdns_context_t context, + void (*value)(getdns_context_t context, uint16_t changed_item) +);
+

The value is a pointer to the callback function that will be +called when any context is changed. Such changes might be from automatic +changes from the API (such as changes to /etc/resolv.conf), or might be from any of the +API functions in this section being called. The second argument to the callback function +specifies which of the context changed; the context codes are listed +later in this document.

+ +

8.3 Contexts for Basic Resolution

+ +
+getdns_return_t +getdns_context_set_resolution_type( + getdns_context_t context, + uint16_t value +);
+

Specifies whether DNS queries are performed with nonrecurive lookups or +as a stub resolver. The value is GETDNS_CONTEXT_RECURSING or +GETDNS_CONTEXT_STUB.

+ +

All implementations of this API can act as recursive resolvers, and that must be the +default mode of the default context. +Some implementations of this API are expected to also be able to act as stub resolvers. +If an +implementation of this API is only able to act as a recursive resolver, a call to +getdns_context_set_resolution_type(somecontext, GETDNS_CONTEXT_STUB) will +return GETDNS_RETURN_CONTEXT_UPDATE_FAIL.

+ +
+getdns_return_t +getdns_context_set_namespaces( + getdns_context_t context, + size_t namespace_count, + uint16_t *namespaces +);
+

The namespaces array contains an ordered list +of namespaces that will be queried. +Important: this context setting is ignored for the getdns_general and +getdns_general_sync functions; it is used for the other funtions. +The values +are GETDNS_CONTEXT_NAMESPACE_DNS, +GETDNS_CONTEXT_NAMESPACE_LOCALNAMES, +GETDNS_CONTEXT_NAMESPACE_NETBIOS, +GETDNS_CONTEXT_NAMESPACE_MDNS, and +GETDNS_CONTEXT_NAMESPACE_NIS. When a normal lookup is done, +the API does the lookups in the order given and stops when it gets the +first result; a different method with the same result would be to run +the queries in parallel and return when it gets the first result. +Because lookups might be done over different mechanisms because of the +different namespaces, there can be information leakage that is similar +to that seen with getaddrinfo(). The +default is determined by the OS.

+ +
+getdns_return_t +getdns_context_set_dns_transport( + getdns_context_t context, + uint16_t value +);
+

Specifies what transport is used for DNS lookups. +The value is +GETDNS_CONTEXT_UDP_FIRST_AND_FALL_BACK_TO_TCP, +GETDNS_CONTEXT_UDP_ONLY, +GETDNS_CONTEXT_TCP_ONLY, or +GETDNS_CONTEXT_TCP_ONLY_KEEP_CONNECTIONS_OPEN.

+ +
+getdns_return_t +getdns_context_set_limit_outstanding_queries( + getdns_context_t context, + uint16_t limit +);
+

Specifies limit the number of outstanding DNS queries. +The API will block itself from sending more queries if it is about to exceed +this value, and instead keep those queries in an internal queue. +The a value of 0 indicates that +the number of outstanding DNS queries is unlimited.

+ +
+getdns_return_t +getdns_context_set_timeout( + getdns_context_t context, + uint16_t timeout +);
+

Specifies number of seconds the API will wait for request to return. +The default is not specified.

+ +

8.4 Context for Recursive Resolvers

+ +
+getdns_return_t +getdns_context_set_follow_redirects( + getdns_context_t context, + uint16_t value +);
+

Specifies whether or not DNS queries follow redirects. +The value is GETDNS_CONTEXT_FOLLOW_REDIRECTS for normal +following of redirects though CNAME and DNAME; or +GETDNS_CONTEXT_DO_NOT_FOLLOW_REDIRECTS to cause any lookups that would have gone +through CNAME and DNAME to return the CNAME or DNAME, not the eventual target.

+ +
+getdns_return_t +getdns_context_set_dns_root_servers( + getdns_context_t context, + struct getdns_list *addresses +);
+

The list contains dicts that are addresses to be used for looking up top-level +domains; the default is the list of "normal" IANA root servers. Each dict in the list +contains at least two names: address_type (whose value is a bindata; it is currently +either "IPv4" or "IPv6") and address_data (whose value is a bindata).

+ +

8.5 Context for Local Naming

+ +
+getdns_return_t +getdns_context_set_append_name( + getdns_context_t context, + uint16_t value +);
+

Specifies whether to append a suffix to the query string +before the API starts resolving a name. +The value is +GETDNS_CONTEXT_APPEND_NAME_ALWAYS, +GETDNS_CONTEXT_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE, +GETDNS_CONTEXT_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE, +or GETDNS_CONTEXT_DO_NOT_APPEND_NAMES. This controls +whether or not to append the suffix given by getdns_context_set_suffix

+ +
+getdns_return_t +getdns_context_set_suffix( + getdns_context_t context, + struct getdns_list *value +);
+

The value is a list of bindatas that are strings that are +to be appended based on getdns_context_set_append_name; the default is an empty list. The values here follow the rules in section 2.1 of RFC 4343 +to allow non-ASCII octets and special characters in labels.

+ +

8.6 Context for DNSSEC

+ +

These context settings affect queries that have extensions that specify the use of DNSSEC.

+ +

Applications that need to specify the DNSSEC trust anchors can use:

+
+getdns_return_t +getdns_context_set_dnssec_trust_anchors( + getdns_context_t context, + struct getdns_list *value +);
+

The value is a list of bindatas that are the DNSSEC trust anchors. The default +is the trust anchors from the IANA root. The trust anchors +are expressed as RDATAs from DNSKEY resource records.

+ +

In the rare case that an application needs to set the DNSSEC skew, it can:

+
+getdns_return_t +getdns_context_set_dnssec_allowed_skew( + getdns_context_t context, + uint16_t value +);
+

The value is the number of seconds of skew that is allowed in either direction when +checking an RRSIG's Expiration and Inception fields. The default +is 0.

+ +

8.7 Context Specific to Stub Resolvers

+ +

An application can change the quering mechanism of a context to be to act as a stub +resolver. Such an application might first get the default information to make this change +from the operating system, probably through DHCP.

+ +

Note that if a context is changed to being a stub resolver, this automatically prevents the application +from using the extenstions for DNSSEC. An application that wants to both do DNSSEC and stub resolution +must do its own DNSSEC processing, possibly with the getdns_validate_dnssec() function.

+ +
+getdns_return_t +getdns_context_set_stub_resolution( + getdns_context_t context, + struct getdns_list *upstream_list +);
+

The list of dicts define where a stub resolver will send queries. Each dict contains +at least two names: address_type (whose value is a bindata; it is currently either +"IPv4" or "IPv6") and address_data (whose value is a bindata). It might also contain +port to specify which port to use to contact these DNS servers; the default is 53. If +the stub and a recursive resolver both support TSIG (RFC 2845), the upstream_list entry +can also contain tsig_algorithm (a bindata) that is the name of the TSIG hash +algorithm, and tsig_secret (a bindata) that is the TSIG key.

+ +

8.8 Context for EDNS

+ +

These context settings affect queries that have extensions that specify the use of OPT resource records. +These come from RFC 2671.

+ +
+getdns_return_t +getdns_context_set_edns_maximum_udp_payload_size( + getdns_context_t context, + uint16_t value +);
+

The value is between 512 and 65535; the default +is 512.

+ +
+getdns_return_t +getdns_context_set_edns_extended_rcode( + getdns_context_t context, + uint8_t value +);
+

The value is between 0 and 256; the default +is 0.

+ +
+getdns_return_t +getdns_context_set_edns_version( + getdns_context_t context, + uint8_t value +);
+

The value is between 0 and 256; the default +is 0.

+ +
+getdns_return_t +getdns_context_set_edns_do_bit( + getdns_context_t context, + uint8_t value +);
+

The value is between 0 and 1; the default +is 0.

+ +

8.9 Context Use of C Functions

+ +
+getdns_return_t +getdns_context_set_memory_allocator( + getdns_context_t context, + void (*value)(size_t somesize) +);
+

The value is a function pointer to the memory allocator; the +default is the malloc function.

+ +
+getdns_return_t +getdns_context_set_memory_deallocator( + getdns_context_t context, + void (*value)(void*) +);
+

The value is a function pointer to the memory deallocator; the +default is the free function.

+ +
+getdns_return_t +getdns_context_set_memory_reallocator( + getdns_context_t context, + void (*value)(void*) +);
+

The value is a function pointer to the memory reallocator; the +default is the realloc function.

+ +

8.10 Context Codes

+ +

The context codes for getdns_context_set_context_update_callback() are:

+ +

GETDNS_CONTEXT_CODE_NAMESPACES

+

Change related to getdns_context_set_namespaces

+

GETDNS_CONTEXT_CODE_RESOLUTION_TYPE

+

Change related to getdns_context_set_resolution_type

+

GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS

+

Change related to getdns_context_set_follow_redirects

+

GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS

+

Change related to getdns_context_set_upstream_recursive_servers

+

GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS

+

Change related to getdns_context_set_dns_root_servers

+

GETDNS_CONTEXT_CODE_USE_UDP_TCP

+

Change related to getdns_context_set_use_udp_tcp

+

GETDNS_CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES

+

Change related to getdns_context_set_limit_outstanding_queries

+

GETDNS_CONTEXT_CODE_APPEND_NAME

+

Change related to getdns_context_set_append_name

+

GETDNS_CONTEXT_CODE_SUFFIX

+

Change related to getdns_context_set_suffix

+

GETDNS_CONTEXT_CODE_DNSSEC_TRUST_ANCHORS

+

Change related to getdns_context_set_dnssec_trust_anchors

+

GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE

+

Change related to getdns_context_set_edns_maximum_udp_payload_size

+

GETDNS_CONTEXT_CODE_EDNS_EXTENDED_RCODE

+

Change related to getdns_context_set_edns_extended_rcode

+

GETDNS_CONTEXT_CODE_EDNS_VERSION

+

Change related to getdns_context_set_edns_version

+

GETDNS_CONTEXT_CODE_EDNS_DO_BIT

+

Change related to getdns_context_set_edns_do_bit

+

GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW

+

Change related to getdns_context_set_dnssec_allowed_skew

+

GETDNS_CONTEXT_CODE_MEMORY_ALLOCATOR

+

Change related to getdns_context_set_memory_allocator

+

GETDNS_CONTEXT_CODE_MEMORY_DEALLOCATOR

+

Change related to getdns_context_set_memory_deallocator

+

GETDNS_CONTEXT_CODE_MEMORY_REALLOCATOR

+

Change related to getdns_context_set_memory_reallocator

+ + +

9. The Generated Files

+ +

There is a tarball that includes the .h files, +the examples, and so on. The examples all make, even though there is no API implementation, based +on a pseudo-implementation in the tarball; see make-examples-PLATFORM.sh. Note that this currently builds fine +on the Macintosh and Ubuntu; help is definitely appreciated on making the build process +work on more platforms if it fails there.

+ +

10. Commentary

+ +

The following description of the API may be of value to those who might implement the design, and +those who are using an implementation of the design.

+ +

10.1 API Design Considerations

+ +

The genesis of this DNS API design was seeing other DNS API designs flounder. There are other +DNS APIs already available (such as draft-hayatnagarkar-dnsext-validator-api, as well +as DNSSEC APIs in BIND and Unbound), but there has been very little uptake of them. In talking to +application developers, there was a consistent story: that they felt that the APIs were developed by and +for DNS people, not applications developers.

+ +

This API design comes from talking to a small handful of applications developers about what they +would want to see in a modern DNS API. Now that the API is public, it would be great to hear from many +more application developers about whether it would meet their needs if it was implemented. My goal +is to create a design that is a natural follow-on to getaddrinfo() that has all the +capabilities that most application developers might want now or in the next few years: access to all +types of DNS records (including those which are yet to be defined), full DNSSEC awareness, IDN +handling, and parity for IPv4 and IPv6 addresses.

+ +

Note that this is just a design for a new API: there is no implementation of the design yet, but +at least one is being worked on. The process of designing the API without implementing it at the +same time has the huge advantage that major design changes could be made without any worry about +"but we already coded it the other way". In the early revisions of this document, many fundamental +design choices changed over and over, and even bike-shedding-like changes were allowed because they +didn't involve any programming effort.

+ +

This work was done independently, not through the IETF because the IETF generally doesn't take on +API work, and has explicitly avoided DNS API work in the past.

+ +

This API design has a Creative Commons license so that it can be +used widely by potential API implementers. This also allows other people who want to fork the design +to do so cleanly. Of course, any implementation of this API can choose whatever kind of license the +API implementer wishes, but it would be fabulous if one or more such implementations had Creative +Commons or BSD-ish licenses.

+ +

The API relies heavily on C macros and hopefully has no magic numbers.

+ +

10.2 API Implementation Considerations

+ +

All implementations of this API must act as recursive resolvers, and some might choose not to be +able to act as stub resolvers. Note that all implementations of this API must be DNSSEC validators.

+ +

Because there are many C event libraries available, and they have different calling routines, +it is the implementation of an API that determines which event library is used. This is certainly +not optimal for C programmers, but they appear to have gotten used to is so far. All implementations +of this API must support synchronous calls with getdns_sync_request().

+ +

Versions are differentiated by version strings instead of version numbers. The version string for +this API is "getdns April 2013". Each implementation is free to set the implementation string as it +feels fit.

+ +

The API's .h file contains a macro called GETDNS_COMPILATION_COMMENT. This can be useful +to an application which will use the API because it can check the string without calling any +functions. Each time the API implementation is compiled, this string should be updated with unique +information about the implementation build.

+ +

The implementation of both the async and sync getdns functions will +copy all the values of the parameters into local memory, in case the application changes or +deallocates them.

+ +
+ +

Creative
+Commons License
This work is licensed under a Creative Commons Attribution 3.0 +Unported License.

+ + diff --git a/spec/make-examples-linux.sh b/spec/make-examples-linux.sh new file mode 100755 index 00000000..ca56726d --- /dev/null +++ b/spec/make-examples-linux.sh @@ -0,0 +1,22 @@ +rm -rf *.o *.dylib +gcc -std=c89 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c getdns_core_only.c +gcc -std=c89 -shared -fPIC -levent_core -o libgetdns.so getdns_core_only.o +gcc -std=c89 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-all-functions.c +gcc -std=c89 -fPIC -L./ example-all-functions.o -levent_core -lgetdns -o example-all-functions +gcc -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-simple-answers.c +gcc -std=c99 -fPIC -L./ example-simple-answers.o -levent_core -lgetdns -o example-simple-answers +gcc -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-tree.c +gcc -std=c99 -fPIC -L./ example-tree.o -levent_core -lgetdns -o example-tree +gcc -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-synchronous.c +gcc -std=c99 -fPIC -L./ example-synchronous.o -levent_core -lgetdns -o example-synchronous +rm -rf *.o *.dylib +clang -std=c89 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c getdns_core_only.c +clang -std=c89 -shared -fPIC -levent_core -o libgetdns.so getdns_core_only.o +clang -std=c89 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-all-functions.c +clang -std=c89 -fPIC -L./ example-all-functions.o -levent_core -lgetdns -o example-all-functions +clang -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-simple-answers.c +clang -std=c99 -fPIC -L./ example-simple-answers.o -levent_core -lgetdns -o example-simple-answers +clang -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-tree.c +clang -std=c99 -fPIC -L./ example-tree.o -levent_core -lgetdns -o example-tree +clang -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-synchronous.c +clang -std=c99 -fPIC -L./ example-synchronous.o -levent_core -lgetdns -o example-synchronous diff --git a/spec/make-examples-mac.sh b/spec/make-examples-mac.sh new file mode 100755 index 00000000..02c91eb0 --- /dev/null +++ b/spec/make-examples-mac.sh @@ -0,0 +1,22 @@ +rm -rf *.o *.dylib +gcc -std=c89 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c getdns_core_only.c +gcc -std=c89 -dynamiclib -fPIC -levent_core -o libgetdns.dylib getdns_core_only.o +gcc -std=c89 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-all-functions.c +gcc -std=c89 -fPIC -L./ example-all-functions.o -levent_core -lgetdns -o example-all-functions +gcc -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-simple-answers.c +gcc -std=c99 -fPIC -L./ example-simple-answers.o -levent_core -lgetdns -o example-simple-answers +gcc -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-tree.c +gcc -std=c99 -fPIC -L./ example-tree.o -levent_core -lgetdns -o example-tree +gcc -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-synchronous.c +gcc -std=c99 -fPIC -L./ example-synchronous.o -levent_core -lgetdns -o example-synchronous +rm -rf *.o *.dylib +clang -std=c89 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c getdns_core_only.c +clang -std=c89 -dynamiclib -fPIC -levent_core -o libgetdns.dylib getdns_core_only.o +clang -std=c89 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-all-functions.c +clang -std=c89 -fPIC -L./ example-all-functions.o -levent_core -lgetdns -o example-all-functions +clang -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-simple-answers.c +clang -std=c99 -fPIC -L./ example-simple-answers.o -levent_core -lgetdns -o example-simple-answers +clang -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-tree.c +clang -std=c99 -fPIC -L./ example-tree.o -levent_core -lgetdns -o example-tree +clang -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-synchronous.c +clang -std=c99 -fPIC -L./ example-synchronous.o -levent_core -lgetdns -o example-synchronous