void truncation_check(evldns_server_request *srq) { ldns_pkt *req = srq->request; ldns_pkt *resp = srq->response; unsigned int bufsize = 512; /* if it's TCP, business as usual */ if (srq->is_tcp) { return; } /* otherwise, convert to wire format, if necessary */ if (!srq->wire_response) { (void) ldns_pkt2wire(&srq->wire_response, resp, &srq->wire_resplen); } /* if it's under the RFC 1035 limit, we're OK */ if (srq->wire_resplen <= bufsize) { return; } /* if the client used EDNS, use that new bufsize */ if (ldns_pkt_edns(req)) { unsigned int ednssize = ldns_pkt_edns_udp_size(req); if (ednssize > bufsize) { bufsize = ednssize; } /* it fits - we're OK */ if (srq->wire_resplen <= bufsize) { return; } } /* * if we got here, it didn't fit - throw away the * existing wire buffer and the non-question sections */ free(srq->wire_response); LDNS_rr_list_empty_rr_list(ldns_pkt_additional(resp)); LDNS_rr_list_empty_rr_list(ldns_pkt_authority(resp)); LDNS_rr_list_empty_rr_list(ldns_pkt_answer(resp)); /* set the TC bit and reset section counts */ ldns_pkt_set_tc(resp, true); ldns_pkt_set_ancount(resp, 0); ldns_pkt_set_nscount(resp, 0); ldns_pkt_set_arcount(resp, 0); /* and convert to wire format again */ (void) ldns_pkt2wire(&srq->wire_response, resp, &srq->wire_resplen); }
DCPluginSyncFilterResult dcplugin_sync_pre_filter(DCPlugin *dcplugin, DCPluginDNSPacket *dcp_packet) { uint8_t *new_packet; ldns_rdf *edns_data; ldns_pkt *packet; size_t new_packet_size; ldns_wire2pkt(&packet, dcplugin_get_wire_data(dcp_packet), dcplugin_get_wire_data_len(dcp_packet)); edns_data = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_HEX, dcplugin_get_user_data(dcplugin)); ldns_pkt_set_edns_data(packet, edns_data); ldns_pkt2wire(&new_packet, packet, &new_packet_size); if (dcplugin_get_wire_data_max_len(dcp_packet) >= new_packet_size) { dcplugin_set_wire_data(dcp_packet, new_packet, new_packet_size); } free(new_packet); ldns_pkt_free(packet); return DCP_SYNC_FILTER_RESULT_OK; }
bool handle_domain(void *k, void *l, void *c) { lookup_t *lookup = (lookup_t *) l; lookup_context_t *context = (lookup_context_t *) c; struct timeval now; gettimeofday(&now, NULL); if (timediff(&now, &lookup->next_lookup) < 0) { uint16_t query_flags = 0; if (!context->cmd_args.norecurse) { query_flags |= LDNS_RD; } ldns_pkt *packet; if(LDNS_STATUS_OK != ldns_pkt_query_new_frm_str(&packet, lookup->domain, context->cmd_args.record_types, LDNS_RR_CLASS_IN, query_flags)) { abort(); } ldns_pkt_set_id(packet, lookup->transaction); uint8_t *buf = NULL; size_t packet_size = 0; if(LDNS_STATUS_OK != ldns_pkt2wire(&buf, packet, &packet_size)) { abort(); } ldns_pkt_free(packet); packet = NULL; sockaddr_in_t *resolver = massdns_get_resolver((size_t) rand(), &context->resolvers); ssize_t n = -1; while (n < 0) { n = sendto(context->sock, buf, packet_size, 0, (sockaddr_t *) resolver, sizeof(*resolver)); } free(buf); long addusec = context->cmd_args.interval_ms * 1000; addusec += rand() % (addusec / 5); // Avoid congestion by adding some randomness lookup->next_lookup.tv_usec = (now.tv_usec + addusec) % 1000000; lookup->next_lookup.tv_sec = now.tv_sec + (now.tv_usec + addusec) / 1000000; lookup->tries++; if (lookup->tries == context->cmd_args.resolve_count) { hashmapRemove(context->map, lookup->domain); free(lookup->domain); free(lookup); } } return true; }
void dump_hex(const ldns_pkt *pkt, const char *filename) { uint8_t *wire = NULL; size_t size, i; FILE *fp; ldns_status status; fp = fopen(filename, "w"); if (fp == NULL) { error("Unable to open %s for writing", filename); return; } status = ldns_pkt2wire(&wire, pkt, &size); if (status != LDNS_STATUS_OK) { error("Unable to convert packet: error code %u", status); LDNS_FREE(wire); fclose(fp); return; } fprintf(fp, "; 0"); for (i = 1; i < 20; i++) { fprintf(fp, " %2u", (unsigned int) i); } fprintf(fp, "\n"); fprintf(fp, ";--"); for (i = 1; i < 20; i++) { fprintf(fp, " --"); } fprintf(fp, "\n"); for (i = 0; i < size; i++) { if (i % 20 == 0 && i > 0) { fprintf(fp, "\t;\t%4u-%4u\n", (unsigned int) i-19, (unsigned int) i); } fprintf(fp, " %02x", (unsigned int)wire[i]); } fprintf(fp, "\n"); fclose(fp); LDNS_FREE(wire); }
bool dump_hex(FILE *fp, const ldns_pkt *pkt) { uint8_t *wire; size_t size, i; ldns_status status; status = ldns_pkt2wire(&wire, pkt, &size); if (status != LDNS_STATUS_OK) { fprintf(stdout, "= Unable to convert packet back to wire: error code %u", status); fprintf(stdout, "= original hex:\n"); return false; } for (i = 0; i < size; i++) { fprintf(fp, "%02x", (unsigned int)wire[i]); } LDNS_FREE(wire); return true; }
/** entry to packet buffer with wireformat */ static void entry_to_buf(struct entry* e, ldns_buffer* pkt) { unit_assert(e->reply_list); if(e->reply_list->reply_from_hex) { ldns_buffer_copy(pkt, e->reply_list->reply_from_hex); } else { ldns_status status; size_t answer_size; uint8_t* ans = NULL; status = ldns_pkt2wire(&ans, e->reply_list->reply, &answer_size); if(status != LDNS_STATUS_OK) { log_err("could not create reply: %s", ldns_get_errorstr_by_id(status)); fatal_exit("error in test"); } ldns_buffer_clear(pkt); ldns_buffer_write(pkt, ans, answer_size); ldns_buffer_flip(pkt); free(ans); } }
void zkdns_start(const char* my_address, int port, const char* my_zone) { rp_handle = rp_initialize(my_zone); /* network */ int sock; ssize_t nb; struct sockaddr addr_me; struct sockaddr addr_him; socklen_t hislen = (socklen_t) sizeof(addr_him); uint8_t inbuf[INBUF_SIZE]; uint8_t *outbuf; /* dns */ ldns_status status; ldns_pkt *query_pkt; ldns_pkt *answer_pkt; size_t answer_size; ldns_rr *query_rr; ldns_rr_list *answer_qr; ldns_rr_list *answer_an; ldns_rr_list *answer_ns; ldns_rr_list *answer_ad; ldns_rdf *origin = NULL; /* zone */ ldns_zone *zone; int line_nr; FILE *zone_fp; if (ldns_str2rdf_dname(&origin, my_zone) != LDNS_STATUS_OK) { fprintf(stderr, "Bad origin, not a correct domain name\n"); exit(EXIT_FAILURE); } printf("Listening on port %d\n", port); sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { fprintf(stderr, "socket(): %s\n", strerror(errno)); exit(1); } memset(&addr_me, 0, sizeof(addr_me)); /* bind: try all ports in that range */ if (udp_bind(sock, port, my_address)) { fprintf(stderr, "cannot bind(): %s\n", strerror(errno)); exit(errno); } /* Done. Now receive */ while (1) { nb = recvfrom(sock, (void*)inbuf, INBUF_SIZE, 0, &addr_him, &hislen); if (nb < 1) { fprintf(stderr, "recvfrom(): %s\n", strerror(errno)); exit(1); } /* show(inbuf, nb, nn, hp, sp, ip, bp); */ status = ldns_wire2pkt(&query_pkt, inbuf, (size_t) nb); if (status != LDNS_STATUS_OK) { printf("Got bad packet: %s\n", ldns_get_errorstr_by_id(status)); } query_rr = ldns_rr_list_rr(ldns_pkt_question(query_pkt), 0); answer_qr = ldns_rr_list_new(); ldns_rr_list_push_rr(answer_qr, ldns_rr_clone(query_rr)); answer_an = get_rrset(zone, ldns_rr_owner(query_rr), ldns_rr_get_type(query_rr), ldns_rr_get_class(query_rr)); answer_pkt = ldns_pkt_new(); answer_ns = ldns_rr_list_new(); answer_ad = ldns_rr_list_new(); ldns_pkt_set_qr(answer_pkt, 1); ldns_pkt_set_aa(answer_pkt, 1); ldns_pkt_set_id(answer_pkt, ldns_pkt_id(query_pkt)); ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_QUESTION, answer_qr); ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ANSWER, answer_an); ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_AUTHORITY, answer_ns); ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ADDITIONAL, answer_ad); status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size); if (status != LDNS_STATUS_OK) { printf("Error creating answer: %s\n", ldns_get_errorstr_by_id(status)); } else { nb = sendto(sock, (void*)outbuf, answer_size, 0, &addr_him, hislen); } ldns_pkt_free(query_pkt); ldns_pkt_free(answer_pkt); LDNS_FREE(outbuf); ldns_rr_list_free(answer_qr); ldns_rr_list_free(answer_an); ldns_rr_list_free(answer_ns); ldns_rr_list_free(answer_ad); } ldns_rdf_deep_free(origin); ldns_zone_deep_free(zone); rp_shutdown(rp_handle); }
ldns_status ldns_pkt_tsig_sign_next(ldns_pkt *pkt, const char *key_name, const char *key_data, uint16_t fudge, const char *algorithm_name, ldns_rdf *query_mac, int tsig_timers_only) { ldns_rr *tsig_rr; ldns_rdf *key_name_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, key_name); ldns_rdf *fudge_rdf = NULL; ldns_rdf *orig_id_rdf = NULL; ldns_rdf *algorithm_rdf; ldns_rdf *error_rdf = NULL; ldns_rdf *mac_rdf = NULL; ldns_rdf *other_data_rdf = NULL; ldns_status status = LDNS_STATUS_OK; uint8_t *pkt_wire = NULL; size_t pkt_wire_len; struct timeval tv_time_signed; uint8_t *time_signed = NULL; ldns_rdf *time_signed_rdf = NULL; algorithm_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, algorithm_name); if(!key_name_rdf || !algorithm_rdf) { status = LDNS_STATUS_MEM_ERR; goto clean; } /* eww don't have create tsigtime rdf yet :( */ /* bleh :p */ if (gettimeofday(&tv_time_signed, NULL) == 0) { time_signed = LDNS_XMALLOC(uint8_t, 6); if(!time_signed) { status = LDNS_STATUS_MEM_ERR; goto clean; } ldns_write_uint64_as_uint48(time_signed, (uint64_t)tv_time_signed.tv_sec); } else { status = LDNS_STATUS_INTERNAL_ERR; goto clean; } time_signed_rdf = ldns_rdf_new(LDNS_RDF_TYPE_TSIGTIME, 6, time_signed); if(!time_signed_rdf) { LDNS_FREE(time_signed); status = LDNS_STATUS_MEM_ERR; goto clean; } fudge_rdf = ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, fudge); orig_id_rdf = ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, ldns_pkt_id(pkt)); error_rdf = ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, 0); other_data_rdf = ldns_native2rdf_int16_data(0, NULL); if(!fudge_rdf || !orig_id_rdf || !error_rdf || !other_data_rdf) { status = LDNS_STATUS_MEM_ERR; goto clean; } if (ldns_pkt2wire(&pkt_wire, pkt, &pkt_wire_len) != LDNS_STATUS_OK) { status = LDNS_STATUS_ERR; goto clean; } status = ldns_tsig_mac_new(&mac_rdf, pkt_wire, pkt_wire_len, key_data, key_name_rdf, fudge_rdf, algorithm_rdf, time_signed_rdf, error_rdf, other_data_rdf, query_mac, tsig_timers_only); if (!mac_rdf) { goto clean; } LDNS_FREE(pkt_wire); /* Create the TSIG RR */ tsig_rr = ldns_rr_new(); if(!tsig_rr) { status = LDNS_STATUS_MEM_ERR; goto clean; } ldns_rr_set_owner(tsig_rr, key_name_rdf); ldns_rr_set_class(tsig_rr, LDNS_RR_CLASS_ANY); ldns_rr_set_type(tsig_rr, LDNS_RR_TYPE_TSIG); ldns_rr_set_ttl(tsig_rr, 0); ldns_rr_push_rdf(tsig_rr, algorithm_rdf); ldns_rr_push_rdf(tsig_rr, time_signed_rdf); ldns_rr_push_rdf(tsig_rr, fudge_rdf); ldns_rr_push_rdf(tsig_rr, mac_rdf); ldns_rr_push_rdf(tsig_rr, orig_id_rdf); ldns_rr_push_rdf(tsig_rr, error_rdf); ldns_rr_push_rdf(tsig_rr, other_data_rdf); ldns_pkt_set_tsig(pkt, tsig_rr); return status; clean: LDNS_FREE(pkt_wire); ldns_rdf_free(key_name_rdf); ldns_rdf_free(algorithm_rdf); ldns_rdf_free(time_signed_rdf); ldns_rdf_free(fudge_rdf); ldns_rdf_free(orig_id_rdf); ldns_rdf_free(error_rdf); ldns_rdf_free(other_data_rdf); return status; }
int main(int argc, char **argv) { /* arguments */ int port; const char *zone_file; /* network */ int sock; ssize_t nb; struct sockaddr addr_me; struct sockaddr addr_him; socklen_t hislen = (socklen_t) sizeof(addr_him); uint8_t inbuf[INBUF_SIZE]; uint8_t *outbuf; /* dns */ ldns_status status; ldns_pkt *query_pkt; ldns_pkt *answer_pkt; size_t answer_size; ldns_rr *query_rr; ldns_rr_list *answer_qr; ldns_rr_list *answer_an; ldns_rr_list *answer_ns; ldns_rr_list *answer_ad; ldns_rdf *origin = NULL; /* zone */ ldns_zone *zone; int line_nr; FILE *zone_fp; /* use this to listen on specified interfaces later? */ char *my_address = NULL; if (argc < 5) { usage(stderr); exit(EXIT_FAILURE); } else { my_address = argv[1]; port = atoi(argv[2]); if (port < 1) { usage(stderr); exit(EXIT_FAILURE); } if (ldns_str2rdf_dname(&origin, argv[3]) != LDNS_STATUS_OK) { fprintf(stderr, "Bad origin, not a correct domain name\n"); usage(stderr); exit(EXIT_FAILURE); } zone_file = argv[4]; } printf("Reading zone file %s\n", zone_file); zone_fp = fopen(zone_file, "r"); if (!zone_fp) { fprintf(stderr, "Unable to open %s: %s\n", zone_file, strerror(errno)); exit(EXIT_FAILURE); } line_nr = 0; status = ldns_zone_new_frm_fp_l(&zone, zone_fp, origin, 0, LDNS_RR_CLASS_IN, &line_nr); if (status != LDNS_STATUS_OK) { printf("Zone reader failed, aborting\n"); exit(EXIT_FAILURE); } else { printf("Read %u resource records in zone file\n", (unsigned int) ldns_zone_rr_count(zone)); } fclose(zone_fp); printf("Listening on port %d\n", port); sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { fprintf(stderr, "%s: socket(): %s\n", argv[0], strerror(errno)); exit(1); } memset(&addr_me, 0, sizeof(addr_me)); /* bind: try all ports in that range */ if (udp_bind(sock, port, my_address)) { fprintf(stderr, "%s: cannot bind(): %s\n", argv[0], strerror(errno)); exit(errno); } /* Done. Now receive */ while (1) { nb = recvfrom(sock, (void*)inbuf, INBUF_SIZE, 0, &addr_him, &hislen); if (nb < 1) { fprintf(stderr, "%s: recvfrom(): %s\n", argv[0], strerror(errno)); exit(1); } /* show(inbuf, nb, nn, hp, sp, ip, bp); */ printf("Got query of %u bytes\n", (unsigned int) nb); status = ldns_wire2pkt(&query_pkt, inbuf, (size_t) nb); if (status != LDNS_STATUS_OK) { printf("Got bad packet: %s\n", ldns_get_errorstr_by_id(status)); } else { ldns_pkt_print(stdout, query_pkt); } query_rr = ldns_rr_list_rr(ldns_pkt_question(query_pkt), 0); printf("QUERY RR: \n"); ldns_rr_print(stdout, query_rr); answer_qr = ldns_rr_list_new(); ldns_rr_list_push_rr(answer_qr, ldns_rr_clone(query_rr)); answer_an = get_rrset(zone, ldns_rr_owner(query_rr), ldns_rr_get_type(query_rr), ldns_rr_get_class(query_rr)); answer_pkt = ldns_pkt_new(); answer_ns = ldns_rr_list_new(); answer_ad = ldns_rr_list_new(); ldns_pkt_set_qr(answer_pkt, 1); ldns_pkt_set_aa(answer_pkt, 1); ldns_pkt_set_id(answer_pkt, ldns_pkt_id(query_pkt)); ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_QUESTION, answer_qr); ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ANSWER, answer_an); ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_AUTHORITY, answer_ns); ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ADDITIONAL, answer_ad); status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size); printf("Answer packet size: %u bytes.\n", (unsigned int) answer_size); if (status != LDNS_STATUS_OK) { printf("Error creating answer: %s\n", ldns_get_errorstr_by_id(status)); } else { nb = sendto(sock, (void*)outbuf, answer_size, 0, &addr_him, hislen); } ldns_pkt_free(query_pkt); ldns_pkt_free(answer_pkt); LDNS_FREE(outbuf); ldns_rr_list_free(answer_qr); ldns_rr_list_free(answer_an); ldns_rr_list_free(answer_ns); ldns_rr_list_free(answer_ad); } /* No cleanup because of the infinite loop * * ldns_rdf_deep_free(origin); * ldns_zone_deep_free(zone); * return 0; */ }
void* run_server(void* data) { timeout_thread_data* tdata = (timeout_thread_data*)data; int fd; struct sockaddr_in serv_addr; uint8_t mesg[65536]; fd_set read_fds; ldns_rdf* answerfrom; ldns_resolver* resolver; int num_received = 0; queued_response responses[10]; ldns_resolver_new_frm_file(&resolver, NULL); fd=socket(AF_INET,SOCK_DGRAM,0); memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr=htonl(INADDR_ANY); serv_addr.sin_port=htons(tdata->port); bind(fd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)); /* signal that it's listening */ /* dirty timing hack to yield */ sleep(1); tdata->running = 1; /* queue up query responses to send out, and delay sending them * for a second */ while (tdata->running) { struct sockaddr_in client_addr; FD_ZERO(&read_fds); FD_SET(fd, &read_fds); struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; int r = select(fd + 1, &read_fds, NULL, NULL, &tv); if (r > 0 && num_received < 10) { ldns_pkt* query; socklen_t len = sizeof(client_addr); int n = recvfrom(fd,mesg,65536,0,(struct sockaddr *)&(responses[num_received].client_addr),&len); ldns_wire2pkt(&query, mesg, n); ldns_resolver_send_pkt(&(responses[num_received].pkt), resolver, query); ldns_str2rdf_a(&answerfrom, "127.0.0.1"); ldns_pkt_set_answerfrom(responses[num_received].pkt, answerfrom); ldns_pkt_free(query); ++num_received; } else if (r == 0 && num_received > 0) { int i = 0; /* timeout - see if we have anything to send */ for (i = 0; i < num_received; ++i) { uint8_t* pkt_data; size_t pkt_len; ldns_pkt* answer = responses[i].pkt; ldns_pkt2wire(&pkt_data, answer, &pkt_len); sendto(fd,pkt_data,pkt_len,0,(struct sockaddr *)&(responses[i].client_addr),sizeof(client_addr)); free(pkt_data); ldns_pkt_free(answer); } num_received = 0; } } ldns_resolver_deep_free(resolver); return NULL; }
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; }
/* * Parses data buffer to a query, finds the correct answer * and calls the given function for every packet to send. */ void handle_query(uint8_t* inbuf, ssize_t inlen, struct entry* entries, int* count, enum transport_type transport, void (*sendfunc)(uint8_t*, size_t, void*), void* userdata, FILE* verbose_out) { ldns_status status; ldns_pkt *query_pkt = NULL; ldns_pkt *answer_pkt = NULL; struct reply_packet *p; ldns_rr *query_rr = NULL; uint8_t *outbuf = NULL; size_t answer_size = 0; struct entry* entry = NULL; ldns_rdf *stop_command = ldns_dname_new_frm_str("server.stop."); status = ldns_wire2pkt(&query_pkt, inbuf, (size_t)inlen); if (status != LDNS_STATUS_OK) { verbose(1, "Got bad packet: %s\n", ldns_get_errorstr_by_id(status)); ldns_rdf_free(stop_command); return; } query_rr = ldns_rr_list_rr(ldns_pkt_question(query_pkt), 0); verbose(1, "query %d: id %d: %s %d bytes: ", ++(*count), (int)ldns_pkt_id(query_pkt), (transport==transport_tcp)?"TCP":"UDP", (int)inlen); if(verbose_out) ldns_rr_print(verbose_out, query_rr); if(verbose_out) ldns_pkt_print(verbose_out, query_pkt); if (ldns_rr_get_type(query_rr) == LDNS_RR_TYPE_TXT && ldns_rr_get_class(query_rr) == LDNS_RR_CLASS_CH && ldns_dname_compare(ldns_rr_owner(query_rr), stop_command) == 0) { exit(0); } /* fill up answer packet */ entry = find_match(entries, query_pkt, transport); if(!entry || !entry->reply_list) { verbose(1, "no answer packet for this query, no reply.\n"); ldns_pkt_free(query_pkt); ldns_rdf_free(stop_command); return; } for(p = entry->reply_list; p; p = p->next) { verbose(3, "Answer pkt:\n"); if (p->reply_from_hex) { /* try to parse the hex packet, if it can be * parsed, we can use adjust rules. if not, * send packet literally */ status = ldns_buffer2pkt_wire(&answer_pkt, p->reply_from_hex); if (status == LDNS_STATUS_OK) { adjust_packet(entry, answer_pkt, query_pkt); if(verbose_out) ldns_pkt_print(verbose_out, answer_pkt); status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size); verbose(2, "Answer packet size: %u bytes.\n", (unsigned int)answer_size); if (status != LDNS_STATUS_OK) { verbose(1, "Error creating answer: %s\n", ldns_get_errorstr_by_id(status)); ldns_pkt_free(query_pkt); ldns_rdf_free(stop_command); return; } ldns_pkt_free(answer_pkt); answer_pkt = NULL; } else { verbose(3, "Could not parse hex data (%s), sending hex data directly.\n", ldns_get_errorstr_by_id(status)); /* still try to adjust ID */ answer_size = ldns_buffer_capacity(p->reply_from_hex); outbuf = LDNS_XMALLOC(uint8_t, answer_size); memcpy(outbuf, ldns_buffer_export(p->reply_from_hex), answer_size); if(entry->copy_id) { ldns_write_uint16(outbuf, ldns_pkt_id(query_pkt)); } } } else { answer_pkt = ldns_pkt_clone(p->reply); adjust_packet(entry, answer_pkt, query_pkt); if(verbose_out) ldns_pkt_print(verbose_out, answer_pkt); status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size); verbose(1, "Answer packet size: %u bytes.\n", (unsigned int)answer_size); if (status != LDNS_STATUS_OK) { verbose(1, "Error creating answer: %s\n", ldns_get_errorstr_by_id(status)); ldns_pkt_free(query_pkt); ldns_rdf_free(stop_command); return; } ldns_pkt_free(answer_pkt); answer_pkt = NULL; } if(p->packet_sleep) { verbose(3, "sleeping for next packet %d secs\n", p->packet_sleep); #ifdef HAVE_SLEEP sleep(p->packet_sleep); #else Sleep(p->packet_sleep * 1000); #endif verbose(3, "wakeup for next packet " "(slept %d secs)\n", p->packet_sleep); } sendfunc(outbuf, answer_size, userdata); LDNS_FREE(outbuf); outbuf = NULL; answer_size = 0; } ldns_pkt_free(query_pkt); ldns_rdf_free(stop_command); }
int main(int argc, char **argv) { /* arguments */ int port; int soa; ldns_rdf *zone_name; size_t count; size_t maxcount; /* network */ int sock; ssize_t nb; struct sockaddr addr_me; struct sockaddr addr_him; socklen_t hislen = sizeof(addr_him); const char *my_address; uint8_t inbuf[INBUF_SIZE]; uint8_t *outbuf; /* dns */ ldns_status status; ldns_pkt *query_pkt; ldns_pkt *answer_pkt; size_t answer_size; ldns_rr *query_rr; ldns_rr *rr; char rr_string[MAX_LEN + 1]; ldns_rr *soa_rr; char soa_string[MAX_LEN + 1]; /* use this to listen on specified interfaces later? */ my_address = NULL; if(argc == 5) { /* -# num given */ if (argv[1][0] == '-') { maxcount = atoi(argv[1] + 1); if (maxcount == 0) { usage(stdout); exit(EXIT_FAILURE); } else { fprintf(stderr, "quiting after %d qs\n", (int)maxcount); } } else { fprintf(stderr, "Use -Number for max count\n"); exit(EXIT_FAILURE); } argc--; argv++; } else { maxcount = 0; } if (argc != 4) { usage(stdout); exit(EXIT_FAILURE); } else { port = atoi(argv[1]); if (port < 1) { fprintf(stderr, "Use a number for the port\n"); usage(stdout); exit(EXIT_FAILURE); } zone_name = ldns_dname_new_frm_str(argv[2]); if (!zone_name) { fprintf(stderr, "Illegal domain name: %s\n", argv[2]); usage(stdout); exit(EXIT_FAILURE); } soa = atoi(argv[3]); if (soa < 1) { fprintf(stderr, "Illegal soa number\n"); usage(stdout); exit(EXIT_FAILURE); } } printf("Listening on port %d\n", port); sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { fprintf(stderr, "%s: socket(): %s\n", argv[0], strerror(errno)); exit(EXIT_FAILURE); } memset(&addr_me, 0, sizeof(addr_me)); /* bind: try all ports in that range */ if (udp_bind(sock, port, my_address)) { fprintf(stderr, "%s: cannot bind(): %s\n", argv[0], strerror(errno)); } /* create our ixfr answer */ answer_pkt = ldns_pkt_new(); snprintf(rr_string, MAX_LEN, "%s IN IXFR", argv[2]); (void)ldns_rr_new_frm_str(&rr, rr_string , 0, NULL, NULL); (void)ldns_pkt_push_rr(answer_pkt, LDNS_SECTION_QUESTION, rr); /* next add some rrs, with SOA stuff so that we mimic or ixfr reply */ snprintf(soa_string, MAX_LEN, "%s IN SOA miek.miek.nl elektron.atoom.net %d 1 2 3000 4", argv[2], soa); (void)ldns_rr_new_frm_str(&soa_rr, soa_string, 0, NULL, NULL); snprintf(rr_string, MAX_LEN, "%s IN A 127.0.0.1", argv[2]); (void)ldns_rr_new_frm_str(&rr, rr_string , 0, NULL, NULL); /* compose the ixfr pkt */ (void)ldns_pkt_push_rr(answer_pkt, LDNS_SECTION_ANSWER, soa_rr); (void)ldns_pkt_push_rr(answer_pkt, LDNS_SECTION_ANSWER, rr); (void)ldns_pkt_push_rr(answer_pkt, LDNS_SECTION_ANSWER, soa_rr); /* Done. Now receive */ count = 0; while (1) { nb = recvfrom(sock, inbuf, INBUF_SIZE, 0, &addr_him, &hislen); if (nb < 1) { fprintf(stderr, "%s: recvfrom(): %s\n", argv[0], strerror(errno)); exit(EXIT_FAILURE); } printf("Got query of %d bytes\n", (int)nb); status = ldns_wire2pkt(&query_pkt, inbuf, nb); if (status != LDNS_STATUS_OK) { printf("Got bad packet: %s\n", ldns_get_errorstr_by_id(status)); continue; } query_rr = ldns_rr_list_rr(ldns_pkt_question(query_pkt), 0); printf("%d QUERY RR +%d: \n", (int)++count, ldns_pkt_id(query_pkt)); ldns_rr_print(stdout, query_rr); ldns_pkt_set_id(answer_pkt, ldns_pkt_id(query_pkt)); status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size); printf("Answer packet size: %u bytes.\n", (unsigned int) answer_size); if (status != LDNS_STATUS_OK) { printf("Error creating answer: %s\n", ldns_get_errorstr_by_id(status)); } else { nb = (size_t) sendto(sock, outbuf, answer_size, 0, &addr_him, hislen); } if (maxcount > 0 && count >= maxcount) { fprintf(stderr, "%d queries seen... goodbye\n", (int)count); exit(EXIT_SUCCESS); } } return 0; }