/* 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 static int debug = 1; static getdns_return_t dump_reply(FILE *fp, getdns_dict *reply, const char *section_name) { getdns_list *section = NULL; size_t section_len = -1; getdns_return_t r; uint8_t res_buf[4096], *res = NULL; size_t res_len = sizeof(res_buf); r = getdns_dict_get_list(reply, section_name, §ion); if (r) { fprintf(stderr, "unable to get section \"%s\" from reply\n", section_name); return r; } r = getdns_list_get_length(section, §ion_len); if (r) { fprintf(stderr, "unable to get length of section\n"); return r; } for (size_t j = 0; j < section_len; j++) { getdns_dict *rr = NULL; r = getdns_list_get_dict(section, j , &rr); if (r) { fprintf(stderr, "unable to get rr from entry " "%d: %d\n", j, r); return r; } r = getdns_rr_dict2wire(rr, &res, &res_len); if (r) { fprintf(stderr, "unable to convert entry %d " "to wire format: %d\n", j, r); return r; } if (0 && debug) { char *s = getdns_pretty_print_dict(rr); puts(s); free(s); } if (fwrite(res, 1, res_len, fp) != res_len) { fprintf(stderr, "unable to write buffer to file: %s\n", strerror(errno)); return -errno; } free(res); } return 0; } int dump_tree(FILE *fp, const getdns_dict *response, const char *tree_name) { getdns_return_t r; getdns_list *tree = NULL; size_t n_replies = -1; r = getdns_dict_get_list(response, tree_name, &tree); if (r) { fprintf(stderr, "unable to get tree %s\n", tree_name); return r; } r = getdns_list_get_length(tree, &n_replies); if (r) { fprintf(stderr, "unable to get number of replies\n"); return r; } for (size_t i = 0; i < n_replies; i++) { getdns_dict *reply = NULL; r = getdns_list_get_dict(tree, i, &reply); if (r) { fprintf(stderr, "unable to get reply %d from tree\n", i); return r; } if (debug) { char *s = getdns_pretty_print_dict(reply); printf("Pretty-printing reply #%d:%s\n", i, s); free(s); } dump_reply(fp, reply, "answer"); } return 0; } /* 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])) 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; } 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; if (argc > 1) query_name = argv[1]; if (argc > 2) query_type = (uint16_t) atoi(argv[2]); if ((r = getdns_context_create(&context, 1))) fprintf(stderr, "Trying to create the context failed"); 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); }