/* Basic response check (4 TAP tests). */ static void answer_sanity_check(const uint8_t *query, const uint8_t *answer, uint16_t answer_len, uint8_t expected_rcode, const char *name) { ok(answer_len >= KNOT_WIRE_HEADER_SIZE, "ns: len(%s answer) >= DNS header", name); if (answer_len >= KNOT_WIRE_HEADER_SIZE) { ok(knot_wire_get_qr(answer), "ns: %s answer has QR=1", name); is_int(expected_rcode, knot_wire_get_rcode(answer), "ns: %s answer RCODE=%d", name, expected_rcode); is_int(knot_wire_get_id(query), knot_wire_get_id(answer), "ns: %s MSGID match", name); } else { skip_block(3, "ns: can't check DNS header"); } }
int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len, uint16_t tsig_rcode, const knot_rrset_t *tsig_rr) { /*! \todo Revise!! */ if (!msg || !msg_len || !tsig_rr) { return KNOT_EINVAL; } /*! \todo What key to use, when we do not sign? Does this even work? */ knot_rrset_t *tmp_tsig = knot_rrset_new(tsig_rr->owner, KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, NULL); if (!tmp_tsig) { dbg_tsig("TSIG: tmp_tsig = NULL\n"); return KNOT_ENOMEM; } assert(tsig_rcode != KNOT_RCODE_BADTIME); tsig_create_rdata(tmp_tsig, tsig_rdata_alg_name(tsig_rr), 0, tsig_rcode); tsig_rdata_set_time_signed(tmp_tsig, tsig_rdata_time_signed(tsig_rr)); /* Comparing to BIND it was found out that the Fudge should always be * set to the server's value. */ tsig_rdata_set_fudge(tmp_tsig, KNOT_TSIG_FUDGE_DEFAULT); /* Set original ID */ tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg)); /* Set other len. */ tsig_rdata_set_other_data(tmp_tsig, 0, 0); /* Append TSIG RR. */ int ret = knot_tsig_append(msg, msg_len, msg_max_len, tsig_rr); /* key_name already referenced in RRSet, no need to free separately. */ knot_rrset_free(&tmp_tsig, NULL); return ret; }
int knot_tsig_sign(uint8_t *msg, size_t *msg_len, size_t msg_max_len, const uint8_t *request_mac, size_t request_mac_len, uint8_t *digest, size_t *digest_len, const knot_tsig_key_t *key, uint16_t tsig_rcode, uint64_t request_time_signed) { if (!msg || !msg_len || !key || digest == NULL || digest_len == NULL) { return KNOT_EINVAL; } knot_rrset_t *tmp_tsig = knot_rrset_new(key->name, KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, NULL); if (!tmp_tsig) { dbg_tsig("TSIG: tmp_tsig = NULL\n"); return KNOT_ENOMEM; } /* Create rdata for TSIG RR. */ uint16_t rdata_rcode = 0; if (tsig_rcode == KNOT_RCODE_BADTIME) rdata_rcode = tsig_rcode; tsig_create_rdata(tmp_tsig, tsig_alg_to_dname(key->algorithm), knot_tsig_digest_length(key->algorithm), rdata_rcode); /* Distinguish BADTIME response. */ if (tsig_rcode == KNOT_RCODE_BADTIME) { /* Set client's time signed into the time signed field. */ tsig_rdata_set_time_signed(tmp_tsig, request_time_signed); /* Store current time into Other data. */ uint8_t time_signed[6]; time_t curr_time = time(NULL); uint64_t time64 = curr_time; knot_wire_write_u48(time_signed, time64); tsig_rdata_set_other_data(tmp_tsig, 6, time_signed); } else { tsig_rdata_store_current_time(tmp_tsig); /* Set other len. */ tsig_rdata_set_other_data(tmp_tsig, 0, 0); } tsig_rdata_set_fudge(tmp_tsig, KNOT_TSIG_FUDGE_DEFAULT); /* Set original ID */ tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg)); uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE]; size_t digest_tmp_len = 0; int ret = KNOT_ERROR; ret = knot_tsig_create_sign_wire(msg, *msg_len, /*msg_max_len,*/ request_mac, request_mac_len, digest_tmp, &digest_tmp_len, tmp_tsig, key); if (ret != KNOT_EOK) { dbg_tsig("TSIG: could not create wire or sign wire: %s\n", knot_strerror(ret)); knot_rrset_free(&tmp_tsig, NULL); return ret; } /* Set the digest. */ size_t tsig_wire_len = 0; dbg_tsig("TSIG: msg_len=%zu, msg_max_len=%zu, tsig_max_len=%zu\n", *msg_len, msg_max_len, tsig_wire_len); uint16_t rr_count = 0; tsig_rdata_set_mac(tmp_tsig, digest_tmp_len, digest_tmp); /* Write RRSet to wire */ ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len, &tsig_wire_len, msg_max_len - *msg_len, &rr_count, NULL); if (ret != KNOT_EOK) { dbg_tsig("TSIG: rrset_to_wire = %s\n", knot_strerror(ret)); *digest_len = 0; knot_rrset_free(&tmp_tsig, NULL); return ret; } knot_rrset_free(&tmp_tsig, NULL); dbg_tsig("TSIG: written TSIG RR (wire len %zu)\n", tsig_wire_len); *msg_len += tsig_wire_len; uint16_t arcount = knot_wire_get_arcount(msg); knot_wire_set_arcount(msg, ++arcount); // everything went ok, save the digest to the output parameter memcpy(digest, digest_tmp, digest_tmp_len); *digest_len = digest_tmp_len; return KNOT_EOK; }
int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len, const uint8_t *prev_digest, size_t prev_digest_len, uint8_t *digest, size_t *digest_len, const knot_tsig_key_t *key, uint8_t *to_sign, size_t to_sign_len) { if (!msg || !msg_len || !key || !digest || !digest_len) { return KNOT_EINVAL; } uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE]; size_t digest_tmp_len = 0; knot_rrset_t *tmp_tsig = knot_rrset_new(key->name, KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, NULL); if (!tmp_tsig) { return KNOT_ENOMEM; } /* Create rdata for TSIG RR. */ tsig_create_rdata(tmp_tsig, tsig_alg_to_dname(key->algorithm), knot_tsig_digest_length(key->algorithm), 0); tsig_rdata_store_current_time(tmp_tsig); tsig_rdata_set_fudge(tmp_tsig, KNOT_TSIG_FUDGE_DEFAULT); /* Create wire to be signed. */ size_t wire_len = prev_digest_len + to_sign_len + KNOT_TSIG_TIMERS_LENGTH + 2; uint8_t *wire = malloc(wire_len); if (!wire) { ERR_ALLOC_FAILED; knot_rrset_free(&tmp_tsig, NULL); return KNOT_ENOMEM; } memset(wire, 0, wire_len); /* Write previous digest length. */ knot_wire_write_u16(wire, prev_digest_len); /* Write previous digest. */ memcpy(wire + 2, prev_digest, sizeof(uint8_t) * prev_digest_len); /* Write original message. */ memcpy(wire + prev_digest_len + 2, to_sign, to_sign_len); /* Write timers. */ knot_tsig_wire_write_timers(wire + prev_digest_len + to_sign_len + 2, tmp_tsig); dbg_tsig_detail("Previous digest: \n"); dbg_tsig_hex_detail((char *)prev_digest, prev_digest_len); dbg_tsig_detail("Timers: \n"); dbg_tsig_hex_detail((char *)(wire + prev_digest_len + *msg_len), KNOT_TSIG_TIMERS_LENGTH); int ret = KNOT_ERROR; ret = knot_tsig_compute_digest(wire, wire_len, digest_tmp, &digest_tmp_len, key); /* No matter how the function did, this data is no longer needed. */ free(wire); if (ret != KNOT_EOK) { knot_rrset_free(&tmp_tsig, NULL); *digest_len = 0; return ret; } if (digest_tmp_len > *digest_len) { knot_rrset_free(&tmp_tsig, NULL); *digest_len = 0; return KNOT_ESPACE; } /* Set the MAC. */ tsig_rdata_set_mac(tmp_tsig, digest_tmp_len, digest_tmp); /* Set original id. */ tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg)); /* Set other data. */ tsig_rdata_set_other_data(tmp_tsig, 0, NULL); dbg_tsig_verb("Message max length: %zu, message length: %zu\n", msg_max_len, *msg_len); size_t tsig_wire_size = 0; uint16_t rr_count = 0; ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len, &tsig_wire_size, msg_max_len - *msg_len, &rr_count, NULL); if (ret != KNOT_EOK) { knot_rrset_free(&tmp_tsig, NULL); *digest_len = 0; return ret; } /* This should not happen, at least one rr has to be converted. */ if (rr_count == 0) { knot_rrset_free(&tmp_tsig, NULL); return KNOT_EINVAL; } knot_rrset_free(&tmp_tsig, NULL); *msg_len += tsig_wire_size; uint16_t arcount = knot_wire_get_arcount(msg); knot_wire_set_arcount(msg, ++arcount); memcpy(digest, digest_tmp, digest_tmp_len); *digest_len = digest_tmp_len; return KNOT_EOK; }
static void print_header(const knot_pkt_t *packet, const style_t *style, const uint16_t ext_rcode) { char flags[64] = ""; uint8_t opcode_id; const char *rcode_str = "Unknown"; const char *opcode_str = "Unknown"; lookup_table_t *rcode, *opcode; // Get RCODE from Header and check for Extended RCODE from OPT RR. rcode = lookup_by_id(knot_rcode_names, ext_rcode); if (rcode != NULL) { rcode_str = rcode->name; } // Get OPCODE. opcode_id = knot_wire_get_opcode(packet->wire); opcode = lookup_by_id(knot_opcode_names, opcode_id); if (opcode != NULL) { opcode_str = opcode->name; } // Get flags. size_t flags_rest = sizeof(flags); const size_t flag_len = 4; if (knot_wire_get_qr(packet->wire) != 0 && flags_rest > flag_len) { flags_rest -= strlcat(flags, " qr", flags_rest); } if (knot_wire_get_aa(packet->wire) != 0 && flags_rest > flag_len) { flags_rest -= strlcat(flags, " aa", flags_rest); } if (knot_wire_get_tc(packet->wire) != 0 && flags_rest > flag_len) { flags_rest -= strlcat(flags, " tc", flags_rest); } if (knot_wire_get_rd(packet->wire) != 0 && flags_rest > flag_len) { flags_rest -= strlcat(flags, " rd", flags_rest); } if (knot_wire_get_ra(packet->wire) != 0 && flags_rest > flag_len) { flags_rest -= strlcat(flags, " ra", flags_rest); } if (knot_wire_get_z(packet->wire) != 0 && flags_rest > flag_len) { flags_rest -= strlcat(flags, " z", flags_rest); } if (knot_wire_get_ad(packet->wire) != 0 && flags_rest > flag_len) { flags_rest -= strlcat(flags, " ad", flags_rest); } if (knot_wire_get_cd(packet->wire) != 0 && flags_rest > flag_len) { strlcat(flags, " cd", flags_rest); } uint16_t id = knot_wire_get_id(packet->wire); uint16_t qdcount = knot_wire_get_qdcount(packet->wire); uint16_t ancount = knot_wire_get_ancount(packet->wire); uint16_t nscount = knot_wire_get_nscount(packet->wire); uint16_t arcount = knot_wire_get_arcount(packet->wire); if (knot_pkt_has_tsig(packet)) { arcount++; } // Print formatted info. switch (style->format) { case FORMAT_NSUPDATE: printf(";; ->>HEADER<<- opcode: %s; status: %s; id: %u\n" ";; Flags:%1s; " "ZONE: %u; PREREQ: %u; UPDATE: %u; ADDITIONAL: %u\n", opcode_str, rcode_str, id, flags, qdcount, ancount, nscount, arcount); break; default: printf(";; ->>HEADER<<- opcode: %s; status: %s; id: %u\n" ";; Flags:%1s; " "QUERY: %u; ANSWER: %u; AUTHORITY: %u; ADDITIONAL: %u\n", opcode_str, rcode_str, id, flags, qdcount, ancount, nscount, arcount); break; } }