Downloaded from:
http://lizzy.dyndns.org/~jos/djbdns-1.05-jumbo-josb.patch

This patch combines the following patches:
- Claudiu Costin's jumbo-p13.patch
  http://www.ro.kde.org/djbdns/mywork/jumbo/jumbo-p13.patch.gz
- Guilherme Balena Versiani's djbdns SRV+NAPTR combined patch
  http://mywebpage.netscape.com/guibv/djbdns-1.05-srvnaptr.diff

diff -ruN djbdns-1.05-dist/CHANGES djbdns-1.05/CHANGES
--- djbdns-1.05-dist/CHANGES	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/CHANGES	2008-08-11 19:33:30.000000000 -0700
@@ -374,3 +374,5 @@
 	ui: servers print starting message.
 	internal: some respond() declarations.
 	version: djbdns 1.05.
+20010313
+	patch: to dump and reload the cache
diff -ruN djbdns-1.05-dist/Makefile djbdns-1.05/Makefile
--- djbdns-1.05-dist/Makefile	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/Makefile	2008-08-11 19:33:30.000000000 -0700
@@ -4,6 +4,8 @@
 
 default: it
 
+include Makefile.sig
+
 alloc.a: \
 makelib alloc.o alloc_re.o getln.o getln2.o stralloc_cat.o \
 stralloc_catb.o stralloc_cats.o stralloc_copy.o stralloc_eady.o \
@@ -149,13 +151,13 @@
 
 cache.o: \
 compile cache.c alloc.h byte.h uint32.h exit.h tai.h uint64.h cache.h \
-uint32.h uint64.h
+uint32.h uint64.h env.h error.h open.h openreadclose.h
 	./compile cache.c
 
 cachetest: \
-load cachetest.o cache.o libtai.a buffer.a alloc.a unix.a byte.a
-	./load cachetest cache.o libtai.a buffer.a alloc.a unix.a \
-	byte.a 
+load cachetest.o cache.o libtai.a buffer.a alloc.a unix.a byte.a env.a
+	./load cachetest cache.o libtai.a buffer.a unix.a env.a \
+	alloc.a byte.a dns.a
 
 cachetest.o: \
 compile cachetest.c buffer.h exit.h cache.h uint32.h uint64.h str.h
@@ -228,11 +230,11 @@
 dns.a: \
 makelib dns_dfd.o dns_domain.o dns_dtda.o dns_ip.o dns_ipq.o dns_mx.o \
 dns_name.o dns_nd.o dns_packet.o dns_random.o dns_rcip.o dns_rcrw.o \
-dns_resolve.o dns_sortip.o dns_transmit.o dns_txt.o
+dns_resolve.o dns_rotateip.o dns_sortip.o dns_transmit.o dns_txt.o
 	./makelib dns.a dns_dfd.o dns_domain.o dns_dtda.o dns_ip.o \
 	dns_ipq.o dns_mx.o dns_name.o dns_nd.o dns_packet.o \
 	dns_random.o dns_rcip.o dns_rcrw.o dns_resolve.o \
-	dns_sortip.o dns_transmit.o dns_txt.o
+	dns_rotateip.o dns_sortip.o dns_transmit.o dns_txt.o
 
 dns_dfd.o: \
 compile dns_dfd.c error.h alloc.h byte.h dns.h stralloc.h gen_alloc.h \
@@ -301,6 +303,10 @@
 dns.h stralloc.h gen_alloc.h iopause.h taia.h
 	./compile dns_resolve.c
 
+dns_rotateip.o: \
+compile dns_rotateip.c byte.h dns.h stralloc.h gen_alloc.h
+	./compile dns_rotateip.c
+
 dns_sortip.o: \
 compile dns_sortip.c byte.h dns.h stralloc.h gen_alloc.h iopause.h \
 taia.h tai.h uint64.h taia.h
@@ -320,10 +326,10 @@
 dnscache: \
 load dnscache.o droproot.o okclient.o log.o cache.o query.o \
 response.o dd.o roots.o iopause.o prot.o dns.a env.a alloc.a buffer.a \
-libtai.a unix.a byte.a socket.lib
+libtai.a unix.a byte.a sig.a socket.lib
 	./load dnscache droproot.o okclient.o log.o cache.o \
 	query.o response.o dd.o roots.o iopause.o prot.o dns.a \
-	env.a alloc.a buffer.a libtai.a unix.a byte.a  `cat \
+	env.a alloc.a buffer.a libtai.a unix.a byte.a sig.a  `cat \
 	socket.lib`
 
 dnscache-conf: \
@@ -626,9 +632,9 @@
 	./compile parsetype.c
 
 pickdns: \
-load pickdns.o server.o response.o droproot.o qlog.o prot.o dns.a \
+load pickdns.o server.o iopause.o response.o droproot.o qlog.o prot.o dns.a \
 env.a libtai.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib
-	./load pickdns server.o response.o droproot.o qlog.o \
+	./load pickdns server.o iopause.o response.o droproot.o qlog.o \
 	prot.o dns.a env.a libtai.a cdb.a alloc.a buffer.a unix.a \
 	byte.a  `cat socket.lib`
 
@@ -704,9 +710,9 @@
 	./compile random-ip.c
 
 rbldns: \
-load rbldns.o server.o response.o dd.o droproot.o qlog.o prot.o dns.a \
+load rbldns.o server.o iopause.o response.o dd.o droproot.o qlog.o prot.o dns.a \
 env.a libtai.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib
-	./load rbldns server.o response.o dd.o droproot.o qlog.o \
+	./load rbldns server.o iopause.o response.o dd.o droproot.o qlog.o \
 	prot.o dns.a env.a libtai.a cdb.a alloc.a buffer.a unix.a \
 	byte.a  `cat socket.lib`
 
@@ -774,7 +780,7 @@
 compile server.c byte.h case.h env.h buffer.h strerr.h ip4.h uint16.h \
 ndelay.h socket.h uint16.h droproot.h qlog.h uint16.h response.h \
 uint32.h dns.h stralloc.h gen_alloc.h iopause.h taia.h tai.h uint64.h \
-taia.h
+taia.h iopause.h alloc.h
 	./compile server.c
 
 setup: \
@@ -979,10 +985,10 @@
 	./compile timeoutwrite.c
 
 tinydns: \
-load tinydns.o server.o droproot.o tdlookup.o response.o qlog.o \
+load tinydns.o server.o iopause.o droproot.o tdlookup.o response.o qlog.o \
 prot.o dns.a libtai.a env.a cdb.a alloc.a buffer.a unix.a byte.a \
 socket.lib
-	./load tinydns server.o droproot.o tdlookup.o response.o \
+	./load tinydns server.o iopause.o droproot.o tdlookup.o response.o \
 	qlog.o prot.o dns.a libtai.a env.a cdb.a alloc.a buffer.a \
 	unix.a byte.a  `cat socket.lib`
 
@@ -1084,10 +1090,10 @@
 	./compile utime.c
 
 walldns: \
-load walldns.o server.o response.o droproot.o qlog.o prot.o dd.o \
+load walldns.o server.o iopause.o response.o droproot.o qlog.o prot.o dd.o \
 dns.a env.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib
-	./load walldns server.o response.o droproot.o qlog.o \
-	prot.o dd.o dns.a env.a cdb.a alloc.a buffer.a unix.a \
+	./load walldns server.o iopause.o response.o droproot.o qlog.o \
+	prot.o dd.o dns.a libtai.a env.a cdb.a alloc.a buffer.a unix.a \
 	byte.a  `cat socket.lib`
 
 walldns-conf: \
diff -ruN djbdns-1.05-dist/Makefile.sig djbdns-1.05/Makefile.sig
--- djbdns-1.05-dist/Makefile.sig	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/Makefile.sig	2008-08-11 19:33:30.000000000 -0700
@@ -0,0 +1,27 @@
+sig.o: \
+compile sig.c sig.h
+	./compile sig.c
+
+sig_block.o: \
+compile sig_block.c sig.h hassgprm.h
+	./compile sig_block.c
+
+sig_catch.o: \
+compile sig_catch.c sig.h hassgact.h
+	./compile sig_catch.c
+
+sig_pause.o: \
+compile sig_pause.c sig.h hassgprm.h
+	./compile sig_pause.c
+
+sig.a: \
+makelib sig.o sig_block.o sig_catch.o sig_pause.o
+	./makelib sig.a sig.o sig_block.o sig_catch.o sig_pause.o
+
+hassgact.h: \
+choose compile load trysgact.c hassgact.h1 hassgact.h2
+	./choose cl trysgact hassgact.h1 hassgact.h2 > hassgact.h
+
+hassgprm.h: \
+choose compile load trysgprm.c hassgprm.h1 hassgprm.h2
+	./choose cl trysgprm hassgprm.h1 hassgprm.h2 > hassgprm.h
diff -ruN djbdns-1.05-dist/README djbdns-1.05/README
--- djbdns-1.05-dist/README	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/README	2008-08-11 19:33:30.000000000 -0700
@@ -1,3 +1,9 @@
+patchlevel fg1
+20010313
+by Florent Guillaume <florent.guillaume@mail.com>
+patch home page: http://mapage.noos.fr/efgeor/djbdns/index.html
+Uses parts of Felix von Leitner's djb-0.5.2 package: http://www.fefe.de/djb/
+
 djbdns 1.05
 20010211
 Copyright 2001
diff -ruN djbdns-1.05-dist/SYSDEPS djbdns-1.05/SYSDEPS
--- djbdns-1.05-dist/SYSDEPS	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/SYSDEPS	2008-08-11 19:33:30.000000000 -0700
@@ -7,4 +7,6 @@
 direntry.h
 hasshsgr.h
 hasdevtcp.h
+hassgact.h
+hassgprm.h
 socket.lib
diff -ruN djbdns-1.05-dist/TARGETS djbdns-1.05/TARGETS
--- djbdns-1.05-dist/TARGETS	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/TARGETS	2008-08-11 19:33:30.000000000 -0700
@@ -214,3 +214,10 @@
 it
 setup
 check
+sig.o
+sig.a
+sig_catch.o
+sig_block.o
+hassgact.h
+hassgprm.h
+sig_pause.o
diff -ruN djbdns-1.05-dist/VERSION djbdns-1.05/VERSION
--- djbdns-1.05-dist/VERSION	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/VERSION	2008-08-11 19:33:30.000000000 -0700
@@ -1 +1 @@
-djbdns 1.05
+djbdns 1.05-fg1
diff -ruN djbdns-1.05-dist/auto_home.c djbdns-1.05/auto_home.c
--- djbdns-1.05-dist/auto_home.c	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/auto_home.c	2008-08-12 09:17:21.000000000 -0700
@@ -0,0 +1,3 @@
+const char auto_home[] = "\
+\057\165\163\162\057\154\157\143\141\154\
+";
diff -ruN djbdns-1.05-dist/axfr-get.c djbdns-1.05/axfr-get.c
--- djbdns-1.05-dist/axfr-get.c	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/axfr-get.c	2008-08-11 22:49:05.000000000 -0700
@@ -209,6 +209,57 @@
     if (!stralloc_cats(&line,".:")) return 0;
     if (!stralloc_catulong0(&line,dist,0)) return 0;
   }
+  else if (byte_equal(data,2,DNS_T_SRV)) {
+    uint16 priority, weight, port;
+    if (!stralloc_copys(&line,"S")) return 0;
+    if (!dns_domain_todot_cat(&line,d1)) return 0;
+    if (!stralloc_cats(&line,"::")) return 0;
+    pos = x_copy(buf,len,pos,data,2);
+    uint16_unpack_big(data,&priority);
+    pos = x_copy(buf,len,pos,data,2);
+    uint16_unpack_big(data,&weight);
+    pos = x_copy(buf,len,pos,data,2);
+    uint16_unpack_big(data,&port);
+    x_getname(buf,len,pos,&d1);
+    if (!dns_domain_todot_cat(&line,d1)) return 0;
+    if (!stralloc_cats(&line,".:")) return 0;
+    if (!stralloc_catulong0(&line,port,0)) return 0;
+    if (!stralloc_cats(&line,":")) return 0;
+    if (!stralloc_catulong0(&line,priority,0)) return 0;
+    if (!stralloc_cats(&line,":")) return 0;
+    if (!stralloc_catulong0(&line,weight,0)) return 0;
+  }
+  else if (byte_equal(data,2,DNS_T_NAPTR)) {
+    uint16 order, preference;
+    char flags[255], service[255], regexp[255];
+    char fs, ss, rs;
+    if (!stralloc_copys(&line,"N")) return 0;
+    if (!dns_domain_todot_cat(&line,d1)) return 0;
+    if (!stralloc_cats(&line,":")) return 0;
+    pos = x_copy(buf,len,pos,data,2);
+    uint16_unpack_big(data,&order);
+    pos = x_copy(buf,len,pos,data,2);
+    uint16_unpack_big(data,&preference);
+    pos = x_copy(buf,len,pos,&fs,1);
+    pos = x_copy(buf,len,pos,flags,fs);
+    pos = x_copy(buf,len,pos,&ss,1);
+    pos = x_copy(buf,len,pos,service,ss);
+    pos = x_copy(buf,len,pos,&rs,1);
+    pos = x_copy(buf,len,pos,regexp,rs);
+    x_getname(buf,len,pos,&d1);
+    if (!stralloc_catulong0(&line,order,0)) return 0;
+    if (!stralloc_cats(&line,":")) return 0;
+    if (!stralloc_catulong0(&line,preference,0)) return 0;
+    if (!stralloc_cats(&line,":")) return 0;
+    if (!stralloc_catb(&line,flags,fs)) return 0;
+    if (!stralloc_cats(&line,":")) return 0;
+    if (!stralloc_catb(&line,service,ss)) return 0;
+    if (!stralloc_cats(&line,":")) return 0;
+    if (!stralloc_catb(&line,regexp,rs)) return 0;
+    if (!stralloc_cats(&line,":")) return 0;
+    if (!dns_domain_todot_cat(&line,d1)) return 0;
+    if (!stralloc_cats(&line,".")) return 0;
+  }
   else if (byte_equal(data,2,DNS_T_A) && (dlen == 4)) {
     char ipstr[IP4_FMT];
     if (!stralloc_copys(&line,"+")) return 0;
@@ -217,6 +268,14 @@
     x_copy(buf,len,pos,data,4);
     if (!stralloc_catb(&line,ipstr,ip4_fmt(ipstr,data))) return 0;
   }
+  else if (byte_equal(data,2,DNS_T_PTR)) {
+    if (!stralloc_copys(&line,"^")) return 0;
+    if (!dns_domain_todot_cat(&line,d1)) return 0;
+    if (!stralloc_cats(&line,":")) return 0;
+    x_getname(buf,len,pos,&d1);
+    if (!dns_domain_todot_cat(&line,d1)) return 0;
+    if (!stralloc_cats(&line,".")) return 0;
+  }
   else {
     unsigned char ch;
     unsigned char ch2;
diff -ruN djbdns-1.05-dist/cache.c djbdns-1.05/cache.c
--- djbdns-1.05-dist/cache.c	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/cache.c	2008-08-11 19:33:30.000000000 -0700
@@ -1,12 +1,23 @@
+#ifdef DUMPCACHE
+#include <stdio.h>
+#include <unistd.h>
+#include "env.h"
+#include "error.h"
+#include "open.h"
+#include "openreadclose.h"
+#endif
 #include "alloc.h"
 #include "byte.h"
 #include "uint32.h"
 #include "exit.h"
 #include "tai.h"
 #include "cache.h"
+#include "dns.h"
+#include "buffer.h"
 
 uint64 cache_motion = 0;
 
+static char *rrobin;
 static char *x = 0;
 static uint32 size;
 static uint32 hsize;
@@ -87,6 +98,12 @@
   uint32 u;
   unsigned int loop;
   double d;
+  static int trigger=0;
+  
+  if (!trigger) {
+    rrobin = env_get("ROUNDROBIN");
+    trigger++;
+  }
 
   if (!x) return 0;
   if (keylen > MAXKEYLEN) return 0;
@@ -111,7 +128,11 @@
         u = get4(pos + 8);
         if (u > size - pos - 20 - keylen) cache_impossible();
         *datalen = u;
-
+	if (byte_equal(key,2,DNS_T_A)) {
+	  if (rrobin) {
+            dns_rotateip(x + pos + 20 + keylen,u);
+	  }
+	}
         return x + pos + 20 + keylen;
       }
     }
@@ -205,3 +226,97 @@
 
   return 1;
 }
+
+#ifdef DUMPCACHE
+static int fd;
+
+static int cache_writeline(const char *buf, unsigned int len)
+{
+  int w;
+
+  while (len) {
+    w = write(fd,buf,len);
+    if (w == -1) {
+      if (errno == error_intr) continue;
+      close(fd);
+      return -1;
+    }
+    buf += w;
+    len -= w;
+  }
+  return 0;
+}
+
+int cache_dump(void)
+{
+  static char *fn;
+  static char *fntmp;
+  uint32 pos;
+  unsigned int len;
+
+  fn = env_get("DUMPCACHE");
+  if (!fn) return 999;
+  fntmp = env_get("DUMPCACHETMP");
+  if (!fntmp) return 999;
+  fd = open_trunc(fntmp);
+  if (fd == -1) return -1;
+
+  pos = oldest;
+  while (pos < unused) {
+    len = get4(pos + 4) + get4(pos + 8) + 16;
+    if (cache_writeline(x + pos + 4, len)) return -1;
+    pos += 4 + len;
+  }
+  pos = hsize;
+  while (pos < writer) {
+    len = get4(pos + 4) + get4(pos + 8) + 16;
+    if (cache_writeline(x + pos + 4, len)) return -1;
+    pos += 4 + len;
+  }
+
+  if (fsync(fd) == -1) return -1;
+  if (close(fd) == -1) return -1;
+  if (rename(fntmp,fn) == -1) return -1;
+  return 0;
+}
+
+int cache_slurp(const char *fn)
+{
+  static stralloc buf = {0};
+  char *p;
+  uint32 pos;
+  unsigned int len;
+  uint32 keylen;
+  uint32 datalen;
+  struct tai now;
+  struct tai expire;
+  int nb;
+
+  if (openreadclose(fn,&buf,16384) != 1) goto DIE;
+  tai_now(&now);
+  p = buf.s;
+  pos = 0;
+  len = buf.len;
+  nb = 0;
+  while (pos + 16 <= len) {
+    uint32_unpack(p + pos, &keylen);
+    uint32_unpack(p + pos + 4, &datalen);
+    tai_unpack(p + pos + 8, &expire);
+    pos += 16;
+    if (pos + keylen + datalen > len) break; /* missing data */
+    if (!tai_less(&expire,&now)) {
+      tai_sub(&expire,&expire,&now);
+      cache_set(p + pos, keylen, p + pos + keylen, datalen, (unsigned int)expire.x);
+    }
+    pos += keylen + datalen;
+    nb++;
+  }
+  alloc_free(buf.s); buf.s = 0;
+  return nb;
+
+ DIE:
+  alloc_free(buf.s); buf.s = 0;
+  if (errno == error_noent) return 0;
+  return -1;
+}
+#endif
diff -ruN djbdns-1.05-dist/cache.h djbdns-1.05/cache.h
--- djbdns-1.05-dist/cache.h	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/cache.h	2008-08-11 19:33:30.000000000 -0700
@@ -8,5 +8,9 @@
 extern int cache_init(unsigned int);
 extern void cache_set(const char *,unsigned int,const char *,unsigned int,uint32);
 extern char *cache_get(const char *,unsigned int,unsigned int *,uint32 *);
+#ifdef DUMPCACHE
+extern int cache_dump(void);
+extern int cache_slurp(const char *);
+#endif
 
 #endif
diff -ruN djbdns-1.05-dist/chkshsgr.c djbdns-1.05/chkshsgr.c
--- djbdns-1.05-dist/chkshsgr.c	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/chkshsgr.c	2008-08-11 19:33:30.000000000 -0700
@@ -1,4 +1,6 @@
 #include "exit.h"
+#include <grp.h>
+#include <unistd.h>
 
 int main()
 {
diff -ruN djbdns-1.05-dist/direntry.h djbdns-1.05/direntry.h
--- djbdns-1.05-dist/direntry.h	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/direntry.h	2008-08-11 22:55:14.000000000 -0700
@@ -0,0 +1,10 @@
+#ifndef DIRENTRY_H
+#define DIRENTRY_H
+
+/* sysdep: +dirent */
+
+#include <sys/types.h>
+#include <dirent.h>
+#define direntry struct dirent
+
+#endif
diff -ruN djbdns-1.05-dist/dns.h djbdns-1.05/dns.h
--- djbdns-1.05-dist/dns.h	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/dns.h	2008-08-11 22:49:25.000000000 -0700
@@ -20,6 +20,8 @@
 #define DNS_T_SIG "\0\30"
 #define DNS_T_KEY "\0\31"
 #define DNS_T_AAAA "\0\34"
+#define DNS_T_SRV "\0\41"
+#define DNS_T_NAPTR "\0\43"
 #define DNS_T_AXFR "\0\374"
 #define DNS_T_ANY "\0\377"
 
@@ -43,6 +45,7 @@
 extern unsigned int dns_random(unsigned int);
 
 extern void dns_sortip(char *,unsigned int);
+extern void dns_rotateip(char *,unsigned int);
 
 extern void dns_domain_free(char **);
 extern int dns_domain_copy(char **,const char *);
diff -ruN djbdns-1.05-dist/dns_rotateip.c djbdns-1.05/dns_rotateip.c
--- djbdns-1.05-dist/dns_rotateip.c	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/dns_rotateip.c	2008-08-11 19:33:30.000000000 -0700
@@ -0,0 +1,15 @@
+#include "byte.h"
+
+void dns_rotateip(char *s, unsigned int n)
+{
+  unsigned int i;
+  char tmp[4];
+
+  i = n >> 2;
+  while (i > 1) {
+    --i;
+    byte_copy(tmp,4,s + (i << 2));
+    byte_copy(s + (i << 2),4,s);
+    byte_copy(s,4,tmp);
+  }
+}
diff -ruN djbdns-1.05-dist/dnscache-conf.c djbdns-1.05/dnscache-conf.c
--- djbdns-1.05-dist/dnscache-conf.c	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/dnscache-conf.c	2008-08-11 19:33:30.000000000 -0700
@@ -32,6 +32,10 @@
 char *user;
 char *loguser;
 struct passwd *pw;
+#ifdef DUMPCACHE
+int useruid;
+int usergid;
+#endif
 const char *myip;
 
 uint32 seed[32];
@@ -81,6 +85,14 @@
   myip = argv[4];
   if (!myip) myip = "127.0.0.1";
 
+#ifdef DUMPCACHE
+  pw = getpwnam(user);
+  seed_addtime();
+  if (!pw)
+    strerr_die3x(111,FATAL,"unknown account ",user);
+  useruid = pw->pw_uid;
+  usergid = pw->pw_gid;
+#endif
   pw = getpwnam(loguser);
   seed_addtime();
   if (!pw)
@@ -120,6 +132,14 @@
   seed_addtime(); perm(0644);
   seed_addtime(); start("env/DATALIMIT"); outs("3000000\n"); finish();
   seed_addtime(); perm(0644);
+#ifdef DUMPCACHE
+  seed_addtime(); start("env/SLURPCACHE"); outs("dump/slurpcache\n"); finish();
+  seed_addtime(); perm(0644);
+  seed_addtime(); start("env/DUMPCACHE"); outs("dump/dumpcache\n"); finish();
+  seed_addtime(); perm(0644);
+  seed_addtime(); start("env/DUMPCACHETMP"); outs("dump/dumpcache.tmp\n"); finish();
+  seed_addtime(); perm(0644);
+#endif
   seed_addtime(); start("run");
   outs("#!/bin/sh\nexec 2>&1\nexec <seed\nexec envdir ./env sh -c '\n  exec envuidgid "); outs(user);
   outs(" softlimit -o250 -d \"$DATALIMIT\" ");
@@ -131,6 +151,11 @@
   seed_addtime(); perm(0755);
   seed_addtime(); makedir("root");
   seed_addtime(); perm(02755);
+#ifdef DUMPCACHE
+  seed_addtime(); makedir("root/dump");
+  seed_addtime(); owner(useruid,usergid);
+  seed_addtime(); perm(02755);
+#endif
   seed_addtime(); makedir("root/ip");
   seed_addtime(); perm(02755);
   seed_addtime(); start("root/ip/127.0.0.1"); finish();
diff -ruN djbdns-1.05-dist/dnscache.c djbdns-1.05/dnscache.c
--- djbdns-1.05-dist/dnscache.c	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/dnscache.c	2008-08-11 19:33:30.000000000 -0700
@@ -5,6 +5,7 @@
 #include "strerr.h"
 #include "error.h"
 #include "ip4.h"
+#include "str.h"
 #include "uint16.h"
 #include "uint64.h"
 #include "socket.h"
@@ -22,6 +23,7 @@
 #include "log.h"
 #include "okclient.h"
 #include "droproot.h"
+#include "sig.h"
 
 static int packetquery(char *buf,unsigned int len,char **q,char qtype[2],char qclass[2],char id[2])
 {
@@ -47,12 +49,20 @@
 
 
 static char myipoutgoing[4];
-static char myipincoming[4];
 static char buf[1024];
 uint64 numqueries = 0;
 
+struct interf {
+  char ip[4];
+  int udp53;
+  int tcp53;
+  iopause_fd *udp53io;
+  iopause_fd *tcp53io;
+  
+  struct interf *next;
+} ;
 
-static int udp53;
+struct interf *interhead = 0;
 
 #define MAXUDP 200
 static struct udpclient {
@@ -60,6 +70,7 @@
   struct taia start;
   uint64 active; /* query number, if active; otherwise 0 */
   iopause_fd *io;
+  int fd;
   char ip[4];
   uint16 port;
   char id[2];
@@ -78,12 +89,12 @@
   if (!u[j].active) return;
   response_id(u[j].id);
   if (response_len > 512) response_tc();
-  socket_send4(udp53,response,response_len,u[j].ip,u[j].port);
+  socket_send4(u[j].fd,response,response_len,u[j].ip,u[j].port);
   log_querydone(&u[j].active,response_len);
   u[j].active = 0; --uactive;
 }
 
-void u_new(void)
+void u_new(int fd)
 {
   int j;
   int i;
@@ -108,8 +119,9 @@
 
   x = u + j;
   taia_now(&x->start);
+  x->fd = fd;
 
-  len = socket_recv4(udp53,buf,sizeof buf,x->ip,&x->port);
+  len = socket_recv4(x->fd,buf,sizeof buf,x->ip,&x->port);
   if (len == -1) return;
   if (len >= sizeof buf) return;
   if (x->port < 1024) if (x->port != 53) return;
@@ -129,8 +141,6 @@
 }
 
 
-static int tcp53;
-
 #define MAXTCP 20
 struct tcpclient {
   struct query q;
@@ -138,6 +148,7 @@
   struct taia timeout;
   uint64 active; /* query number or 1, if active; otherwise 0 */
   iopause_fd *io;
+  int fd;
   char ip[4]; /* send response to this address */
   uint16 port; /* send response to this port */
   char id[2];
@@ -266,7 +277,7 @@
   x->state = 0;
 }
 
-void t_new(void)
+void t_new(int fd)
 {
   int i;
   int j;
@@ -290,8 +301,9 @@
 
   x = t + j;
   taia_now(&x->start);
+  x->fd = fd;
 
-  x->tcp = socket_accept4(tcp53,x->ip,&x->port);
+  x->tcp = socket_accept4(x->fd,x->ip,&x->port);
   if (x->tcp == -1) return;
   if (x->port < 1024) if (x->port != 53) { close(x->tcp); return; }
   if (!okclient(x->ip)) { close(x->tcp); return; }
@@ -304,19 +316,44 @@
   log_tcpopen(x->ip,x->port);
 }
 
+#ifdef DUMPCACHE
+static void do_dump(void)
+{
+  int r;
+  r = cache_dump();
+  if (r < 0)
+    r = errno;
+  log_dump(r);
+}
+#endif
+
+#define FATAL "dnscache: fatal: "
+
+iopause_fd *io = 0;
+int numio;
+
+void hup_me()
+{
+  if (!roots_init())
+    strerr_die2sys(111,FATAL,"unable to read servers: ");
+
+  log_reread();
+}
 
-iopause_fd io[3 + MAXUDP + MAXTCP];
-iopause_fd *udp53io;
-iopause_fd *tcp53io;
 
 static void doit(void)
 {
   int j;
   struct taia deadline;
   struct taia stamp;
+  struct interf *inter;
   int iolen;
   int r;
 
+  io = (iopause_fd *) alloc((numio + 1 + MAXUDP + MAXTCP) * sizeof(iopause_fd));
+  if (!io)
+    strerr_die2sys(111,FATAL,"unable to alloc io: ");
+
   for (;;) {
     taia_now(&stamp);
     taia_uint(&deadline,120);
@@ -324,13 +361,15 @@
 
     iolen = 0;
 
-    udp53io = io + iolen++;
-    udp53io->fd = udp53;
-    udp53io->events = IOPAUSE_READ;
-
-    tcp53io = io + iolen++;
-    tcp53io->fd = tcp53;
-    tcp53io->events = IOPAUSE_READ;
+    for (inter = interhead; inter != 0; inter = inter->next) {
+      inter->udp53io = io + iolen++;
+      inter->udp53io->fd = inter->udp53;
+      inter->udp53io->events = IOPAUSE_READ;
+
+      inter->tcp53io = io + iolen++;
+      inter->tcp53io->fd = inter->tcp53;
+      inter->tcp53io->events = IOPAUSE_READ;
+    }
 
     for (j = 0;j < MAXUDP;++j)
       if (u[j].active) {
@@ -372,46 +411,83 @@
 	    t_rw(j);
       }
 
-    if (udp53io)
-      if (udp53io->revents)
-	u_new();
-
-    if (tcp53io)
-      if (tcp53io->revents)
-	t_new();
+    for (inter = interhead; inter != 0; inter = inter->next) {
+      if (inter->udp53io)
+        if (inter->udp53io->revents)
+	  u_new(inter->udp53);
+
+      if (inter->tcp53io)
+        if (inter->tcp53io->revents)
+	  t_new(inter->tcp53);
+    }
   }
 }
   
-#define FATAL "dnscache: fatal: "
-
 char seed[128];
 
 int main()
 {
   char *x;
+  char nxdip[4];
+  int len;
+  int pos;
+  int oldpos;
+  char iptmp[4];
+  char iperr[IP4_FMT];
+  struct interf *inter;
+  struct interf *itmp;
   unsigned long cachesize;
 
   x = env_get("IP");
   if (!x)
     strerr_die2x(111,FATAL,"$IP not set");
-  if (!ip4_scan(x,myipincoming))
-    strerr_die3x(111,FATAL,"unable to parse IP address ",x);
 
-  udp53 = socket_udp();
-  if (udp53 == -1)
-    strerr_die2sys(111,FATAL,"unable to create UDP socket: ");
-  if (socket_bind4_reuse(udp53,myipincoming,53) == -1)
-    strerr_die2sys(111,FATAL,"unable to bind UDP socket: ");
-
-  tcp53 = socket_tcp();
-  if (tcp53 == -1)
-    strerr_die2sys(111,FATAL,"unable to create TCP socket: ");
-  if (socket_bind4_reuse(tcp53,myipincoming,53) == -1)
-    strerr_die2sys(111,FATAL,"unable to bind TCP socket: ");
+  len = str_len(x);
+  numio = pos = oldpos = 0;
+  
+  while (pos < len) {
+    if (pos) oldpos = pos + 1;
+    pos = oldpos + str_chr(x + oldpos,'/');
+    x[pos] = 0;
+    if (!str_len(x + oldpos)) continue;
+    
+    if (!ip4_scan(x + oldpos,iptmp))
+      strerr_die3x(111,FATAL,"unable to parse IP address ",x + oldpos);
+      
+    inter = (struct interf *) alloc(sizeof(struct interf));
+    
+    if (interhead == 0) interhead = inter;
+    else if (interhead->next == 0) interhead->next = inter;
+    else {
+      for (itmp = interhead; itmp->next != 0; itmp = itmp->next);
+      itmp->next = inter;
+    }
+    
+    inter->next = 0;
+    
+    inter->udp53 = socket_udp();
+    if (inter->udp53 == -1)
+      strerr_die4sys(111,FATAL,"unable to create UDP socket for IP address ",x + oldpos,": ");
+    if (socket_bind4_reuse(inter->udp53,iptmp,53) == -1)
+      strerr_die4sys(111,FATAL,"unable to bind UDP socket for IP address ",x + oldpos,": ");
+      
+    inter->tcp53 = socket_tcp();
+    if (inter->tcp53 == -1)
+      strerr_die4sys(111,FATAL,"unable to create TCP socket for IP address ",x + oldpos,": ");
+    if (socket_bind4_reuse(inter->tcp53,iptmp,53) == -1)
+      strerr_die4sys(111,FATAL,"unable to bind TCP socket for IP address ",x + oldpos,": ");
+      
+    numio++;
+    log_listen(iptmp);
+  }
+
+  if (interhead == 0)
+    strerr_die2x(111,FATAL,"no interfaces to listen on");
 
   droproot(FATAL);
 
-  socket_tryreservein(udp53,131072);
+  for (inter = interhead; inter != 0; inter = inter->next)
+    socket_tryreservein(inter->udp53,131072);
 
   byte_zero(seed,sizeof seed);
   read(0,seed,sizeof seed);
@@ -430,17 +506,42 @@
   scan_ulong(x,&cachesize);
   if (!cache_init(cachesize))
     strerr_die3x(111,FATAL,"not enough memory for cache of size ",x);
+#ifdef DUMPCACHE
+  x = env_get("SLURPCACHE");
+  if (x) {
+    int nb = cache_slurp(x);
+    if (nb < 0)
+      strerr_die4sys(111,FATAL,"unable to slurp cache ",x," : ");
+    else
+      log_slurp(nb);
+  }
+#endif
 
   if (env_get("HIDETTL"))
     response_hidettl();
   if (env_get("FORWARDONLY"))
     query_forwardonly();
 
+  x = env_get("NXDSPECIAL");
+  if (x) {
+    if (!ip4_scan(x,nxdip))
+      strerr_die3x(111,FATAL,"unable to parse NXDSPECIAL IP address ",x);
+    query_nxdspecial(nxdip);
+  }
+
   if (!roots_init())
     strerr_die2sys(111,FATAL,"unable to read servers: ");
 
-  if (socket_listen(tcp53,20) == -1)
-    strerr_die2sys(111,FATAL,"unable to listen on TCP socket: ");
+  for (inter = interhead; inter != 0; inter = inter->next)
+    if (socket_listen(inter->tcp53,20) == -1) {
+      iperr[ip4_fmt(iperr,inter->ip)] = 0;
+      strerr_die4sys(111,FATAL,"unable to listen on TCP socket for IP ",iperr,": ");
+    }
+
+#ifdef DUMPCACHE
+  sig_catch(sig_alarm,do_dump);
+#endif
+  sig_catch(sig_hangup, hup_me);
 
   log_startup();
   doit();
diff -ruN djbdns-1.05-dist/dnsfilter.c djbdns-1.05/dnsfilter.c
--- djbdns-1.05-dist/dnsfilter.c	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/dnsfilter.c	2008-08-11 19:33:30.000000000 -0700
@@ -41,6 +41,7 @@
 iopause_fd *inio;
 int flag0 = 1;
 
+int opt_replace = 0;
 iopause_fd *io;
 int iolen;
 
@@ -51,12 +52,16 @@
 void errout(int i)
 {
   int j;
-
-  if (!stralloc_copys(&x[i].middle,":")) nomem();
-  if (!stralloc_cats(&x[i].middle,error_str(errno))) nomem();
-  for (j = 0;j < x[i].middle.len;++j)
-    if (x[i].middle.s[j] == ' ')
-      x[i].middle.s[j] = '-';
+ 
+  if (opt_replace) 
+    x[i].middle.len=0;
+  else {
+    if (!stralloc_copys(&x[i].middle,":")) nomem();
+    if (!stralloc_cats(&x[i].middle,error_str(errno))) nomem();
+    for (j = 0;j < x[i].middle.len;++j)
+      if (x[i].middle.s[j] == ' ')
+        x[i].middle.s[j] = '-';
+  }
 }
 
 int main(int argc,char **argv)
@@ -69,7 +74,7 @@
   int j;
   int r;
 
-  while ((opt = getopt(argc,argv,"c:l:")) != opteof)
+  while ((opt = getopt(argc,argv,"c:l:r")) != opteof)
     switch(opt) {
       case 'c':
 	scan_ulong(optarg,&u);
@@ -83,8 +88,11 @@
 	if (u > 1000000) u = 1000000;
 	xmax = u;
 	break;
+      case 'r':
+	opt_replace = 1;	  
+	break;
       default:
-	strerr_die1x(111,"dnsfilter: usage: dnsfilter [ -c concurrency ] [ -l lines ]");
+	strerr_die1x(111,"dnsfilter: usage: dnsfilter [ -c concurrency ] [ -l lines ] [-r]");
     }
 
   x = (struct line *) alloc(xmax * sizeof(struct line));
@@ -140,8 +148,13 @@
 	else if (r == 1) {
 	  if (dns_name_packet(&x[i].middle,x[i].dt.packet,x[i].dt.packetlen) == -1)
 	    errout(i);
-	  if (x[i].middle.len)
-	    if (!stralloc_cats(&x[i].left,"=")) nomem();
+	  if (x[i].middle.len) {
+	    if (opt_replace) {
+	      if (!stralloc_copys(&x[i].left, "")) nomem();
+	    } else {
+	      if (!stralloc_cats(&x[i].left, "=")) nomem();
+	    }
+	  }
 	  x[i].flagactive = 0;
 	  --numactive;
 	}
diff -ruN djbdns-1.05-dist/hasdevtcp.h djbdns-1.05/hasdevtcp.h
--- djbdns-1.05-dist/hasdevtcp.h	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/hasdevtcp.h	2008-08-11 22:55:09.000000000 -0700
@@ -0,0 +1 @@
+/* sysdep: -devtcp */
diff -ruN djbdns-1.05-dist/hassgact.h djbdns-1.05/hassgact.h
--- djbdns-1.05-dist/hassgact.h	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/hassgact.h	2008-08-11 22:55:16.000000000 -0700
@@ -0,0 +1,2 @@
+/* sysdep: +sigaction */
+#define HASSIGACTION 1
diff -ruN djbdns-1.05-dist/hassgact.h1 djbdns-1.05/hassgact.h1
--- djbdns-1.05-dist/hassgact.h1	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/hassgact.h1	2008-08-11 19:33:30.000000000 -0700
@@ -0,0 +1 @@
+/* sysdep: -sigaction */
diff -ruN djbdns-1.05-dist/hassgact.h2 djbdns-1.05/hassgact.h2
--- djbdns-1.05-dist/hassgact.h2	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/hassgact.h2	2008-08-11 19:33:30.000000000 -0700
@@ -0,0 +1,2 @@
+/* sysdep: +sigaction */
+#define HASSIGACTION 1
diff -ruN djbdns-1.05-dist/hassgprm.h djbdns-1.05/hassgprm.h
--- djbdns-1.05-dist/hassgprm.h	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/hassgprm.h	2008-08-11 22:55:15.000000000 -0700
@@ -0,0 +1,2 @@
+/* sysdep: +sigprocmask */
+#define HASSIGPROCMASK 1
diff -ruN djbdns-1.05-dist/hassgprm.h1 djbdns-1.05/hassgprm.h1
--- djbdns-1.05-dist/hassgprm.h1	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/hassgprm.h1	2008-08-11 19:33:30.000000000 -0700
@@ -0,0 +1 @@
+/* sysdep: -sigprocmask */
diff -ruN djbdns-1.05-dist/hassgprm.h2 djbdns-1.05/hassgprm.h2
--- djbdns-1.05-dist/hassgprm.h2	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/hassgprm.h2	2008-08-11 19:33:30.000000000 -0700
@@ -0,0 +1,2 @@
+/* sysdep: +sigprocmask */
+#define HASSIGPROCMASK 1
diff -ruN djbdns-1.05-dist/hasshsgr.h djbdns-1.05/hasshsgr.h
--- djbdns-1.05-dist/hasshsgr.h	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/hasshsgr.h	2008-08-12 09:17:24.000000000 -0700
@@ -0,0 +1 @@
+/* sysdep: -shortsetgroups */
diff -ruN djbdns-1.05-dist/iopause.h djbdns-1.05/iopause.h
--- djbdns-1.05-dist/iopause.h	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/iopause.h	2008-08-11 22:55:12.000000000 -0700
@@ -0,0 +1,18 @@
+#ifndef IOPAUSE_H
+#define IOPAUSE_H
+
+/* sysdep: +poll */
+#define IOPAUSE_POLL
+
+#include <sys/types.h>
+#include <poll.h>
+
+typedef struct pollfd iopause_fd;
+#define IOPAUSE_READ POLLIN
+#define IOPAUSE_WRITE POLLOUT
+
+#include "taia.h"
+
+extern void iopause(iopause_fd *,unsigned int,struct taia *,struct taia *);
+
+#endif
diff -ruN djbdns-1.05-dist/log.c djbdns-1.05/log.c
--- djbdns-1.05-dist/log.c	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/log.c	2008-08-11 19:33:30.000000000 -0700
@@ -88,12 +88,39 @@
   }
 }
 
+void log_reread(void)
+{
+  string("rereading servers configuration");
+  line();
+}
+
 void log_startup(void)
 {
   string("starting");
   line();
 }
 
+void log_listen(const char addr[4])
+{
+  string("listening on ");
+  ip(addr);
+  line();
+}
+
+#ifdef DUMPCACHE
+void log_slurp(int nb)
+{
+  string("slurp "); number(nb);
+  line();
+}
+
+void log_dump(int err)
+{
+  string("dump err "); number(err);
+  line();
+}
+#endif
+
 void log_query(uint64 *qnum,const char client[4],unsigned int port,const char id[2],const char *q,const char qtype[2])
 {
   string("query "); number(*qnum); space();
diff -ruN djbdns-1.05-dist/log.h djbdns-1.05/log.h
--- djbdns-1.05-dist/log.h	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/log.h	2008-08-11 19:33:30.000000000 -0700
@@ -4,6 +4,12 @@
 #include "uint64.h"
 
 extern void log_startup(void);
+extern void log_listen(const char *);
+#ifdef DUMPCACHE
+extern void log_slurp(int);
+extern void log_dump(int);
+#endif
+extern void log_reread(void);
 
 extern void log_query(uint64 *,const char *,unsigned int,const char *,const char *,const char *);
 extern void log_querydrop(uint64 *);
diff -ruN djbdns-1.05-dist/okclient.c djbdns-1.05/okclient.c
--- djbdns-1.05-dist/okclient.c	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/okclient.c	2008-08-11 19:33:30.000000000 -0700
@@ -1,5 +1,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
+#include "env.h"
 #include "str.h"
 #include "ip4.h"
 #include "okclient.h"
@@ -10,6 +11,14 @@
 {
   struct stat st;
   int i;
+  static int init_done=0;
+  if (!init_done) {
+    if (env_get("OKCLIENT")) {
+      init_done=1;
+    } else
+      init_done=2;
+  }
+  if (init_done==1) return 1;
 
   fn[0] = 'i';
   fn[1] = 'p';
diff -ruN djbdns-1.05-dist/parsetype.c djbdns-1.05/parsetype.c
--- djbdns-1.05-dist/parsetype.c	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/parsetype.c	2008-08-11 22:49:52.000000000 -0700
@@ -24,6 +24,8 @@
   else if (case_equals(s,"key")) byte_copy(type,2,DNS_T_KEY);
   else if (case_equals(s,"aaaa")) byte_copy(type,2,DNS_T_AAAA);
   else if (case_equals(s,"axfr")) byte_copy(type,2,DNS_T_AXFR);
+  else if (case_equals(s,"srv")) byte_copy(type,2,DNS_T_SRV);
+  else if (case_equals(s,"naptr")) byte_copy(type,2,DNS_T_NAPTR);
   else
     return 0;
 
diff -ruN djbdns-1.05-dist/printrecord.c djbdns-1.05/printrecord.c
--- djbdns-1.05-dist/printrecord.c	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/printrecord.c	2008-08-11 23:10:20.000000000 -0700
@@ -82,6 +82,56 @@
       if (!stralloc_catulong0(out,ch,0)) return 0;
     }
   }
+  else if (byte_equal(misc,2,DNS_T_SRV)) {
+    if (!stralloc_cats(out," SRV ")) return 0;
+    pos = dns_packet_copy(buf,len,pos,misc,2); if (!pos) return 0;
+    uint16_unpack_big(misc,&u16);
+    if (!stralloc_catulong0(out,u16,0)) return 0;
+    if (!stralloc_cats(out," ")) return 0;
+    pos = dns_packet_copy(buf,len,pos,misc,2); if (!pos) return 0;
+    uint16_unpack_big(misc,&u16);
+    if (!stralloc_catulong0(out,u16,0)) return 0;
+    if (!stralloc_cats(out," ")) return 0;
+    pos = dns_packet_copy(buf,len,pos,misc,2); if (!pos) return 0;
+    uint16_unpack_big(misc,&u16);
+    if (!stralloc_catulong0(out,u16,0)) return 0;
+    if (!stralloc_cats(out," ")) return 0;
+    pos = dns_packet_getname(buf,len,pos,&d); if (!pos) return 0;
+    if (!dns_domain_todot_cat(out,d)) return 0;
+  }
+  else if (byte_equal(misc,2,DNS_T_NAPTR)) {
+    char str[255];
+    unsigned int oldpos;
+    if (!stralloc_cats(out," NAPTR ")) return 0;
+    pos = dns_packet_copy(buf,len,pos,misc,2); if (!pos) return 0;
+    uint16_unpack_big(misc,&u16);
+    if (!stralloc_catulong0(out,u16,0)) return 0;
+    if (!stralloc_cats(out," ")) return 0;
+    pos = dns_packet_copy(buf,len,pos,misc,2); if (!pos) return 0;
+    uint16_unpack_big(misc,&u16);
+    if (!stralloc_catulong0(out,u16,0)) return 0;
+    if (!stralloc_cats(out," ")) return 0;
+    pos = dns_packet_copy(buf,len,pos,&ch,1); if (!pos) return 0;
+    pos = dns_packet_copy(buf,len,pos,str,ch); if (!pos) return 0;
+    if (!stralloc_cats(out,"\"")) return 0;
+    if (!stralloc_catb(out,str,ch)) return 0;
+    if (!stralloc_cats(out,"\" ")) return 0;
+    pos = dns_packet_copy(buf,len,pos,&ch,1); if (!pos) return 0;
+    pos = dns_packet_copy(buf,len,pos,str,ch); if (!pos) return 0;
+    if (!stralloc_cats(out,"\"")) return 0;
+    if (!stralloc_catb(out,str,ch)) return 0;
+    if (!stralloc_cats(out,"\" ")) return 0;
+    pos = dns_packet_copy(buf,len,pos,&ch,1); if (!pos) return 0;
+    pos = dns_packet_copy(buf,len,pos,str,ch); if (!pos) return 0;
+    if (!stralloc_cats(out,"\"")) return 0;
+    if (!stralloc_catb(out,str,ch)) return 0;
+    if (!stralloc_cats(out,"\" ")) return 0;
+    pos = dns_packet_getname(buf,len,pos,&d); if (!pos) return 0;
+    oldpos = out->len;
+    if (!dns_domain_todot_cat(out,d)) return 0;
+    if (out->len == oldpos)
+      if (!stralloc_cats(out,".")) return 0;
+  }
   else {
     if (!stralloc_cats(out," ")) return 0;
     uint16_unpack_big(misc,&u16);
diff -ruN djbdns-1.05-dist/prot.c djbdns-1.05/prot.c
--- djbdns-1.05-dist/prot.c	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/prot.c	2008-08-11 19:33:30.000000000 -0700
@@ -1,5 +1,7 @@
 #include "hasshsgr.h"
 #include "prot.h"
+#include <grp.h>
+#include <unistd.h>
 
 int prot_gid(int gid)
 {
diff -ruN djbdns-1.05-dist/query.c djbdns-1.05/query.c
--- djbdns-1.05-dist/query.c	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/query.c	2008-08-11 19:33:30.000000000 -0700
@@ -20,6 +20,15 @@
   flagforwardonly = 1;
 }
 
+static int flagnxdspecial = 0;
+static char nxdip[4];
+
+void query_nxdspecial(const char ip[4])
+{
+  byte_copy(nxdip,4,ip);
+  flagnxdspecial = 1;
+}
+
 static void cachegeneric(const char type[2],const char *d,const char *data,unsigned int datalen,uint32 ttl)
 {
   unsigned int len;
@@ -246,6 +255,7 @@
     case_lowerb(key + 2,dlen);
     cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
     if (cached) {
+      soattl = rcode = 0;
       log_cachednxdomain(d);
       goto NXDOMAIN;
     }
@@ -695,7 +705,12 @@
     NXDOMAIN:
     if (z->level) goto LOWERLEVEL;
     if (!rqa(z)) goto DIE;
-    response_nxdomain();
+    if (flagnxdspecial && typematch(DNS_T_A,dtype)) {
+      if (!response_rstart(d,DNS_T_A,rcode == 3 ? soattl : ttl)) goto DIE;
+      if (!response_addbytes(nxdip,4)) goto DIE;
+      response_rfinish(RESPONSE_ANSWER);
+    } else
+      response_nxdomain();
     cleanup(z);
     return 1;
   }
diff -ruN djbdns-1.05-dist/query.h djbdns-1.05/query.h
--- djbdns-1.05-dist/query.h	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/query.h	2008-08-11 19:33:30.000000000 -0700
@@ -28,5 +28,6 @@
 extern int query_get(struct query *,iopause_fd *,struct taia *);
 
 extern void query_forwardonly(void);
+extern void query_nxdspecial(const char *);
 
 #endif
diff -ruN djbdns-1.05-dist/seek_set.c djbdns-1.05/seek_set.c
--- djbdns-1.05-dist/seek_set.c	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/seek_set.c	2008-08-11 19:33:30.000000000 -0700
@@ -1,4 +1,5 @@
 #include <sys/types.h>
+#include <unistd.h>
 #include "seek.h"
 
 #define SET 0 /* sigh */
diff -ruN djbdns-1.05-dist/select.h djbdns-1.05/select.h
--- djbdns-1.05-dist/select.h	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/select.h	2008-08-11 22:55:14.000000000 -0700
@@ -0,0 +1,11 @@
+#ifndef SELECT_H
+#define SELECT_H
+
+/* sysdep: +sysselect */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/select.h>
+extern int select();
+
+#endif
diff -ruN djbdns-1.05-dist/server.c djbdns-1.05/server.c
--- djbdns-1.05-dist/server.c	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/server.c	2008-08-11 19:33:30.000000000 -0700
@@ -11,6 +11,8 @@
 #include "qlog.h"
 #include "response.h"
 #include "dns.h"
+#include "alloc.h"
+#include "iopause.h"
 
 extern char *fatal;
 extern char *starting;
@@ -25,6 +27,44 @@
 
 static char *q;
 
+
+static void hex(unsigned char c)
+{
+  buffer_put(buffer_2,"0123456789abcdef" + (c >> 4),1);
+  buffer_put(buffer_2,"0123456789abcdef" + (c & 15),1);
+}
+
+static void put_ip(const char i[4])
+{
+  hex(i[0]);
+  hex(i[1]);
+  hex(i[2]);
+  hex(i[3]);
+}
+
+static void string(const char *s)
+{
+  buffer_puts(buffer_2,s);
+}
+
+static void line(void)
+{
+  string("\n");
+  buffer_flush(buffer_2);
+}
+
+void log_listen(const char addr[4])
+{
+  string("listening on ");
+  put_ip(addr);
+  line();
+}
+
+void nomem()
+{
+  strerr_die2x(111,fatal,"out of memory");
+}
+
 static int doit(void)
 {
   unsigned int pos;
@@ -51,6 +91,13 @@
   response[3] &= ~128;
   if (!(header[2] & 1)) response[2] &= ~1;
 
+  if ((header[2] & 126) == 0x24) /* NOTIFY + AA */
+    if (byte_equal(qtype,2,DNS_T_SOA)) {
+      response[2] |= 0x20; /* NOTIFY */
+      qlog(ip,port,header,q,qtype," N ");
+      return 1;
+    }
+
   if (header[2] & 126) goto NOTIMP;
   if (byte_equal(qtype,2,DNS_T_AXFR)) goto NOTIMP;
 
@@ -59,7 +106,12 @@
     qlog(ip,port,header,q,qtype," - ");
     return 0;
   }
-  qlog(ip,port,header,q,qtype," + ");
+
+  if ((response[2] & 4) && (response[3] & 3))
+    qlog(ip,port,header,q,qtype," X ");
+  else
+    qlog(ip,port,header,q,qtype," + ");
+
   return 1;
 
   NOTIMP:
@@ -82,35 +134,75 @@
 int main()
 {
   char *x;
-  int udp53;
+  int *udp53;
+  unsigned int off;
+  unsigned int cnt;
+  iopause_fd *iop;
 
   x = env_get("IP");
   if (!x)
     strerr_die2x(111,fatal,"$IP not set");
-  if (!ip4_scan(x,ip))
-    strerr_die3x(111,fatal,"unable to parse IP address ",x);
-
-  udp53 = socket_udp();
-  if (udp53 == -1)
-    strerr_die2sys(111,fatal,"unable to create UDP socket: ");
-  if (socket_bind4_reuse(udp53,ip,53) == -1)
-    strerr_die2sys(111,fatal,"unable to bind UDP socket: ");
+  off=0;
+  cnt=0;
+  while (x[off]) {
+    unsigned int l;
+    char dummy[4];
+    l=ip4_scan(x+off,dummy);
+	if (!l)
+      strerr_die3x(111,fatal,"unable to parse IP address ",x+off);
+	cnt++;
+	if (!x[off+l]) break;
+	if (x[off+l]!='/')
+      strerr_die3x(111,fatal,"unable to parse IP address ",x+off);
+	off+=l+1;
+  }
+  udp53=(int *) alloc(sizeof(int) *cnt);
+  if (!udp53) nomem();
+  iop=(iopause_fd *) alloc(sizeof(*iop) * cnt);
+  if (!iop) nomem();
+
+  off=0;
+  cnt=0;
+  while (x[off]) {
+    unsigned int l;
+    l=ip4_scan(x+off,ip);
+    udp53[cnt] = socket_udp();
+    if (udp53[cnt] == -1)
+      strerr_die2sys(111,fatal,"unable to create UDP socket: ");
+    if (socket_bind4_reuse(udp53[cnt],ip,53) == -1)
+      strerr_die2sys(111,fatal,"unable to bind UDP socket: ");
+    ndelay_off(udp53[cnt]);
+    socket_tryreservein(udp53[cnt],65536);
+    iop[cnt].fd=udp53[cnt];
+    iop[cnt].events=IOPAUSE_READ;
+    log_listen(ip);
+    cnt++;
+    if (!x[off+l]) break;
+    off+=l+1;
+  }
 
   droproot(fatal);
 
   initialize();
-  
-  ndelay_off(udp53);
-  socket_tryreservein(udp53,65536);
 
   buffer_putsflush(buffer_2,starting);
-
+  
   for (;;) {
-    len = socket_recv4(udp53,buf,sizeof buf,ip,&port);
-    if (len < 0) continue;
-    if (!doit()) continue;
-    if (response_len > 512) response_tc();
-    socket_send4(udp53,response,response_len,ip,port);
-    /* may block for buffer space; if it fails, too bad */
+    struct taia stamp;
+    struct taia deadline;
+	unsigned int i;
+    taia_now(&stamp);
+    taia_uint(&deadline,300);
+    taia_add(&deadline,&deadline,&stamp);
+    iopause(iop,cnt,&deadline,&stamp);
+	for (i=0;i<cnt;i++)
+	  if (iop[i].revents) {
+        len = socket_recv4(udp53[i],buf,sizeof buf,ip,&port);
+        if (len < 0) continue;
+        if (!doit()) continue;
+        if (response_len > 512) response_tc();
+        socket_send4(udp53[i],response,response_len,ip,port);
+        /* may block for buffer space; if it fails, too bad */
+	  }
   }
 }
diff -ruN djbdns-1.05-dist/sig.c djbdns-1.05/sig.c
--- djbdns-1.05-dist/sig.c	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/sig.c	2008-08-11 19:33:30.000000000 -0700
@@ -0,0 +1,12 @@
+#include <signal.h>
+#include "sig.h"
+
+int sig_alarm = SIGALRM;
+int sig_child = SIGCHLD;
+int sig_cont = SIGCONT;
+int sig_hangup = SIGHUP;
+int sig_pipe = SIGPIPE;
+int sig_term = SIGTERM;
+
+void (*sig_defaulthandler)() = SIG_DFL;
+void (*sig_ignorehandler)() = SIG_IGN;
diff -ruN djbdns-1.05-dist/sig.h djbdns-1.05/sig.h
--- djbdns-1.05-dist/sig.h	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/sig.h	2008-08-11 19:33:30.000000000 -0700
@@ -0,0 +1,25 @@
+#ifndef SIG_H
+#define SIG_H
+
+extern int sig_alarm;
+extern int sig_child;
+extern int sig_cont;
+extern int sig_hangup;
+extern int sig_pipe;
+extern int sig_term;
+
+extern void (*sig_defaulthandler)();
+extern void (*sig_ignorehandler)();
+
+extern void sig_catch(int,void (*)());
+#define sig_ignore(s) (sig_catch((s),sig_ignorehandler))
+#define sig_uncatch(s) (sig_catch((s),sig_defaulthandler))
+
+extern void sig_block(int);
+extern void sig_unblock(int);
+extern void sig_blocknone(void);
+extern void sig_pause(void);
+
+extern void sig_dfl(int);
+
+#endif
diff -ruN djbdns-1.05-dist/sig_block.c djbdns-1.05/sig_block.c
--- djbdns-1.05-dist/sig_block.c	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/sig_block.c	2008-08-11 19:33:30.000000000 -0700
@@ -0,0 +1,38 @@
+#include <signal.h>
+#include "sig.h"
+#include "hassgprm.h"
+
+void sig_block(int sig)
+{
+#ifdef HASSIGPROCMASK
+  sigset_t ss;
+  sigemptyset(&ss);
+  sigaddset(&ss,sig);
+  sigprocmask(SIG_BLOCK,&ss,(sigset_t *) 0);
+#else
+  sigblock(1 << (sig - 1));
+#endif
+}
+
+void sig_unblock(int sig)
+{
+#ifdef HASSIGPROCMASK
+  sigset_t ss;
+  sigemptyset(&ss);
+  sigaddset(&ss,sig);
+  sigprocmask(SIG_UNBLOCK,&ss,(sigset_t *) 0);
+#else
+  sigsetmask(sigsetmask(~0) & ~(1 << (sig - 1)));
+#endif
+}
+
+void sig_blocknone(void)
+{
+#ifdef HASSIGPROCMASK
+  sigset_t ss;
+  sigemptyset(&ss);
+  sigprocmask(SIG_SETMASK,&ss,(sigset_t *) 0);
+#else
+  sigsetmask(0);
+#endif
+}
diff -ruN djbdns-1.05-dist/sig_catch.c djbdns-1.05/sig_catch.c
--- djbdns-1.05-dist/sig_catch.c	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/sig_catch.c	2008-08-11 19:33:30.000000000 -0700
@@ -0,0 +1,16 @@
+#include <signal.h>
+#include "sig.h"
+#include "hassgact.h"
+
+void sig_catch(int sig,void (*f)())
+{
+#ifdef HASSIGACTION
+  struct sigaction sa;
+  sa.sa_handler = f;
+  sa.sa_flags = 0;
+  sigemptyset(&sa.sa_mask);
+  sigaction(sig,&sa,(struct sigaction *) 0);
+#else
+  signal(sig,f); /* won't work under System V, even nowadays---dorks */
+#endif
+}
diff -ruN djbdns-1.05-dist/sig_pause.c djbdns-1.05/sig_pause.c
--- djbdns-1.05-dist/sig_pause.c	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/sig_pause.c	2008-08-11 19:33:30.000000000 -0700
@@ -0,0 +1,14 @@
+#include <signal.h>
+#include "sig.h"
+#include "hassgprm.h"
+
+void sig_pause(void)
+{
+#ifdef HASSIGPROCMASK
+  sigset_t ss;
+  sigemptyset(&ss);
+  sigsuspend(&ss);
+#else
+  sigpause(0);
+#endif
+}
diff -ruN djbdns-1.05-dist/tinydns-data.c djbdns-1.05/tinydns-data.c
--- djbdns-1.05-dist/tinydns-data.c	2008-08-11 19:32:53.000000000 -0700
+++ djbdns-1.05/tinydns-data.c	2008-08-11 22:56:09.000000000 -0700
@@ -159,11 +159,7 @@
     die_datatmp();
 }
 
-buffer b;
-char bspace[1024];
-
 static stralloc line;
-int match = 1;
 unsigned long linenum = 0;
 
 #define NUMFIELDS 15
@@ -171,6 +167,8 @@
 
 static char *d1;
 static char *d2;
+static char *contact;
+
 char dptr[DNS_NAME4_DOMAIN];
 
 char strnum[FMT_ULONG];
@@ -181,7 +179,7 @@
   strerr_die4x(111,FATAL,"unable to parse data line ",strnum,why);
 }
 
-int main()
+int load(const char *fname)
 {
   int fddata;
   int i;
@@ -196,20 +194,20 @@
   char type[2];
   char soa[20];
   char buf[4];
+  char naptr[4];
+  char srv[6];
+  int match;
+  buffer b;
+  char bspace[1024];
 
-  umask(022);
-
-  fddata = open_read("data");
+  fddata = open_read(fname);
   if (fddata == -1)
-    strerr_die2sys(111,FATAL,"unable to open data: ");
+    strerr_die4sys(111,FATAL,"unable to open ",fname,": ");
   defaultsoa_init(fddata);
 
   buffer_init(&b,buffer_unixread,fddata,bspace,sizeof bspace);
 
-  fdcdb = open_trunc("data.tmp");
-  if (fdcdb == -1) die_datatmp();
-  if (cdb_make_start(&cdb,fdcdb) == -1) die_datatmp();
-
+  match = 1;
   while (match) {
     ++linenum;
     if (getln(&b,&line,&match,'\n') == -1)
@@ -247,6 +245,11 @@
           die_datatmp();
 	break;
 
+      case 'D':
+       if (!dns_domain_fromdot(&contact,f[0].s,f[0].len)) nomem();
+       if (f[0].len == 0) contact = NULL;
+       break;
+
       case 'Z':
 	if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
 
@@ -298,8 +301,13 @@
 	if (line.s[0] == '.') {
 	  rr_start(DNS_T_SOA,ttl ? TTL_NEGATIVE : 0,ttd,loc);
 	  rr_addname(d2);
-	  rr_add("\12hostmaster",11);
-	  rr_addname(d1);
+          if (!contact) {
+            rr_add("\12hostmaster",11);
+            rr_addname(d1);
+          } else {
+            rr_addname(contact);
+          }
+	  
 	  rr_add(defaultsoa,20);
 	  rr_finish(d1);
 	}
@@ -369,6 +377,43 @@
 	  rr_finish(d2);
 	}
 	break;
+	
+      case 'S':
+	if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
+	if (!stralloc_0(&f[6])) nomem();
+	if (!scan_ulong(f[6].s,&ttl)) ttl = TTL_POSITIVE;
+	ttdparse(&f[7],ttd);
+	locparse(&f[8],loc);
+
+	if (!stralloc_0(&f[1])) nomem();
+
+	if (byte_chr(f[2].s,f[2].len,'.') >= f[2].len) {
+	  if (!stralloc_cats(&f[2],".srv.")) nomem();
+	  if (!stralloc_catb(&f[2],f[0].s,f[0].len)) nomem();
+	}
+	if (!dns_domain_fromdot(&d2,f[2].s,f[2].len)) nomem();
+
+	if (!stralloc_0(&f[4])) nomem();
+	if (!scan_ulong(f[4].s,&u)) u = 0;
+	uint16_pack_big(srv,u);
+	if (!stralloc_0(&f[5])) nomem();
+	if (!scan_ulong(f[5].s,&u)) u = 0;
+	uint16_pack_big(srv + 2,u);
+	if (!stralloc_0(&f[3])) nomem();
+	if (!scan_ulong(f[3].s,&u)) nomem();
+	uint16_pack_big(srv + 4,u);
+
+	rr_start(DNS_T_SRV,ttl,ttd,loc);
+	rr_add(srv,6);
+	rr_addname(d2);
+	rr_finish(d1);
+
+	if (ip4_scan(f[1].s,ip)) {
+	  rr_start(DNS_T_A,ttl,ttd,loc);
+	  rr_add(ip,4);
+	  rr_finish(d2);
+	}
+	break;
 
       case '^': case 'C':
 	if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
@@ -441,10 +486,61 @@
 	rr_finish(d1);
 	break;
 
+      case 'N':
+       if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
+       if (!dns_domain_fromdot(&d2,f[6].s,f[6].len)) nomem();
+       if (!stralloc_0(&f[7])) nomem();
+       if (!scan_ulong(f[7].s,&ttl)) ttl = TTL_POSITIVE;
+       ttdparse(&f[8],ttd);
+       locparse(&f[9],loc);
+
+       if (!stralloc_0(&f[1])) nomem();
+       if (!scan_ulong(f[1].s,&u)) u = 0;
+       uint16_pack_big(naptr,u);
+       if (!stralloc_0(&f[2])) nomem();
+       if (!scan_ulong(f[2].s,&u)) u = 0;
+       uint16_pack_big(naptr + 2,u);
+
+       txtparse(&f[3]); if (f[3].len > 255)
+         syntaxerror(": it is not allowed more than 255 chars in a label");
+       txtparse(&f[4]); if (f[4].len > 255)
+         syntaxerror(": it is not allowed more than 255 chars in a label");
+       txtparse(&f[5]); if (f[5].len > 255)
+         syntaxerror(": it is not allowed more than 255 chars in a label");
+
+       rr_start(DNS_T_NAPTR,ttl,ttd,loc);
+       rr_add(naptr,4);
+
+       ch = f[3].len; rr_add(&ch,1);
+       rr_add(f[3].s, f[3].len);
+       ch = f[4].len; rr_add(&ch,1);
+       rr_add(f[4].s, f[4].len);
+       ch = f[5].len; rr_add(&ch,1);
+       rr_add(f[5].s, f[5].len);
+
+       rr_addname(d2);
+       rr_finish(d1);
+       break;
+
       default:
         syntaxerror(": unrecognized leading character");
     }
   }
+  close(fddata);
+}
+
+int main(int argc, char **argv)
+{
+  umask(022);
+  fdcdb = open_trunc("data.tmp");
+  if (fdcdb == -1) die_datatmp();
+  if (cdb_make_start(&cdb,fdcdb) == -1) die_datatmp();
+
+  if (argc == 1)
+    load("data");
+  while(--argc) {
+    load(argv[argc]);
+  }
 
   if (cdb_make_finish(&cdb) == -1) die_datatmp();
   if (fsync(fdcdb) == -1) die_datatmp();
diff -ruN djbdns-1.05-dist/trysgact.c djbdns-1.05/trysgact.c
--- djbdns-1.05-dist/trysgact.c	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/trysgact.c	2008-08-11 19:33:30.000000000 -0700
@@ -0,0 +1,10 @@
+#include <signal.h>
+
+main()
+{
+  struct sigaction sa;
+  sa.sa_handler = 0;
+  sa.sa_flags = 0;
+  sigemptyset(&sa.sa_mask);
+  sigaction(0,&sa,(struct sigaction *) 0);
+}
diff -ruN djbdns-1.05-dist/trysgprm.c djbdns-1.05/trysgprm.c
--- djbdns-1.05-dist/trysgprm.c	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/trysgprm.c	2008-08-11 19:33:30.000000000 -0700
@@ -0,0 +1,10 @@
+#include <signal.h>
+
+main()
+{
+  sigset_t ss;
+ 
+  sigemptyset(&ss);
+  sigaddset(&ss,SIGCHLD);
+  sigprocmask(SIG_SETMASK,&ss,(sigset_t *) 0);
+}
diff -ruN djbdns-1.05-dist/uint32.h djbdns-1.05/uint32.h
--- djbdns-1.05-dist/uint32.h	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/uint32.h	2008-08-11 22:55:10.000000000 -0700
@@ -0,0 +1,11 @@
+#ifndef UINT32_H
+#define UINT32_H
+
+typedef unsigned long uint32;
+
+extern void uint32_pack(char *,uint32);
+extern void uint32_pack_big(char *,uint32);
+extern void uint32_unpack(const char *,uint32 *);
+extern void uint32_unpack_big(const char *,uint32 *);
+
+#endif
diff -ruN djbdns-1.05-dist/uint64.h djbdns-1.05/uint64.h
--- djbdns-1.05-dist/uint64.h	1969-12-31 16:00:00.000000000 -0800
+++ djbdns-1.05/uint64.h	2008-08-11 22:55:10.000000000 -0700
@@ -0,0 +1,8 @@
+#ifndef UINT64_H
+#define UINT64_H
+
+/* sysdep: -ulong64 */
+
+typedef unsigned long long uint64;
+
+#endif
