diff --exclude CVS -BburN djbdns-1.05/FILES djbdns/FILES
--- djbdns-1.05/FILES	Sun Feb 11 22:11:45 2001
+++ djbdns/FILES	Sun Sep  2 00:04:41 2001
@@ -241,3 +241,7 @@
 warn-shsgr
 buffer_read.c
 buffer_write.c
+dnssort.c
+dnssort.h
+ctdlookup.c
+cserver.c
diff --exclude CVS -BburN djbdns-1.05/Makefile djbdns/Makefile
--- djbdns-1.05/Makefile	Sun Feb 11 22:11:45 2001
+++ djbdns/Makefile	Sun Sep  2 00:04:43 2001
@@ -1,5 +1,7 @@
 # Don't edit Makefile! Use conf-* for configuration.
 
+DNSSORT=-DDNSSORT #switch to turn dnssort on
+
 SHELL=/bin/sh
 
 default: it
@@ -209,6 +211,10 @@
 	> choose
 	chmod 755 choose
 
+clean: \
+TARGETS
+	rm -f `cat TARGETS`
+
 compile: \
 warn-auto.sh conf-cc
 	( cat warn-auto.sh; \
@@ -216,6 +222,16 @@
 	) > compile
 	chmod 755 compile
 
+cserver.o: \
+compile cserver.c byte.h case.h env.h buffer.h strerr.h ip4.h uint16.h \
+ndelay.h socket.h droproot.h qlog.h response.h dns.h alloc.h scan.h dnssort.h
+	./compile $(DNSSORT) cserver.c
+
+ctdlookup.o: \
+compile ctdlookup.c uint16.h open.h tai.h cdb.h byte.h case.h dns.h \
+seek.h response.h dnssort.h
+	./compile $(DNSSORT) ctdlookup.c
+
 dd.o: \
 compile dd.c dns.h stralloc.h gen_alloc.h iopause.h taia.h tai.h \
 uint64.h taia.h dd.h
@@ -428,6 +444,11 @@
 gen_alloc.h parsetype.h dns.h stralloc.h iopause.h taia.h
 	./compile dnsqr.c
 
+dnssort.o: \
+compile dnssort.c uint16.h uint32.h byte.h error.h tai.h iopause.h \
+socket.h scan.h dns.h ip4.h strerr.h dnssort.h
+	./compile $(DNSSORT) dnssort.c
+
 dnstrace: \
 load dnstrace.o dd.o iopause.o printrecord.o parsetype.o dns.a env.a \
 libtai.a alloc.a buffer.a unix.a byte.a socket.lib
@@ -979,11 +1000,12 @@
 	./compile timeoutwrite.c
 
 tinydns: \
-load tinydns.o server.o droproot.o tdlookup.o response.o qlog.o \
+load tinydns.o cserver.o droproot.o ctdlookup.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 \
-	qlog.o prot.o dns.a libtai.a env.a cdb.a alloc.a buffer.a \
+socket.lib timeoutread.o timeoutwrite.o iopause.o dnssort.o
+	./load tinydns cserver.o droproot.o ctdlookup.o dnssort.o response.o \
+	qlog.o prot.o dns.a timeoutread.o timeoutwrite.o iopause.o \
+	libtai.a env.a cdb.a alloc.a buffer.a \
 	unix.a byte.a  `cat socket.lib`
 
 tinydns-conf: \
diff --exclude CVS -BburN djbdns-1.05/TARGETS djbdns/TARGETS
--- djbdns-1.05/TARGETS	Sun Feb 11 22:11:45 2001
+++ djbdns/TARGETS	Sun Sep  2 00:04:46 2001
@@ -214,3 +214,6 @@
 it
 setup
 check
+dnssort.o
+cserver.o
+ctdlookup.o
diff --exclude CVS -BburN djbdns-1.05/conf-ld djbdns/conf-ld
--- djbdns-1.05/conf-ld	Sun Feb 11 22:11:45 2001
+++ djbdns/conf-ld	Sun Sep  2 00:04:39 2001
@@ -1,3 +1,3 @@
-gcc -s
+gcc 
 
 This will be used to link .o files into an executable.
diff --exclude CVS -BburN djbdns-1.05/cserver.c djbdns/cserver.c
--- djbdns-1.05/cserver.c	Thu Jan  1 01:00:00 1970
+++ djbdns/cserver.c	Wed Nov 28 09:12:51 2001
@@ -0,0 +1,292 @@
+#include "byte.h"
+#include "case.h"
+#include "env.h"
+#include "buffer.h"
+#include "strerr.h"
+#include "ip4.h"
+#include "uint16.h"
+#include "ndelay.h"
+#include "socket.h"
+#include "droproot.h"
+#include "qlog.h"
+#include "response.h"
+#include "dns.h"
+
+#ifdef DNSSORT
+#include "alloc.h"
+#include "scan.h"
+#include "dnssort.h"
+#endif
+
+
+extern char *fatal;
+extern char *starting;
+#ifndef DNSSORT
+extern int respond(char *,char *,char *);
+#else
+extern int respond(char *,char *,char *, struct ctx *);
+#endif
+extern void initialize(void);
+
+static char ip[4];
+static uint16 port;
+
+static char buf[513];
+static int len;
+
+static char *q;
+
+#ifndef DNSSORT
+static int doit(void)
+#else
+static int doit(struct ctx *ctx)
+#endif
+{
+  unsigned int pos;
+  char header[12];
+  char qtype[2];
+  char qclass[2];
+  char *b;
+#ifdef DNSSORT
+  int flag;
+  
+  len = ctx->len;
+  b = ctx->buf;
+  dnssort_print = 1;
+  flag = ctx->flags;
+#else
+  b = buf;
+#endif
+
+  if (len >= sizeof buf) goto NOQ;
+  pos = dns_packet_copy(b,len,0,header,12); if (!pos) goto NOQ;
+  if (header[2] & 128) goto NOQ;
+  if (header[4]) goto NOQ;
+  if (header[5] != 1) goto NOQ;
+
+  pos = dns_packet_getname(b,len,pos,&q); if (!pos) goto NOQ;
+  pos = dns_packet_copy(b,len,pos,qtype,2); if (!pos) goto NOQ;
+  pos = dns_packet_copy(b,len,pos,qclass,2); if (!pos) goto NOQ;
+
+  if (!response_query(q,qtype,qclass)) goto NOQ;
+  response_id(header);
+  if (byte_equal(qclass,2,DNS_C_IN))
+    response[2] |= 4;
+  else
+    if (byte_diff(qclass,2,DNS_C_ANY)) goto WEIRDCLASS;
+  response[3] &= ~128;
+  if (!(header[2] & 1)) response[2] &= ~1;
+
+  if (header[2] & 126) goto NOTIMP;
+  if (byte_equal(qtype,2,DNS_T_AXFR)) goto NOTIMP;
+
+  case_lowerb(q,dns_domain_length(q));
+  if (!respond(q,qtype,ctx->ip,ctx) ) {
+#ifdef DNSSORT
+    if ( dnssort_print )
+#endif
+    qlog(ctx->ip,ctx->port,header,q,qtype," - ");
+    return 0;
+  }
+#ifdef DNSSORT
+  if ( flag == 4 )
+    qlog(ctx->ip,ctx->port,header,q,qtype," T ");
+  else
+#endif
+  qlog(ctx->ip,ctx->port,header,q,qtype," + ");
+  return 1;
+
+  NOTIMP:
+  response[3] &= ~15;
+  response[3] |= 4;
+  qlog(ctx->ip,ctx->port,header,q,qtype," I ");
+  return 1;
+
+  WEIRDCLASS:
+  response[3] &= ~15;
+  response[3] |= 1;
+  qlog(ctx->ip,ctx->port,header,q,qtype," C ");
+  return 1;
+
+  NOQ:
+  qlog(ctx->ip,ctx->port,"\0\0","","\0\0"," / ");
+  return 0;
+}
+
+#ifdef DNSSORT
+/* XXX: breaks tai encapsulation */
+static void taia_uint_ms(struct taia *t,unsigned int ms)
+{
+	unsigned int s = ms/1000;
+	ms %= 1000;
+	
+	t->sec.x = s;
+	t->nano = ms*1000000; /* 1ms = 1e6ns -> 1s = 1e9ns */
+	t->atto = 0;
+}
+#endif
+
+int main()
+{
+  char *x;
+  int udp53;
+#ifdef DNSSORT
+  unsigned long poll = 500; /* ms */
+  unsigned long concurrency = 128; /* 128req / 1.5s ~ 85 req/s */
+  int i;
+  struct ctx *ca;
+  char *bufa;
+  struct taia now;
+  struct taia deadline;
+  iopause_fd iop[2];
+  iopause_fd *iopp;
+  int iopl;
+  char *y;
+#endif
+
+  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: ");
+
+  droproot(fatal);
+
+#ifdef DNSSORT
+  y = env_get("DNSSORT_IP");
+  if ( !y ) goto off;
+  if (!ip4_scan(y,dnssort_ip))
+    strerr_die3x(111,fatal,"unable to parse DNSSORT_IP address ",y);
+  
+  x = env_get("DNSSORT_PORT");
+  if (!x) dnssort_port = 179; /* default port */
+  else scan_ulong(x, &dnssort_port);
+
+  x = env_get("DNSSORT_POLL");
+  if (x) scan_ulong(x, &poll);
+  
+  dnssort_fd = socket_udp();
+  if (dnssort_fd == -1)
+    strerr_die2sys(111,fatal,"unable to create DNSSORT UDP socket");
+
+off:
+  x = env_get("DNSSORT_CONCURRENCY");
+  if (x) scan_ulong(x, &concurrency);
+  
+  ca = (struct ctx *) alloc((concurrency+1)*sizeof(struct ctx) );
+  if (!ca)
+    strerr_die2sys(111,fatal,"unable to allocate concurrency structures");
+  bufa = alloc((concurrency+1)*sizeof(buf));
+  if (!bufa)
+    strerr_die2sys(111,fatal,"unable to allocate receive buffers");
+
+  for (i = 0; i <= concurrency; i++ ) {
+    ca[i].flags = 0;
+    ca[i].id = 0;
+    ca[i].len = 513;
+    ca[i].buf = bufa + i*sizeof(buf);
+    /* ip and port are only valid when flags != 0 */
+  }
+#endif
+
+  initialize();
+  
+  ndelay_off(udp53);
+  socket_tryreservein(udp53,65536);
+
+#ifdef DNSSORT
+  ndelay_off(dnssort_fd);
+  socket_tryreservein(dnssort_fd,65536);
+
+  buffer_putsflush(buffer_2,starting);
+
+  taia_now(&now);
+  taia_uint_ms(&deadline,poll);
+  taia_add(&deadline,&now,&deadline);
+
+  for (;;) {
+    /* get empty slot */
+    for (i = 0; i < concurrency; i++)
+      if ( ca[i].flags == 0 ) break;
+    
+    /* setup iopause struct */
+    iopp = &iop[1];
+    iopl = 0;
+    iop[0].fd = udp53;
+    iop[0].events = IOPAUSE_READ;
+    iopp = iop;
+    iopl++;
+    if ( dnssort_fd != -1 ) {
+      iop[1].fd = dnssort_fd;
+      iop[1].events = IOPAUSE_READ;
+      iopl++;
+    } else {
+      iop[1].revents = 0; /* do not trap later */
+    }
+
+    /* do iopause read */
+    for (;;) {
+      taia_now(&now);
+      iopause(iopp,iopl,&deadline,&now);
+      if (iop[0].revents) {
+	/* data on udp 53 */
+	ca[i].len = socket_recv4(udp53,ca[i].buf,sizeof buf,ca[i].ip,&ca[i].port);
+	if ( i == concurrency ) {
+	  /* all slots full, drop packet */
+          qlog(ca[i].ip,ca[i].port,"\0\0","","\0\0"," D ");
+	  break;
+	}
+  //-CJ qlog(ca[i].ip,ca[i].port,"\0\0","","\0\0"," R ");
+	if (ca[i].len < 0) break;
+	if (!doit(&ca[i])) break;
+	if (response_len > 512) response_tc();
+	socket_send4(udp53,response,response_len,ca[i].ip,ca[i].port);
+	/* may block for buffer space; if it fails, too bad */
+      }
+      if (iop[1].revents) {
+	/* data on dnssort fd */
+	if (!dnssort_recv(ca, concurrency, &i, 2) ) break;
+  //-CJ qlog(ca[i].ip,ca[i].port,"\0\0","","\0\0"," RD ");
+	if (!doit(&ca[i])) break;
+	if (response_len > 512) response_tc();
+	socket_send4(udp53,response,response_len,ca[i].ip,ca[i].port);
+	/* may block for buffer space; if it fails, too bad */
+      }
+      if (taia_less(&deadline,&now)) {
+	taia_now(&now);
+	taia_uint_ms(&deadline,poll);
+	taia_add(&deadline,&now,&deadline);
+	for ( i=0; i < concurrency; i++ ) {
+	  if ( ca[i].flags == 0 ) continue;
+	  if ( ++(ca[i].flags) >= 4 ) { /* XXX if 3*poll time too long reduce count to 3 */
+	    /* timeout, send back random data */
+	    ca[i].flags = 4;
+	    if (!doit(&ca[i])) continue;
+	    if (response_len > 512) response_tc();
+	    socket_send4(udp53,response,response_len,ca[i].ip,ca[i].port);
+	    /* may block for buffer space; if it fails, too bad */
+	  }
+	}
+	break;
+      }
+    }
+  }  
+#else
+  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 */
+  }
+#endif
+}
diff --exclude CVS -BburN djbdns-1.05/ctdlookup.c djbdns/ctdlookup.c
--- djbdns-1.05/ctdlookup.c	Thu Jan  1 01:00:00 1970
+++ djbdns/ctdlookup.c	Wed Nov 14 17:57:17 2001
@@ -0,0 +1,356 @@
+#include <unistd.h>
+#include "uint16.h"
+#include "open.h"
+#include "tai.h"
+#include "cdb.h"
+#include "byte.h"
+#include "case.h"
+#include "dns.h"
+#include "seek.h"
+#include "response.h"
+#ifdef DNSSORT
+#include "dnssort.h"
+#endif
+
+static int want(const char *owner,const char type[2])
+{
+  unsigned int pos;
+  static char *d;
+  char x[10];
+  uint16 datalen;
+
+  pos = dns_packet_skipname(response,response_len,12); if (!pos) return 0;
+  pos += 4;
+
+  while (pos < response_len) {
+    pos = dns_packet_getname(response,response_len,pos,&d); if (!pos) return 0;
+    pos = dns_packet_copy(response,response_len,pos,x,10); if (!pos) return 0;
+    if (dns_domain_equal(d,owner))
+      if (byte_equal(type,2,x))
+        return 0;
+    uint16_unpack_big(x + 8,&datalen);
+    pos += datalen;
+  }
+  return 1;
+}
+
+static char *d1;
+
+static char clientloc[2];
+static struct tai now;
+static struct cdb c;
+
+static char data[32767];
+static uint32 dlen;
+static unsigned int dpos;
+static char type[2];
+static uint32 ttl;
+
+static int find(char *d,int flagwild)
+{
+  int r;
+  char ch;
+  struct tai cutoff;
+  char ttd[8];
+  char ttlstr[4];
+  char recordloc[2];
+  double newttl;
+
+  for (;;) {
+    r = cdb_findnext(&c,d,dns_domain_length(d));
+    if (r <= 0) return r;
+    dlen = cdb_datalen(&c);
+    if (dlen > sizeof data) return -1;
+    if (cdb_read(&c,data,dlen,cdb_datapos(&c)) == -1) return -1;
+    dpos = dns_packet_copy(data,dlen,0,type,2); if (!dpos) return -1;
+    dpos = dns_packet_copy(data,dlen,dpos,&ch,1); if (!dpos) return -1;
+    if ((ch == '=' + 1) || (ch == '*' + 1)) {
+      --ch;
+      dpos = dns_packet_copy(data,dlen,dpos,recordloc,2); if (!dpos) return -1;
+      if (byte_diff(recordloc,2,clientloc)) continue;
+    }
+    if (flagwild != (ch == '*')) continue;
+    dpos = dns_packet_copy(data,dlen,dpos,ttlstr,4); if (!dpos) return -1;
+    uint32_unpack_big(ttlstr,&ttl);
+    dpos = dns_packet_copy(data,dlen,dpos,ttd,8); if (!dpos) return -1;
+    if (byte_diff(ttd,8,"\0\0\0\0\0\0\0\0")) {
+      tai_unpack(ttd,&cutoff);
+      if (ttl == 0) {
+	if (tai_less(&cutoff,&now)) continue;
+	tai_sub(&cutoff,&cutoff,&now);
+	newttl = tai_approx(&cutoff);
+	if (newttl <= 2.0) newttl = 2.0;
+	if (newttl >= 3600.0) newttl = 3600.0;
+	ttl = newttl;
+      }
+      else
+	if (!tai_less(&cutoff,&now)) continue;
+    }
+    return 1;
+  }
+}
+
+static int dobytes(unsigned int len)
+{
+  char buf[20];
+  if (len > 20) return 0;
+  dpos = dns_packet_copy(data,dlen,dpos,buf,len);
+  if (!dpos) return 0;
+  return response_addbytes(buf,len);
+}
+
+static int doname(void)
+{
+  dpos = dns_packet_getname(data,dlen,dpos,&d1);
+  if (!dpos) return 0;
+  return response_addname(d1);
+}
+
+#ifdef DNSSORT
+static int doit(char *q,char qtype[2],char ip[4], struct ctx *ctx)
+#else
+static int doit(char *q,char qtype[2],char ip[4])
+#endif
+{
+  unsigned int bpos;
+  unsigned int anpos;
+  unsigned int aupos;
+  unsigned int arpos;
+  char *control;
+  char *wild;
+  int flaggavesoa;
+  int flagfound;
+  int r;
+  int flagns;
+  int flagauthoritative;
+  char x[20];
+  uint16 u16;
+  char addr[8][4];
+  int addrnum;
+  uint32 addrttl;
+  int i;
+  
+#ifdef DNSSORT
+  /* init dnssort structures */
+  dnssort_new();
+  dnssort_add4(ip);
+#endif
+
+  anpos = response_len;
+
+  control = q;
+  for (;;) {
+    flagns = 0;
+    flagauthoritative = 0;
+    cdb_findstart(&c);
+    while (r = find(control,0)) {
+      if (r == -1) return 0;
+      if (byte_equal(type,2,DNS_T_SOA)) flagauthoritative = 1;
+      if (byte_equal(type,2,DNS_T_NS)) flagns = 1;
+    }
+    if (flagns) break;
+    if (!*control) return 0; /* q is not within our bailiwick */
+    control += *control;
+    control += 1;
+  }
+
+  if (!flagauthoritative) {
+    response[2] &= ~4;
+    goto AUTHORITY; /* q is in a child zone */
+  }
+
+
+  flaggavesoa = 0;
+  flagfound = 0;
+  wild = q;
+
+  for (;;) {
+    addrnum = 0;
+    addrttl = 0;
+    cdb_findstart(&c);
+    while (r = find(wild,wild != q)) {
+      if (r == -1) return 0;
+      flagfound = 1;
+      if (flaggavesoa && byte_equal(type,2,DNS_T_SOA)) continue;
+      if (byte_diff(type,2,qtype) && byte_diff(qtype,2,DNS_T_ANY) && byte_diff(type,2,DNS_T_CNAME)) continue;
+      if (byte_equal(type,2,DNS_T_A) && (dlen - dpos == 4)) {
+	addrttl = ttl;
+#ifdef DNSSORT
+	/* here we have to populate our packet until full, the header is added later */
+	dnssort_add4(data + dpos);
+#else
+	i = dns_random(addrnum + 1);
+	if (i < 8) {
+	  if ((i < addrnum) && (addrnum < 8))
+	    byte_copy(addr[addrnum],4,addr[i]);
+	  byte_copy(addr[i],4,data + dpos);
+	}
+#endif	
+	if (addrnum < 1000000) ++addrnum;
+	continue;
+      }
+      if (!response_rstart(q,type,ttl)) return 0;
+      if (byte_equal(type,2,DNS_T_NS) || byte_equal(type,2,DNS_T_CNAME) || byte_equal(type,2,DNS_T_PTR)) {
+	if (!doname()) return 0;
+      }
+      else if (byte_equal(type,2,DNS_T_MX)) {
+	if (!dobytes(2)) return 0;
+	if (!doname()) return 0;
+      }
+      else if (byte_equal(type,2,DNS_T_SOA)) {
+	if (!doname()) return 0;
+	if (!doname()) return 0;
+	if (!dobytes(20)) return 0;
+        flaggavesoa = 1;
+      }
+      else
+        if (!response_addbytes(data + dpos,dlen - dpos)) return 0;
+      response_rfinish(RESPONSE_ANSWER);
+    }
+#ifdef DNSSORT
+    switch ( ctx->flags ) {
+      case 0:
+	/* request send */
+	if ( addrnum > 1 ) { /* for zero or one addresses we do no bgp sort */
+	  dnssort_header4(ctx, 2); /* server sorting */
+	  if ( dnssort_send(ctx) == -1 ) {
+	    dnssort_shuffle4(1, -1, addr);
+	    break;
+	  }
+	  dnssort_print = 0;
+	  return 0; /* done, wait for answer */
+	} else {
+	  break;
+	}
+      case 4:
+	/* timeout */
+	dnssort_shuffle4(1, -1, addr);
+	break;
+      case 8:
+	/* request recved */
+	dnssort_8best4(1, -1, addr);
+	break;
+      default:
+	break;
+    }
+    ctx->flags = 0; /* we send an answer so this slot will be empty */
+#endif
+    for (i = 0;i < addrnum;++i)
+      if (i < 8) {
+	if (!response_rstart(q,DNS_T_A,addrttl)) return 0;
+	if (!response_addbytes(addr[i],4)) return 0;
+	response_rfinish(RESPONSE_ANSWER);
+      }
+
+    if (flagfound) break;
+    if (wild == control) break;
+    if (!*wild) break; /* impossible */
+    wild += *wild;
+    wild += 1;
+  }
+
+  if (!flagfound)
+    response_nxdomain();
+
+
+  AUTHORITY:
+  aupos = response_len;
+
+  if (flagauthoritative && (aupos == anpos)) {
+    cdb_findstart(&c);
+    while (r = find(control,0)) {
+      if (r == -1) return 0;
+      if (byte_equal(type,2,DNS_T_SOA)) {
+        if (!response_rstart(control,DNS_T_SOA,ttl)) return 0;
+	if (!doname()) return 0;
+	if (!doname()) return 0;
+	if (!dobytes(20)) return 0;
+        response_rfinish(RESPONSE_AUTHORITY);
+        break;
+      }
+    }
+  }
+  else
+    if (want(control,DNS_T_NS)) {
+      cdb_findstart(&c);
+      while (r = find(control,0)) {
+        if (r == -1) return 0;
+        if (byte_equal(type,2,DNS_T_NS)) {
+          if (!response_rstart(control,DNS_T_NS,ttl)) return 0;
+	  if (!doname()) return 0;
+          response_rfinish(RESPONSE_AUTHORITY);
+        }
+      }
+    }
+
+  arpos = response_len;
+
+  bpos = anpos;
+  while (bpos < arpos) {
+    bpos = dns_packet_skipname(response,arpos,bpos); if (!bpos) return 0;
+    bpos = dns_packet_copy(response,arpos,bpos,x,10); if (!bpos) return 0;
+    if (byte_equal(x,2,DNS_T_NS) || byte_equal(x,2,DNS_T_MX)) {
+      if (byte_equal(x,2,DNS_T_NS)) {
+        if (!dns_packet_getname(response,arpos,bpos,&d1)) return 0;
+      }
+      else
+        if (!dns_packet_getname(response,arpos,bpos + 2,&d1)) return 0;
+      case_lowerb(d1,dns_domain_length(d1));
+      if (want(d1,DNS_T_A)) {
+	cdb_findstart(&c);
+	while (r = find(d1,0)) {
+          if (r == -1) return 0;
+	  if (byte_equal(type,2,DNS_T_A)) {
+            if (!response_rstart(d1,DNS_T_A,ttl)) return 0;
+	    if (!dobytes(4)) return 0;
+            response_rfinish(RESPONSE_ADDITIONAL);
+	  }
+        }
+      }
+    }
+    uint16_unpack_big(x + 8,&u16);
+    bpos += u16;
+  }
+
+  if (flagauthoritative && (response_len > 512)) {
+    byte_zero(response + RESPONSE_ADDITIONAL,2);
+    response_len = arpos;
+    if (response_len > 512) {
+      byte_zero(response + RESPONSE_AUTHORITY,2);
+      response_len = aupos;
+    }
+  }
+
+  return 1;
+}
+
+int respond(char *q,char qtype[2],char ip[4], struct ctx *ctx)
+{
+  int fd;
+  int r;
+  char key[6];
+
+  tai_now(&now);
+  fd = open_read("data.cdb");
+  if (fd == -1) return 0;
+  cdb_init(&c,fd);
+
+  byte_zero(clientloc,2);
+  key[0] = 0;
+  key[1] = '%';
+  byte_copy(key + 2,4,ip);
+  r = cdb_find(&c,key,6);
+  if (!r) r = cdb_find(&c,key,5);
+  if (!r) r = cdb_find(&c,key,4);
+  if (!r) r = cdb_find(&c,key,3);
+  if (!r) r = cdb_find(&c,key,2);
+  if (r == -1) return 0;
+  if (r && (cdb_datalen(&c) == 2))
+    if (cdb_read(&c,clientloc,2,cdb_datapos(&c)) == -1) return 0;
+
+  r = doit(q,qtype,ip, ctx);
+
+  cdb_free(&c);
+  close(fd);
+  return r;
+}
diff --exclude CVS -BburN djbdns-1.05/dnssort.c djbdns/dnssort.c
--- djbdns-1.05/dnssort.c	Thu Jan  1 01:00:00 1970
+++ djbdns/dnssort.c	Tue Dec 18 10:09:07 2001
@@ -0,0 +1,217 @@
+#ifdef DNSSORT
+#include <unistd.h>
+#include "uint16.h"
+#include "uint32.h"
+#include "byte.h"
+#include "error.h"
+#include "tai.h"
+#include "iopause.h"
+#include "socket.h"
+#include "scan.h"
+#include "dns.h"
+#include "ip4.h"
+#include "strerr.h"
+#include "dnssort.h"
+
+#include <assert.h>
+#include <stdio.h> /* XXX for printf */
+
+/* structure of a dnssort message:
+	char version[2];     / protocol version: 1 = IPv4, 2 = IPv6
+	char querytype;      / querytype: 1 = client sorting, 2 = server sorting
+	char requesttype;    / requesttype: 1 = request, 2 = answer
+	char requestid[4];   / request id: unique id for this request
+	char unused[4];      / reserved for future use
+	char unused[4];      / reserved for future use
+	char numobjects[4];  / # of valid request objects in packet
+	/ start of data /
+	char addr[4];        / address: IPv4 address /
+	char preference[4];  / preference: preference of this address, the higher the better,
+	                                    set to zero in requests /
+
+	The first addr-preference pair in server sorting is the client address
+*/
+
+#define DNSSORT_HSIZE 16 /* 2 + 1 + 1 + 4 + 4 + 4 */
+#define MAX_DNSSORTMSG_LEN 1024 /* enough for 126 ipv4 or 50 ipv6 entries */
+
+static char dnssort_sendbuf[MAX_DNSSORTMSG_LEN]; /* the size is guaranteed by the protocol */
+static char dnssort_recvbuf[MAX_DNSSORTMSG_LEN]; 
+/* this is a temporary buffer so the request is not overwritten by a bogus answer */
+
+int dnssort_fd = -1; /* this is also the on/off switch, will be set in tinydns.c */
+char dnssort_ip[4]; /* ip address of server, will be set in tinydns.c */
+unsigned long dnssort_port; /* ip port of server, will be set in tinydns.c */
+int dnssort_print;
+
+static uint32 dnssort_sendnum;
+static int dnssort_sendlen;
+static int dnssort_recvlen;
+static uint32 dnssort_recvnum;
+
+void dnssort_new()
+{
+	dnssort_sendnum = 0;
+	dnssort_sendlen = DNSSORT_HSIZE;
+}
+
+void dnssort_add4(char ip[4])
+{
+    /* note also the client has to be added with this function */
+	char *s = dnssort_sendbuf + dnssort_sendlen;
+	
+	if ( dnssort_sendlen+8 > MAX_DNSSORTMSG_LEN ) return;
+	byte_copy(s,4,ip);
+	byte_zero(s+4,4);
+	dnssort_sendlen += 8;
+	dnssort_sendnum++;
+}
+
+void dnssort_header4(struct ctx *ctx, unsigned char qt)
+{
+	char *s = dnssort_sendbuf;
+	
+	uint16_pack_big(s,(uint16) 1); /* IPv4 */ s+=2;
+	*s++ = qt;
+	*s++ = 1; /* allways a request (dns can not respond) */
+	ctx->id = dns_random(-1L);
+	uint32_pack_big(s, ctx->id); /* requestid */ s+=4;
+	byte_zero(s, 4); /* RFU */ s+=4;
+	byte_zero(s, 4); /* RFU2 */ s+=4;
+	uint32_pack_big(s, dnssort_sendnum); /* don't forget to include the client ip */
+}
+
+int dnssort_send(struct ctx *ctx)
+{
+	if ( dnssort_fd == -1 ) return -1; /* dnssort not enabled */
+	
+	ctx->flags = 1;
+	return socket_send4(dnssort_fd, dnssort_sendbuf, dnssort_sendlen, dnssort_ip, dnssort_port);
+	/* under extrem havy load this could block, then it would be useful to use a send queue */
+}
+
+int dnssort_recv(struct ctx *ctx, int cc, int *req, unsigned char qt)
+{
+	char ip[4];
+	char *s;
+	int i;
+	uint32 u32; 
+	uint16 u16;
+
+	assert( dnssort_fd != -1 ); /* paranoia: dnssort not enabled */
+
+	dnssort_recvlen = socket_recv4(dnssort_fd,dnssort_recvbuf,MAX_DNSSORTMSG_LEN, ip, &u16);
+	if ( dnssort_recvlen == -1 ) return 0;
+	if ( u16 != dnssort_port && !byte_diff(ip, 4, dnssort_ip) ) {
+		return 0;
+	}
+	if (dnssort_recvlen < DNSSORT_HSIZE ) /* bad packet */
+		return 0;
+		
+	s = dnssort_recvbuf;
+	uint16_unpack_big(s, &u16); s+=2;
+	if ( u16 != 1 ) return 0; /* IPv4 */
+	if ( *s++ != (char) qt ) return 0; /* query type */
+	if ( *s++ != 2 ) return 0; /* answer */
+	uint32_unpack_big(s, &u32); s+=4;
+
+	/* find request via id */
+	for ( i = 0; i < cc; i++) {
+		if ( ctx[i].flags == 0 ) continue;
+		if ( ctx[i].id == u32 )
+			if ( ctx[i].flags <= 4 ) break;
+	}
+	if ( i >= cc ) return 0; /* no such id */
+	*req = i;
+	
+	s+=4;
+	uint32_unpack_big(s, &dnssort_recvnum); s+=4;
+	if ( ((dnssort_recvnum<<3) + s) != (dnssort_recvbuf + dnssort_recvlen) ) return 0;
+
+	/* for somebody who can listen to the communication between the dns server and
+	   the bgp server can spoof the message and modify the dns addresses.
+	   If it can be done on this connection it can also be done on the connection 
+	   client <-> dns server. So hopefully you have trust in your local network */
+	ctx->flags = 8;
+	return 1;
+}
+
+/* works on recv buffer */
+void dnssort_8best4(int from, int till, char addr[8][4])
+{
+	char *s;
+	char *t;
+	char *match;
+	int i,j;
+	int diff;
+	uint32 max;
+	uint32 u32;
+	
+	if ( from < 0 ) from = 0;
+	if ( (uint32) till > dnssort_recvnum || till < 0 ) till = dnssort_recvnum;
+	if ( till<<3 + DNSSORT_HSIZE > dnssort_recvlen ) {
+		/* would overflow the packet, adjust till */
+		till = (dnssort_recvlen-DNSSORT_HSIZE)>>3;
+	}
+	if ( from > till ) return;
+		
+	diff = till-from;
+	s = dnssort_recvbuf + DNSSORT_HSIZE + (from<<3);
+	for ( j = 0, t=s; j < diff; j++ ) {
+		assert(t < dnssort_recvbuf + dnssort_recvlen);
+		t += 8;
+	}
+	match = NULL;
+	for ( i = 0; i < 8 && i < till-from; i++ ) {
+		t = s + (diff<<3);
+		for(j = 0, max = 0; j < diff; j++) {
+			assert(t >= s);
+			t-=8;
+			uint32_unpack_big(t+4, &u32);
+			if ( u32 >= max ) {
+				match = t;
+				max = u32;
+			}
+		}			
+		
+		assert(match != NULL);
+		/* let's swap */
+		byte_copy(addr[i], 4, match);
+
+		byte_copy(match, 8, s);
+		s+=8; diff--; 
+	}	
+	/* now we should have the top 8 entries in addr */
+}
+
+/* works on send buffer because there is no recv buffer after a timeout */
+void dnssort_shuffle4(int from, int till, char addr[8][4])
+{
+	char *s = dnssort_sendbuf;
+	int diff;
+	int i,j;
+	
+	if ( from < 0 ) from = 0;
+	if ( (uint32) till > dnssort_sendnum || till < 0 ) till = dnssort_sendnum;
+	if ( till<<3 + DNSSORT_HSIZE > dnssort_sendlen ) {
+		/* would overflow the packet, adjust till */
+		till = (dnssort_sendlen-DNSSORT_HSIZE)>>3;
+	}
+	if ( from > till ) return;
+	
+	diff = till-from;
+	s = dnssort_sendbuf + DNSSORT_HSIZE + (from<<3);
+	
+	for ( i = 0; i < diff ; i++ ) {
+		assert(s < dnssort_sendbuf + dnssort_sendlen);
+				
+		j = dns_random(i + 1);
+		if ( j < 8 ) {
+			if ((j < i) && (i < 8))
+				byte_copy(addr[i],4,addr[j]);
+			byte_copy(addr[j],4,s);
+			s += 8;
+		}
+	}
+}
+#endif
diff --exclude CVS -BburN djbdns-1.05/dnssort.h djbdns/dnssort.h
--- djbdns-1.05/dnssort.h	Thu Jan  1 01:00:00 1970
+++ djbdns/dnssort.h	Wed Nov 28 08:54:15 2001
@@ -0,0 +1,32 @@
+#ifdef DNSSORT
+#ifndef __DNSSORT_H__
+#define __DNSSORT_H__
+
+#include "uint32.h"
+
+struct ctx {
+	uint16 flags;   /* flags 0 = unused, 1-3 = recv pending, 4 = timeout, 8 = recv ok (4 & 8 transient) */ 
+	uint16 port;		/* remote port of request */
+	char ip[4];			/* remote address of request */
+	uint32 id;      /* request id of for packet */
+	uint32 len;     /* absolute lenght of buffer */
+	char *buf;      /* dns request buffer */
+};
+
+extern int dnssort_fd;
+extern char dnssort_ip[4];
+extern unsigned long dnssort_port;
+extern int dnssort_print;
+
+extern void dnssort_new();
+extern void dnssort_add4(char ip[4]);
+extern void dnssort_header4(struct ctx *ctx, unsigned char qt);
+extern int dnssort_send(struct ctx *ctx);
+
+extern int dnssort_recv(struct ctx *ctx, int cc, int *req, unsigned char qt);
+
+extern void dnssort_8best4(int from, int till, char addr[8][4]);
+extern void dnssort_shuffle4(int from, int till, char addr[8][4]);
+
+#endif
+#endif
