--- /dev/null
+#include "includes.h"
+#include <talloc.h>
+#include <tevent.h>
+#include "lib/util/samba_util.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/ndr_dns.h"
+#include "libcli/dns/libdns.h"
+#include "lib/crypto/hmacmd5.h"
+#include "system/network.h"
+#include "dns_server/dns_server.h"
+
+static void usage(void)
+{
+ printf("Usage: dns-tsig <dns-server-ip>\n\n");
+}
+
+static WERROR dns_copy_tsig(TALLOC_CTX *mem_ctx,
+ struct dns_res_rec *old,
+ struct dns_res_rec *new_rec)
+{
+ new_rec->name = talloc_strdup(mem_ctx, old->name);
+ W_ERROR_HAVE_NO_MEMORY(new_rec->name);
+
+ new_rec->rr_type = old->rr_type;
+ new_rec->rr_class = old->rr_class;
+ new_rec->ttl = old->ttl;
+ new_rec->length = old->length;
+ new_rec->rdata.tsig_record.algorithm_name = talloc_strdup(mem_ctx,
+ old->rdata.tsig_record.algorithm_name);
+ W_ERROR_HAVE_NO_MEMORY(new_rec->rdata.tsig_record.algorithm_name);
+
+ new_rec->rdata.tsig_record.time_high = old->rdata.tsig_record.time_high;
+ new_rec->rdata.tsig_record.time_low = old->rdata.tsig_record.time_low;
+ new_rec->rdata.tsig_record.fudge = old->rdata.tsig_record.fudge;
+ new_rec->rdata.tsig_record.mac_size = old->rdata.tsig_record.mac_size;
+ new_rec->rdata.tsig_record.mac = talloc_memdup(mem_ctx,
+ old->rdata.tsig_record.mac,
+ old->rdata.tsig_record.mac_size);
+ W_ERROR_HAVE_NO_MEMORY(new_rec->rdata.tsig_record.mac);
+
+ new_rec->rdata.tsig_record.original_id = old->rdata.tsig_record.original_id;
+ new_rec->rdata.tsig_record.error = old->rdata.tsig_record.error;
+ new_rec->rdata.tsig_record.other_size = old->rdata.tsig_record.other_size;
+ new_rec->rdata.tsig_record.other_data = talloc_memdup(mem_ctx,
+ old->rdata.tsig_record.other_data,
+ old->rdata.tsig_record.other_size);
+ W_ERROR_HAVE_NO_MEMORY(new_rec->rdata.tsig_record.other_data);
+
+ return WERR_OK;
+}
+
+
+static struct dns_name_packet *make_name_packet(TALLOC_CTX *mem_ctx)
+{
+ struct dns_name_packet *packet = talloc_zero(mem_ctx,
+ struct dns_name_packet);
+ struct dns_name_question *q = talloc_zero(packet, struct dns_name_question);
+
+ packet->id = 0x165a;
+ packet->operation |= DNS_FLAG_RECURSION_DESIRED;
+
+ q->name = talloc_strdup(q, "gonzo.ad.home.kblin.org");
+ q->question_type = DNS_QTYPE_A;
+ q->question_class = DNS_QCLASS_IN;
+
+ packet->qdcount = 1;
+ packet->questions = q;
+
+ packet->nscount = 0;
+ packet->nsrecs = NULL;
+
+ packet->arcount = 0;
+ packet->additional = NULL;
+
+ return packet;
+}
+
+static WERROR dns_generate_tsig_mac(TALLOC_CTX *mem_ctx,
+ const struct dns_server_key *key,
+ const struct dns_name_packet *packet,
+ const struct dns_res_rec *tsig,
+ uint8_t **mac,
+ uint16_t *mac_length)
+{
+ HMACMD5Context *ctx;
+ uint16_t digest_length = 16;
+ uint8_t *digest;
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+ uint16_t dummy16;
+ uint32_t dummy32;
+
+ if (key == NULL) {
+ DEBUG(1, ("No key found, bailing out\n"));
+ *mac = NULL;
+ *mac_length = 0;
+ return WERR_OK;
+ }
+
+ ndr_err = ndr_push_struct_blob(&blob, mem_ctx, packet,
+ (ndr_push_flags_fn_t)ndr_push_dns_name_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return DNS_ERR(FORMAT_ERROR);
+ }
+
+ ctx = talloc_zero(mem_ctx, HMACMD5Context);
+ W_ERROR_HAVE_NO_MEMORY(ctx);
+
+ /* Build up the MAC as per RFC2845 */
+ hmac_md5_init_rfc2104(key->data, key->length, ctx);
+
+ dump_data(1, blob.data, blob.length);
+
+ /* 3.4.1 dns message */
+ hmac_md5_update(blob.data, blob.length, ctx);
+
+ /* 3.4.2 tsig variables */
+ dump_data(1, tsig->name, strlen(tsig->name)+1);
+ hmac_md5_update((const uint8_t *)tsig->name, strlen(tsig->name)+1, ctx);
+
+ dummy16 = htons(tsig->rr_class);
+ hmac_md5_update((const uint8_t *)&dummy16, 2, ctx);
+
+ dummy32 = htonl(tsig->ttl);
+ hmac_md5_update((const uint8_t *)&dummy32, 4, ctx);
+
+ dump_data(1, tsig->rdata.tsig_record.algorithm_name,
+ strlen(tsig->rdata.tsig_record.algorithm_name)+1);
+ hmac_md5_update((const uint8_t *)tsig->rdata.tsig_record.algorithm_name,
+ strlen(tsig->rdata.tsig_record.algorithm_name)+1, ctx);
+
+ dummy16 = htons(tsig->rdata.tsig_record.time_low);
+ hmac_md5_update((const uint8_t *)&dummy16, 2, ctx);
+
+ dummy32 = htonl(tsig->rdata.tsig_record.time_high);
+ hmac_md5_update((const uint8_t *)&dummy32, 4, ctx);
+
+ dummy16 = htons(tsig->rdata.tsig_record.fudge);
+ hmac_md5_update((const uint8_t *)&dummy16, 2, ctx);
+
+ dummy16 = htons(tsig->rdata.tsig_record.error);
+ hmac_md5_update((const uint8_t *)&dummy16, 2, ctx);
+
+ dummy16 = htons(tsig->rdata.tsig_record.other_size);
+ hmac_md5_update((const uint8_t *)&dummy16, 2, ctx);
+
+ hmac_md5_update((const uint8_t*)&tsig->rdata.tsig_record.other_data,
+ tsig->rdata.tsig_record.other_size, ctx);
+
+ digest = talloc_array(mem_ctx, uint8_t, digest_length);
+ W_ERROR_HAVE_NO_MEMORY(digest);
+ hmac_md5_final(digest, ctx);
+
+ *mac = digest;
+ *mac_length = digest_length;
+
+ return WERR_OK;
+}
+
+static WERROR sign_tsig(TALLOC_CTX *mem_ctx,
+ struct dns_server_key *key,
+ struct dns_name_packet *packet)
+{
+ WERROR werror;
+ time_t current_time = time(NULL);
+ uint8_t *mac, *fake_mac;
+ uint16_t mac_length = 0;
+ struct dns_res_rec *tsig = talloc_zero(packet, struct dns_res_rec);
+ W_ERROR_HAVE_NO_MEMORY(tsig);
+
+ tsig->name = talloc_strdup(tsig, "\x4test");
+ W_ERROR_HAVE_NO_MEMORY(tsig->name);
+
+ tsig->rr_class = DNS_QCLASS_ANY;
+ tsig->rr_type = DNS_QTYPE_TSIG;
+ tsig->ttl = 0;
+ tsig->length = UINT16_MAX;
+ tsig->rdata.tsig_record.algorithm_name = talloc_strdup(tsig,
+ "\x8hmac-md5\x7sig-alg\x3reg\x3int");
+ tsig->rdata.tsig_record.time_high = 0x4f74;
+ tsig->rdata.tsig_record.time_low = 0x048e;
+ tsig->rdata.tsig_record.fudge = 300;
+ tsig->rdata.tsig_record.original_id = 0x165a;
+ tsig->rdata.tsig_record.error = 0;
+ tsig->rdata.tsig_record.other_size = 0;
+ tsig->rdata.tsig_record.other_data = NULL;
+
+ werror = dns_generate_tsig_mac(mem_ctx, key, packet, tsig,
+ &mac, &mac_length);
+
+ /* And here's the part where we fake stuff */
+ fake_mac = talloc_zero_size(tsig, 16);
+ fake_mac[0] = 0xe2;
+ fake_mac[1] = 0x31;
+ fake_mac[2] = 0x2d;
+ fake_mac[3] = 0xc3;
+ fake_mac[4] = 0x80;
+ fake_mac[5] = 0x71;
+ fake_mac[6] = 0x2f;
+ fake_mac[7] = 0x35;
+ fake_mac[8] = 0x20;
+ fake_mac[9] = 0x5c;
+ fake_mac[10] = 0xe2;
+ fake_mac[11] = 0xed;
+ fake_mac[12] = 0x01;
+ fake_mac[13] = 0x62;
+ fake_mac[14] = 0xc2;
+ fake_mac[15] = 0x47;
+ tsig->rdata.tsig_record.mac_size = 16;
+ tsig->rdata.tsig_record.mac = fake_mac;
+
+ dump_data(1, mac, mac_length);
+ dump_data(1, fake_mac, 16);
+
+ if (packet->arcount == 0) {
+ packet->additional = talloc_zero(packet, struct dns_res_rec);
+ W_ERROR_HAVE_NO_MEMORY(packet->additional);
+ }
+ packet->additional = talloc_realloc(packet, packet->additional,
+ struct dns_res_rec,
+ packet->arcount + 1);
+ W_ERROR_HAVE_NO_MEMORY(packet->additional);
+
+ werror = dns_copy_tsig(packet, tsig,
+ &packet->additional[packet->arcount]);
+ W_ERROR_NOT_OK_RETURN(werror);
+
+ packet->arcount++;
+
+ return WERR_OK;
+}
+
+int main(int argc, char **argv)
+{
+ TALLOC_CTX *mem_ctx = talloc_init("samba-dig");
+ struct tevent_context *ev;
+ struct dns_name_packet *dns_packet, *in_packet;
+ struct dns_server_key *key;
+ enum dns_qtype type;
+ enum ndr_err_code ndr_err;
+ struct tevent_req *req;
+ WERROR w_err;
+ DATA_BLOB out, in;
+ int ret = 0;
+
+#if 0
+ if (argc < 2) {
+ usage();
+ exit(1);
+ }
+#endif
+
+ ev = tevent_context_init(mem_ctx);
+ setup_logging("samba-dig", DEBUG_STDERR);
+ debug_parse_levels("1");
+
+ dns_packet = make_name_packet(mem_ctx);
+
+ key = talloc_zero(mem_ctx, struct dns_server_key);
+ key->name = talloc_strdup(key, "test");
+
+ /* FIXME: 12??? */
+ key->length = 12;
+ key->data = talloc_zero_size(key, key->length);
+
+ sign_tsig(mem_ctx, key, dns_packet);
+
+#if 0
+ NDR_PRINT_DEBUG(dns_name_packet, dns_packet);
+ ndr_err = ndr_push_struct_blob(&out, mem_ctx, dns_packet,
+ (ndr_push_flags_fn_t)ndr_push_dns_name_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("Failed to marshall dns_name_packet: %d\n", ndr_err));
+ ret = 1;
+ goto error;
+ }
+
+ dump_data(1, out.data, out.length);
+#endif
+
+error:
+ return ret;
+}