ldns_status ldns_resolver_send(ldns_pkt **answer, ldns_resolver *r, const ldns_rdf *name, ldns_rr_type type, ldns_rr_class c, uint16_t flags) { ldns_pkt *query_pkt; ldns_pkt *answer_pkt; ldns_status status; assert(r != NULL); assert(name != NULL); answer_pkt = NULL; /* do all the preprocessing here, then fire of an query to * the network */ if (0 == type) { type = LDNS_RR_TYPE_A; } if (0 == c) { c = LDNS_RR_CLASS_IN; } if (0 == ldns_resolver_nameserver_count(r)) { return LDNS_STATUS_RES_NO_NS; } if (ldns_rdf_get_type(name) != LDNS_RDF_TYPE_DNAME) { return LDNS_STATUS_RES_QUERY; } status = ldns_resolver_prepare_query_pkt(&query_pkt, r, name, type, c, flags); if (status != LDNS_STATUS_OK) { return status; } /* if tsig values are set, tsign it */ /* TODO: make last 3 arguments optional too? maybe make complete rr instead of seperate values in resolver (and packet) Jelte should this go in pkt_prepare? */ #ifdef HAVE_SSL if (ldns_resolver_tsig_keyname(r) && ldns_resolver_tsig_keydata(r)) { status = ldns_pkt_tsig_sign(query_pkt, ldns_resolver_tsig_keyname(r), ldns_resolver_tsig_keydata(r), 300, ldns_resolver_tsig_algorithm(r), NULL); if (status != LDNS_STATUS_OK) { return LDNS_STATUS_CRYPTO_TSIG_ERR; } } #endif /* HAVE_SSL */ status = ldns_resolver_send_pkt(&answer_pkt, r, query_pkt); ldns_pkt_free(query_pkt); /* allows answer to be NULL when not interested in return value */ if (answer) { *answer = answer_pkt; } return status; }
int main(int argc, char **argv) { int c; int i; /* LDNS types */ ldns_pkt *notify; ldns_rr *question; ldns_resolver *res; ldns_rdf *ldns_zone_name = NULL; ldns_status status; const char *zone_name = NULL; int include_soa = 0; uint32_t soa_version = 0; ldns_tsig_credentials tsig_cred = {0,0,0}; int do_hexdump = 1; uint8_t *wire = NULL; size_t wiresize = 0; char *port = "53"; srandom(time(NULL) ^ getpid()); while ((c = getopt(argc, argv, "vhdp:r:s:y:z:")) != -1) { switch (c) { case 'd': verbose++; break; case 'p': port = optarg; break; case 'r': max_num_retry = atoi(optarg); break; case 's': include_soa = 1; soa_version = (uint32_t)atoi(optarg); break; case 'y': tsig_cred.algorithm = "hmac-md5.sig-alg.reg.int."; tsig_cred.keyname = optarg; tsig_cred.keydata = strchr(optarg, ':'); *tsig_cred.keydata = '\0'; tsig_cred.keydata++; printf("Sign with %s : %s\n", tsig_cred.keyname, tsig_cred.keydata); break; case 'z': zone_name = optarg; ldns_zone_name = ldns_dname_new_frm_str(zone_name); if(!ldns_zone_name) { printf("cannot parse zone name: %s\n", zone_name); exit(1); } break; case 'v': version(); case 'h': case '?': default: usage(); } } argc -= optind; argv += optind; if (argc == 0 || zone_name == NULL) { usage(); } notify = ldns_pkt_new(); question = ldns_rr_new(); res = ldns_resolver_new(); if (!notify || !question || !res) { /* bail out */ printf("error: cannot create ldns types\n"); exit(1); } /* create the rr for inside the pkt */ ldns_rr_set_class(question, LDNS_RR_CLASS_IN); ldns_rr_set_owner(question, ldns_zone_name); ldns_rr_set_type(question, LDNS_RR_TYPE_SOA); ldns_pkt_set_opcode(notify, LDNS_PACKET_NOTIFY); ldns_pkt_push_rr(notify, LDNS_SECTION_QUESTION, question); ldns_pkt_set_aa(notify, true); ldns_pkt_set_id(notify, random()&0xffff); if(include_soa) { char buf[10240]; ldns_rr *soa_rr=NULL; ldns_rdf *prev=NULL; snprintf(buf, sizeof(buf), "%s 3600 IN SOA . . %u 0 0 0 0", zone_name, (unsigned)soa_version); /*printf("Adding soa %s\n", buf);*/ status = ldns_rr_new_frm_str(&soa_rr, buf, 3600, NULL, &prev); if(status != LDNS_STATUS_OK) { printf("Error adding SOA version: %s\n", ldns_get_errorstr_by_id(status)); } ldns_pkt_push_rr(notify, LDNS_SECTION_ANSWER, soa_rr); } if(tsig_cred.keyname) { #ifdef HAVE_SSL status = ldns_pkt_tsig_sign(notify, tsig_cred.keyname, tsig_cred.keydata, 300, tsig_cred.algorithm, NULL); if(status != LDNS_STATUS_OK) { printf("Error TSIG sign query: %s\n", ldns_get_errorstr_by_id(status)); } #else fprintf(stderr, "Warning: TSIG needs OpenSSL support, which has not been compiled in, TSIG skipped\n"); #endif } if(verbose) { printf("# Sending packet:\n"); ldns_pkt_print(stdout, notify); } status = ldns_pkt2wire(&wire, notify, &wiresize); if(wiresize == 0) { printf("Error converting notify packet to hex.\n"); exit(1); } if(do_hexdump && verbose > 1) { printf("Hexdump of notify packet:\n"); for(i=0; i<(int)wiresize; i++) printf("%02x", (unsigned)wire[i]); printf("\n"); } for(i=0; i<argc; i++) { struct addrinfo hints, *res0, *res; int error; int default_family = AF_INET; if(verbose) printf("# sending to %s\n", argv[i]); memset(&hints, 0, sizeof(hints)); hints.ai_family = default_family; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; error = getaddrinfo(argv[i], port, &hints, &res0); if (error) { printf("skipping bad address: %s: %s\n", argv[i], gai_strerror(error)); continue; } for (res = res0; res; res = res->ai_next) { int s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if(s == -1) continue; /* send the notify */ notify_host(s, res, wire, wiresize, argv[i]); } freeaddrinfo(res0); } ldns_pkt_free(notify); free(wire); return 0; }