[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Unblock request for ldns 1.6.6-1, dnsruby 1.49-1 and opendnssec 1.1.2-1



On Sun, Aug 29, 2010 at 18:53, Julien Cristau <jcristau@debian.org> wrote:
> On Wed, Aug 25, 2010 at 14:31:52 +0200, Ondřej Surý wrote:
>
>> No Debian packaging changes. Please Cc: me if you have any questions.
>>
>> opendnssec 1.1.2 is just a bug fix release, upstream changelog:
>>
>>         * ods-control stop did not stopped zone fetcher (bug was
>> introduced in 1.1.0)
>>         * Auditor correctly handles chains of empty nonterminals
>>         * Zone fetcher can block zone transfers if AXFR once failed.
>> This is a bug in ldns versions 1.6.5 and lower. See KNOWN_ISSUES for
>> more information.
>>         * Bugreport #165: Ensure Output SOA serial is always bigger
>> than Input SOA serial.
>>         * Bugreport #166: Correct exit value from signer.
>>         * Bugreport #167: Zone fetcher now also picks up changes when
>> zonelist is reloaded
>>         * Bugreport #168: ods-control with tightened control for the Enforcer
>>         * Bugreport #169: Do not include config.h in the distribution
>>         * Bugreport #170: Typo in a man page (ods-signer)
>>         * Bugreport #172: Correction of some macros in a man page (ods-timing)
>>         * Bugreport #173: A man page used a macro that does not exist
>> (ods-ksmutil)
>>
>> Please note that I will upload 1.1.2-1 after dnsruby 1.49-1 is
>> uploaded to main archive.
>>
> Hrm.  1.1.1-2 was unblocked, but you didn't give it enough time to make
> it into testing...

Yes, but it was blocked by sqlite3 anyway.

I have attached cleaned-up diff of opendnssec.

>> And it needs ldns 1.6.6 and dnsruby 1.49 for some bugfixes
>> Both are also just a bugfix releases, changelogs:
>>
>> ldns 1.6.6
>> http://www.nlnetlabs.nl/svn/ldns/tags/release-1.6.6/Changelog
>>
>>       * Fix ldns_rr_clone to copy question rrs properly.
>>       * Fix ldns_sign_zone(_nsec3) to clone the soa for the new zone.
>>       * Fix ldns_wire2dname size check from reading 1 byte beyond buffer end.
>>       * Fix ldns_wire2dname from reading 1 byte beyond end for pointer.
>>       * Fix crash using GOST for particular platform configurations.
>>       * extern C declarations used in the header file.
>>       * Removed debug fprintf from resolver.c.
>>       * ldns-signzone checks if public key file is for the right zone.
>>       * NETLDNS, .NET port of ldns functionality, by Alex Nicoll, in contrib.
>>       * Fix handling of comments in resolv.conf parse.
>>       * GOST code enabled if SSL recent, RFC 5933.
>>       * bugfix #317: segfault util.c ldns_init_random() fixed.
>>       * Fix ldns_tsig_mac_new: allocate enough memory for the hash, fix use of
>>         b64_pton_calculate_size.
>>       * Fix ldns_dname_cat: size calculation and handling of realloc().
>>       * Fix ldns_rr_pop_rdf: fix handling of realloc().
>>       * Fix ldns-signzone for single type key scheme: sign whole zone if there
>>         are only KSKs.
>>       * Fix ldns_resolver: also close socket if AXFR failed (if you don't,
>>           it would block subsequent transfers (thanks Roland van Rijswijk).
>>         * Fix drill: allow for a secure trace if you use DS records as trust
>>         anchors (thanks Jan Komissar).
>>
>  107 files changed, 10620 insertions(+), 19520 deletions(-)
>
> Most of it seems to be autotools noise, but still... Care to provide a
> stripped down diff?

Attached. I have also removed the 'extern "C"' changes, readmes, etc.

>> dnsruby 1.49
>> http://rubyforge.org/frs/shownotes.php?group_id=2387&release_id=44440\
>>
>>         * Socket memory leak plugged in select_thread.
>>         * Fix OSX errors for TCP.
>>         * Fix ZoneReader truncation for heavily escaped TXT records.
>>
> Will look at this one later.

Diff attached as well.

Ondrej
-- 
Ondřej Surý <ondrej@sury.org>
diff -urNapwB ldns-1.6.5/dname.c ldns-1.6.6/dname.c
--- ldns-1.6.5/dname.c	2010-06-03 14:44:09.000000000 +0200
+++ ldns-1.6.6/dname.c	2010-07-27 14:08:02.000000000 +0200
@@ -73,6 +73,7 @@ ldns_dname_cat(ldns_rdf *rd1, ldns_rdf *
 {
 	uint16_t left_size;
 	uint16_t size;
+	uint8_t* newd;
 
 	if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
 			ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
@@ -86,10 +87,17 @@ ldns_dname_cat(ldns_rdf *rd1, ldns_rdf *
 	if (left_size > 0 &&ldns_rdf_data(rd1)[left_size - 1] == 0) {
 		left_size--;
 	}
+        if(left_size == 0) {
+                return LDNS_STATUS_OK;
+        }
 
 	size = left_size + ldns_rdf_size(rd2);
+	newd = LDNS_XREALLOC(ldns_rdf_data(rd1), uint8_t, size);
+	if(!newd) {
+		return LDNS_STATUS_MEM_ERR;
+	}
 
-	ldns_rdf_set_data(rd1, LDNS_XREALLOC(ldns_rdf_data(rd1), uint8_t, size));
+	ldns_rdf_set_data(rd1, newd);
 	memcpy(ldns_rdf_data(rd1) + left_size, ldns_rdf_data(rd2),
 			ldns_rdf_size(rd2));
 	ldns_rdf_set_size(rd1, size);
diff -urNapwB ldns-1.6.5/dnssec_sign.c ldns-1.6.6/dnssec_sign.c
--- ldns-1.6.5/dnssec_sign.c	2010-05-18 17:01:39.000000000 +0200
+++ ldns-1.6.6/dnssec_sign.c	2010-08-03 15:20:24.000000000 +0200
@@ -230,12 +230,7 @@ ldns_sign_public(ldns_rr_list *rrset, ld
 		current_key = ldns_key_list_key(keys, key_count);
 		/* sign all RRs with keys that have ZSKbit, !SEPbit.
 		   sign DNSKEY RRs with keys that have ZSKbit&SEPbit */
-		if (
-		    ldns_key_flags(current_key) & LDNS_KEY_ZONE_KEY &&
-		    (!(ldns_key_flags(current_key) & LDNS_KEY_SEP_KEY)
-			|| ldns_rr_get_type(ldns_rr_list_rr(rrset, 0))
-		        == LDNS_RR_TYPE_DNSKEY)
-		    ) {
+		if (ldns_key_flags(current_key) & LDNS_KEY_ZONE_KEY) {
 			current_sig = ldns_create_empty_rrsig(rrset_clone,
 			                                      current_key);
 
@@ -813,6 +808,25 @@ ldns_key_list_filter_for_dnskey(ldns_key
 			ldns_key_set_use(ldns_key_list_key(key_list, i), 0);
 }
 
+/** If there are no ZSKs use KSK as ZSK */
+static void
+ldns_key_list_filter_for_non_dnskey(ldns_key_list *key_list)
+{
+	int saw_zsk = 0;
+	size_t i;
+	for(i=0; i<ldns_key_list_key_count(key_list); i++)
+		if(!(ldns_key_flags(ldns_key_list_key(key_list, i))&LDNS_KEY_SEP_KEY)) {
+			saw_zsk = 1;
+			break;
+		}
+	if(!saw_zsk)
+		return;
+	/* else filter all KSKs */
+	for(i=0; i<ldns_key_list_key_count(key_list); i++)
+		if((ldns_key_flags(ldns_key_list_key(key_list, i))&LDNS_KEY_SEP_KEY))
+			ldns_key_set_use(ldns_key_list_key(key_list, i), 0);
+}
+
 ldns_status
 ldns_dnssec_zone_create_rrsigs_flg(ldns_dnssec_zone *zone,
                                ldns_rr_list *new_rrs,
@@ -865,6 +879,9 @@ ldns_dnssec_zone_create_rrsigs_flg(ldns_
 					cur_rrset->type == LDNS_RR_TYPE_DNSKEY)
 					ldns_key_list_filter_for_dnskey(key_list);
 				
+				if(cur_rrset->type != LDNS_RR_TYPE_DNSKEY)
+					ldns_key_list_filter_for_non_dnskey(key_list);
+
 				/* TODO: just set count to zero? */
 				rr_list = ldns_rr_list_new();
 				
@@ -1094,7 +1111,7 @@ ldns_zone_sign(const ldns_zone *zone, ld
 	dnssec_zone = ldns_dnssec_zone_new();
 
 	(void) ldns_dnssec_zone_add_rr(dnssec_zone, ldns_zone_soa(zone));
-	ldns_zone_set_soa(signed_zone, ldns_zone_soa(zone));
+	ldns_zone_set_soa(signed_zone, ldns_rr_clone(ldns_zone_soa(zone)));
 	
 	for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) {
 		(void) ldns_dnssec_zone_add_rr(dnssec_zone,
@@ -1135,7 +1152,7 @@ ldns_zone_sign_nsec3(ldns_zone *zone, ld
 	dnssec_zone = ldns_dnssec_zone_new();
 
 	(void) ldns_dnssec_zone_add_rr(dnssec_zone, ldns_zone_soa(zone));
-	ldns_zone_set_soa(signed_zone, ldns_zone_soa(zone));
+	ldns_zone_set_soa(signed_zone, ldns_rr_clone(ldns_zone_soa(zone)));
 	
 	for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) {
 		(void) ldns_dnssec_zone_add_rr(dnssec_zone,
diff -urNapwB ldns-1.6.5/drill/drill.c ldns-1.6.6/drill/drill.c
--- ldns-1.6.5/drill/drill.c	2010-04-16 14:52:52.000000000 +0200
+++ ldns-1.6.6/drill/drill.c	2010-08-06 09:09:45.000000000 +0200
@@ -48,7 +48,7 @@ usage(FILE *stream, const char *progname
 	fprintf(stream, "\t-a\t\tfallback to EDNS0 and TCP if the answer is truncated\n");
 	fprintf(stream, "\t-b <bufsize>\tuse <bufsize> as the buffer size (defaults to 512 b)\n");
 	fprintf(stream, "\t-c <file>\t\tuse file for rescursive nameserver configuration (/etc/resolv.conf)\n");
-	fprintf(stream, "\t-k <file>\tspecify a file that contains a trusted DNSSEC key [**]\n");
+	fprintf(stream, "\t-k <file>\tspecify a file that contains a trusted DNSSEC key (DNSKEY|DS) [**]\n");
 	fprintf(stream, "\t\t\tused to verify any signatures in the current answer\n");
 	fprintf(stream, "\t-o <mnemonic>\tset flags to: [QR|qr][AA|aa][TC|tc][RD|rd][CD|cd][RA|ra][AD|ad]\n");
 	fprintf(stream, "\t\t\tlowercase: unset bit, uppercase: set bit\n");
diff -urNapwB ldns-1.6.5/drill/drill.1 ldns-1.6.6/drill/drill.1
--- ldns-1.6.5/drill/drill.1	2009-08-10 12:20:02.000000000 +0200
+++ ldns-1.6.6/drill/drill.1	2010-08-06 09:09:45.000000000 +0200
@@ -159,7 +159,7 @@ Use TCP/IP when querying a server
 Use this file to read a (trusted) key from. When this options is
 given \fBdrill\fR tries to validate the current answer with this
 key. No chasing is done. When \fBdrill\fR is doing a secure trace, this
-key will be used as trust anchor.
+key will be used as trust anchor. Can contain a DNSKEY or a DS record.
 
 .TP
 \fB\-o \fImnemonic\fR
diff -urNapwB ldns-1.6.5/drill/securetrace.c ldns-1.6.6/drill/securetrace.c
--- ldns-1.6.5/drill/securetrace.c	2010-06-08 08:54:53.000000000 +0200
+++ ldns-1.6.6/drill/securetrace.c	2010-08-05 14:02:38.000000000 +0200
@@ -208,6 +207,13 @@ do_secure_trace(ldns_resolver *local_res
 		result = -1;
 		return result;
 	}
+        /* Add all preset trusted DS signatures to the list of trusted DS RRs. */
+        for (j = 0; j < ldns_rr_list_rr_count(trusted_keys); j++) {
+            ldns_rr* one_rr = ldns_rr_list_rr(trusted_keys, j);
+            if (ldns_rr_get_type(one_rr)  == LDNS_RR_TYPE_DS) {
+                ldns_rr_list_push_rr(trusted_ds_rrs, ldns_rr_clone(one_rr));
+            }
+        }
 
 	/* transfer some properties of local_res to res */
 	ldns_resolver_set_ip6(res, 
diff -urNapwB ldns-1.6.5/examples/ldns-keygen.c ldns-1.6.6/examples/ldns-keygen.c
--- ldns-1.6.5/examples/ldns-keygen.c	2010-06-02 10:47:45.000000000 +0200
+++ ldns-1.6.6/examples/ldns-keygen.c	2010-06-23 10:45:44.000000000 +0200
@@ -157,6 +157,14 @@ main(int argc, char *argv[])
 	case LDNS_SIGN_HMACMD5:
 	case LDNS_SIGN_HMACSHA1:
 	case LDNS_SIGN_HMACSHA256:
+#ifdef USE_GOST
+	case LDNS_SIGN_ECC_GOST:
+		if(!ldns_key_EVP_load_gost_id()) {
+			fprintf(stderr, "error: libcrypto does not provide GOST\n");
+			exit(EXIT_FAILURE);
+		}
+		break;
+#endif
 	default:
 		break;
 	}
diff -urNapwB ldns-1.6.5/examples/ldns-key2ds.c ldns-1.6.6/examples/ldns-key2ds.c
--- ldns-1.6.5/examples/ldns-key2ds.c	2010-06-02 10:46:54.000000000 +0200
+++ ldns-1.6.6/examples/ldns-key2ds.c	2010-08-09 11:13:49.000000000 +0200
@@ -92,6 +92,10 @@ main(int argc, char *argv[])
 		}
 #ifdef USE_GOST
 		if (strcmp(argv[0], "-g") == 0) {
+			if(!ldns_key_EVP_load_gost_id()) {
+				fprintf(stderr, "error: libcrypto does not provide GOST\n");
+				exit(EXIT_FAILURE);
+			}
 			h = LDNS_HASH_GOST;
 			similar_hash = 0;
 		}
diff -urNapwB ldns-1.6.5/examples/ldns-signzone.c ldns-1.6.6/examples/ldns-signzone.c
--- ldns-1.6.5/examples/ldns-signzone.c	2010-04-06 14:10:35.000000000 +0200
+++ ldns-1.6.6/examples/ldns-signzone.c	2010-08-09 11:13:49.000000000 +0200
@@ -266,6 +266,11 @@ find_or_create_pubkey(const char *keyfil
 				ldns_key_set_keytag(key, ldns_key_keytag(key) - 1);
 			}
 		}
+		if(pubkey && ldns_dname_compare(ldns_rr_owner(pubkey), ldns_rr_owner(ldns_zone_soa(orig_zone))) != 0) {
+			fprintf(stderr, "Error %s.key has wrong name: %s\n",
+				keyfile_name_base, ldns_rdf2str(ldns_rr_owner(pubkey)));
+			exit(EXIT_FAILURE); /* leak rdf2str, but we exit */
+		}
 	}
 	
 	if (!pubkey) {
@@ -520,9 +525,7 @@ main(int argc, char *argv[])
 					case LDNS_SIGN_RSASHA512:
 					case LDNS_SIGN_DSA:
 					case LDNS_SIGN_DSA_NSEC3:
-#ifdef USE_GOST
 					case LDNS_SIGN_ECC_GOST:
-#endif
 						ldns_key_list_push_key(keys, key);
 						/*printf("Added key at %p:\n", key);*/
 						/*ldns_key_print(stdout, key);*/
@@ -703,7 +706,7 @@ main(int argc, char *argv[])
 				
 				ldns_key_list_push_key(keys, key);
 			} else {
-				fprintf(stderr, "Error reading key from %s at line %d\n", argv[argi], line_nr);
+				fprintf(stderr, "Error reading key from %s at line %d: %s\n", argv[argi], line_nr, ldns_get_errorstr_by_id(s));
 			}
 		}
 		/* and, if not unset by -p, find or create the corresponding DNSKEY record */
diff -urNapwB ldns-1.6.5/examples/ldns-testns.c ldns-1.6.6/examples/ldns-testns.c
--- ldns-1.6.5/examples/ldns-testns.c	2010-02-10 15:15:22.000000000 +0100
+++ ldns-1.6.6/examples/ldns-testns.c	2010-07-02 13:21:39.000000000 +0200
@@ -207,7 +207,11 @@ static int bind_port(int sock, int port,
 	memset(&addr6, 0, sizeof(addr6));
 	addr6.sin6_family = AF_INET6;
     	addr6.sin6_port = (in_port_t)htons((uint16_t)port);
+#  if HAVE_DECL_IN6ADDR_ANY
 	addr6.sin6_addr = in6addr_any;
+#  else
+	memset(&addr6.sin6_addr, 0, sizeof(addr6.sin6_addr));
+#  endif
     	return bind(sock, (struct sockaddr *)&addr6, (socklen_t) sizeof(addr6));
     }
 #endif
diff -urNapwB ldns-1.6.5/examples/ldns-update.c ldns-1.6.6/examples/ldns-update.c
--- ldns-1.6.5/examples/ldns-update.c	2010-04-16 14:52:52.000000000 +0200
+++ ldns-1.6.6/examples/ldns-update.c	2010-07-27 16:45:47.000000000 +0200
@@ -56,21 +56,24 @@ ldns_update_resolver_new(const char *fqd
         if (zone) {
                 soa_zone = ldns_dname_new_frm_str(zone);
                 if (ldns_update_soa_mname(soa_zone, r1, class, &soa_mname)
-                    != LDNS_STATUS_OK)
+                    != LDNS_STATUS_OK) {
                         goto bad;
+		}
         } else {
                 if (ldns_update_soa_zone_mname(fqdn, r1, class, &soa_zone,
-                        &soa_mname) != LDNS_STATUS_OK)
+                        &soa_mname) != LDNS_STATUS_OK) {
                         goto bad;
         }
+        }
 
         /* Pass zone_rdf on upwards. */
         *zone_rdf = ldns_rdf_clone(soa_zone);
 
         /* NS */
         query = ldns_pkt_query_new(soa_zone, LDNS_RR_TYPE_NS, class, LDNS_RD);
-        if (!query)
+        if (!query) {
                 goto bad;
+	}
         soa_zone = NULL;
 
         ldns_pkt_set_random_id(query);
@@ -80,9 +83,9 @@ ldns_update_resolver_new(const char *fqd
                 goto bad;
         }
         ldns_pkt_free(query);
-        if (!resp)
+        if (!resp) {
                 goto bad;
-
+	}
         /* Match SOA MNAME to NS list, adding it first */
         nslist = ldns_pkt_answer(resp);
         for (i = 0; i < ldns_rr_list_rr_count(nslist); i++) {
@@ -144,14 +147,15 @@ ldns_update_send_simple_addr(const char 
 
         /* Create resolver */
         res = ldns_update_resolver_new(fqdn, zone, 0, p, tsig_cred, &zone_rdf);
-        if (!res || !zone_rdf)
+        if (!res || !zone_rdf) {
                 goto cleanup;
+	}
 
         /* Set up the update section. */
         up_rrlist = ldns_rr_list_new();
-        if (!up_rrlist)
+        if (!up_rrlist) {
                 goto cleanup;
-
+	}
         /* Create input for ldns_rr_new_frm_str() */
         if (ipaddr) {
                 /* We're adding A or AAAA */
@@ -197,15 +201,17 @@ ldns_update_send_simple_addr(const char 
 
         /* Add TSIG */
         if (tsig_cred)
-                if (ldns_update_pkt_tsig_add(u_pkt, res) != LDNS_STATUS_OK)
+                if (ldns_update_pkt_tsig_add(u_pkt, res) != LDNS_STATUS_OK) {
                         goto cleanup;
+		}
 
-        if (ldns_resolver_send_pkt(&r_pkt, res, u_pkt) != LDNS_STATUS_OK)
+        if (ldns_resolver_send_pkt(&r_pkt, res, u_pkt) != LDNS_STATUS_OK) {
                 goto cleanup;
+	}
         ldns_pkt_free(u_pkt);
-        if (!r_pkt)
+        if (!r_pkt) {
                 goto cleanup;
-
+	}
         if (ldns_pkt_get_rcode(r_pkt) != LDNS_RCODE_NOERROR) {
                 ldns_lookup_table *t = ldns_lookup_by_id(ldns_rcodes,
                                 (int)ldns_pkt_get_rcode(r_pkt));
diff -urNapwB ldns-1.6.5/keys.c ldns-1.6.6/keys.c
--- ldns-1.6.5/keys.c	2010-05-18 17:01:39.000000000 +0200
+++ ldns-1.6.6/keys.c	2010-06-23 10:03:59.000000000 +0200
@@ -103,6 +103,9 @@ ldns_key_new_frm_engine(ldns_key **key, 
 #endif
 
 #ifdef USE_GOST
+/** store GOST engine reference loaded into OpenSSL library */
+ENGINE* ldns_gost_engine = NULL;
+
 int
 ldns_key_EVP_load_gost_id(void)
 {
@@ -138,17 +141,29 @@ ldns_key_EVP_load_gost_id(void)
 	}
 
 	meth = EVP_PKEY_asn1_find_str(&e, "gost2001", -1);
-	ENGINE_finish(e);
-	ENGINE_free(e);
 	if(!meth) {
 		/* algo not found */
+		ENGINE_finish(e);
+		ENGINE_free(e);
 		return 0;
 	}
+        /* Note: do not ENGINE_finish and ENGINE_free the acquired engine
+         * on some platforms this frees up the meth and unloads gost stuff */
+        ldns_gost_engine = e;
 	
 	EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth);
 	return gost_id;
 }
 
+void ldns_key_EVP_unload_gost(void)
+{
+        if(ldns_gost_engine) {
+                ENGINE_finish(ldns_gost_engine);
+                ENGINE_free(ldns_gost_engine);
+                ldns_gost_engine = NULL;
+        }
+}
+
 /** read GOST private key */
 static EVP_PKEY*
 ldns_key_new_frm_fp_gost_l(FILE* fp, int* line_nr)
@@ -335,6 +350,10 @@ ldns_key_new_frm_fp_l(ldns_key **key, FI
 		case LDNS_SIGN_ECC_GOST:
 			ldns_key_set_algorithm(k, alg);
 #if defined(HAVE_SSL) && defined(USE_GOST)
+                        if(!ldns_key_EVP_load_gost_id()) {
+				ldns_key_free(k);
+                                return LDNS_STATUS_CRYPTO_ALGO_NOT_IMPL;
+                        }
 			ldns_key_set_evp_key(k, 
 				ldns_key_new_frm_fp_gost_l(fp, line_nr));
 			if(!k->_key.key) {
diff -urNapwB ldns-1.6.5/ldns/keys.h ldns-1.6.6/ldns/keys.h
--- ldns-1.6.5/ldns/keys.h	2010-04-15 13:28:15.000000000 +0200
+++ ldns-1.6.6/ldns/keys.h	2010-06-25 15:11:53.000000000 +0200
@@ -307,6 +311,9 @@ void ldns_key_set_dsa_key(ldns_key *k, D
  * \return the gost id for EVP_CTX creation.
  */
 int ldns_key_EVP_load_gost_id(void);
+
+/** Release the engine reference held for the GOST engine. */
+void ldns_key_EVP_unload_gost(void);
 #endif /* HAVE_SSL */
 
 /**
diff -urNapwB ldns-1.6.5/ldns_symbols.def ldns-1.6.6/ldns_symbols.def
--- ldns-1.6.5/ldns_symbols.def	2010-04-08 15:05:09.000000000 +0200
+++ ldns-1.6.6/ldns_symbols.def	2010-06-22 14:17:15.000000000 +0200
@@ -165,6 +165,7 @@ ldns_get_rr_type_by_name
 ldns_gost2pkey_raw
 ldns_digest_evp
 ldns_key_EVP_load_gost_id
+ldns_key_EVP_unload_gost
 ldns_hexdigit_to_int
 ldns_hexstring_to_data
 ldns_init_random
diff -urNapwB ldns-1.6.5/net.c ldns-1.6.6/net.c
--- ldns-1.6.5/net.c	2010-04-01 10:17:25.000000000 +0200
+++ ldns-1.6.6/net.c	2010-08-05 13:18:10.000000000 +0200
@@ -765,18 +765,30 @@ ldns_axfr_start(ldns_resolver *resolver,
 		                            ldns_resolver_tsig_keydata(resolver),
 		                            300, ldns_resolver_tsig_algorithm(resolver), NULL);
 		if (status != LDNS_STATUS_OK) {
+			/* RoRi: to prevent problems on subsequent calls to ldns_axfr_start
+			   we have to close the socket here! */
+			close(resolver->_socket);
+			resolver->_socket = 0;
+
 			return LDNS_STATUS_CRYPTO_TSIG_ERR;
 		}
 	}
 #endif /* HAVE_SSL */
 
-        /* Convert the query to a buffer          * Is this necessary?
+        /* Convert the query to a buffer
+         * Is this necessary?
          */
         query_wire = ldns_buffer_new(LDNS_MAX_PACKETLEN);
         status = ldns_pkt2buffer_wire(query_wire, query);
         if (status != LDNS_STATUS_OK) {
                 ldns_pkt_free(query);
                 LDNS_FREE(ns);
+
+		/* RoRi: to prevent problems on subsequent calls to ldns_axfr_start
+		    we have to close the socket here! */
+		close(resolver->_socket);
+		resolver->_socket = 0;
+
                 return status;
         }
         /* Send the query */
@@ -785,6 +797,13 @@ ldns_axfr_start(ldns_resolver *resolver,
                 ldns_pkt_free(query);
                 ldns_buffer_free(query_wire);
                 LDNS_FREE(ns);
+
+		/* RoRi: to prevent problems on subsequent calls to ldns_axfr_start
+		         we have to close the socket here! */
+
+		close(resolver->_socket);
+		resolver->_socket = 0;
+
                 return LDNS_STATUS_NETWORK_ERR;
         }
 
diff -urNapwB ldns-1.6.5/resolver.c ldns-1.6.6/resolver.c
--- ldns-1.6.5/resolver.c	2010-05-18 17:01:39.000000000 +0200
+++ ldns-1.6.6/resolver.c	2010-08-05 13:18:10.000000000 +0200
@@ -608,6 +608,8 @@ ldns_resolver_new(void)
 	r->_timeout.tv_sec = LDNS_DEFAULT_TIMEOUT_SEC;
 	r->_timeout.tv_usec = LDNS_DEFAULT_TIMEOUT_USEC;
 
+	/* TODO: fd=0 is actually a valid socket (stdin),
+           replace with -1 */
 	r->_socket = 0;
 	r->_axfr_soa_count = 0;
 	r->_axfr_i = 0;
@@ -667,9 +669,11 @@ ldns_resolver_new_frm_fp_l(ldns_resolver
 	gtr = 1;
 	word[0] = 0;
         oldline = *line_nr;
+        expect = LDNS_RESOLV_KEYWORD;
 	while (gtr > 0) {
 		/* check comments */
 		if (word[0] == '#') {
+                        word[0]='x';
                         if(oldline == *line_nr) {
                                 /* skip until end of line */
                                 int c;
@@ -680,7 +684,6 @@ ldns_resolver_new_frm_fp_l(ldns_resolver
                         }
 			/* and read next to prepare for further parsing */
                         oldline = *line_nr;
-			gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_NORMAL, 0, line_nr);
 			continue;
 		}
                 oldline = *line_nr;
@@ -689,6 +692,7 @@ ldns_resolver_new_frm_fp_l(ldns_resolver
 				/* keyword */
 				gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_NORMAL, 0, line_nr);
 				if (gtr != 0) {
+                                        if(word[0] == '#') continue;
 					for(i = 0; i < LDNS_RESOLV_KEYWORDS; i++) {
 						if (strcasecmp(keyword[i], word) == 0) {
 							/* chosen the keyword and
@@ -714,6 +718,10 @@ ldns_resolver_new_frm_fp_l(ldns_resolver
 				if (gtr == 0) {
 					return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR;
 				}
+                                if(word[0] == '#') {
+                                        expect = LDNS_RESOLV_KEYWORD;
+                                        continue;
+                                }
 				tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, word);
 				if (!tmp) {
 					ldns_resolver_deep_free(r);
@@ -730,6 +738,10 @@ ldns_resolver_new_frm_fp_l(ldns_resolver
 				if (gtr == 0) {
 					return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR;
 				}
+                                if(word[0] == '#') {
+                                        expect = LDNS_RESOLV_KEYWORD;
+                                        continue;
+                                }
 				tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, word);
 				if (!tmp) {
 					/* try ip4 */
@@ -752,6 +764,10 @@ ldns_resolver_new_frm_fp_l(ldns_resolver
 				ldns_buffer_new_frm_data(b, word, (size_t) gtr);
 				gtr = ldns_bget_token(b, word, LDNS_PARSE_NORMAL, (size_t) gtr + 1);
 				while (gtr > 0) {
+                                        if(word[0] == '#') {
+                                                expect = LDNS_RESOLV_KEYWORD;
+                                                continue;
+                                        }
 					tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, word);
 					if (!tmp) {
 						ldns_resolver_deep_free(r);
@@ -783,6 +799,10 @@ ldns_resolver_new_frm_fp_l(ldns_resolver
 				if (gtr == 0) {
 					return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR;
 				}
+                                if(word[0] == '#') {
+                                        expect = LDNS_RESOLV_KEYWORD;
+                                        continue;
+                                }
 
 #ifdef HAVE_SSL
 				tmp_rr = ldns_read_anchor_file(word);
@@ -933,7 +953,6 @@ ldns_resolver_query(const ldns_resolver 
 			if (pkt) {
 				ldns_pkt_free(pkt);
 			}
-			fprintf(stderr, "error: %s\n", ldns_get_errorstr_by_id(status));
 			return NULL;
 		}
 	}
@@ -1164,10 +1183,24 @@ ldns_axfr_next(ldns_resolver *resolver)
 		if (status != LDNS_STATUS_OK) {
 			/* TODO: make status return type of this function (...api change) */
 			fprintf(stderr, "Error parsing rr during AXFR: %s\n", ldns_get_errorstr_by_id(status));
+
+			/* RoRi: we must now also close the socket, otherwise subsequent uses of the
+			   same resolver structure will fail because the link is still open or
+			   in an undefined state */
+			close(resolver->_socket);
+			resolver->_socket = 0;
+
 			return NULL;
 		} else if (ldns_pkt_get_rcode(resolver->_cur_axfr_pkt) != 0) {
 			rcode = ldns_lookup_by_id(ldns_rcodes, (int) ldns_pkt_get_rcode(resolver->_cur_axfr_pkt));
 			fprintf(stderr, "Error in AXFR: %s\n", rcode->name);
+
+			/* RoRi: we must now also close the socket, otherwise subsequent uses of the
+			   same resolver structure will fail because the link is still open or
+			   in an undefined state */
+			close(resolver->_socket);
+			resolver->_socket = 0;
+
 			return NULL;
 		} else {
 			return ldns_axfr_next(resolver);
diff -urNapwB ldns-1.6.5/rr.c ldns-1.6.6/rr.c
--- ldns-1.6.5/rr.c	2010-06-02 11:23:04.000000000 +0200
+++ ldns-1.6.6/rr.c	2010-07-27 14:18:54.000000000 +0200
@@ -732,6 +732,7 @@ ldns_rr_pop_rdf(ldns_rr *rr)
 {
 	size_t rd_count;
 	ldns_rdf *pop;
+	ldns_rdf** newrd;
 
 	rd_count = ldns_rr_rd_count(rr);
 
@@ -741,9 +742,15 @@ ldns_rr_pop_rdf(ldns_rr *rr)
 
 	pop = rr->_rdata_fields[rd_count - 1];
 
-	/* shrink the array */
-	rr->_rdata_fields = LDNS_XREALLOC(
+	/* try to shrink the array */
+	if(rd_count > 1) {
+		newrd = LDNS_XREALLOC(
 		rr->_rdata_fields, ldns_rdf *, rd_count - 1);
+		if(newrd)
+			rr->_rdata_fields = newrd;
+	} else {
+		LDNS_FREE(rr->_rdata_fields);
+	}
 
 	ldns_rr_set_rd_count(rr, rd_count - 1);
 	return pop;
@@ -1253,6 +1260,7 @@ ldns_rr_clone(const ldns_rr *rr)
 	ldns_rr_set_ttl(new_rr, ldns_rr_ttl(rr));
 	ldns_rr_set_type(new_rr, ldns_rr_get_type(rr));
 	ldns_rr_set_class(new_rr, ldns_rr_get_class(rr));
+	ldns_rr_set_question(new_rr, ldns_rr_is_question(rr));
 
 	for (i = 0; i < ldns_rr_rd_count(rr); i++) {
         	if (ldns_rr_rdf(rr,i)) {
diff -urNapwB ldns-1.6.5/tsig.c ldns-1.6.6/tsig.c
--- ldns-1.6.5/tsig.c	2009-12-17 14:02:31.000000000 +0100
+++ ldns-1.6.6/tsig.c	2010-07-27 13:40:38.000000000 +0200
@@ -166,6 +166,9 @@ ldns_tsig_mac_new(ldns_rdf **tsig_mac, u
 	 * prepare the digestable information
 	 */
 	data_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+	if(!data_buffer) {
+		return LDNS_STATUS_MEM_ERR;
+	}
 	/* if orig_mac is not NULL, add it too */
 	if (orig_mac_rdf) {
 		(void) ldns_rdf2buffer_wire(data_buffer, orig_mac_rdf);
@@ -184,19 +187,38 @@ ldns_tsig_mac_new(ldns_rdf **tsig_mac, u
 	wiresize = (int) ldns_buffer_position(data_buffer);
 
 	algorithm_name = ldns_rdf2str(algorithm_rdf);
+	if(!algorithm_name) {
+		ldns_buffer_free(data_buffer);
+		return LDNS_STATUS_MEM_ERR;
+	}
 
 	/* prepare the key */
 	key_bytes = LDNS_XMALLOC(unsigned char,
 			ldns_b64_pton_calculate_size(strlen(key_data)));
-	key_size = ldns_b64_pton(key_data, key_bytes, strlen(key_data) * 2);
+	if(!key_bytes) {
+		LDNS_FREE(algorithm_name);
+		ldns_buffer_free(data_buffer);
+		return LDNS_STATUS_MEM_ERR;
+	}
+	key_size = ldns_b64_pton(key_data, key_bytes,
+                ldns_b64_pton_calculate_size(strlen(key_data)));
 	if (key_size < 0) {
+		LDNS_FREE(algorithm_name);
+		LDNS_FREE(key_bytes);
+		ldns_buffer_free(data_buffer);
 		/* LDNS_STATUS_INVALID_B64 */
 		return LDNS_STATUS_INVALID_B64;
 	}
 	/* hmac it */
 	/* 2 spare bytes for the length */
-	mac_bytes = LDNS_XMALLOC(unsigned char, md_len);
-	memset(mac_bytes, 0, md_len);
+	mac_bytes = LDNS_XMALLOC(unsigned char, md_len+2);
+	if(!mac_bytes) {
+		LDNS_FREE(algorithm_name);
+		LDNS_FREE(key_bytes);
+		ldns_buffer_free(data_buffer);
+		return LDNS_STATUS_MEM_ERR;
+	}
+	memset(mac_bytes, 0, md_len+2);
 
 	digester = ldns_digest_function(algorithm_name);
 
@@ -208,6 +230,10 @@ ldns_tsig_mac_new(ldns_rdf **tsig_mac, u
 		result = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT16_DATA, md_len + 2,
 				mac_bytes);
 	} else {
+		LDNS_FREE(algorithm_name);
+		LDNS_FREE(mac_bytes);
+		LDNS_FREE(key_bytes);
+		ldns_buffer_free(data_buffer);
 		return LDNS_STATUS_CRYPTO_UNKNOWN_ALGO;
 	}
 
diff -urNapwB ldns-1.6.5/util.c ldns-1.6.6/util.c
--- ldns-1.6.5/util.c	2010-05-18 09:08:09.000000000 +0200
+++ ldns-1.6.6/util.c	2010-07-22 20:14:01.000000000 +0200
@@ -311,7 +311,7 @@ ldns_init_random(FILE *fd, unsigned int 
 	}
 
 	if (!fd) {
-		fclose(rand_f);
+                if (rand_f) fclose(rand_f);
 	}
 
 	return 0;
diff -urNapwB ldns-1.6.5/wire2host.c ldns-1.6.6/wire2host.c
--- ldns-1.6.5/wire2host.c	2010-01-05 10:55:40.000000000 +0100
+++ ldns-1.6.6/wire2host.c	2010-06-17 15:13:23.000000000 +0200
@@ -88,7 +88,7 @@ ldns_wire2dname(ldns_rdf **dname, const 
 
 			if (pointer_target == 0) {
 				return LDNS_STATUS_INVALID_POINTER;
-			} else if (pointer_target > max) {
+			} else if (pointer_target >= max) {
 				return LDNS_STATUS_INVALID_POINTER;
 			} else if (pointer_count > LDNS_MAX_POINTERS) {
 				return LDNS_STATUS_INVALID_POINTER;
@@ -101,7 +101,7 @@ ldns_wire2dname(ldns_rdf **dname, const 
 		if (label_size > LDNS_MAX_LABELLEN) {
 			return LDNS_STATUS_LABEL_OVERFLOW;
 		}
-		if (*pos + label_size > max) {
+		if (*pos + 1 + label_size > max) {
 			return LDNS_STATUS_LABEL_OVERFLOW;
 		}
 
@@ -433,7 +433,7 @@ ldns_wire2pkt(ldns_pkt **packet_p, const
 				ldns_pkt_set_edns_data(packet, ldns_rdf_clone(ldns_rr_rdf(rr, 0)));
 			}
 			ldns_rr_free(rr);
-			have_edns = 1;
+			have_edns += 1;
 		} else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_TSIG) {
 			ldns_pkt_set_tsig(packet, rr);
 			ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) - 1);
@@ -444,7 +444,8 @@ ldns_wire2pkt(ldns_pkt **packet_p, const
 	}
 	ldns_pkt_set_size(packet, max);
 	if(have_edns)
-		ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) - 1);
+		ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet)
+                        - have_edns);
 
 	*packet_p = packet;
 	return status;
diff -urNapwB dnsruby-1.48/lib/Dnsruby/Cache.rb dnsruby-1.49/lib/Dnsruby/Cache.rb
--- dnsruby-1.48/lib/Dnsruby/Cache.rb	2010-08-29 22:01:28.529486593 +0200
+++ dnsruby-1.49/lib/Dnsruby/Cache.rb	2010-08-29 22:01:26.380487278 +0200
@@ -41,6 +41,9 @@ module Dnsruby
         @cache = Hash.new
       }
     end
+    def length
+      return @cache.length
+    end
     def add(message)
       q = message.question[0]
       key = CacheKey.new(q.qname, q.qtype, q.qclass).to_s
diff -urNapwB dnsruby-1.48/lib/Dnsruby/Resolver.rb dnsruby-1.49/lib/Dnsruby/Resolver.rb
--- dnsruby-1.48/lib/Dnsruby/Resolver.rb	2010-08-29 22:01:28.533487355 +0200
+++ dnsruby-1.49/lib/Dnsruby/Resolver.rb	2010-08-29 22:01:26.384487691 +0200
@@ -1073,19 +1073,21 @@ module Dnsruby
         timeouts = @timeouts[client_query_id]
         if (!(error.to_s=~/Errno::EMFILE/))
           Dnsruby.log.debug{"Removing #{resolver.server} from resolver list for this query"}
+          if (timeouts)
           timeouts[1].each do |key, value|
             res = value[0]
             if (res == resolver)
               timeouts[1].delete(key)
             end
           end
+          end
           # Also stick it to the back of the list for future queries
           demote_resolver(resolver)
         else
           Dnsruby.log.debug{"NOT Removing #{resolver.server} due to Errno::EMFILE"}
         end
         #        - if it was the last server, then return an error to the client (and clean up)
-        if (outstanding.empty? && timeouts && timeouts[1].values.empty?)
+        if (outstanding.empty? && ((!timeouts) || (timeouts && timeouts[1].values.empty?)))
           #          if (outstanding.empty?)
           Dnsruby.log.debug{"Sending error to client"}
           send_result_and_stop_querying(client_queue, client_query_id, select_queue, response, error)
diff -urNapwB dnsruby-1.48/lib/Dnsruby/select_thread.rb dnsruby-1.49/lib/Dnsruby/select_thread.rb
--- dnsruby-1.48/lib/Dnsruby/select_thread.rb	2010-08-29 22:01:28.541487273 +0200
+++ dnsruby-1.49/lib/Dnsruby/select_thread.rb	2010-08-29 22:01:26.396489210 +0200
@@ -58,6 +58,8 @@ module Dnsruby
         @@queued_responses=[]
         @@queued_validation_responses=[]
         @@wakeup_sockets = get_socket_pair
+        @@sockets << @@wakeup_sockets[1]
+
         # Suppress reverse lookups
         BasicSocket.do_not_reverse_lookup = true
         #    end
@@ -75,7 +77,7 @@ module Dnsruby
       srv = nil
       begin
         srv = TCPServer.new('localhost', 0)
-      rescue Errno::EADDRNOTAVAIL # OSX Snow Leopard issue - need to use explicit IP
+      rescue Errno::EADDRNOTAVAIL, SocketError # OSX Snow Leopard issue - need to use explicit IP
         begin
           srv = TCPServer.new('127.0.0.1', 0)
         rescue Error # Try IPv6
@@ -164,7 +166,6 @@ module Dnsruby
           timeouts = @@timeouts.values
           has_observer = !@@observers.empty?
         }
-        sockets << @@wakeup_sockets[1]
         if (timeouts.length > 0)
           timeouts.sort!
           timeout = timeouts[0] - Time.now
diff -urNapwB dnsruby-1.48/lib/Dnsruby/zone_reader.rb dnsruby-1.49/lib/Dnsruby/zone_reader.rb
--- dnsruby-1.48/lib/Dnsruby/zone_reader.rb	2010-08-29 22:01:28.545487686 +0200
+++ dnsruby-1.49/lib/Dnsruby/zone_reader.rb	2010-08-29 22:01:26.396489210 +0200
@@ -176,7 +176,7 @@ module Dnsruby
             else
               if (c == ";")
                 if (!quoted)
-                  return line[0, pos]
+                  return line[0, pos+1]
                 end
               end
             end
diff -urNapwB dnsruby-1.48/lib/dnsruby.rb dnsruby-1.49/lib/dnsruby.rb
--- dnsruby-1.48/lib/dnsruby.rb	2010-08-29 22:01:28.545487686 +0200
+++ dnsruby-1.49/lib/dnsruby.rb	2010-08-29 22:01:26.396489210 +0200
@@ -104,7 +104,7 @@ require 'Dnsruby/TheLog'
 module Dnsruby
 
   # @TODO@ Remember to update version in dnsruby.gemspec!
-  VERSION = 1.48
+  VERSION = 1.49
   def Dnsruby.version
     return VERSION
   end
diff -urNapwB dnsruby-1.48/test/tc_dlv.rb dnsruby-1.49/test/tc_dlv.rb
--- dnsruby-1.48/test/tc_dlv.rb	2010-08-29 22:01:28.513489619 +0200
+++ dnsruby-1.49/test/tc_dlv.rb	2010-08-29 22:01:26.368487086 +0200
@@ -53,8 +53,9 @@ class TestDlv < Test::Unit::TestCase
     ret = res.query("ns2.nic.se", Dnsruby::Types.A)
     assert(ret.security_level == Dnsruby::Message::SecurityLevel::SECURE)
 
-    ret = res.query("b.ns.nic.cz", Dnsruby::Types.A)
-    assert(ret.security_level == Dnsruby::Message::SecurityLevel::SECURE)
+    # .cz no longer in dlv?
+#    ret = res.query("b.ns.nic.cz", Dnsruby::Types.A)
+#    assert(ret.security_level == Dnsruby::Message::SecurityLevel::SECURE)
 
     # Test .gov
 #    Dnsruby::TheLog.level = Logger::DEBUG
diff -urNapwB dnsruby-1.48/test/tc_rr-txt.rb dnsruby-1.49/test/tc_rr-txt.rb
--- dnsruby-1.48/test/tc_rr-txt.rb	2010-08-29 22:01:28.525487018 +0200
+++ dnsruby-1.49/test/tc_rr-txt.rb	2010-08-29 22:01:26.376488331 +0200
@@ -141,5 +141,10 @@ class TestRrTest < Test::Unit::TestCase
   def test_nasty_txt
    t = RR.create('txt2.t.net-dns.org. 60 IN TXT "Net-DNS\; complicated $tuff" "sort of \" text\; and binary \000 data"')
    assert(t.rdata.to_s == '"Net-DNS\; complicated $tuff" "sort of \" text\; and binary \000 data"', t.to_s)
+
+   r1 = RR.create("auto._domainkey.cacert.org.  43200 IN	TXT	\"v=DKIM1\;g=*\;k=rsa\;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDNFxiNr+NHJwih3OPhGr4iwLE+BBDu72YrMSzUnU1FF50CW7iOtuhg796UZ6xrZ5VuhAix6YmmzcvF2UxYzoD/XpfZ4MzBu0ND4/nkt9/YOTyIBzwQqn9uMNve0Y76Zsel89dIJtOI+y+lfnFExV0jKwe53gzmxMVpMSSCcZPGwIDAQAB\"	; ----- DKIM auto for cacert.org")
+   r2 = RR.create("auto._domainkey.cacert.org.	43200	IN	TXT	\"v=DKIM1;g=*;k=rsa;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDNFxiNr+NHJwih3OPhGr4iwLE+BBDu72YrMSzUnU1FF50CW7iOtuhg796UZ6xrZ5VuhAix6YmmzcvF2UxYzoD/XpfZ4MzBu0ND4/nkt9/YOTyIBzwQqn9uMNve0Y76Zsel89dIJtOI+y+lfnFExV0jKwe53gzmxMVpMSSCcZPGwIDAQAB\"")
+   assert(r1.to_s == r2.to_s)
   end
+
 end
diff -urNapwB dnsruby-1.48/test/tc_verifier.rb dnsruby-1.49/test/tc_verifier.rb
--- dnsruby-1.48/test/tc_verifier.rb	2010-08-29 22:01:28.525487018 +0200
+++ dnsruby-1.49/test/tc_verifier.rb	2010-08-29 22:01:26.380487278 +0200
@@ -269,6 +269,16 @@ class VerifierTest < Test::Unit::TestCas
   end
 
   def test_naptr
+    begin
+      begin
+        require 'rubygems'
+      rescue LoadError
+      end
+      require 'timecop'
+    rescue LoadError
+      return
+    end
+    Timecop.travel(2010, 03, 24, 0, 0, 0) {
     key = Dnsruby::RR.create("all.rr.org.	2678400	IN	DNSKEY	256 3 7 AwEAAcW1ZJxnMxZAAfsQ0JJQPHOlVNeGzs/AWVSGXiIYsg9UUSsvRTiK/Wy2wD7XC6osZpgy4Blhm846wktPbCwHpkxxbjxpaMABjbhH14gRol1Gpzf+gOr8vpdii8c2y6VMN9kIXZyaZUWcshLii19ysSGlqY1a1g2XZjogFtvzDHjH ;{id = 43068 (zsk), size = 1024b}")
     verifier = Dnsruby::SingleVerifier.new(Dnsruby::SingleVerifier::VerifierType::ANCHOR)
     key_rrset = Dnsruby::RRSet.new(key)
@@ -278,9 +288,20 @@ class VerifierTest < Test::Unit::TestCas
     rrset = Dnsruby::RRSet.new(naptr)
     rrset.add(sig)
     verifier.verify_rrset(rrset, key_rrset)
+    }
   end
 
   def test_txt_rr
+    begin
+      begin
+        require 'rubygems'
+      rescue LoadError
+      end
+      require 'timecop'
+    rescue LoadError
+      return
+    end
+    Timecop.travel(2010, 03, 24, 0, 0, 0) {
     txt = 'txt2.all.rr.org.        86400   IN      TXT     "Net-DNS\\\\; complicated $tuff" "sort of \\" text\\\\; and binary \\000 data"'
     rr = Dnsruby::RR.create(txt)
     assert(rr.to_s.index('"Net-DNS\\\\; complicated $tuff" "sort of \\" text\\\\; and binary \\000 data"'), rr.to_s)
@@ -294,8 +315,20 @@ class VerifierTest < Test::Unit::TestCas
     rrset = Dnsruby::RRSet.new(txt)
     rrset.add(sig)
     verifier.verify_rrset(rrset, key_rrset)
+    }
   end
 
+#  def test_txt_zonefile
+#     reader = Dnsruby::ZoneReader.new("cacert.org.")
+#     zone = reader.process_file("cacert.txt")
+#     reader2 = Dnsruby::ZoneReader.new("cacert.org.")
+#     zone2 = reader.process_file("cacert.signed.txt")
+#     assert(zone[1].to_s.index("DAQAB\""))
+#     assert(zone2[1].to_s.index("DAQAB\""))
+#
+#     assert(zone[1].to_s == zone2[1].to_s)
+#  end
+#
   #  def test_txt_from_zone
   #    reader = Dnsruby::ZoneReader.new("all.rr.org.")
   #    zone = reader.process_file("zone.txt")
diff -urNapwB opendnssec-1.1.1/auditor/lib/kasp_auditor/auditor.rb opendnssec-1.1.2/auditor/lib/kasp_auditor/auditor.rb
--- opendnssec-1.1.1/auditor/lib/kasp_auditor/auditor.rb	2010-07-08 22:53:50.000000000 +0200
+++ opendnssec-1.1.2/auditor/lib/kasp_auditor/auditor.rb	2010-08-25 10:47:44.000000000 +0200
@@ -856,7 +856,7 @@ module KASPAuditor
       while (last.labels.length > name_to_check_against.labels.length + 1)
         # Add the empty nonterminal to the list
         last.labels = last.labels[1,last.labels.length]
-        empty_nonterminals.push(last)
+        empty_nonterminals.push(last.clone)
       end
 
       # If so, should it be covered by an NSEC3 record?
diff -urNapwB opendnssec-1.1.1/auditor/lib/kasp_auditor.rb opendnssec-1.1.2/auditor/lib/kasp_auditor.rb
--- opendnssec-1.1.1/auditor/lib/kasp_auditor.rb	2010-07-08 22:53:50.000000000 +0200
+++ opendnssec-1.1.2/auditor/lib/kasp_auditor.rb	2010-08-25 10:47:44.000000000 +0200
@@ -25,6 +25,7 @@
 # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
 
+require 'etc'
 begin
   require 'dnsruby'
 rescue LoadError
@@ -40,7 +41,6 @@ require 'kasp_auditor/auditor.rb'
 require 'kasp_auditor/partial_auditor.rb'
 require 'kasp_auditor/parse.rb'
 require 'kasp_auditor/preparser.rb'
-require 'etc'
 
 # This module provides auditing capabilities to OpenDNSSEC.
 # Once an unsigned zone has been signed, this module is used to check that
diff -urNapwB opendnssec-1.1.1/auditor/lib/kasp_checker.rb opendnssec-1.1.2/auditor/lib/kasp_checker.rb
--- opendnssec-1.1.1/auditor/lib/kasp_checker.rb	2010-07-08 22:53:50.000000000 +0200
+++ opendnssec-1.1.2/auditor/lib/kasp_checker.rb	2010-08-25 10:47:44.000000000 +0200
@@ -380,6 +380,14 @@ module KASPChecker
                   "(#{max_default_denial} seconds) for #{name} policy in #{kasp_file}")
             end
 
+            # Error if jitter is greater than either Defaulyt or Denial Validity
+            if (jitter_secs > default_secs)
+              log(LOG_ERR, "Jitter time (#{jitter_secs}) is greater than the Default Validity (#{default_secs}) for #{name} policy in #{kasp_file}")
+            end
+            if (jitter_secs > denial_secs)
+              log(LOG_ERR, "Jitter time (#{jitter_secs}) is greater than the Denial Validity (#{denial_secs}) for #{name} policy in #{kasp_file}")
+            end
+
             #   5. Warn if the InceptionOffset is greater than ten minutes. (Again arbitrary - but do we really expect the times on two systems to differ by more than this?)
             inception_offset_secs = get_duration(policy, 'Signatures/InceptionOffset', kasp_file)
             if (inception_offset_secs > (10 * 60))
diff -urNapwB opendnssec-1.1.1/configure.ac opendnssec-1.1.2/configure.ac
diff -urNapwB opendnssec-1.1.1/enforcer/common/Makefile.am opendnssec-1.1.2/enforcer/common/Makefile.am
--- opendnssec-1.1.1/enforcer/common/Makefile.am	2010-07-08 22:53:45.000000000 +0200
+++ opendnssec-1.1.2/enforcer/common/Makefile.am	2010-08-25 10:47:40.000000000 +0200
@@ -13,4 +13,7 @@ noinst_LIBRARIES = libenforcer.a
 
 libenforcer_a_SOURCES = daemon.c daemon_util.c kaspaccess.c privdrop.c
 
-EXTRA_DIST = $(srcdir)/*.h
+EXTRA_DIST =	$(srcdir)/daemon.h \
+		$(srcdir)/daemon_util.h \
+		$(srcdir)/kaspaccess.h \
+		$(srcdir)/privdrop.h
diff -urNapwB opendnssec-1.1.1/enforcer/common/Makefile.in opendnssec-1.1.2/enforcer/common/Makefile.in
--- opendnssec-1.1.1/enforcer/common/Makefile.in	2010-07-08 23:30:54.000000000 +0200
+++ opendnssec-1.1.2/enforcer/common/Makefile.in	2010-08-25 10:48:47.000000000 +0200
@@ -252,7 +252,11 @@ AM_CPPFLAGS = \
 
 noinst_LIBRARIES = libenforcer.a
 libenforcer_a_SOURCES = daemon.c daemon_util.c kaspaccess.c privdrop.c
-EXTRA_DIST = $(srcdir)/*.h
+EXTRA_DIST = $(srcdir)/daemon.h \
+		$(srcdir)/daemon_util.h \
+		$(srcdir)/kaspaccess.h \
+		$(srcdir)/privdrop.h
+
 all: config.h
 	$(MAKE) $(AM_MAKEFLAGS) all-am
 
diff -urNapwB opendnssec-1.1.1/enforcer/utils/ods-ksmutil.1.in opendnssec-1.1.2/enforcer/utils/ods-ksmutil.1.in
--- opendnssec-1.1.1/enforcer/utils/ods-ksmutil.1.in	2010-07-08 22:53:44.000000000 +0200
+++ opendnssec-1.1.2/enforcer/utils/ods-ksmutil.1.in	2010-08-25 10:47:40.000000000 +0200
@@ -1,5 +1,5 @@
 .TH "ods-ksmutil" "1" "February 2010" OpenDNSSEC "OpenDNSSEC ods-ksmutil"
-.\" $Id: ods-ksmutil.1.in 3083 2010-03-24 23:39:24Z sion $
+.\" $Id: ods-ksmutil.1.in 3720 2010-08-11 07:10:50Z rb $
 .SH "NAME"
 .LP
 .B ods-ksmutil
@@ -250,11 +250,15 @@ This is a necessary step for repositorie
 Note that the KASP Enforcer may take the initiative to generate keys after
 the backup has started and before the backup is done.  In the current version
 of OpenDNSSEC, it is therefore needed to stop the KASP Enforcer to be assured
-that all keys are backed up.  The sequence would therefore be
-.LI Issue \fBods-control ksm stop\fR
-.LI Make a backup of the repository
-.LI Issue \fBods-ksmutil backup done\fR
-.LI Issue \fBods-control ksm start\fR
+that all keys are backed up.  The sequence would therefore be:
+.br
+1. Issue \fBods-control ksm stop\fR
+.br
+2. Make a backup of the repository
+.br
+3. Issue \fBods-ksmutil backup done\fR
+.br
+4. Issue \fBods-control ksm start\fR
 .TP
 .B database backup [\-\-output|\-o output]
 Make a copy of the database of the KASP Enforcer (if using sqlite).
diff -urNapwB opendnssec-1.1.1/KNOWN_ISSUES opendnssec-1.1.2/KNOWN_ISSUES
--- opendnssec-1.1.1/KNOWN_ISSUES	2010-07-08 22:53:52.000000000 +0200
+++ opendnssec-1.1.2/KNOWN_ISSUES	2010-08-25 10:47:50.000000000 +0200
@@ -1,4 +1,4 @@
-$Id: KNOWN_ISSUES 3404 2010-05-05 14:10:15Z sion $
+$Id: KNOWN_ISSUES 3645 2010-08-05 11:21:50Z matthijs $
 
 OpenDNSSEC 1.1.0 - Known Restrictions
 
@@ -110,6 +110,13 @@ If a RR owner name looks like a directiv
 the quicksorter filters them away as being incorrect directives. It will crash 
 on owner names like \$ORIGIN. 
 
+Zone fetcher would block transfers if AXFR failed once
+------------------------------------------------------
+
+The zone fetcher makes use of ldns_resolver from the ldns library. If a zone
+transfer fails, the ldns_resolver keeps open the socket. This blocks subsequent
+transfers. Using ldns 1.6.6 resolves this issue.
+
 
 Enforcer unit tests require environment variables
 -------------------------------------------------
diff -urNapwB opendnssec-1.1.1/signer/signer_engine/Engine.py opendnssec-1.1.2/signer/signer_engine/Engine.py
--- opendnssec-1.1.1/signer/signer_engine/Engine.py	2010-07-08 23:40:40.000000000 +0200
+++ opendnssec-1.1.2/signer/signer_engine/Engine.py	2010-08-25 10:55:55.000000000 +0200
@@ -431,6 +431,7 @@ class Engine:
                         response += self.read_zonelist()
                         response += "\n" + self.check_zone_conf_updates()
                 self.notify_all()
+		self.notify_zonefetcher ()
             if command[:4] == "stop":
                 self.stop_engine()
                 response = "Engine stopped"
@@ -515,6 +516,21 @@ class Engine:
         syslog.syslog(syslog.LOG_INFO, "close syslog")
         syslog.closelog()
 
+    def notify_zonefetcher(self):
+        """Reload the zone list into the zone fetcher daemon"""
+        pid_file = self.config.zonefetch_pidfile
+        if not os.path.exists(pid_file):
+            syslog.syslog(syslog.LOG_ERR, "could not notify zone fetcher: pid file does not exist: " + pid_file)
+        else:
+            pf = open(pid_file, 'r')
+            pid = pf.read()
+            syslog.syslog(syslog.LOG_DEBUG, "send notify to pid " + pid)
+            pf.close()
+            try:
+                os.kill(int(pid), signal.SIGUSR1)
+            except OSError:
+                syslog.syslog(syslog.LOG_ERR, "could not notify zone fetcher: no such process " + pid)
+
     def read_zonelist(self):
         """Reads the list of zones from the zone list xml file. Added
         zones are automatically scheduled for signing at the appropriate
diff -urNapwB opendnssec-1.1.1/signer/signer_engine/Engine.py.in opendnssec-1.1.2/signer/signer_engine/Engine.py.in
--- opendnssec-1.1.1/signer/signer_engine/Engine.py.in	2010-07-08 22:53:41.000000000 +0200
+++ opendnssec-1.1.2/signer/signer_engine/Engine.py.in	2010-08-25 10:47:47.000000000 +0200
@@ -431,6 +431,7 @@ class Engine:
                         response += self.read_zonelist()
                         response += "\n" + self.check_zone_conf_updates()
                 self.notify_all()
+		self.notify_zonefetcher ()
             if command[:4] == "stop":
                 self.stop_engine()
                 response = "Engine stopped"
@@ -515,6 +516,21 @@ class Engine:
         syslog.syslog(syslog.LOG_INFO, "close syslog")
         syslog.closelog()
 
+    def notify_zonefetcher(self):
+        """Reload the zone list into the zone fetcher daemon"""
+        pid_file = self.config.zonefetch_pidfile
+        if not os.path.exists(pid_file):
+            syslog.syslog(syslog.LOG_ERR, "could not notify zone fetcher: pid file does not exist: " + pid_file)
+        else:
+            pf = open(pid_file, 'r')
+            pid = pf.read()
+            syslog.syslog(syslog.LOG_DEBUG, "send notify to pid " + pid)
+            pf.close()
+            try:
+                os.kill(int(pid), signal.SIGUSR1)
+            except OSError:
+                syslog.syslog(syslog.LOG_ERR, "could not notify zone fetcher: no such process " + pid)
+
     def read_zonelist(self):
         """Reads the list of zones from the zone list xml file. Added
         zones are automatically scheduled for signing at the appropriate
diff -urNapwB opendnssec-1.1.1/signer/signer_engine/ods-signer.in opendnssec-1.1.2/signer/signer_engine/ods-signer.in
--- opendnssec-1.1.1/signer/signer_engine/ods-signer.in	2010-07-08 22:53:41.000000000 +0200
+++ opendnssec-1.1.2/signer/signer_engine/ods-signer.in	2010-08-25 10:47:47.000000000 +0200
@@ -143,5 +143,7 @@ if __name__ == "__main__":
     try:
         result = parse_args()
         sys.exit(result)
+    except SystemExit, e:
+        raise
     except Exception, e:
         sys.exit(2)
diff -urNapwB opendnssec-1.1.1/signer/signer_engine/ods-signer.8.in opendnssec-1.1.2/signer/signer_engine/ods-signer.8.in
--- opendnssec-1.1.1/signer/signer_engine/ods-signer.8.in	2010-07-08 22:53:41.000000000 +0200
+++ opendnssec-1.1.2/signer/signer_engine/ods-signer.8.in	2010-08-25 10:47:47.000000000 +0200
@@ -1,5 +1,5 @@
-.TH "ods-signer" "1" "February 2010" "OpenDNSSEC" "OpenDNSSEC ods-signer"
-.\" $Id: ods-signer.8.in 3101 2010-03-29 11:01:49Z matthijs $
+.TH "ods-signer" "8" "February 2010" "OpenDNSSEC" "OpenDNSSEC ods-signer"
+.\" $Id: ods-signer.8.in 3709 2010-08-10 13:03:45Z rb $
 .SH "NAME"
 .B ods\-signer 
 \- OpenDNSSEC Signer Engine client
diff -urNapwB opendnssec-1.1.1/signer/signer_engine/Zone.py opendnssec-1.1.2/signer/signer_engine/Zone.py
--- opendnssec-1.1.1/signer/signer_engine/Zone.py	2010-07-08 22:53:41.000000000 +0200
+++ opendnssec-1.1.2/signer/signer_engine/Zone.py	2010-08-25 10:47:47.000000000 +0200
@@ -530,9 +530,19 @@ class Zone:
            and 'keep'."""
         soa_serial = None
         serial_file = self.get_zone_tmp_filename(".serial")
+        # RvR: in the case where you are switching from serving
+        #      a zone directly to bump-in-the-wire mode, it is
+        #      a necessity to take the serial from the input zone
+        #      if that is larger than the last used serial. This
+        #      ensures that downstream public primaries/secondaries
+        #      will never miss an update; this behaviour has been
+        #      implemented below (old behaviour was to always take
+        #      the previously used serial as starting point which
+        #      was set to 0 in case of no previously available
+        #      serial)
         if self.zone_config.soa_serial == "unixtime":
             soa_serial = int(time.time())
-            prev_serial = self.get_output_serial()
+            prev_serial = max(self.get_output_serial(), self.get_input_serial())
             if self.compare_serial(prev_serial, soa_serial) <= 0:
                 soa_serial = prev_serial + 1
             update_serial = soa_serial - prev_serial
@@ -540,7 +550,7 @@ class Zone:
             soa_serial = self.get_input_serial()
             # it must be larger than the output serial!
             # otherwise updates won't be accepted
-            prev_serial = self.get_output_serial()
+            prev_serial = max(self.get_output_serial(), self.get_input_serial())
             if self.compare_serial(prev_serial, soa_serial) <= 0:
                 soa_serial = prev_serial + 1
             update_serial = soa_serial - prev_serial
@@ -548,7 +558,7 @@ class Zone:
             # if current output serial >= <date>00,
             # just increment by one
             soa_serial = int(time.strftime("%Y%m%d")) * 100
-            prev_serial = self.get_output_serial()
+            prev_serial = max(self.get_output_serial(), self.get_input_serial())
             if self.compare_serial(prev_serial, soa_serial) <= 0:
                 soa_serial = prev_serial + 1
             update_serial = soa_serial - prev_serial
diff -urNapwB opendnssec-1.1.1/signer/tools/Makefile.am opendnssec-1.1.2/signer/tools/Makefile.am
--- opendnssec-1.1.1/signer/tools/Makefile.am	2010-07-08 22:53:41.000000000 +0200
+++ opendnssec-1.1.2/signer/tools/Makefile.am	2010-08-25 10:47:46.000000000 +0200
@@ -49,7 +49,12 @@ create_dnskey_DEPENDENCIES=	@BUILD_LIBHS
 finalizer_SOURCES=		finalizer.c util.c
 finalizer_LDADD=		@LDNS_LIBS@
 
-EXTRA_DIST = $(srcdir)/*.h $(srcdir)/quicksorter.c
+EXTRA_DIST =	$(srcdir)/privdrop.h \
+		$(srcdir)/logging.h \
+		$(srcdir)/util.h \
+		$(srcdir)/quicksorter_encode.h \
+		$(srcdir)/zone_fetcher.h \
+		$(srcdir)/quicksorter.c
 
 ../../libhsm/src/libhsm.la:
 	(cd ../../libhsm/src; ${MAKE} libhsm.la)
diff -urNapwB opendnssec-1.1.1/signer/tools/Makefile.in opendnssec-1.1.2/signer/tools/Makefile.in
--- opendnssec-1.1.1/signer/tools/Makefile.in	2010-07-08 23:31:06.000000000 +0200
+++ opendnssec-1.1.2/signer/tools/Makefile.in	2010-08-25 10:49:00.000000000 +0200
@@ -295,7 +295,13 @@ create_dnskey_LDADD = @LDNS_LIBS@ @LIBHS
 create_dnskey_DEPENDENCIES = @BUILD_LIBHSM@
 finalizer_SOURCES = finalizer.c util.c
 finalizer_LDADD = @LDNS_LIBS@
-EXTRA_DIST = $(srcdir)/*.h $(srcdir)/quicksorter.c
+EXTRA_DIST = $(srcdir)/privdrop.h \
+		$(srcdir)/logging.h \
+		$(srcdir)/util.h \
+		$(srcdir)/quicksorter_encode.h \
+		$(srcdir)/zone_fetcher.h \
+		$(srcdir)/quicksorter.c
+
 all: config.h
 	$(MAKE) $(AM_MAKEFLAGS) all-am
 
diff -urNapwB opendnssec-1.1.1/signer/tools/quicksorter.c opendnssec-1.1.2/signer/tools/quicksorter.c
--- opendnssec-1.1.1/signer/tools/quicksorter.c	2010-07-08 22:53:40.000000000 +0200
+++ opendnssec-1.1.2/signer/tools/quicksorter.c	2010-08-25 10:47:46.000000000 +0200
@@ -369,6 +369,8 @@ int read_file(char* filename,
     while (1) {
         /* terminate line */
         char* end = strchr(ptr, '\n');
+
+        DEBUGF("debug: quicksorter ptr is %s\n", ptr);
         if (!end)
             break; /* end of file */
         *end = 0;
diff -urNapwB opendnssec-1.1.1/signer/tools/zone_fetcher.c opendnssec-1.1.2/signer/tools/zone_fetcher.c
--- opendnssec-1.1.1/signer/tools/zone_fetcher.c	2010-07-08 22:53:40.000000000 +0200
+++ opendnssec-1.1.2/signer/tools/zone_fetcher.c	2010-08-25 10:47:46.000000000 +0200
@@ -49,6 +49,8 @@
 #define DNS_SERIAL_GT(a, b) ((int)(((a) - (b)) & 0xFFFFFFFF) > 0)
 
 static int sig_quit = 0;
+static int sig_reload = 0;
+static char* zonelist_file = NULL;
 
 static void
 usage(FILE *out)
@@ -81,14 +83,15 @@ new_zone(char* zone_name, char* input_fi
 static void
 free_zonelist(zonelist_type* zlt)
 {
-    if (zlt) {
-        free_zonelist(zlt->next);
+    while (zlt) {
+	zonelist_type* next = zlt->next;
         free((void*) zlt->name);
         if (zlt->dname) {
             ldns_rdf_deep_free(zlt->dname);
         }
         free((void*) zlt->input_file);
         free((void*) zlt);
+	zlt = next;
     }
 }
 
@@ -538,6 +541,9 @@ sig_handler(int sig)
         case SIGHUP:
             sig_quit = 1;
             break;
+	case SIGUSR1:
+	    sig_reload = 1;
+	    break;
         default:
             break;
     }
@@ -573,6 +579,7 @@ setup_daemon(config_type* config)
     sigfillset(&action.sa_mask);
     action.sa_flags = 0;
     sigaction(SIGHUP, &action, NULL);
+    sigaction(SIGUSR1, &action, NULL);
 
     pid = getpid();
     if (writepid(config->pidfile, pid) == -1)
@@ -827,7 +834,7 @@ free_sockets(sockets_type* sockets)
 }
 
 static int
-odd_xfer(zonelist_type* zone, uint32_t serial, config_type* config)
+odd_xfer(zonelist_type* zone, uint32_t serial, config_type* config, int kick_signer)
 {
     ldns_status status = LDNS_STATUS_OK;
     ldns_rr* axfr_rr = NULL, *soa_rr = NULL;
@@ -933,6 +940,7 @@ odd_xfer(zonelist_type* zone, uint32_t s
             /* moving and kicking */
             snprintf(dest_file, sizeof(dest_file), "%s.axfr", zone->input_file);
             if(rename(axfr_file, dest_file) == 0) {
+		if (kick_signer) {
                 snprintf(engine_sign_cmd, sizeof(engine_sign_cmd),
                     "%s %s", SIGNER_CLI_SIGN, zone->name);
                 if (system(engine_sign_cmd) != 0) {
@@ -940,6 +948,7 @@ odd_xfer(zonelist_type* zone, uint32_t s
                         "the signer engine to sign zone %s", zone->name);
                 }
             }
+            }
             else {
                 log_msg(LOG_ERR, "zone fetcher could not move AXFR to %s",
                     dest_file);
@@ -1120,7 +1129,7 @@ handle_query(uint8_t* inbuf, ssize_t inl
                 serial = lookup_serial(fd);
                 fclose(fd);
             }
-            if (odd_xfer(zonelist, serial, config) != 0) {
+            if (odd_xfer(zonelist, serial, config, 1) != 0) {
                 log_msg(LOG_ERR, "AXFR for zone '%s' failed", zonelist->name);
             }
             ldns_pkt_free(query_pkt);
@@ -1277,6 +1286,73 @@ handle_tcp(int tcp_sock, config_type* co
     close(s);
 }
 
+/* Reload the zonelist file and merge it with the existing configuration */
+static void reload_zonelist (config_type *config) {
+    zonelist_type *new_zonelist, **thisp;
+    zonelist_type *added_zonelist = NULL, *kept_zonelist = NULL;
+    int added_count = 0, changed_count = 0, kept_count = 0;
+    /* Fail softly if the zonelist cannot be accessed for reloading */
+    if (!zonelist_file) {
+	log_msg(LOG_ERR, "zone fetcher is unable to access the zonelist");
+	return;
+    } else {
+	log_msg(LOG_INFO, "zone fetcher will reload the zonelist");
+    }
+    /* Read the zonelist file and construct a new linked list of zonelist entries */
+    new_zonelist = read_zonelist (zonelist_file);
+    /* Iterate over the new zonelist file and compare it to previously configured zonelist entries */
+    while (new_zonelist) {
+	zonelist_type *next_zonelist = new_zonelist->next;
+	zonelist_type *this = config->zonelist;
+	int found = 0;
+	while (this && !found) {
+	   found = !strcmp (this->name, new_zonelist->name);
+	   if (!found)
+		this = this->next;
+	}
+	/* If the zone name is found in the old zonelist, it is either a full match or a replacement */
+	if (found) {
+	    if (strcmp (new_zonelist->input_file, this->input_file)) {
+		/* the zonelist entry has changed -- treat as a replacement/new zonelist entry */
+		changed_count++;
+		new_zonelist->next = added_zonelist;
+		added_zonelist = new_zonelist;
+	    } else {
+		/* the zonelist entry is already configured -- treat as a kept zonelist entry */
+		kept_count++;
+		new_zonelist->next = kept_zonelist;
+		kept_zonelist = new_zonelist;
+	    }
+	} else {
+	    /* new_zonelist introduces a new zonelist entry */
+	    added_count++;
+	    new_zonelist->next = added_zonelist;
+	    added_zonelist = new_zonelist;
+	}
+	new_zonelist = next_zonelist;
+    }
+    /* Replace the configured zonelist with the added_zonelist and kept_zonelist */
+    free_zonelist (config->zonelist);
+    config->zonelist = kept_zonelist;
+    thisp = &config->zonelist;
+    while (*thisp) {
+	thisp = &(*thisp)->next;
+    }
+    *thisp = added_zonelist;
+    /* Perform an initial AXFR for the newly added zones (assume no present inputfile) */
+    new_zonelist = added_zonelist;
+    while (new_zonelist) {
+	/* send the request -- assume no file is present so SOA is 0 */
+	if (odd_xfer (new_zonelist, 0, config, 0) != 0) {
+	    log_msg(LOG_ERR, "AXFR for new zone '%s' failed", new_zonelist->name);
+	}
+	/* next */
+	new_zonelist = new_zonelist->next;
+    }
+    log_msg(LOG_INFO, "Reloaded zonelist -- kept %d, changed %d and added %d zones",
+		kept_count, changed_count, added_count);
+}
+
 static void
 xfrd_ns(sockets_type* sockets, config_type* cfg)
 {
@@ -1289,7 +1365,11 @@ xfrd_ns(sockets_type* sockets, config_ty
     count = 0;
     timeout.tv_sec = 0;
     timeout.tv_usec = 0;
-    while (1) {
+    while (!sig_quit) {
+	if (sig_reload) {
+	    reload_zonelist (cfg);
+	    sig_reload = 0;
+	}
         FD_ZERO(&rset);
         FD_ZERO(&wset);
         FD_ZERO(&eset);
@@ -1304,7 +1384,7 @@ xfrd_ns(sockets_type* sockets, config_ty
 
         if (select(maxfd+1, &rset, &wset, &eset, NULL) < 0) {
             if (errno == EINTR)
-                break;
+                continue;
             log_msg(LOG_ERR, "zone fetcher select(): %s", strerror(errno));
         }
 
@@ -1364,7 +1444,7 @@ list_settings(config_type* config, const
 int
 main(int argc, char **argv)
 {
-    const char* zonelist_file = NULL, *config_file = NULL;
+    const char* config_file = NULL;
     zonelist_type *zonelist = NULL;
     config_type* config = NULL;
     int c, run_as_daemon = 0;
@@ -1461,7 +1541,7 @@ main(int argc, char **argv)
             fclose(fd);
         }
         /* send the request */
-        if (odd_xfer(zonelist, serial, config) != 0) {
+        if (odd_xfer(zonelist, serial, config, 1) != 0) {
             log_msg(LOG_ERR, "AXFR for zone '%s' failed", zonelist->name);
         }
         /* next */
@@ -1492,6 +1572,22 @@ main(int argc, char **argv)
             log_msg(LOG_NOTICE, "zone fetcher exiting...");
             exit(EXIT_FAILURE);
         }
+	/* if chroot used, strip it off zonelist_file */
+	if (chroot && zonelist_file) {
+	    size_t chrootlen = strlen (chroot);
+	    if ((chrootlen > 0) && (chroot [chrootlen-1] == '/'))
+		chrootlen--;
+	    if ((strlen (zonelist_file) <= chrootlen)
+			|| strncmp (zonelist_file, chroot, chrootlen)
+			|| (zonelist_file [chrootlen] != '/')) {
+		log_msg(LOG_ERR, "zone fetcher will not be able to reload zonelist after chroot");
+		zonelist_file = NULL;
+	    } else {
+		char *new_zonelist_file = strdup (zonelist_file + chrootlen);
+		free (zonelist_file);
+		zonelist_file = new_zonelist_file;
+	    }
+	}
 
         xfrd_ns(&sockets, config);
 
diff -urNapwB opendnssec-1.1.1/tools/ods-control.in opendnssec-1.1.2/tools/ods-control.in
--- opendnssec-1.1.1/tools/ods-control.in	2010-07-08 22:53:42.000000000 +0200
+++ opendnssec-1.1.2/tools/ods-control.in	2010-08-25 10:47:49.000000000 +0200
@@ -37,41 +37,89 @@ case "$1" in
 
 'ksm')
 	shift
-	$bindir/ods-ksmutil $@
+	"$bindir/ods-ksmutil" $@
 	;;
 
 'hsm')
 	shift
-	$bindir/ods-hsmutil $@
+	"$bindir/ods-hsmutil" $@
 	;;
 	
 'signer')
 	shift
-	$sbindir/ods-signer $@
+	"$sbindir/ods-signer" $@
 	;;
 
-'start')
-	echo "Starting signer engine..."
-	$sbindir/ods-signer start
+'enforcer')
+	case "$2" in
 
+	'start')
+		if [ -r "$enforcer_pid_file" ]; then
+			echo "Enforcer is already running"
+			RETVAL=-1
+		else
 	echo "Starting enforcer..."
-	$sbindir/ods-enforcerd
+			"$sbindir/ods-enforcerd"
+			RETVAL=$?
+			if [ $RETVAL = 0 ]; then
+				while [ ! -r "$enforcer_pid_file" ]; do
+					sleep 1
+				done
+			fi
+		fi
+		exit $RETVAL
 	;;
 
 'stop')
 	echo "Stopping enforcer..."
-	if [ -r $enforcer_pid_file ]; then
-		kill -TERM `cat $enforcer_pid_file`
+		if [ -r "$enforcer_pid_file" ]; then
+			kill -TERM `cat "$enforcer_pid_file"`
+			RETVAL=$?
+			while [ -r "$enforcer_pid_file" ]; do
+				sleep 1
+			done
 	else
 		echo "Cannot find PID file"
+			RETVAL=1
 	fi
+		exit $RETVAL
+		;;
+
+	'notify')
+		echo "Notifying enforcer of new database..."
+		if [ -r "$enforcer_pid_file" ]; then
+			kill -HUP `cat "$enforcer_pid_file"`
+			RETVAL=$?
+		else
+			echo "Cannot find PID file"
+			RETVAL=1
+		fi
+		exit $RETVAL
+		;;
+
+	*)
+		echo "usage: $progname enforcer start|stop|notify"
+		;;
+
+	esac
+	;;
+
+'start')
+	echo "Starting signer engine..."
+	"$sbindir/ods-signer" start
+
+	"$0" enforcer start
+	;;
+
+'stop')
+	"$0" enforcer stop
 
 	echo "Stopping signer engine.."
-	$sbindir/ods-signer stop
+	"$sbindir/ods-signer" stop
 	;;
 	
 *)
-	echo "usage: $progname ksm|hsm|signer|start|stop ..."
+	echo "usage: $progname ksm|hsm|signer|enforcer|start|stop ..."
 	;;
 
 esac
diff -urNapwB opendnssec-1.1.1/tools/ods-control.8.in opendnssec-1.1.2/tools/ods-control.8.in
--- opendnssec-1.1.1/tools/ods-control.8.in	2010-07-08 22:53:42.000000000 +0200
+++ opendnssec-1.1.2/tools/ods-control.8.in	2010-08-25 10:47:49.000000000 +0200
@@ -15,6 +15,12 @@
 .B ods\-control start
 .br
 .B ods\-control stop
+.br
+.B ods\-control enforcer start
+.br
+.B ods\-control enforcer stop
+.br
+.B ods\-control enforcer notify
 .SH "DESCRIPTION"
 .LP
 ods\-control is a helper utility which gives a combined interface for different
@@ -37,6 +43,18 @@ Will start the two daemons of OpenDNSSEC
 .TP
 \fBstop\fR
 Will stop the two daemons of OpenDNSSEC, ods\-enforcerd and ods\-signerd
+.TP
+\fBenforcer start\fR
+Start the ods\-enforcerd daemon without touching the ods\-signerd and
+return non-zero on problems
+.TP
+\fBenforcer stop\fR
+Stop the ods\-enforcerd daemon without touching the ods\-signerd and
+return non-zero on problems
+.TP
+\fBenforcer notify\fR
+Notify the enforcer that its database has been updated and may need
+further processing by the KASP Enforcer.
 .SH "SEE ALSO"
 .LP
 ods\-auditor(1), ods\-enforcerd(8), ods\-hsmspeed(1),
diff -urNapwB opendnssec-1.1.1/tools/ods-timing.5.in opendnssec-1.1.2/tools/ods-timing.5.in
--- opendnssec-1.1.1/tools/ods-timing.5.in	2010-07-08 22:53:42.000000000 +0200
+++ opendnssec-1.1.2/tools/ods-timing.5.in	2010-08-25 10:47:49.000000000 +0200
@@ -18,15 +18,12 @@ notably for periods.  These descriptions
 for the duration of a month and a year, as these periods would be allowed
 to vary if ISO 8601 were strictly adhered to.
 .PP
-Durations are represented by the format
-.B P[n]Y[n]M[n]DT[n]H[n]M[n]S
-. In these representations, the
-.B [n]
-is replaced by the value for each of the date and time elements that follow the
-.B [n]
-. Leading zeros are not required. The capital letters \fBP\fR, \fBY\fR,
-\fBM\fR, \fBW\fR, \fBD\fR, \fBT\fR, \fBH\fR, \fBM\fR and \fBS\fR
-are designators for each of the date and time elements and are not replaced.
+Durations are represented by the format \fBP[n]Y[n]M[n]DT[n]H[n]M[n]S\fR.
+In these representations, the \fB[n]\fR is replaced by the value for each
+of the date and time elements that follow the \fB[n]\fR. Leading zeros are
+not required. The capital letters \fBP\fR, \fBY\fR, \fBM\fR, \fBW\fR,
+\fBD\fR, \fBT\fR, \fBH\fR, \fBM\fR and \fBS\fR are designators for each of
+the date and time elements and are not replaced
 .TP
 .B P
 is the duration designator (historically called "period") placed at the start of the duration representation.

Reply to: