uint8_t * ldns_tcp_read_wire_timeout(int sockfd, size_t *size, struct timeval timeout) { uint8_t *wire; uint16_t wire_size; ssize_t bytes = 0, rc = 0; wire = LDNS_XMALLOC(uint8_t, 2); if (!wire) { *size = 0; return NULL; } while (bytes < 2) { if(!ldns_sock_wait(sockfd, timeout, 0)) { *size = 0; LDNS_FREE(wire); return NULL; } rc = recv(sockfd, (void*) (wire + bytes), (size_t) (2 - bytes), 0); if (rc == -1 || rc == 0) { *size = 0; LDNS_FREE(wire); return NULL; } bytes += rc; } wire_size = ldns_read_uint16(wire); LDNS_FREE(wire); wire = LDNS_XMALLOC(uint8_t, wire_size); if (!wire) { *size = 0; return NULL; } bytes = 0; while (bytes < (ssize_t) wire_size) { if(!ldns_sock_wait(sockfd, timeout, 0)) { *size = 0; LDNS_FREE(wire); return NULL; } rc = recv(sockfd, (void*) (wire + bytes), (size_t) (wire_size - bytes), 0); if (rc == -1 || rc == 0) { LDNS_FREE(wire); *size = 0; return NULL; } bytes += rc; } *size = (size_t) bytes; return wire; }
ldns_status ldns_pkt2wire(uint8_t **dest, const ldns_pkt *packet, size_t *result_size) { ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); uint8_t *result = NULL; ldns_status status; *result_size = 0; *dest = NULL; status = ldns_pkt2buffer_wire(buffer, packet); if (status == LDNS_STATUS_OK) { *result_size = ldns_buffer_position(buffer); result = (uint8_t *) ldns_buffer_export(buffer); } else { return status; } if (result) { *dest = LDNS_XMALLOC(uint8_t, ldns_buffer_position(buffer)); memcpy(*dest, result, ldns_buffer_position(buffer)); } ldns_buffer_free(buffer); return status; }
ldns_status ldns_rr2wire(uint8_t **dest, const ldns_rr *rr, int section, size_t *result_size) { ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); uint8_t *result = NULL; ldns_status status; *result_size = 0; *dest = NULL; if(!buffer) return LDNS_STATUS_MEM_ERR; status = ldns_rr2buffer_wire(buffer, rr, section); if (status == LDNS_STATUS_OK) { *result_size = ldns_buffer_position(buffer); result = (uint8_t *) ldns_buffer_export(buffer); } else { ldns_buffer_free(buffer); return status; } if (result) { *dest = LDNS_XMALLOC(uint8_t, ldns_buffer_position(buffer)); if(!*dest) { ldns_buffer_free(buffer); return LDNS_STATUS_MEM_ERR; } memcpy(*dest, result, ldns_buffer_position(buffer)); } ldns_buffer_free(buffer); return status; }
uint8_t * ldns_udp_read_wire(int sockfd, size_t *size, struct sockaddr_storage *from, socklen_t *fromlen) { uint8_t *wire, *wireout; ssize_t wire_size; wire = LDNS_XMALLOC(uint8_t, LDNS_MAX_PACKETLEN); if (!wire) { *size = 0; return NULL; } wire_size = recvfrom(sockfd, (void*)wire, LDNS_MAX_PACKETLEN, 0, (struct sockaddr *)from, fromlen); /* recvfrom can also return 0 */ if (wire_size == -1 || wire_size == 0) { *size = 0; LDNS_FREE(wire); return NULL; } *size = (size_t)wire_size; wireout = LDNS_XREALLOC(wire, uint8_t, (size_t)wire_size); if(!wireout) LDNS_FREE(wire); return wireout; }
/** * Sign data with DSA * * \param[in] to_sign The ldns_buffer containing raw data that is * to be signed * \param[in] key The DSA key structure to sign with * \return ldns_rdf for the RRSIG ldns_rr */ ldns_rdf * ldns_sign_public_dsa(ldns_buffer *to_sign, DSA *key) { unsigned char *sha1_hash; ldns_rdf *sigdata_rdf; ldns_buffer *b64sig; DSA_SIG *sig; uint8_t *data; size_t pad; b64sig = ldns_buffer_new(LDNS_MAX_PACKETLEN); if (!b64sig) { return NULL; } sha1_hash = SHA1((unsigned char*)ldns_buffer_begin(to_sign), ldns_buffer_position(to_sign), NULL); if (!sha1_hash) { ldns_buffer_free(b64sig); return NULL; } sig = DSA_do_sign(sha1_hash, SHA_DIGEST_LENGTH, key); if(!sig) { ldns_buffer_free(b64sig); return NULL; } data = LDNS_XMALLOC(uint8_t, 1 + 2 * SHA_DIGEST_LENGTH); if(!data) { ldns_buffer_free(b64sig); DSA_SIG_free(sig); return NULL; } data[0] = 1; pad = 20 - (size_t) BN_num_bytes(sig->r); if (pad > 0) { memset(data + 1, 0, pad); } BN_bn2bin(sig->r, (unsigned char *) (data + 1) + pad); pad = 20 - (size_t) BN_num_bytes(sig->s); if (pad > 0) { memset(data + 1 + SHA_DIGEST_LENGTH, 0, pad); } BN_bn2bin(sig->s, (unsigned char *) (data + 1 + SHA_DIGEST_LENGTH + pad)); sigdata_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, 1 + 2 * SHA_DIGEST_LENGTH, data); ldns_buffer_free(b64sig); LDNS_FREE(data); DSA_SIG_free(sig); return sigdata_rdf; }
void ldns_buffer_new_frm_data(ldns_buffer *buffer, void *data, size_t size) { assert(data != NULL); buffer->_position = 0; buffer->_limit = buffer->_capacity = size; buffer->_fixed = 0; buffer->_data = LDNS_XMALLOC(uint8_t, size); if(!buffer->_data) { buffer->_status = LDNS_STATUS_MEM_ERR; return; } memcpy(buffer->_data, data, size); buffer->_status = LDNS_STATUS_OK; ldns_buffer_invariant(buffer); }
ssize_t ldns_tcp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to, socklen_t tolen) { uint8_t *sendbuf; ssize_t bytes; /* add length of packet */ sendbuf = LDNS_XMALLOC(uint8_t, ldns_buffer_position(qbin) + 2); if(!sendbuf) return 0; ldns_write_uint16(sendbuf, ldns_buffer_position(qbin)); memcpy(sendbuf + 2, ldns_buffer_begin(qbin), ldns_buffer_position(qbin)); bytes = sendto(sockfd, (void*)sendbuf, ldns_buffer_position(qbin) + 2, 0, (struct sockaddr *)to, tolen); LDNS_FREE(sendbuf); if (bytes == -1 || (size_t) bytes != ldns_buffer_position(qbin) + 2 ) { return 0; } return bytes; }
ldns_buffer * ldns_buffer_new(size_t capacity) { ldns_buffer *buffer = LDNS_MALLOC(ldns_buffer); if (!buffer) { return NULL; } buffer->_data = (uint8_t *) LDNS_XMALLOC(uint8_t, capacity); if (!buffer->_data) { LDNS_FREE(buffer); return NULL; } buffer->_position = 0; buffer->_limit = buffer->_capacity = capacity; buffer->_fixed = 0; buffer->_status = LDNS_STATUS_OK; ldns_buffer_invariant(buffer); return buffer; }
/* * Makes an exact copy of the wire, but with the tsig rr removed */ static uint8_t * ldns_tsig_prepare_pkt_wire(uint8_t *wire, size_t wire_len, size_t *result_len) { uint8_t *wire2 = NULL; uint16_t qd_count; uint16_t an_count; uint16_t ns_count; uint16_t ar_count; ldns_rr *rr; size_t pos; uint16_t i; ldns_status status; if(wire_len < LDNS_HEADER_SIZE) { return NULL; } /* fake parse the wire */ qd_count = LDNS_QDCOUNT(wire); an_count = LDNS_ANCOUNT(wire); ns_count = LDNS_NSCOUNT(wire); ar_count = LDNS_ARCOUNT(wire); if (ar_count > 0) { ar_count--; } else { return NULL; } pos = LDNS_HEADER_SIZE; for (i = 0; i < qd_count; i++) { status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_QUESTION); if (status != LDNS_STATUS_OK) { return NULL; } ldns_rr_free(rr); } for (i = 0; i < an_count; i++) { status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_ANSWER); if (status != LDNS_STATUS_OK) { return NULL; } ldns_rr_free(rr); } for (i = 0; i < ns_count; i++) { status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_AUTHORITY); if (status != LDNS_STATUS_OK) { return NULL; } ldns_rr_free(rr); } for (i = 0; i < ar_count; i++) { status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_ADDITIONAL); if (status != LDNS_STATUS_OK) { return NULL; } ldns_rr_free(rr); } *result_len = pos; wire2 = LDNS_XMALLOC(uint8_t, *result_len); if(!wire2) { return NULL; } memcpy(wire2, wire, *result_len); ldns_write_uint16(wire2 + LDNS_ARCOUNT_OFF, ar_count); return wire2; }
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[]) { ldns_rdf *dname, *hashed_dname; uint8_t nsec3_algorithm = 1; size_t nsec3_iterations_cmd = 1; uint16_t nsec3_iterations = 1; uint8_t nsec3_salt_length = 0; uint8_t *nsec3_salt = NULL; char *prog = strdup(argv[0]); int c; while ((c = getopt(argc, argv, "a:s:t:")) != -1) { switch (c) { case 'a': nsec3_algorithm = (uint8_t) atoi(optarg); break; case 's': if (strlen(optarg) % 2 != 0) { fprintf(stderr, "Salt value is not valid hex data, not a multiple of 2 characters\n"); exit(EXIT_FAILURE); } if (strlen(optarg) > 512) { fprintf(stderr, "Salt too long\n"); exit(EXIT_FAILURE); } nsec3_salt_length = (uint8_t) (strlen(optarg) / 2); nsec3_salt = LDNS_XMALLOC(uint8_t, nsec3_salt_length); for (c = 0; c < (int) strlen(optarg); c += 2) { if (isxdigit((int) optarg[c]) && isxdigit((int) optarg[c+1])) { nsec3_salt[c/2] = (uint8_t) ldns_hexdigit_to_int(optarg[c]) * 16 + ldns_hexdigit_to_int(optarg[c+1]); } else { fprintf(stderr, "Salt value is not valid hex data.\n"); exit(EXIT_FAILURE); } } break; case 't': nsec3_iterations_cmd = (size_t) atol(optarg); if (nsec3_iterations_cmd > LDNS_NSEC3_MAX_ITERATIONS) { fprintf(stderr, "Iterations count can not exceed %u, quitting\n", LDNS_NSEC3_MAX_ITERATIONS); exit(EXIT_FAILURE); } nsec3_iterations = (uint16_t) nsec3_iterations_cmd; break; default: usage(stderr, prog); exit(EXIT_SUCCESS); } } argc -= optind; argv += optind; if (argc < 1) { printf("Error: not enough arguments\n"); usage(stdout, prog); exit(EXIT_FAILURE); } else { dname = ldns_dname_new_frm_str(argv[0]); if (!dname) { fprintf(stderr, "Error: unable to parse domain name\n"); return EXIT_FAILURE; } hashed_dname = ldns_nsec3_hash_name(dname, nsec3_algorithm, nsec3_iterations, nsec3_salt_length, nsec3_salt); if (!hashed_dname) { fprintf(stderr, "Error creating NSEC3 hash\n"); return EXIT_FAILURE; } ldns_rdf_print(stdout, hashed_dname); printf("\n"); ldns_rdf_deep_free(dname); ldns_rdf_deep_free(hashed_dname); } if (nsec3_salt) { free(nsec3_salt); } free(prog); return EXIT_SUCCESS; }
/* * 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); }
/** convert hex buffer to binary buffer */ static ldns_buffer * data_buffer2wire(ldns_buffer *data_buffer) { ldns_buffer *wire_buffer = NULL; int c; /* stat hack * 0 = normal * 1 = comment (skip to end of line) * 2 = unprintable character found, read binary data directly */ size_t data_buf_pos = 0; int state = 0; uint8_t *hexbuf; int hexbufpos = 0; size_t wirelen; uint8_t *data_wire = (uint8_t *) ldns_buffer_export(data_buffer); uint8_t *wire = LDNS_XMALLOC(uint8_t, LDNS_MAX_PACKETLEN); hexbuf = LDNS_XMALLOC(uint8_t, LDNS_MAX_PACKETLEN); for (data_buf_pos = 0; data_buf_pos < ldns_buffer_position(data_buffer); data_buf_pos++) { c = (int) data_wire[data_buf_pos]; if (state < 2 && !isascii(c)) { /*verbose("non ascii character found in file: (%d) switching to raw mode\n", c);*/ state = 2; } switch (state) { case 0: if ( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) { hexbuf[hexbufpos] = (uint8_t) c; hexbufpos++; } else if (c == ';') { state = 1; } else if (c == ' ' || c == '\t' || c == '\n') { /* skip whitespace */ } break; case 1: if (c == '\n' || c == EOF) { state = 0; } break; case 2: hexbuf[hexbufpos] = (uint8_t) c; hexbufpos++; break; default: error("unknown state while reading"); LDNS_FREE(hexbuf); return 0; break; } } if (hexbufpos >= LDNS_MAX_PACKETLEN) { /*verbose("packet size reached\n");*/ } /* lenient mode: length must be multiple of 2 */ if (hexbufpos % 2 != 0) { hexbuf[hexbufpos] = (uint8_t) '0'; hexbufpos++; } if (state < 2) { wirelen = hexstr2bin((char *) hexbuf, hexbufpos, wire, 0, LDNS_MAX_PACKETLEN); wire_buffer = ldns_buffer_new(wirelen); ldns_buffer_new_frm_data(wire_buffer, wire, wirelen); } else { error("Incomplete hex data, not at byte boundary\n"); } LDNS_FREE(wire); LDNS_FREE(hexbuf); return wire_buffer; }