diff -ur deadwood-2.9.02/src/DwRecurse.h deadwood-2.9.03/src/DwRecurse.h
--- deadwood-2.9.02/src/DwRecurse.h	2010-07-29 10:39:10.000000000 -0700
+++ deadwood-2.9.03/src/DwRecurse.h	2010-08-02 08:49:55.000000000 -0700
@@ -68,12 +68,13 @@
 #define TYPE_ANSWER 0
 #define TYPE_NXDOMAIN 1
 #define TYPE_NOT_THERE 2 /* Non-NXDOMAIN negative reply */
+#define TYPE_TRUNCATED 3 /* Non-NXDOMAIN truncated reply */
+#define TYPE_TRUNCATED_NXDOMAIN 4 /* NXDOMAIN truncated reply */
 #define TYPE_NS_REFER 16 /* NS referral */
 #define TYPE_CNAME_REFER 17 /* CNAME referral */
 #define TYPE_SERVER_TIMEOUT 18
 #define TYPE_NO_USEFUL_DATA 19
 #define TYPE_ERROR 20
-#define TYPE_TRUNCATED 21
 #define TYPE_UPSTREAM_REFER 22 /* Upstream server; set RD and stop here */
 /* These won't be used by Deadwood, but may be useful if I ever
  * expand DwHash to support for datatypes for elements besides
diff -ur deadwood-2.9.02/src/DwStr.c deadwood-2.9.03/src/DwStr.c
--- deadwood-2.9.02/src/DwStr.c	2010-07-29 10:39:10.000000000 -0700
+++ deadwood-2.9.03/src/DwStr.c	2010-08-02 09:16:06.000000000 -0700
@@ -438,6 +438,8 @@
  *
  * Should this function succeed, it will return a 0.  Otherwise, it
  * will return a -1
+ *
+ * BUG: Does not work correctly with length-1 (1-byte) strings
  */
 
 int dw_put_u8(dw_str *obj, uint8_t value, int32_t offset) {
diff -ur deadwood-2.9.02/src/DwUdpSocket.c deadwood-2.9.03/src/DwUdpSocket.c
--- deadwood-2.9.02/src/DwUdpSocket.c	2010-07-29 10:39:09.000000000 -0700
+++ deadwood-2.9.03/src/DwUdpSocket.c	2010-08-02 10:32:13.000000000 -0700
@@ -451,9 +451,12 @@
         dw_str *out = 0;
 
         is_nxdomain = dw_pop_u8(answer);
-        arcount = dw_pop_u16(answer);
-        nscount = dw_pop_u16(answer);
-        ancount = dw_pop_u16(answer);
+	if(is_nxdomain != TYPE_TRUNCATED && 
+			is_nxdomain != TYPE_TRUNCATED_NXDOMAIN) {
+        	arcount = dw_pop_u16(answer);
+        	nscount = dw_pop_u16(answer);
+        	ancount = dw_pop_u16(answer);
+	} 
 
         if(is_nxdomain == 0 || is_nxdomain == 2) {
                 /* 0x8180: QR = 1; Opcode = 0; AA = 0; TC = 0; RD = 1; RA = 1;
@@ -462,16 +465,26 @@
         } else if(is_nxdomain == 1) {
                 /* Same header as before, but with RCODE of "name error" */
                 out = make_dns_header(id,0x8183,ancount,nscount,arcount);
+	} else if(is_nxdomain == TYPE_TRUNCATED) {
+		/* Set TC to 1 */
+                out = make_dns_header(id,0x8380,0,0,0);
+	} else if(is_nxdomain == TYPE_TRUNCATED_NXDOMAIN) {
+		/* TC 1; RCODE "name error" */
+                out = make_dns_header(id,0x8383,0,0,0);
         } else {
                 goto catch_make_dns_packet;
         }
 
         if(dw_append(question,out) == -1 ||
-           dw_put_u16(out,1,-1) == -1 || /* QCLASS: 1 */
-           dw_append(answer,out) == -1) {
+           dw_put_u16(out,1,-1) == -1 /* QCLASS: 1 */ ) {
                 goto catch_make_dns_packet;
         }
-
+	if(is_nxdomain != TYPE_TRUNCATED && 
+			is_nxdomain != TYPE_TRUNCATED_NXDOMAIN &&
+           		dw_append(answer,out) == -1) {
+                goto catch_make_dns_packet;
+        }
+		
         return out;
 
 catch_make_dns_packet:
@@ -491,7 +504,7 @@
         dw_str *comp = 0; /* Compressed DNS packet */
         dw_str *packet = 0;
         socklen_t c_len = sizeof(struct sockaddr_in);
-        int ret = -1, type = 0;
+        int ret = -1, type = 0, cache_type = 0;
 
 #ifdef IPV6
         if (client->Family == AF_INET6) {
@@ -505,9 +518,22 @@
                 dwc_process(cache,query,3); /* RR rotation, TTL aging, etc. */
         }
         value = dwh_get(cache,query,resurrect,1);
-        comp = dwc_compress(query,value);
+	cache_type = dw_fetch_u8(value,-1);
+	if(cache_type != TYPE_TRUNCATED && 
+			cache_type != TYPE_TRUNCATED_NXDOMAIN) {
+        	comp = dwc_compress(query,value);
+	} else {
+		/* Immediately zap truncated from cache when fetched */
+		dwh_zap(cache,query,0,1);
+		if(client == 0) { /* DNS-over-TCP */
+			ret = 2;
+			goto catch_get_reply_from_cache;
+		}
+		comp = dw_copy(value);
+	}
+
         if(comp == 0) {
-                goto catch_get_reply_from_cache;
+               	goto catch_get_reply_from_cache;
         }
 
         if(comp->len == 7) { /* Empty packet; workaround */
@@ -669,7 +695,7 @@
 
 /* Add a reply we have received from the remote (upstream) DNS server to
  * the cache */
-int cache_dns_reply(unsigned char *packet, int count, int b) {
+int cache_dns_reply(unsigned char *packet, int count, int b, int truncated) {
         int32_t ttl = 60;
         int32_t ancount = 0;
         int is_nxdomain = 0;
@@ -683,35 +709,46 @@
         if((packet[3] & 0x0f) == 3) {
                 is_nxdomain = 1;
         }
-        answer = dw_packet_to_cache(packet,count,is_nxdomain);
-        decomp = dwc_decompress(question,answer);
-        if(dwc_has_bad_ip(decomp,blacklist_dict) ||
-           (qtype == 28 /* AAAA */ && key_n[DWM_N_reject_aaaa] == 1)) {
-                ret = -2; /* Tell caller we need synth "not there" */
-                goto catch_cache_dns_reply;
-        }
-        ancount = dw_cachepacket_to_ancount(answer);
-        if(ancount == 0) {
-                ancount = 32; /* So we can correctly cache negative answers */
-        }
-
-        if(question == 0 || answer == 0 || ancount == -1) {
-                goto catch_cache_dns_reply;
-        }
-
-        ttl = dw_get_a_dnsttl(answer,0,31536000,ancount);
-
-        if(ttl == -1) {
-                goto catch_cache_dns_reply;
-        }
-        if(ttl < 30) {
-                ttl = 30;
-        }
-
-        /* Have routines in DwRecurse.c process the packet and let us know
-         * what kind of packet we got upstream (so we know how to continue)
-         */
-        ret = dwx_cache_reply(cache,question,decomp,ttl,b);
+	if(truncated == 1) {
+		is_nxdomain += 3; 
+		answer = dw_create(2);
+		if(dw_put_u8(answer, is_nxdomain, 0) == -1) {
+			goto catch_cache_dns_reply;
+		}
+		dwh_add(cache,question,answer,7,1);
+		ret = 1;
+	} else {
+        	answer = dw_packet_to_cache(packet,count,is_nxdomain);
+        	decomp = dwc_decompress(question,answer);
+        	if(dwc_has_bad_ip(decomp,blacklist_dict) ||
+           	   (qtype == 28 /* AAAA */ && key_n[DWM_N_reject_aaaa] == 1)) {
+                	ret = -2; /* Tell caller we need synth "not there" */
+                	goto catch_cache_dns_reply;
+        	}
+        	ancount = dw_cachepacket_to_ancount(answer);
+        	if(ancount == 0) {
+                	ancount = 32; /* Correct negative answer caching */
+        	}
+
+        	if(question == 0 || answer == 0 || ancount == -1) {
+                	goto catch_cache_dns_reply;
+        	}
+
+        	ttl = dw_get_a_dnsttl(answer,0,31536000,ancount);
+
+        	if(ttl == -1) {
+                	goto catch_cache_dns_reply;
+        	}
+        	if(ttl < 30) {
+                	ttl = 30;
+        	}
+
+        	/* Routines in DwRecurse.c process the packet and let us know
+        	 * what kind of packet we got upstream (so we know how to 
+		 * continue)
+        	 */
+        	ret = dwx_cache_reply(cache,question,decomp,ttl,b);
+	}
 
 catch_cache_dns_reply:
         if(question != 0) {
@@ -879,7 +916,7 @@
         if (rem[b].local[l]->glueless_type != 0) {
                 conn_num = rem[b].local[l]->glueless_conn;
                 if(rem[b].local[l]->glueless_type == 1) { /* Glueless NS */
-                        if(rem[conn_num].child_id == b) {
+                        if(rem[conn_num].child_id == b) { /* Sanity check */
                                 dwx_glueless_done(query, conn_num);
                         }
                         ret = 4; /* Yes, we want to end the connection */
@@ -931,7 +968,7 @@
 
         if((a[2] & 0x02) == 0x00) { /* If not truncated */
                 fflush(stdout);
-                cache_dns_reply_return_value = cache_dns_reply(a,count,b);
+                cache_dns_reply_return_value = cache_dns_reply(a,count,b,0);
                 if(cache_dns_reply_return_value == -2) { /* Make synth NX */
                         make_synth_not_there(b,sock,a,count);
                         return -1; /* Bad reply and they got a Synth NX */
@@ -952,7 +989,10 @@
                  * we can fully process the TCP connection */
                 rem[b].die = get_time() + ((int64_t)timeout_seconds << 10);
                 return 2; /* Don't kill pending UDP connection */
-        }
+        } else { /* Truncated over UDP; just given them a blank "truncated"
+		  * reply */
+		cache_dns_reply(a,count,b,1);
+	}
 
         /* Now make sure the ID is the same as the one the client
          * originally sent us */
--- deadwood-2.9.02/doc/Deadwood.ej	2010-07-29 10:39:09.000000000 -0700
+++ deadwood-2.9.03/doc/Deadwood.ej	2010-08-02 10:39:59.000000000 -0700
@@ -567,11 +567,12 @@
 <h1>BUGS</h1>
 
 DNS-over-TCP needs to be explicitly enabled.  Note that DNS-over-TCP is 
-almost never used. 
-<p>
-
+almost never used.  Also,
 Deadwood does not cache DNS packets larger than 512 bytes in size that
-need to be sent using TCP.  Again, DNS-over-TCP is almost never used.
+need to be sent using TCP.  In addition, DNS-over-TCP packets which
+are "incomplete" DNS replies (replies which a stub resolver can not use,
+namely either a NS referral or an incomplete CNAME reply) are not
+handled correctly by Deadwood.  Again, DNS-over-TCP is very rare.
 <p>
 
 Deadwood can not process DNS resource record types with numbers between
