/* This program is based on (IIRC) * getdns/spec/example/example-simple-answers.c. * * Resolve DNS name argv[1] of type argv[2] using libgetdns and write * the resulting RRs to two files, in DNS binary wire format: * * - binout: /just_address_answers/0/address_data and * /just_address_answers/1/address_data * * - treeout: output from getdns_rr_dict2wire for all RR's in the * answer section * * Based on getdns/spec/example/example-simple-answers.c. */ #include #include #include #include #include #include #include #include #include "common.h" /* Set up the callback function, which will also do the processing of the results */ void callback(getdns_context *context, getdns_callback_type_t callback_type, getdns_dict *response, void *userarg, getdns_transaction_t transaction_id) { getdns_return_t r; /* Holder for all function returns */ uint32_t status; getdns_bindata *address_data; char *first = NULL, *second = NULL; FILE *binoutfp = NULL, *treeoutfp = NULL; (void) context; /* unused parameter */ binoutfp = fopen("binout", "w"); assert(binoutfp != NULL); treeoutfp = fopen("treeout", "w"); assert(treeoutfp != NULL); printf( "Callback for query \"%s\" with request ID %"PRIu64".\n" , (char *)userarg, transaction_id ); switch(callback_type) { case GETDNS_CALLBACK_CANCEL: printf("Transaction with ID %"PRIu64" was cancelled.\n", transaction_id); return; case GETDNS_CALLBACK_TIMEOUT: printf("Transaction with ID %"PRIu64" timed out.\n", transaction_id); return; case GETDNS_CALLBACK_ERROR: printf("An error occurred for transaction ID %"PRIu64".\n", transaction_id); return; default: break; } assert( callback_type == GETDNS_CALLBACK_COMPLETE ); if ((r = getdns_dict_get_int(response, "status", &status))) fprintf(stderr, "Could not get \"status\" from reponse"); else if (status != GETDNS_RESPSTATUS_GOOD) fprintf(stderr, "The search had no results, and a return value of %"PRIu32".\n", status); static char *TREES[] = {"replies_tree", "validation_chain"}; static const int TREES_LEN = 2; for (int i = 0; i < TREES_LEN; i++) { if (dump_tree(treeoutfp, response, TREES[i], "answer")) fprintf(stderr, "Could not dump %s to file\n", TREES[i]); else if ((r = getdns_dict_get_bindata(response, "/just_address_answers/0/address_data", &address_data))) fprintf(stderr, "Could not get first address"); else if (fwrite(address_data->data, 1, address_data->size, binoutfp) != address_data->size) fprintf(stderr, "first fwrite: %s\n", strerror(errno)); else if (!(first = getdns_display_ip_address(address_data))) fprintf(stderr, "Could not convert first address to string\n"); else if ((r = getdns_dict_get_bindata(response, "/just_address_answers/1/address_data", &address_data))) fprintf(stderr, "Could not get second address"); else if (fwrite(address_data->data, 1, address_data->size, binoutfp) != address_data->size) fprintf(stderr, "second fwrite: %s\n", strerror(errno)); else if (!(second = getdns_display_ip_address(address_data))) fprintf(stderr, "Could not convert second address to string\n"); if (first) { printf("The address is %s\n", first); free(first); } if (second) { printf("The address is %s\n", second); free(second); } if (r) { assert( r != GETDNS_RETURN_GOOD ); fprintf(stderr, ": %d\n", r); } } getdns_dict_destroy(response); if (binoutfp) fclose(binoutfp); if (treeoutfp) fclose(treeoutfp); } static getdns_return_t send_query(getdns_context *context, char *query_name, const uint16_t query_type, getdns_transaction_t *transaction_id) { getdns_return_t r = GETDNS_RETURN_GENERIC_ERROR; getdns_dict *extensions = getdns_dict_create(); char *userarg = query_name; assert(extensions != NULL); r = getdns_dict_set_int(extensions, "dnssec_return_validation_chain", GETDNS_EXTENSION_TRUE); if (r) return r; #if 0 r = getdns_dict_set_int(extensions, "dnssec_return_status", GETDNS_EXTENSION_TRUE); if (r) return r; #endif if (query_type == 0) r = getdns_address(context, query_name, extensions, userarg, transaction_id, callback); else r = getdns_general(context, query_name, query_type, extensions, userarg, transaction_id, callback); if (r) return r; return r; } #define OWN_ROOT #ifdef OWN_ROOT getdns_list * read_own_rootfile() { FILE *fp = fopen("root.txt", "r"); getdns_list *list = NULL; if (fp && !getdns_fp2rr_list(fp, &list, ".", 0)) return list; return NULL; } #endif int main(int argc, char *argv[]) { getdns_return_t r; /* Holder for all function returns */ getdns_context *context = NULL; struct event_base *event_base = NULL; char *query_name = "www.example.com"; uint16_t query_type = 0; getdns_transaction_t transaction_id; getdns_list *trust_anchors; getdns_list *root_servers = NULL; if (argc > 1) query_name = argv[1]; if (argc > 2) query_type = (uint16_t) atoi(argv[2]); if ((r = getdns_context_create(&context, 0))) fprintf(stderr, "Trying to create the context failed"); #ifdef OWN_ROOT else if (!(root_servers = read_own_rootfile())) fprintf(stderr, "Reading root hints file failed.\n"); #endif else if ((r = getdns_context_set_dns_root_servers(context, root_servers))) fprintf(stderr, "Setting root name servers failed.\n"); else if ((r = getdns_context_get_dnssec_trust_anchors( context, &trust_anchors)) || trust_anchors == NULL) fprintf(stderr, "No trust anchor.\n"); else if (!(event_base = event_base_new())) fprintf(stderr, "Trying to create the event base failed.\n"); else if ((r = getdns_extension_set_libevent_base(context, event_base))) fprintf(stderr, "Setting the event base failed"); else if ((r = send_query(context, query_name, query_type, &transaction_id))) fprintf(stderr, "Queueing query failed: %d\n", r); else { printf("Request with transaction ID %"PRIu64" scheduled.\n", transaction_id); if (event_base_dispatch(event_base) < 0) fprintf(stderr, "Error dispatching events\n"); } /* Clean up */ if (event_base) event_base_free(event_base); if (context) getdns_context_destroy(context); /* Assuming we get here, leave gracefully */ exit(EXIT_SUCCESS); }