#Changelog for the djbdns port for OpenWRT
+5 20090522 jhalfmoon
+enhancement - added patch: dnsroots_updated
+enhancement - added patch: tinydns_one_second
+enhancement - added patch: srv-records-and-axfrget
+enhancement - added patch: dnscache_less_chatty_log
+enhancement - added patch: tinydns_mmap_leak
+enhancement - added patch: dnscache_dpos_tcp_servfail
+enhancement - added patch: dnscache_negative_ttls
+enhancement - added patch: dnscache_sigpipe_fix
+enhancement - added patch: dnscache_big_udp_packets
+enhancement - added patch: dnscache_ignoreip2 (Note: disabled in config by default!)
+enhancement - added HIDETTL config option
+change - Corrected a typo in the axfrdns description in the Makefile.
+change - Cleaned up some lines in the Makefile
+change - dnsroots.global now gets copied from the djbdns source folder instead of from the package/files folder.
+change - The dnscache-multiple-ip patch was removed as it served no purpose
+change - Renamed a few patches to be more consistent with the other patches
+change - Updated the README file to reflect the changes
+
4 20090418 jhalfmoon
bugfix - The dnscache postinst script had a bug that prevented djbdns from being compiled into a firmware image.
bugfix - The dnscache startup script now uses /dev/urandom instead of /dev/random as a source of randomness. Using /dev/random does not work on 2.6 kernels.
PKG_NAME:=djbdns
PKG_VERSION:=1.05
-PKG_RELEASE:=4
+PKG_RELEASE:=5
PKG_SOURCE:=${PKG_NAME}-${PKG_VERSION}.tar.gz
PKG_SOURCE_URL:=http://cr.yp.to/djbdns/
define Package/djbdns-axfrdns/description
axfrdns is a DNS zone-transfer server.
- It reads a zone-transfer request in DNS-over-TINSTALL_DATA format
+ It reads a zone-transfer request in DNS-over-TCP format
from its standard input and responds with locally configured
information.
endef
TARGET_CC="$(TARGET_CC)" \
TARGET_CFLAGS="$(TARGET_CFLAGS)" \
TARGET_LDFLAGS="$(TARGET_LDFLAGS)" \
+ TARGET_RANLIB="$(TARGET_CROSS)ranlib" \
$(MAKE) -C $(PKG_BUILD_DIR)
endef
define Package/djbdns-dnscache/install
$(INSTALL_DIR) $(1)/usr/bin
(cd $(PKG_BUILD_DIR); \
- $(INSTALL_BIN) dnscache pickdns pickdns-data \
- $(1)/usr/bin)
- $(INSTALL_DIR) $(1)/etc
- $(CP) -r ./files/dnscache $(1)/etc/
+ $(INSTALL_BIN) dnscache pickdns pickdns-data $(1)/usr/bin)
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/dnscache.init $(1)/etc/init.d/dnscache
+ $(CP) -r ./files/dnscache $(1)/etc/
+ $(CP) $(PKG_BUILD_DIR)/dnsroots.global $(1)/etc/dnscache/
+ $(INSTALL_DIR) $(1)/etc/dnscache/ip
+ $(INSTALL_DIR) $(1)/etc/dnscache/servers
+ $(CP) $(PKG_BUILD_DIR)/dnsroots.global $(1)/etc/dnscache/servers/@
endef
define Package/djbdns-tinydns/install
$(INSTALL_DIR) $(1)/usr/bin
(cd $(PKG_BUILD_DIR); \
- $(INSTALL_BIN) tinydns tinydns-data tinydns-edit tinydns-get \
- $(1)/usr/bin)
+ $(INSTALL_BIN) tinydns tinydns-data tinydns-edit tinydns-get $(1)/usr/bin)
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/tinydns.init $(1)/etc/init.d/tinydns
$(CP) -r ./files/tinydns $(1)/etc/
define Package/djbdns-axfrdns/install
$(INSTALL_DIR) $(1)/usr/bin
(cd $(PKG_BUILD_DIR); \
- $(INSTALL_BIN) axfrdns axfr-get \
- $(1)/usr/bin)
+ $(INSTALL_BIN) axfrdns axfr-get $(1)/usr/bin)
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/axfrdns.init $(1)/etc/init.d/axfrdns
$(CP) -r ./files/axfrdns $(1)/etc/
define Package/djbdns-rbldns/install
$(INSTALL_DIR) $(1)/usr/bin
(cd $(PKG_BUILD_DIR); \
- $(INSTALL_BIN) rbldns rbldns-data \
- $(1)/usr/bin)
+ $(INSTALL_BIN) rbldns rbldns-data $(1)/usr/bin)
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/rbldns.init $(1)/etc/init.d/rbldns
$(CP) -r ./files/rbldns $(1)/etc/
define Package/djbdns-walldns/install
$(INSTALL_DIR) $(1)/usr/bin
(cd $(PKG_BUILD_DIR); \
- $(INSTALL_BIN) walldns \
- $(1)/usr/bin)
+ $(INSTALL_BIN) walldns $(1)/usr/bin)
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/walldns.init $(1)/etc/init.d/walldns
endef
- Starting the init.d scripts from the command line with the environment variable DEBUG set to 1 will prevent the servers from daemonizing and show the servers's log dumped to stdout / stderr instead of /dev/null. Example: "DEBUG=1 /etc/init.d/dnscache start"
- By default, all logging is disabled. Each daemon has a seperate option to activate logging. When logging activated the daemon logs to syslog using facility local1.info.
- Each djbdns server requires an IP address on which to listen on. This port of djbdns allows you to define an interface on which to listen instead of an IP address. The advantage of this is that an interface can get a different IP address assigned, the djbdns stuff will not break. The dnscache server has a patch applied so that it is possible to define multiple interfaces on which to listen, separated by slashes. Example: wan/lan .
-- By default, dnscache acts as a recursive name server. If you wish to operate in forwardonly mode, then you need to set the forwardonly flag to '1'. Then you need to do either one of the following: Put the ip addresses of the name servers you wish to use as resolvers in the UCI config (djbdns.dnscache.resolver) or alternatively you can set the useresolvconf flag which will cause the dns servers assigned by dhcp to be used.
+- By default, dnscache acts as a recursive name server. If you wish to operate in forwardonly mode, then you need to set the forwardonly flag to '1'. Then you need to do either one of the following: Put the ip addresses of the name servers you wish to use as resolvers in the UCI config (djbdns.dnscache.resolver) or alternatively you can set the useresolvconf flag which will cause the dns servers assigned by dhcp to be used. That last option is a so called set-and-forget mode which will work quite well in most home environments.
- If you want your OpenWRT machine to make use of its own dnscache, then you must make /etc/resolv.conf reflect this. One way of doin this is as follows: uci set network.wan.dns=127.0.0.1 . If you have dnscache listening on some other interface, you would naturally replace 127.0.0.1 by the address of that interface.
- OpenWRT has several applications that can do DNS serving in one way or another (dnsmasq, Maradns, Bind). Make sure you have none of these apps running when you start running a djbdns name server because having two DNS apps listening on the same address is not something you would usually want. A patch for the dnsmasq configuration script and its config file is included with this package. The patch will allow you to configure dnsmasq to listen only on certain interfaces, instead of on all them as it does by default on OpenWRT. Alternatively, you could completely disable and / or remove dnsmasq, if you do not intend to use any of its functionality (which is serving DNS and DHCP).
+- The ignoreip patch also has a script supplied along with it, with which you can update the ignorelist. The script contains an explanation of why you might want to do this.
+- The ignoreip functionality is disabled by default. If you want to activate it, you need to set the flag 'useignore' flag to '1' in the config. You might also want to check if you are really blocking what you want to block. Be careful with this feature. Think twice before using it.
To apply the dnsmasq patch
==========================
Applied patches
===============
-100-crosscompile.patch
+crosscompile.patch
https://dev.openwrt.org/ticket/2497
Patch to make djbdns compile correctly for OpenWRT. I understand that the original patch comes from FreeWRT and was adapted for OpenWRT by Alexander Tsvyashchenko.
-110-cachestats.patch
+dnsroots-update.patch
+Update the dnsroots.global file to be current.
+
+srv-records-and-axfrget.patch
+http://sol.truespace.ca/Files/djbdns/srv.patch
+Adds native support for srv records (not really necessary) and also patches axfr-get to decompose SRV and PTR records and write them out in native format, rather than opaque. This last thing is needed to fix a possible problem with tinydns-data.
+
+dnscache_less_chatty_log
+http://sol.truespace.ca/Files/djbdns/log.patch
+Makes dnscache log "stat" entries no more than once per 5 seconds.
+
+tinydns_mmap_leak
+http://marc.info/?l=djbdns&m=116399640808774&w=2
+This fixes the following: In the original code if cdb_read encountered an error it returned an error code and the calling function exited without closing the cdb data file resulting in an fd leak, eventually leading to a 'too many files open' error.
+
+dnscache_big_udp_packets
+http://marc.info/?l=djbdns&m=122368590802063&w=2
+Patch to support oversized UDP packets up to 4096 bytes in length, while still correctly truncating responses over 512 bytes when sending them to stub resolvers.
+
+dnscache_dpos_tcp_servfail
+http://marc.info/?l=djbdns&m=119998909915985&w=3
+Fixes broken tcp dns queries in certain situations. For example: A vanilla 1.05 will fail on "dnstxt aol.com aol.com".
+
+dnscache-cache-negatives
+http://sol.truespace.ca/Files/djbdns/nxdomain.patch
+Add support for caching of unsuccessful lookup results.
+
+tinydns_one_second
+http://www.tinydns.org/one-second.patch
+Causes tinydns to keep its mmap() of the data.cdb file open for at most one second, instead of the default one hundred queries. This improves throughput on high traffic machines.
+
+dnscache-cachestats.patch
http://romana.now.ie/#djbdns-cachestats
This patch modifies the dnscache program to keep a counter of cache hits and cache misses. Two new fields are added to the stats output line: the fifth number is the number of cache hits; the sixth number is the number of cache misses.
-120-compiler-temporary-filename.patch
+compiler-temporary-filename.patch
http://homepages.tesco.net/~J.deBoynePollard/Softwares/djbdns/#compiler-temporary-filename
A bit of a nit-picky patch that adjusts the names of generated temorary files to be more 'correct'. A bit silly really.
-130-dnscache-multiple-ip.patch
+dnscache-multiple-ip.patch
http://danp.net/djbdns/patches.html
-When applied, dnscache will accept a /-delimited list of IP address in $IP and bind to each in turn. NOTE: This patch is only really useful on embedded systems with very limited memory. On 'big' systems, ther are other ways to achieve listening on multiple IP adresses. Example: http://www.faqts.com/knowledge_base/view.phtml/aid/9644/fid/699
+When applied, dnscache will accept a /-delimited list of IP address in $IP and bind to each in turn. NOTE: This patch is only really useful on embedded systems with very limited memory. On big systems, ther are other ways to achieve listening on multiple IP adresses. You can read more on that over here: http://www.faqts.com/knowledge_base/view.phtml/aid/9644/fid/699
-140-dnsnamex-extra-command.patch
+dnsnamex-extra-command.patch
http://homepages.tesco.net/~J.deBoynePollard/Softwares/djbdns/#dnsnamex
Not really a patch, but an extra command. dnsnamex prints all of the domain names that the IP address supplied to it maps to, on a single line.
-200-dnscache-cname-handling.patch
+dnscache-cname-handling.patch
http://homepages.tesco.net/~J.deBoynePollard/FGA/#DNS
Fixes mis-handling of client-side aliases
-210-dnscache-strict-forwardonly.patch
+dnscache-strict-forwardonly.patch
http://homepages.tesco.net/~J.deBoynePollard/Softwares/djbdns/#dnscache-strict-forwardonly
This patch modifies the behaviour of dnscache such that "forwardonly" mode is fully enforced.
-220-dnscacheip-space-separator.patch
+dnscacheip-space-separator.patch
http://homepages.tesco.net/~J.deBoynePollard/FGA/djbdns-problems.html#dnscacheip-separator-character
Patch to change the separator in ${DNSCACHEIP} to the space character
-230-tinydns-data-semantic-error.patch
+tinydns-data-semantic-error.patch
http://homepages.tesco.net/~J.deBoynePollard/FGA/djbdns-problems.html#tinydns-data-semantic-error
Fixes the fact that stock tinydns-data doesn't handle semantic errors in its input
-240-tinydns-alias-chain-truncation.patch
+tinydns-alias-chain-truncation.patch
http://homepages.tesco.net/~J.deBoynePollard/FGA/djbdns-problems.html#tinydns-alias-chain-truncation
Fixes truncation of alias chains by tinydns and axfrdns
-250-djbdns-1.05-slogging.patch
+dnscache-slogging.patch
http://www.ohse.de/uwe/patches.html
Patch to enable statistics logging of queried resource records.
This patch is merged with the patch server-1.05-nxdomain-logging.patch that logs nxdomain queries.
http://danp.net/djbdns/
-260-djbdns-1.05-dnsfilter-replace.patch
+dnsfilter-replace.patch
http://www.ohse.de/uwe/patches.html
This patch adds an option to the dnsfilter program (-r). It's use makes dnsfilter simply replace the IP address by the host name if possible. If the IP address cannot be determined for whatever reason then it will be left alone. -r stands for replace.
-300-bugfix1-dempsky.patch
+dnscache_sigpipe_fix
+http://marc.info/?l=djbdns&m=104804013229536&w=2
+This patch tells dnscache to ignore the SIGPIPE signal.
+
+ignoreip2.patch
+http://tinydns.org/djbdns-1.05-ignoreip2.patch
+This patch change djbdns's dnscache so that it will ignore thex IP addresses given in the ignoreip file. This patch was made to boycott Verisign, amongst others, who decided to start supplying replies to non-existant and wildcard domains. NOTE: This feature is disabled in the config file by default. Be careful with this one.
+
+bugfix-dnscache-dempsky-poison.patch
http://www.securityfocus.com/archive/1/501294/30/0/threaded
Patch to fix a potential cache-poisoning attack. This bug only affects domains that serve DNS content using tinydns and axfrdns (only for DNS queries over TCP; clients do not need AXFR permissions) from djbdns 1.05 and allow untrusted users to include arbitrary records.
-310-bugfix2-merge-outgoing-requests.patch
+bugfix-dnscache-merge-outgoing-requests.patch
http://www.your.org/dnscache/
This patch prevents a class of poisoning attack by combining identical requests from clients into one outgoing query. Without this patch, an attacker can coerce dnscache into launching hundreds of identical queries at once, making a specific type of attack several orders of magnitude easier.
-320-bugfix3-cache-soa-records.patch
+bugfix-dnscache-cache-soa-records.patch
http://www.your.org/dnscache/
This patch allows dnscache to store the responses of "SOA" type queries in its cache. SOA responses are the only type of response unconditionally uncached. dnscache uses its internal cache to prevent certain classes of poisoning attack. Attackers may choose to send floods of SOA requests to bypass these protections.
option 'interfacesend' 'wan'
option 'defaultallowif' 'lan wan'
option 'cachesize' '1000000'
+ option 'hidettl' '0'
option 'forwardonly' '1'
option 'useresolvconf' '1'
list 'resolver' '208.67.222.222'
list 'resolver' '208.67.220.220'
+ option 'useignore' '0'
+ list 'ignoreip' '203.119.4.28'
+ list 'ignoreip' '212.181.91.6'
+ list 'ignoreip' '62.4.64.119'
+ list 'ignoreip' '64.70.19.33'
+ list 'ignoreip' '69.25.75.72'
option 'logging' '0'
config 'tinydns'
config_load djbdns
config_foreach get_userids global
mkdir -p $ROOT
- cp -fa /etc/dnscache/ip $ROOT
- cp -fa /etc/dnscache/servers $ROOT
+ cp -fa /etc/dnscache/* $ROOT
rm -f $ROOT/resolvers
+ rm -f $ROOT/ignoreip
chown -R $UID:$GID $ROOT
config_foreach start_dnscache dnscache
}
echo $1 >> $ROOT/resolvers
}
+append_ignore() {
+ echo $1 >> $ROOT/ignoreip
+}
+
start_dnscache() {
local cfg="$1"
config_get logging "$cfg" logging
config_get useresolvconf "$cfg" useresolvconf
- config_get ifaces "$cfg" interface
+ config_get iface "$cfg" interface
config_get ifacesend "$cfg" interfacesend
config_get defaultallowif "$cfg" defaultallowif
config_get CACHESIZE "$cfg" cachesize
config_get FORWARDONLY "$cfg" forwardonly
+ config_get HIDETTL "$cfg" hidettl
config_list_foreach "$cfg" "resolver" append_server
+ config_get useignore "$cfg" useignore
+ if [ "$useignore" == "1" ] ; then
+ config_list_foreach "$cfg" "ignoreip" append_ignore
+ fi
# Add some interface network addresses to list of allowed IP addresses (assumes /24 networks)
include /lib/network
scan_interfaces
done
fi
# Translate listen interface names to IP addresses
- IP=""
- for iface in $ifaces; do
- config_get ipaddr "$iface" ipaddr
- IP="$ipaddr/$IP"
- done
-# Strip trailing slashes
- IP=`echo $IP|sed 's/\/\+$//g'`
+ config_get IP "$iface" ipaddr
# Translante send interface name to an IP address
config_get IPSEND "$ifacesend" ipaddr
+# Unset HIDETTL if equal to 0
+ if [ "$HIDETTL" == "0" ] ; then
+ export -n HIDETTL
+ fi
# If forwardingonly set then activate list of resolvers
if [ "$FORWARDONLY" == "0" ] ; then
# Unset FORWARDONLY if equal to '0'
fi
export IP
export ROOT
-# dnscache likes to receive a 128bit random seed
+# dnscache likes to receive a 128 byte random seed
dd if=/dev/urandom of=$ROOT/randomseed bs=128 count=1 > /dev/null 2>&1
if [ "$DEBUG" == 1 ] ; then
$DAEMON < /$ROOT/randomseed
-198.41.0.4
-192.228.79.201
-192.33.4.12
-128.8.10.90
-192.203.230.10
-192.5.5.241
-192.112.36.4
-128.63.2.53
-192.36.148.17
-192.58.128.30
-193.0.14.129
-199.7.83.42
-202.12.27.33
--- /dev/null
+#!/bin/sh
+#
+# update-ignoreip version 0.1
+# Written by J.P. Larocque, <piranha@thoughtcrime.us>, OpenPGP 0x0c14cdda
+# This software is in the public domain.
+#
+# This script is intended for djbdns users that have applied Russell
+# Nelson's patch to circumvent wildcard A records in TLDs:
+#
+# http://tinydns.org/djbdns-1.05-ignoreip2.patch
+#
+# This script will try the wildcard name for each TLD in the
+# 'stupid_tlds' variable (eg, '*.com', '*.cx', etc.). For those
+# addresses that resolve, they get added to your dnscache
+# 'root/ignoreip' file, and dnscache is restarted.
+#
+# Run this script from your dnscache directory. This script depends
+# on a proper PATH. Old 'root/ignoreips' entries are kept (and dups
+# removed), so you can add this program to a cron job to keep ahead
+# of new bogus redirection addresses added by Verisign and other TLD
+# operators.
+#
+# Adding this script to a cron job was its intended purpose, but
+# please don't do so without understanding how it works and what could
+# happen if it breaks.
+#
+# The latest version of this program can be found at the URL:
+# http://ely.ath.cx/~piranha/software/ignoreip-update/
+# This program has been signed with my public key. Its fingerprint is:
+# 810B A0AC A7F7 2899 46D2 F2F6 3E7D 5279 0C14 CDDA
+# The detached signature can be found at the URL:
+# http://ely.ath.cx/~piranha/software/ignoreip-update/ignoreip-update-0.1.asc
+#
+# Changelog:
+# version 0.1 (2003/Sep/17)
+# Initially written and released.
+
+stupid_tlds='ac cc com cx museum net nu ph sh tm ws'
+ignoreip='root/ignoreip'
+
+set -e
+
+me="`basename "$0"`"
+
+if [ ! -d 'root' ]; then
+ echo "$me: run me from the dnscache directory" >&2
+ exit 1
+fi
+
+# I originally implemented this with random names, then realized all
+# the current $stupid_tlds answer to "*.$stupid_tld" just like any
+# other random name. This code may be useful in the future, if an
+# arms race of sorts develops. (Sigh.)
+
+if which md5sum > /dev/null 2>&1; then
+ hash_prog=md5sum
+elif which md5 > /dev/null 2>&1; then
+ hash_prog=md5
+else
+ echo "$me: can't find a suitable hash program" >&2
+ exit 1
+fi
+
+[ "$1" = '-v' ] && verbose=1 || verbose=''
+
+temp1="`mktemp "ignoreip-update-$$-1-XXXXXX"`"
+temp2="`mktemp "ignoreip-update-$$-2-XXXXXX"`"
+trap 'rm -f "$temp1" "$temp2"' EXIT
+
+## Generate random name
+#rand="`dd if=/dev/urandom bs=16 count=1 2> /dev/null | "$hash_prog"`"
+
+# Do lookups on random addresses; break into one addres/line; remove
+# empty lines
+for stupid_tld in $stupid_tlds; do
+ dnsip "$rand.$stupid_tld"
+ #dnsip "*.$stupid_tld"
+done | xargs -n 1 echo | grep '.' > "$temp1"
+
+# Abort if there were no new bogus addresses
+[ ! -s "$temp1" ] && exit
+
+# Remove duplicates (from old list and, eg, .sh/.tm)
+touch "$ignoreip"
+sort "$ignoreip" "$temp1" | uniq > "$temp2"
+
+if [ "$verbose" ]; then
+ diff -u "$ignoreip" "$temp2" || true
+fi
+
+# Update list and restart dnscache
+chmod 644 "$temp2"
+mv "$temp2" "$ignoreip"
+#svc -t .
+
-198.41.0.4
-192.228.79.201
-192.33.4.12
-128.8.10.90
-192.203.230.10
-192.5.5.241
-192.112.36.4
-128.63.2.53
-192.36.148.17
-192.58.128.30
-193.0.14.129
-199.7.83.42
-202.12.27.33
--- /dev/null
+--- a/Makefile
++++ b/Makefile
+@@ -29,10 +29,6 @@ auto-str.o: \
+ compile auto-str.c buffer.h exit.h
+ ./compile auto-str.c
+
+-auto_home.c: \
+-auto-str conf-home
+- ./auto-str auto_home `head -1 conf-home` > auto_home.c
+-
+ auto_home.o: \
+ compile auto_home.c
+ ./compile auto_home.c
+@@ -221,10 +217,6 @@ compile dd.c dns.h stralloc.h gen_alloc.
+ uint64.h taia.h dd.h
+ ./compile dd.c
+
+-direntry.h: \
+-choose compile trydrent.c direntry.h1 direntry.h2
+- ./choose c trydrent direntry.h1 direntry.h2 > direntry.h
+-
+ 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 \
+@@ -508,12 +500,6 @@ systype hasdevtcp.h1 hasdevtcp.h2
+ *) cat hasdevtcp.h1 ;; \
+ esac ) > hasdevtcp.h
+
+-hasshsgr.h: \
+-choose compile load tryshsgr.c hasshsgr.h1 hasshsgr.h2 chkshsgr \
+-warn-shsgr
+- ./chkshsgr || ( cat warn-shsgr; exit 1 )
+- ./choose clr tryshsgr hasshsgr.h1 hasshsgr.h2 > hasshsgr.h
+-
+ hier.o: \
+ compile hier.c auto_home.h
+ ./compile hier.c
+@@ -534,10 +520,6 @@ instcheck.o: \
+ compile instcheck.c strerr.h error.h exit.h
+ ./compile instcheck.c
+
+-iopause.h: \
+-choose compile load trypoll.c iopause.h1 iopause.h2
+- ./choose clr trypoll iopause.h1 iopause.h2 > iopause.h
+-
+ iopause.o: \
+ compile iopause.c taia.h tai.h uint64.h select.h iopause.h taia.h
+ ./compile iopause.c
+@@ -590,7 +572,7 @@ warn-auto.sh systype
+ dgux-*) ;; \
+ hp-ux-*) ;; \
+ sco*) ;; \
+- *) echo 'ranlib "$$main"' ;; \
++ *) echo '$(if $(TARGET_RANLIB),$(TARGET_RANLIB),ranlib) "$$main"' ;; \
+ esac \
+ ) > makelib
+ chmod 755 makelib
+@@ -766,10 +748,6 @@ seek_set.o: \
+ compile seek_set.c seek.h
+ ./compile seek_set.c
+
+-select.h: \
+-choose compile trysysel.c select.h1 select.h2
+- ./choose c trysysel select.h1 select.h2 > select.h
+-
+ server.o: \
+ 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 \
+@@ -1060,10 +1038,6 @@ uint32_unpack.o: \
+ compile uint32_unpack.c uint32.h
+ ./compile uint32_unpack.c
+
+-uint64.h: \
+-choose compile load tryulong64.c uint64.h1 uint64.h2
+- ./choose clr tryulong64 uint64.h1 uint64.h2 > uint64.h
+-
+ unix.a: \
+ makelib buffer_read.o buffer_write.o error.o error_str.o ndelay_off.o \
+ ndelay_on.o open_read.o open_trunc.o openreadclose.o readclose.o \
+--- /dev/null
++++ b/auto_home.c
+@@ -0,0 +1,3 @@
++const char auto_home[] = "\
++\057\165\163\162\
++";
+--- a/conf-cc
++++ b/conf-cc
+@@ -1,3 +1,3 @@
+-gcc -O2 -Wimplicit -Wunused -Wcomment -Wchar-subscripts -Wuninitialized -Wshadow -Wcast-qual -Wcast-align -Wwrite-strings
++$TARGET_CC $TARGET_CFLAGS -Wimplicit -Wunused -Wcomment -Wchar-subscripts -Wuninitialized -Wshadow -Wcast-qual -Wcast-align -Wwrite-strings -include errno.h
+
+ This will be used to compile .c files.
+--- a/conf-home
++++ b/conf-home
+@@ -1,4 +1,4 @@
+-/usr/local
++/usr
+
+ This is the dnscache home directory. Programs will be installed in
+ .../bin.
+--- a/conf-ld
++++ b/conf-ld
+@@ -1,3 +1,3 @@
+-gcc -s
++$TARGET_CC -s $TARGET_LDFLAGS
+
+ This will be used to link .o files into an executable.
+--- /dev/null
++++ b/direntry.h
+@@ -0,0 +1,10 @@
++#ifndef DIRENTRY_H
++#define DIRENTRY_H
++
++/* sysdep: +dirent */
++
++#include <sys/types.h>
++#include <dirent.h>
++#define direntry struct dirent
++
++#endif
+--- /dev/null
++++ b/hasshsgr.h
+@@ -0,0 +1 @@
++/* sysdep: -shortsetgroups */
+--- /dev/null
++++ b/iopause.h
+@@ -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
+--- /dev/null
++++ b/select.h
+@@ -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
+--- /dev/null
++++ b/uint64.h
+@@ -0,0 +1,8 @@
++#ifndef UINT64_H
++#define UINT64_H
++
++/* sysdep: -ulong64 */
++
++typedef unsigned long long uint64;
++
++#endif
--- /dev/null
+--- a/dnsroots.global
++++ b/dnsroots.global
+@@ -1,5 +1,5 @@
+ 198.41.0.4
+-128.9.0.107
++192.228.79.201
+ 192.33.4.12
+ 128.8.10.90
+ 192.203.230.10
+@@ -7,7 +7,7 @@
+ 192.112.36.4
+ 128.63.2.53
+ 192.36.148.17
+-198.41.0.10
++192.58.128.30
+ 193.0.14.129
+-198.32.64.12
++199.7.83.42
+ 202.12.27.33
--- /dev/null
+From: Michael Handler <handler@sub-rosa.com>
+To: dns@list.cr.yp.to
+Subject: tinydns-data SRV & axfr-get SRV/PTR patches
+Date: Thu, 14 Sep 2000 20:37:50 -0400
+
+Here's a combined patch that:
+
+a) adds a native SRV type to tinydns-data
+
+Sfqdn:ip:x:port:weight:priority:ttl:timestamp
+
+Standard rules for ip, x, ttl, and timestamp apply. Port, weight, and
+priority all range from 0-65535. Weight and priority are optional; they
+default to zero if not provided.
+
+Sconsole.zoinks.example.com:1.2.3.4:rack102-con1:2001:69:7:300:
+
+b) makes axfr-get decompose SRV and PTR records and write them out in
+native format, rather than opaque. Again, this is necessary because if the
+DNAME fields in the records reference the same zone as fqdn, they can have
+compression pointers that are bogus outside the context of that specific
+packet, and which can't be correctly loaded into data.cdb by tinydns-data.
+
+--michael
+
+Laurent G. Bercot <ska-djbdns@skarnet.org> updated it for djbdns-1.05:
+
+--- a/axfr-get.c
++++ b/axfr-get.c
+@@ -209,6 +209,26 @@ unsigned int doit(char *buf,unsigned int
+ if (!stralloc_cats(&line,".:")) return 0;
+ if (!stralloc_catulong0(&line,dist,0)) return 0;
+ }
++ else if (byte_equal(data,2,DNS_T_SRV)) {
++ uint16 dist, 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,&dist);
++ 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,dist,0)) return 0;
++ if (!stralloc_cats(&line,":")) return 0;
++ if (!stralloc_catulong0(&line,weight,0)) return 0;
++ if (!stralloc_cats(&line,":")) return 0;
++ if (!stralloc_catulong0(&line,port,0)) 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 +237,14 @@ unsigned int doit(char *buf,unsigned int
+ 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;
+--- a/dns.h
++++ b/dns.h
+@@ -20,6 +20,7 @@
+ #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_AXFR "\0\374"
+ #define DNS_T_ANY "\0\377"
+
+--- a/tinydns-data.c
++++ b/tinydns-data.c
+@@ -196,6 +196,7 @@ int main()
+ char type[2];
+ char soa[20];
+ char buf[4];
++ char srv[6];
+
+ umask(022);
+
+@@ -369,6 +370,43 @@ int main()
+ 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();
--- /dev/null
+--- a/log.h
++++ b/log.h
+@@ -1,6 +1,8 @@
+ #ifndef LOG_H
+ #define LOG_H
+
++#define STATS_DISPLAY_INTERVAL 5
++
+ #include "uint64.h"
+
+ extern void log_startup(void);
+--- a/log.c
++++ b/log.c
+@@ -1,6 +1,7 @@
+ #include "buffer.h"
+ #include "uint32.h"
+ #include "uint16.h"
++#include "time.h"
+ #include "error.h"
+ #include "byte.h"
+ #include "log.h"
+@@ -274,11 +275,17 @@ void log_rrsoa(const char server[4],cons
+
+ void log_stats(void)
+ {
++ static time_t prev = 0;
++ time_t cur = time(NULL);
+ extern uint64 numqueries;
+ extern uint64 cache_motion;
+ extern int uactive;
+ extern int tactive;
+
++ if(prev == 0) prev = time(NULL);
++ if(cur - prev < STATS_DISPLAY_INTERVAL) return;
++ prev = cur;
++
+ string("stats ");
+ number(numqueries); space();
+ number(cache_motion); space();
--- /dev/null
+--- a/tdlookup.c
++++ b/tdlookup.c
+@@ -298,9 +298,17 @@ int respond(char *q,char qtype[2],char i
+ 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 == -1) {
++ cdb_free(&c);
++ close(fd);
++ return 0;
++ }
+ if (r && (cdb_datalen(&c) == 2))
+- if (cdb_read(&c,clientloc,2,cdb_datapos(&c)) == -1) return 0;
++ if (cdb_read(&c,clientloc,2,cdb_datapos(&c)) == -1) {
++ cdb_free(&c);
++ close(fd);
++ return 0;
++ }
+
+ r = doit(q,qtype);
+
--- /dev/null
+--- a/dns_transmit.c
++++ b/dns_transmit.c
+@@ -240,7 +240,7 @@ void dns_transmit_io(struct dns_transmit
+
+ int dns_transmit_get(struct dns_transmit *d,const iopause_fd *x,const struct taia *when)
+ {
+- char udpbuf[513];
++ char udpbuf[4097];
+ unsigned char ch;
+ int r;
+ int fd;
--- /dev/null
+--- a/dns_transmit.c
++++ b/dns_transmit.c
+@@ -166,6 +166,7 @@ static int thistcp(struct dns_transmit *
+ taia_uint(&d->deadline,10);
+ taia_add(&d->deadline,&d->deadline,&now);
+ if (socket_connect4(d->s1 - 1,ip,53) == 0) {
++ d->pos = 0;
+ d->tcpstate = 2;
+ return 0;
+ }
--- /dev/null
+--- a/query.c
++++ b/query.c
+@@ -193,6 +193,7 @@ static int doit(struct query *z,int stat
+ int k;
+ int p;
+ int q;
++ uint32 cachettl;
+
+ errno = error_io;
+ if (state == 1) goto HAVEPACKET;
+@@ -470,6 +471,7 @@ static int doit(struct query *z,int stat
+ rcode = header[3] & 15;
+ if (rcode && (rcode != 3)) goto DIE; /* impossible; see irrelevant() */
+
++ cachettl = 0;
+ flagout = 0;
+ flagcname = 0;
+ flagreferral = 0;
+@@ -512,6 +514,11 @@ static int doit(struct query *z,int stat
+
+ uint16_unpack_big(header + 8,&datalen);
+ pos += datalen;
++
++ if (flagsoa && (pos <= len)) {
++ cachettl = ttlget(buf + pos - 4);
++ if (soattl < cachettl) cachettl = soattl;
++ }
+ }
+ posglue = pos;
+
+@@ -689,8 +696,8 @@ static int doit(struct query *z,int stat
+ }
+
+ if (rcode == 3) {
+- log_nxdomain(whichserver,d,soattl);
+- cachegeneric(DNS_T_ANY,d,"",0,soattl);
++ log_nxdomain(whichserver,d,cachettl);
++ cachegeneric(DNS_T_ANY,d,"",0,cachettl);
+
+ NXDOMAIN:
+ if (z->level) goto LOWERLEVEL;
--- /dev/null
+--- a/tdlookup.c
++++ b/tdlookup.c
+@@ -280,15 +280,24 @@ static int doit(char *q,char qtype[2])
+
+ int respond(char *q,char qtype[2],char ip[4])
+ {
+- int fd;
++ static struct tai cdb_valid = { 0 };
++ static int fd = -1;
++ struct tai one_second;
+ int r;
+ char key[6];
+
+ tai_now(&now);
+- fd = open_read("data.cdb");
+- if (fd == -1) return 0;
+- cdb_init(&c,fd);
+-
++ if (tai_less(&cdb_valid, &now)) {
++ if (fd != -1) {
++ cdb_free(&c);
++ close(fd);
++ }
++ fd = open_read("data.cdb");
++ if (fd == -1) return 0;
++ cdb_init(&c,fd);
++ tai_uint(&one_second, 1);
++ tai_add(&cdb_valid, &now, &one_second);
++ }
+ byte_zero(clientloc,2);
+ key[0] = 0;
+ key[1] = '%';
+@@ -312,7 +321,5 @@ int respond(char *q,char qtype[2],char i
+
+ r = doit(q,qtype);
+
+- cdb_free(&c);
+- close(fd);
+ return r;
+ }
+++ /dev/null
-diff -urN djbdns-1.05/Makefile djbdns-1.05.new/Makefile
---- djbdns-1.05/Makefile 2001-02-11 23:11:45.000000000 +0200
-+++ djbdns-1.05.new/Makefile 2007-09-30 15:09:51.000000000 +0300
-@@ -29,10 +29,6 @@
- compile auto-str.c buffer.h exit.h
- ./compile auto-str.c
-
--auto_home.c: \
--auto-str conf-home
-- ./auto-str auto_home `head -1 conf-home` > auto_home.c
--
- auto_home.o: \
- compile auto_home.c
- ./compile auto_home.c
-@@ -221,10 +217,6 @@
- uint64.h taia.h dd.h
- ./compile dd.c
-
--direntry.h: \
--choose compile trydrent.c direntry.h1 direntry.h2
-- ./choose c trydrent direntry.h1 direntry.h2 > direntry.h
--
- 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 \
-@@ -508,12 +500,6 @@
- *) cat hasdevtcp.h1 ;; \
- esac ) > hasdevtcp.h
-
--hasshsgr.h: \
--choose compile load tryshsgr.c hasshsgr.h1 hasshsgr.h2 chkshsgr \
--warn-shsgr
-- ./chkshsgr || ( cat warn-shsgr; exit 1 )
-- ./choose clr tryshsgr hasshsgr.h1 hasshsgr.h2 > hasshsgr.h
--
- hier.o: \
- compile hier.c auto_home.h
- ./compile hier.c
-@@ -534,10 +520,6 @@
- compile instcheck.c strerr.h error.h exit.h
- ./compile instcheck.c
-
--iopause.h: \
--choose compile load trypoll.c iopause.h1 iopause.h2
-- ./choose clr trypoll iopause.h1 iopause.h2 > iopause.h
--
- iopause.o: \
- compile iopause.c taia.h tai.h uint64.h select.h iopause.h taia.h
- ./compile iopause.c
-@@ -766,10 +748,6 @@
- compile seek_set.c seek.h
- ./compile seek_set.c
-
--select.h: \
--choose compile trysysel.c select.h1 select.h2
-- ./choose c trysysel select.h1 select.h2 > select.h
--
- server.o: \
- 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 \
-@@ -1060,10 +1038,6 @@
- compile uint32_unpack.c uint32.h
- ./compile uint32_unpack.c
-
--uint64.h: \
--choose compile load tryulong64.c uint64.h1 uint64.h2
-- ./choose clr tryulong64 uint64.h1 uint64.h2 > uint64.h
--
- unix.a: \
- makelib buffer_read.o buffer_write.o error.o error_str.o ndelay_off.o \
- ndelay_on.o open_read.o open_trunc.o openreadclose.o readclose.o \
-diff -urN djbdns-1.05/auto_home.c djbdns-1.05.new/auto_home.c
---- djbdns-1.05/auto_home.c 1970-01-01 03:00:00.000000000 +0300
-+++ djbdns-1.05.new/auto_home.c 2007-09-30 13:32:06.000000000 +0300
-@@ -0,0 +1,3 @@
-+const char auto_home[] = "\
-+\057\165\163\162\
-+";
-diff -urN djbdns-1.05/conf-cc djbdns-1.05.new/conf-cc
---- djbdns-1.05/conf-cc 2007-09-30 14:11:35.000000000 +0300
-+++ djbdns-1.05.new/conf-cc 2007-09-30 15:10:46.000000000 +0300
-@@ -1,3 +1,3 @@
--gcc -O2 -Wimplicit -Wunused -Wcomment -Wchar-subscripts -Wuninitialized -Wshadow -Wcast-qual -Wcast-align -Wwrite-strings
-+$TARGET_CC $TARGET_CFLAGS -Wimplicit -Wunused -Wcomment -Wchar-subscripts -Wuninitialized -Wshadow -Wcast-qual -Wcast-align -Wwrite-strings -include errno.h
-
- This will be used to compile .c files.
-diff -urN djbdns-1.05/conf-home djbdns-1.05.new/conf-home
---- djbdns-1.05/conf-home 2001-02-11 23:11:45.000000000 +0200
-+++ djbdns-1.05.new/conf-home 2007-09-30 14:10:46.000000000 +0300
-@@ -1,4 +1,4 @@
--/usr/local
-+/usr
-
- This is the dnscache home directory. Programs will be installed in
- .../bin.
-diff -urN djbdns-1.05/conf-ld djbdns-1.05.new/conf-ld
---- djbdns-1.05/conf-ld 2001-02-11 23:11:45.000000000 +0200
-+++ djbdns-1.05.new/conf-ld 2007-09-30 15:11:00.000000000 +0300
-@@ -1,3 +1,3 @@
--gcc -s
-+$TARGET_CC -s $TARGET_LDFLAGS
-
- This will be used to link .o files into an executable.
-diff -urN djbdns-1.05/direntry.h djbdns-1.05.new/direntry.h
---- djbdns-1.05/direntry.h 1970-01-01 03:00:00.000000000 +0300
-+++ djbdns-1.05.new/direntry.h 2007-09-30 13:14:14.000000000 +0300
-@@ -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 -urN djbdns-1.05/hasshsgr.h djbdns-1.05.new/hasshsgr.h
---- djbdns-1.05/hasshsgr.h 1970-01-01 03:00:00.000000000 +0300
-+++ djbdns-1.05.new/hasshsgr.h 2007-09-30 13:14:14.000000000 +0300
-@@ -0,0 +1 @@
-+/* sysdep: -shortsetgroups */
-diff -urN djbdns-1.05/iopause.h djbdns-1.05.new/iopause.h
---- djbdns-1.05/iopause.h 1970-01-01 03:00:00.000000000 +0300
-+++ djbdns-1.05.new/iopause.h 2007-09-30 13:14:14.000000000 +0300
-@@ -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 -urN djbdns-1.05/select.h djbdns-1.05.new/select.h
---- djbdns-1.05/select.h 1970-01-01 03:00:00.000000000 +0300
-+++ djbdns-1.05.new/select.h 2007-09-30 13:14:14.000000000 +0300
-@@ -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 -urN djbdns-1.05/uint64.h djbdns-1.05.new/uint64.h
---- djbdns-1.05/uint64.h 1970-01-01 03:00:00.000000000 +0300
-+++ djbdns-1.05.new/uint64.h 2007-09-30 13:23:48.000000000 +0300
-@@ -0,0 +1,8 @@
-+#ifndef UINT64_H
-+#define UINT64_H
-+
-+/* sysdep: -ulong64 */
-+
-+typedef unsigned long long uint64;
-+
-+#endif
+++ /dev/null
-#
-# This patch to djbdns 1.05 modifies the dnscache program to keep a
-# counter of cache hits and cache misses.
-#
-# Two new fields are added to the ``stats'' output line:
-# . the fifth number is the number of cache hits
-# . the sixth number is the number of cache misses
-# e.g.
-# @400000003fa92ccc317d70f4 stats 3 1201 1 0 21 49
-# indicates 21 hits and 49 misses.
-#
-# James Raftery <james@now.ie> 6 Nov. 2003
-#
---- djbdns-1.05.orig/cache.c Sun Feb 11 21:11:45 2001
-+++ djbdns-1.05/cache.c Wed Nov 5 17:21:06 2003
-@@ -7,6 +7,11 @@
-
- uint64 cache_motion = 0;
-
-+/* record cache stats */
-+/* James Raftery <james@now.ie> 6 Nov. 2003 */
-+uint64 cache_hit = 0;
-+uint64 cache_miss = 0;
-+
- static char *x = 0;
- static uint32 size;
- static uint32 hsize;
-@@ -112,15 +117,20 @@
- if (u > size - pos - 20 - keylen) cache_impossible();
- *datalen = u;
-
-+ cache_hit++;
- return x + pos + 20 + keylen;
- }
- }
- nextpos = prevpos ^ get4(pos);
- prevpos = pos;
- pos = nextpos;
-- if (++loop > 100) return 0; /* to protect against hash flooding */
-+ if (++loop > 100) { /* to protect against hash flooding */
-+ cache_miss++;
-+ return 0;
-+ }
- }
-
-+ cache_miss++;
- return 0;
- }
-
---- djbdns-1.05.orig/cache.h Sun Feb 11 21:11:45 2001
-+++ djbdns-1.05/cache.h Wed Nov 5 17:13:36 2003
-@@ -5,6 +5,12 @@
- #include "uint64.h"
-
- extern uint64 cache_motion;
-+
-+/* record cache stats */
-+/* James Raftery <james@now.ie> 6 Nov. 2003 */
-+extern uint64 cache_hit;
-+extern uint64 cache_miss;
-+
- 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 *);
---- djbdns-1.05.orig/log.c Sun Feb 11 21:11:45 2001
-+++ djbdns-1.05/log.c Wed Nov 5 17:21:12 2003
-@@ -276,6 +276,12 @@
- {
- extern uint64 numqueries;
- extern uint64 cache_motion;
-+
-+ /* record cache stats */
-+ /* James Raftery <james@now.ie> 6 Nov. 2003 */
-+ extern uint64 cache_hit;
-+ extern uint64 cache_miss;
-+
- extern int uactive;
- extern int tactive;
-
-@@ -283,6 +289,8 @@
- number(numqueries); space();
- number(cache_motion); space();
- number(uactive); space();
-- number(tactive);
-+ number(tactive); space();
-+ number(cache_hit); space();
-+ number(cache_miss);
- line();
- }
--- /dev/null
+#
+# This patch to djbdns 1.05 modifies the dnscache program to keep a
+# counter of cache hits and cache misses.
+#
+# Two new fields are added to the ``stats'' output line:
+# . the fifth number is the number of cache hits
+# . the sixth number is the number of cache misses
+# e.g.
+# @400000003fa92ccc317d70f4 stats 3 1201 1 0 21 49
+# indicates 21 hits and 49 misses.
+#
+# James Raftery <james@now.ie> 6 Nov. 2003
+#
+--- a/cache.c
++++ b/cache.c
+@@ -7,6 +7,11 @@
+
+ uint64 cache_motion = 0;
+
++/* record cache stats */
++/* James Raftery <james@now.ie> 6 Nov. 2003 */
++uint64 cache_hit = 0;
++uint64 cache_miss = 0;
++
+ static char *x = 0;
+ static uint32 size;
+ static uint32 hsize;
+@@ -112,15 +117,20 @@ char *cache_get(const char *key,unsigned
+ if (u > size - pos - 20 - keylen) cache_impossible();
+ *datalen = u;
+
++ cache_hit++;
+ return x + pos + 20 + keylen;
+ }
+ }
+ nextpos = prevpos ^ get4(pos);
+ prevpos = pos;
+ pos = nextpos;
+- if (++loop > 100) return 0; /* to protect against hash flooding */
++ if (++loop > 100) { /* to protect against hash flooding */
++ cache_miss++;
++ return 0;
++ }
+ }
+
++ cache_miss++;
+ return 0;
+ }
+
+--- a/cache.h
++++ b/cache.h
+@@ -5,6 +5,12 @@
+ #include "uint64.h"
+
+ extern uint64 cache_motion;
++
++/* record cache stats */
++/* James Raftery <james@now.ie> 6 Nov. 2003 */
++extern uint64 cache_hit;
++extern uint64 cache_miss;
++
+ 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 *);
+--- a/log.c
++++ b/log.c
+@@ -279,6 +279,12 @@ void log_stats(void)
+ time_t cur = time(NULL);
+ extern uint64 numqueries;
+ extern uint64 cache_motion;
++
++ /* record cache stats */
++ /* James Raftery <james@now.ie> 6 Nov. 2003 */
++ extern uint64 cache_hit;
++ extern uint64 cache_miss;
++
+ extern int uactive;
+ extern int tactive;
+
+@@ -290,6 +296,8 @@ void log_stats(void)
+ number(numqueries); space();
+ number(cache_motion); space();
+ number(uactive); space();
+- number(tactive);
++ number(tactive); space();
++ number(cache_hit); space();
++ number(cache_miss);
+ line();
+ }
---- djbdns-1.05.original/pickdns-data.c 2001-02-11 21:11:45.000000000 +0000
-+++ djbdns-1.05/pickdns-data.c 2003-10-19 10:47:17.000000000 +0100
-@@ -123,7 +123,7 @@
+--- a/pickdns-data.c
++++ b/pickdns-data.c
+@@ -123,7 +123,7 @@ void syntaxerror(const char *why)
}
void die_datatmp(void)
{
}
int main()
-@@ -142,7 +142,7 @@
+@@ -142,7 +142,7 @@ int main()
if (fd == -1) strerr_die2sys(111,FATAL,"unable to open data: ");
buffer_init(&b,buffer_unixread,fd,bspace,sizeof bspace);
if (fdcdb == -1) die_datatmp();
if (cdb_make_start(&cdb,fdcdb) == -1) die_datatmp();
-@@ -223,8 +223,8 @@
+@@ -223,8 +223,8 @@ int main()
if (cdb_make_finish(&cdb) == -1) die_datatmp();
if (fsync(fdcdb) == -1) die_datatmp();
if (close(fdcdb) == -1) die_datatmp(); /* NFS stupidity */
_exit(0);
}
---- djbdns-1.05.original/rbldns-data.c 2001-02-11 21:11:45.000000000 +0000
-+++ djbdns-1.05/rbldns-data.c 2003-10-19 10:47:30.000000000 +0100
-@@ -42,7 +42,7 @@
+--- a/rbldns-data.c
++++ b/rbldns-data.c
+@@ -42,7 +42,7 @@ void syntaxerror(const char *why)
}
void die_datatmp(void)
{
}
int main()
-@@ -59,7 +59,7 @@
+@@ -59,7 +59,7 @@ int main()
if (fd == -1) strerr_die2sys(111,FATAL,"unable to open data: ");
buffer_init(&b,buffer_unixread,fd,bspace,sizeof bspace);
if (fdcdb == -1) die_datatmp();
if (cdb_make_start(&cdb,fdcdb) == -1) die_datatmp();
-@@ -121,8 +121,8 @@
+@@ -121,8 +121,8 @@ int main()
if (cdb_make_finish(&cdb) == -1) die_datatmp();
if (fsync(fdcdb) == -1) die_datatmp();
if (close(fdcdb) == -1) die_datatmp(); /* NFS stupidity */
_exit(0);
}
---- djbdns-1.05.original/tinydns-data.c 2001-02-11 21:11:45.000000000 +0000
-+++ djbdns-1.05/tinydns-data.c 2003-10-19 11:59:16.000000000 +0100
+--- a/tinydns-data.c
++++ b/tinydns-data.c
@@ -27,7 +27,7 @@
void die_datatmp(void)
}
void nomem(void)
{
-@@ -206,7 +206,7 @@
+@@ -207,7 +207,7 @@ int main()
buffer_init(&b,buffer_unixread,fddata,bspace,sizeof bspace);
if (fdcdb == -1) die_datatmp();
if (cdb_make_start(&cdb,fdcdb) == -1) die_datatmp();
-@@ -449,8 +449,8 @@
+@@ -487,8 +487,8 @@ int main()
if (cdb_make_finish(&cdb) == -1) die_datatmp();
if (fsync(fdcdb) == -1) die_datatmp();
if (close(fdcdb) == -1) die_datatmp(); /* NFS stupidity */
+++ /dev/null
---- djbdns-1.05.orig/dnscache.c.orig Tue Feb 27 00:32:52 2001
-+++ djbdns-1.05/dnscache.c Tue Feb 27 00:30:58 2001
-@@ -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"
-@@ -47,12 +48,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 +69,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 +88,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 +118,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 +140,6 @@
- }
-
-
--static int tcp53;
--
- #define MAXTCP 20
- struct tcpclient {
- struct query q;
-@@ -138,6 +147,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 +276,7 @@
- x->state = 0;
- }
-
--void t_new(void)
-+void t_new(int fd)
- {
- int i;
- int j;
-@@ -290,8 +300,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 +315,24 @@
- log_tcpopen(x->ip,x->port);
- }
-
-+#define FATAL "dnscache: fatal: "
-
--iopause_fd io[3 + MAXUDP + MAXTCP];
--iopause_fd *udp53io;
--iopause_fd *tcp53io;
-+iopause_fd *io = 0;
-+int numio;
-
- 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 +340,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 +390,82 @@
- 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;
-+ 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);
-@@ -439,8 +493,11 @@
- 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,": ");
-+ }
-
- log_startup();
- doit();
---- djbdns-1.05.orig/log.c.orig Tue Feb 27 00:33:02 2001
-+++ djbdns-1.05/log.c Tue Feb 27 00:30:58 2001
-@@ -94,6 +94,13 @@
- line();
- }
-
-+void log_listen(const char addr[4])
-+{
-+ string("listening on ");
-+ ip(addr);
-+ line();
-+}
-+
- 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();
---- djbdns-1.05.orig/log.h.orig Tue Feb 27 00:33:09 2001
-+++ djbdns-1.05/log.h Tue Feb 27 00:30:58 2001
-@@ -4,6 +4,7 @@
- #include "uint64.h"
-
- extern void log_startup(void);
-+extern void log_listen(const char *);
-
- extern void log_query(uint64 *,const char *,unsigned int,const char *,const char *,const char *);
- extern void log_querydrop(uint64 *);
---- ../djbdns-1.05-original/dnsnamex.c Tue May 27 02:17:04 2003
-+++ ./dnsnamex.c Tue May 27 02:18:52 2003
+--- /dev/null
++++ b/dnsnamex.c
@@ -0,0 +1,34 @@
+#include "buffer.h"
+#include "exit.h"
+ buffer_flush(buffer_1);
+ _exit(0);
+}
---- ../djbdns-1.05-original/dns_namex.c Tue May 27 02:17:09 2003
-+++ ./dns_namex.c Tue May 27 02:15:15 2003
+--- /dev/null
++++ b/dns_namex.c
@@ -0,0 +1,48 @@
+#include "stralloc.h"
+#include "uint16.h"
+ dns_domain_free(&q);
+ return 0;
+}
---- ../djbdns-1.05-original/dns.h Sun Feb 11 21:11:45 2001
-+++ ./dns.h Tue May 27 02:10:30 2003
-@@ -69,9 +69,11 @@
+--- a/dns.h
++++ b/dns.h
+@@ -70,9 +70,11 @@ extern struct dns_transmit dns_resolve_t
extern int dns_ip4_packet(stralloc *,const char *,unsigned int);
extern int dns_ip4(stralloc *,const stralloc *);
extern int dns_name_packet(stralloc *,const char *,unsigned int);
extern int dns_txt_packet(stralloc *,const char *,unsigned int);
extern int dns_txt(stralloc *,const stralloc *);
extern int dns_mx_packet(stralloc *,const char *,unsigned int);
---- ../djbdns-1.05-original/Makefile Sun Feb 11 21:11:45 2001
-+++ ./Makefile Tue May 27 02:21:00 2003
-@@ -227,10 +227,10 @@
+--- a/Makefile
++++ b/Makefile
+@@ -219,10 +219,10 @@ uint64.h taia.h dd.h
dns.a: \
makelib dns_dfd.o dns_domain.o dns_dtda.o dns_ip.o dns_ipq.o dns_mx.o \
dns_random.o dns_rcip.o dns_rcrw.o dns_resolve.o \
dns_sortip.o dns_transmit.o dns_txt.o
-@@ -269,6 +269,11 @@
+@@ -261,6 +261,11 @@ compile dns_name.c stralloc.h gen_alloc.
stralloc.h iopause.h taia.h tai.h uint64.h taia.h
./compile dns_name.c
dns_nd.o: \
compile dns_nd.c byte.h fmt.h dns.h stralloc.h gen_alloc.h iopause.h \
taia.h tai.h uint64.h taia.h
-@@ -402,6 +407,17 @@
+@@ -394,6 +399,17 @@ compile dnsname.c buffer.h exit.h strerr
gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h
./compile dnsname.c
dnsq: \
load dnsq.o iopause.o printrecord.o printpacket.o parsetype.o dns.a \
env.a libtai.a buffer.a alloc.a unix.a byte.a socket.lib
-@@ -676,7 +692,7 @@
+@@ -658,7 +674,7 @@ prog: \
dnscache-conf dnscache walldns-conf walldns rbldns-conf rbldns \
rbldns-data pickdns-conf pickdns pickdns-data tinydns-conf tinydns \
tinydns-data tinydns-get tinydns-edit axfr-get axfrdns-conf axfrdns \
---- djbdns-1.05-original/query.c Sun Feb 11 21:11:45 2001
-+++ djbdns-1.05/query.c Wed Mar 26 15:48:20 2003
-@@ -91,6 +91,21 @@
+--- a/query.c
++++ b/query.c
+@@ -91,6 +91,21 @@ static void cleanup(struct query *z)
}
}
static int rqa(struct query *z)
{
int i;
-@@ -123,7 +138,6 @@
+@@ -123,7 +138,6 @@ static int globalip(char *d,char ip[4])
static char *t1 = 0;
static char *t2 = 0;
static char *t3 = 0;
static char *referral = 0;
static unsigned int *records = 0;
-@@ -179,15 +193,14 @@
+@@ -179,15 +193,14 @@ static int doit(struct query *z,int stat
uint16 datalen;
char *control;
char *d;
int i;
int j;
int k;
-@@ -252,7 +265,10 @@
+@@ -253,7 +266,10 @@ static int doit(struct query *z,int stat
byte_copy(key,2,DNS_T_CNAME);
cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
if (typematch(DNS_T_CNAME,dtype)) {
log_cachedanswer(d,DNS_T_CNAME);
if (!rqa(z)) goto DIE;
-@@ -261,8 +277,11 @@
+@@ -262,8 +278,11 @@ static int doit(struct query *z,int stat
return 1;
}
log_cachedcname(d,cached);
}
if (typematch(DNS_T_NS,dtype)) {
-@@ -351,7 +370,7 @@
+@@ -352,7 +371,7 @@ static int doit(struct query *z,int stat
}
}
byte_copy(key,2,dtype);
cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) {
-@@ -471,29 +490,31 @@
- if (rcode && (rcode != 3)) goto DIE; /* impossible; see irrelevant() */
+@@ -473,29 +492,31 @@ static int doit(struct query *z,int stat
+ cachettl = 0;
flagout = 0;
- flagcname = 0;
flagreferral = 0;
posauthority = pos;
for (j = 0;j < numauthority;++j) {
-@@ -515,15 +536,6 @@
+@@ -522,15 +543,6 @@ static int doit(struct query *z,int stat
}
posglue = pos;
if (records) { alloc_free(records); records = 0; }
k = numanswers + numauthority + numglue;
-@@ -670,24 +682,36 @@
+@@ -677,24 +689,36 @@ static int doit(struct query *z,int stat
alloc_free(records); records = 0;
+ /* A "no such name" error applies to the end of any CNAME chain, not to the start. */
if (rcode == 3) {
- log_nxdomain(whichserver,d,soattl);
- cachegeneric(DNS_T_ANY,d,"",0,soattl);
-@@ -700,10 +724,26 @@
+ log_nxdomain(whichserver,d,cachettl);
+ cachegeneric(DNS_T_ANY,d,"",0,cachettl);
+@@ -707,10 +731,26 @@ static int doit(struct query *z,int stat
return 1;
}
save_start();
save_finish(dtype,d,soattl);
log_nodata(whichserver,d,dtype,soattl);
-@@ -815,6 +855,7 @@
+@@ -822,6 +862,7 @@ static int doit(struct query *z,int stat
DIE:
cleanup(z);
if (records) { alloc_free(records); records = 0; }
---- djbdns-1.05.original/log.h 2001-02-11 21:11:45.000000000 +0000
-+++ djbdns-1.05/log.h 2003-07-29 17:12:44.000000000 +0100
-@@ -23,6 +23,7 @@
+--- a/log.h
++++ b/log.h
+@@ -25,6 +25,7 @@ extern void log_nxdomain(const char *,co
extern void log_nodata(const char *,const char *,const char *,unsigned int);
extern void log_servfail(const char *);
extern void log_lame(const char *,const char *,const char *);
extern void log_rr(const char *,const char *,const char *,const char *,unsigned int,unsigned int);
extern void log_rrns(const char *,const char *,const char *,unsigned int);
---- djbdns-1.05.original/log.c 2001-02-11 21:11:45.000000000 +0000
-+++ djbdns-1.05/log.c 2003-07-29 17:12:33.000000000 +0100
-@@ -196,6 +196,13 @@
+--- a/log.c
++++ b/log.c
+@@ -197,6 +197,13 @@ void log_lame(const char server[4],const
line();
}
void log_servfail(const char *dn)
{
const char *x = error_str(errno);
---- djbdns-1.05.original/query.c 2001-02-11 21:11:45.000000000 +0000
-+++ djbdns-1.05/query.c 2003-07-29 17:13:13.000000000 +0100
-@@ -781,6 +781,18 @@
+--- a/query.c
++++ b/query.c
+@@ -828,6 +828,18 @@ static int doit(struct query *z,int stat
if (!dns_domain_suffix(d,referral)) goto DIE;
---- djbdns-1.05.original/dns_rcip.c 2001-02-11 21:11:45.000000000 +0000
-+++ djbdns-1.05/dns_rcip.c 2003-11-03 14:55:10.000000000 +0000
-@@ -17,7 +17,7 @@
+--- a/dns_rcip.c
++++ b/dns_rcip.c
+@@ -17,7 +17,7 @@ static int init(char ip[64])
x = env_get("DNSCACHEIP");
if (x)
while (iplen <= 60) {
---- djbdns-1.05.orig/tinydns-data.c.orig 2004-01-10 02:20:08.000000000 +0000
-+++ djbdns-1.05/tinydns-data.c 2004-01-10 02:28:50.000000000 +0000
+--- a/tinydns-data.c
++++ b/tinydns-data.c
@@ -25,6 +25,14 @@
#define FATAL "tinydns-data: fatal: "
+}
void die_datatmp(void)
{
- strerr_die2sys(111,FATAL,"unable to create data.tmp: ");
-@@ -34,20 +42,39 @@
+ strerr_die2sys(111,FATAL,"unable to create data.cdb.tmp: ");
+@@ -34,20 +42,39 @@ void nomem(void)
strerr_die1sys(111,FATAL);
}
if (!(i & 1)) ch <<= 4;
ttd[i >> 1] |= ch;
}
-@@ -55,6 +82,10 @@
+@@ -55,6 +82,10 @@ void ttdparse(stralloc *sa,char ttd[8])
void locparse(stralloc *sa,char loc[2])
{
loc[0] = (sa->len > 0) ? sa->s[0] : 0;
loc[1] = (sa->len > 1) ? sa->s[1] : 0;
}
-@@ -187,6 +218,7 @@
+@@ -187,6 +218,7 @@ int main()
int i;
int j;
int k;
char ch;
unsigned long ttl;
char ttd[8];
-@@ -266,8 +298,7 @@
+@@ -267,8 +299,7 @@ int main()
if (!scan_ulong(f[7].s,&u)) uint32_unpack_big(defaultsoa + 16,&u);
uint32_pack_big(soa + 16,u);
ttdparse(&f[9],ttd);
locparse(&f[10],loc);
-@@ -282,8 +313,7 @@
+@@ -283,8 +314,7 @@ int main()
case '.': case '&':
if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
ttdparse(&f[4],ttd);
locparse(&f[5],loc);
-@@ -308,24 +338,26 @@
+@@ -309,24 +339,26 @@ int main()
rr_addname(d2);
rr_finish(d1);
rr_start(DNS_T_A,ttl,ttd,loc);
rr_add(ip,4);
rr_finish(d1);
-@@ -336,13 +368,15 @@
+@@ -337,13 +369,15 @@ int main()
rr_addname(d1);
rr_finish(dptr);
}
ttdparse(&f[5],ttd);
locparse(&f[6],loc);
-@@ -363,18 +397,19 @@
+@@ -401,18 +435,19 @@ int main()
rr_addname(d2);
rr_finish(d1);
ttdparse(&f[3],ttd);
locparse(&f[4],loc);
-@@ -388,8 +423,7 @@
+@@ -426,8 +461,7 @@ int main()
case '\'':
if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
ttdparse(&f[3],ttd);
locparse(&f[4],loc);
-@@ -411,8 +445,7 @@
+@@ -449,8 +483,7 @@ int main()
case ':':
if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
---- djbdns-1.05-original/tdlookup.c Sun Feb 11 21:11:45 2001
-+++ djbdns-1.05/tdlookup.c Thu Apr 3 11:56:47 2003
-@@ -103,12 +103,13 @@
+--- a/tdlookup.c
++++ b/tdlookup.c
+@@ -103,12 +103,13 @@ static int doname(void)
return response_addname(d1);
}
char *control;
char *wild;
int flaggavesoa;
-@@ -122,6 +123,12 @@
+@@ -122,6 +123,12 @@ static int doit(char *q,char qtype[2])
int addrnum;
uint32 addrttl;
int i;
anpos = response_len;
-@@ -136,7 +143,14 @@
+@@ -136,7 +143,14 @@ static int doit(char *q,char qtype[2])
if (byte_equal(type,2,DNS_T_NS)) flagns = 1;
}
if (flagns) break;
control += *control;
control += 1;
}
-@@ -172,8 +186,16 @@
+@@ -172,9 +186,17 @@ static int doit(char *q,char qtype[2])
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 (byte_equal(type,2,DNS_T_NS) || byte_equal(type,2,DNS_T_PTR)) {
-+ if (!doname()) return 0;
-+ }
-+ else if (byte_equal(type,2,DNS_T_CNAME)) {
if (!doname()) return 0;
+ }
++ else if (byte_equal(type,2,DNS_T_CNAME)) {
++ if (!doname()) return 0;
+ if (byte_diff(type,2,qtype)) {
+ response_rfinish(RESPONSE_ANSWER);
+ if (!dns_domain_copy(pqname,d1)) return 0 ;
+ goto RESTART ;
+ }
- }
++ }
else if (byte_equal(type,2,DNS_T_MX)) {
if (!dobytes(2)) return 0;
-@@ -275,9 +297,21 @@
+ if (!doname()) return 0;
+@@ -275,9 +297,21 @@ static int doit(char *q,char qtype[2])
}
}
+
int respond(char *q,char qtype[2],char ip[4])
{
- int fd;
+ static struct tai cdb_valid = { 0 };
+++ /dev/null
---- /home/uwe/djbdns-1.05/server.c Sun Feb 11 21:11:45 2001
-+++ ./server.c Fri May 4 07:40:54 2001
-@@ -25,12 +25,63 @@
-
- static char *q;
-
-+static uint64 stats_numq;
-+static uint64 stats_plus;
-+static uint64 stats_minus;
-+static uint64 stats_nx;
-+static uint64 stats_notimp;
-+static uint64 stats_weird;
-+static uint64 stats_noq;
-+
-+/* work around gcc 2.95.2 bug */
-+#define number(x) ( (u64 = (x)), u64_print() )
-+static uint64 u64;
-+static void u64_print(void)
-+{
-+ char ubuf[20];
-+ unsigned int pos;
-+
-+ pos = sizeof ubuf;
-+ do {
-+ if (!pos) break;
-+ ubuf[--pos] = '0' + (u64 % 10);
-+ u64 /= 10;
-+ } while(u64);
-+
-+ buffer_put(buffer_2,ubuf + pos,sizeof ubuf - pos);
-+}
-+
-+static void string(const char *s)
-+{
-+ buffer_puts(buffer_2,s);
-+}
-+
-+static void line(void)
-+{
-+ string("\n");
-+ buffer_flush(buffer_2);
-+}
-+
-+static void log_stats(void)
-+{
-+ string("stats ");
-+ number(stats_numq); string(" ");
-+ number(stats_plus); string(" ");
-+ number(stats_minus); string(" ");
-+ number(stats_nx); string(" ");
-+ number(stats_notimp); string(" ");
-+ number(stats_weird); string(" ");
-+ number(stats_noq);
-+ line();
-+}
-+
- static int doit(void)
- {
- unsigned int pos;
- char header[12];
- char qtype[2];
- char qclass[2];
-+ stats_numq++;
-
- if (len >= sizeof buf) goto NOQ;
- pos = dns_packet_copy(buf,len,0,header,12); if (!pos) goto NOQ;
-@@ -56,25 +105,37 @@
-
- case_lowerb(q,dns_domain_length(q));
- if (!respond(q,qtype,ip)) {
-+ stats_minus++;
- qlog(ip,port,header,q,qtype," - ");
- return 0;
- }
-- qlog(ip,port,header,q,qtype," + ");
-+
-+ if ((response[2] & 4) && (response[3] & 3)) {
-+ stats_nx++;
-+ qlog(ip,port,header,q,qtype," N ");
-+ }
-+ else {
-+ stats_plus++;
-+ qlog(ip,port,header,q,qtype," + ");
-+ }
- return 1;
-
- NOTIMP:
-+ stats_notimp++;
- response[3] &= ~15;
- response[3] |= 4;
- qlog(ip,port,header,q,qtype," I ");
- return 1;
-
- WEIRDCLASS:
-+ stats_weird++;
- response[3] &= ~15;
- response[3] |= 1;
- qlog(ip,port,header,q,qtype," C ");
- return 1;
-
- NOQ:
-+ stats_noq++;
- qlog(ip,port,"\0\0","","\0\0"," / ");
- return 0;
- }
-@@ -83,6 +137,7 @@
- {
- char *x;
- int udp53;
-+ unsigned char flag=0;
-
- x = env_get("IP");
- if (!x)
-@@ -106,6 +161,8 @@
- buffer_putsflush(buffer_2,starting);
-
- for (;;) {
-+ if ((flag++)%32==1)
-+ log_stats();
- len = socket_recv4(udp53,buf,sizeof buf,ip,&port);
- if (len < 0) continue;
- if (!doit()) continue;
--- /dev/null
+--- a/server.c
++++ b/server.c
+@@ -25,12 +25,63 @@ static int len;
+
+ static char *q;
+
++static uint64 stats_numq;
++static uint64 stats_plus;
++static uint64 stats_minus;
++static uint64 stats_nx;
++static uint64 stats_notimp;
++static uint64 stats_weird;
++static uint64 stats_noq;
++
++/* work around gcc 2.95.2 bug */
++#define number(x) ( (u64 = (x)), u64_print() )
++static uint64 u64;
++static void u64_print(void)
++{
++ char ubuf[20];
++ unsigned int pos;
++
++ pos = sizeof ubuf;
++ do {
++ if (!pos) break;
++ ubuf[--pos] = '0' + (u64 % 10);
++ u64 /= 10;
++ } while(u64);
++
++ buffer_put(buffer_2,ubuf + pos,sizeof ubuf - pos);
++}
++
++static void string(const char *s)
++{
++ buffer_puts(buffer_2,s);
++}
++
++static void line(void)
++{
++ string("\n");
++ buffer_flush(buffer_2);
++}
++
++static void log_stats(void)
++{
++ string("stats ");
++ number(stats_numq); string(" ");
++ number(stats_plus); string(" ");
++ number(stats_minus); string(" ");
++ number(stats_nx); string(" ");
++ number(stats_notimp); string(" ");
++ number(stats_weird); string(" ");
++ number(stats_noq);
++ line();
++}
++
+ static int doit(void)
+ {
+ unsigned int pos;
+ char header[12];
+ char qtype[2];
+ char qclass[2];
++ stats_numq++;
+
+ if (len >= sizeof buf) goto NOQ;
+ pos = dns_packet_copy(buf,len,0,header,12); if (!pos) goto NOQ;
+@@ -56,25 +107,37 @@ static int doit(void)
+
+ case_lowerb(q,dns_domain_length(q));
+ if (!respond(q,qtype,ip)) {
++ stats_minus++;
+ qlog(ip,port,header,q,qtype," - ");
+ return 0;
+ }
+- qlog(ip,port,header,q,qtype," + ");
++
++ if ((response[2] & 4) && (response[3] & 3)) {
++ stats_nx++;
++ qlog(ip,port,header,q,qtype," N ");
++ }
++ else {
++ stats_plus++;
++ qlog(ip,port,header,q,qtype," + ");
++ }
+ return 1;
+
+ NOTIMP:
++ stats_notimp++;
+ response[3] &= ~15;
+ response[3] |= 4;
+ qlog(ip,port,header,q,qtype," I ");
+ return 1;
+
+ WEIRDCLASS:
++ stats_weird++;
+ response[3] &= ~15;
+ response[3] |= 1;
+ qlog(ip,port,header,q,qtype," C ");
+ return 1;
+
+ NOQ:
++ stats_noq++;
+ qlog(ip,port,"\0\0","","\0\0"," / ");
+ return 0;
+ }
+@@ -83,6 +146,7 @@ int main()
+ {
+ char *x;
+ int udp53;
++ unsigned char flag=0;
+
+ x = env_get("IP");
+ if (!x)
+@@ -106,6 +170,8 @@ int main()
+ buffer_putsflush(buffer_2,starting);
+
+ for (;;) {
++ if ((flag++)%32==1)
++ log_stats();
+ len = socket_recv4(udp53,buf,sizeof buf,ip,&port);
+ if (len < 0) continue;
+ if (!doit()) continue;
+++ /dev/null
---- a/dnsfilter.c Thu Feb 15 21:29:28 2001
-+++ b/dnsfilter.c Thu Feb 15 21:57:36 2001
-@@ -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;
- }
--- /dev/null
+--- a/dnsfilter.c
++++ b/dnsfilter.c
+@@ -41,6 +41,7 @@ int inbuflen = 0;
+ iopause_fd *inio;
+ int flag0 = 1;
+
++int opt_replace = 0;
+ iopause_fd *io;
+ int iolen;
+
+@@ -51,12 +52,16 @@ char name[DNS_NAME4_DOMAIN];
+ 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 main(int argc,char **argv)
+ 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 @@ int main(int argc,char **argv)
+ 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 @@ int main(int argc,char **argv)
+ 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;
+ }
--- /dev/null
+--- a/dnscache.c
++++ b/dnscache.c
+@@ -1,4 +1,5 @@
+ #include <unistd.h>
++#include <signal.h>
+ #include "env.h"
+ #include "exit.h"
+ #include "scan.h"
+@@ -391,6 +392,7 @@ int main()
+ char *x;
+ unsigned long cachesize;
+
++ signal(SIGPIPE, SIG_IGN);
+ x = env_get("IP");
+ if (!x)
+ strerr_die2x(111,FATAL,"$IP not set");
--- /dev/null
+This patch change djbdns's dnscache program so that it will ignore the
+IP address given in the ignoreip file. I wrote this patch because of
+Verisign's oh-so helpful wildcard A record for *.COM and *.NET.
+
+If you have djbdns-1.05-ignoreip.patch installed, back it out like this:
+ cd /usr/local/src/djbdns-1.05
+ patch -R <djbdns-1.05-ignoreip.patch
+
+Install the patch like this:
+ cd /usr/local/src/djbdns-1.05
+ patch <djbdns-1.05-ignoreip2.patch
+ svc -d /service/dnscache
+ make setup check
+ svc -u /service/dnscache
+
+Configure it to ignore Verisign's wildcard record like this:
+ echo 64.94.110.11 >/service/dnscache/root/ignoreip
+ svc -t /service/dnscache
+
+Configure it to ignore all the cretins like this:
+awk '{print $2}' <<EOF >/service/dnscache/root/ignoreip
+ *.ac 194.205.62.122
+ *.cc 206.253.214.102
+ *.com 64.94.110.11
+ *.cx 219.88.106.80
+ *.museum 195.7.77.20
+ *.net 64.94.110.11
+ *.nu 64.55.105.9
+ and 212.181.91.6
+ *.ph 203.119.4.6
+ *.sh 194.205.62.62
+ *.tm 194.205.62.62
+ *.ws 216.35.187.246
+EOF
+ svc -t /service/dnscache
+
+J.P. Larocque contributes a script which updates root/ignoreip:
+ http://ely.ath.cx/~piranha/software/ignoreip-update/ignoreip-update-0.1
+
+If root/ignoreip is not present, no addresses will be ignored.
+
+--
+--My blog is at angry-economist.russnelson.com | Free markets express in the
+Crynwr sells support for free software | PGPok | practical world our belief
+521 Pleasant Valley Rd. | +1 315 268 1925 voice | that there is that of God
+Potsdam, NY 13676-3213 | +1 315 268 9201 FAX | in all people. -Chris V.
+
+
+--- a/dnscache.c
++++ b/dnscache.c
+@@ -24,6 +24,8 @@
+ #include "okclient.h"
+ #include "droproot.h"
+
++stralloc ignoreip = {0};
++
+ static int packetquery(char *buf,unsigned int len,char **q,char qtype[2],char qclass[2],char id[2])
+ {
+ unsigned int pos;
+@@ -390,6 +392,7 @@ char seed[128];
+ int main()
+ {
+ char *x;
++ unsigned int i, j, k;
+ unsigned long cachesize;
+
+ signal(SIGPIPE, SIG_IGN);
+@@ -433,6 +436,20 @@ int main()
+ if (!cache_init(cachesize))
+ strerr_die3x(111,FATAL,"not enough memory for cache of size ",x);
+
++ if (openreadclose("ignoreip",&ignoreip,64) < 0)
++ strerr_die2x(111,FATAL,"trouble reading ignoreip");
++ for(j = k = i = 0; i < ignoreip.len; i++)
++ if (ignoreip.s[i] == '\n') {
++ ignoreip.s[i] = '\0';
++ if (j + 4 > i)
++ strerr_die3x(111,FATAL,"badly malformed ip4 address ",ignoreip.s+k);
++ if (!ip4_scan(ignoreip.s+k,ignoreip.s+j))
++ strerr_die3x(111,FATAL,"unable to parse address in ignoreip ",ignoreip.s+k);
++ j += 4;
++ k = i + 1;
++ }
++ ignoreip.len = j;
++
+ if (env_get("HIDETTL"))
+ response_hidettl();
+ if (env_get("FORWARDONLY"))
+--- a/query.c
++++ b/query.c
+@@ -13,6 +13,8 @@
+ #include "response.h"
+ #include "query.h"
+
++extern stralloc ignoreip;
++
+ static int flagforwardonly = 0;
+
+ void query_forwardonly(void)
+@@ -173,6 +175,7 @@ static int smaller(char *buf,unsigned in
+
+ static int doit(struct query *z,int state)
+ {
++ unsigned int ii;
+ char key[257];
+ char *cached;
+ unsigned int cachedlen;
+@@ -662,6 +665,9 @@ static int doit(struct query *z,int stat
+ pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
+ if (byte_equal(header + 8,2,"\0\4")) {
+ pos = dns_packet_copy(buf,len,pos,header,4); if (!pos) goto DIE;
++ if (ignoreip.len)
++ for(ii = 0; ii < ignoreip.len; ii+= 4)
++ if (byte_equal(header,4,ignoreip.s+ii)) goto NXDOMAIN;
+ save_data(header,4);
+ log_rr(whichserver,t1,DNS_T_A,header,4,ttl);
+ }
--- /dev/null
+--- a/response.c
++++ b/response.c
+@@ -34,7 +34,7 @@ int response_addname(const char *d)
+ uint16_pack_big(buf,49152 + name_ptr[i]);
+ return response_addbytes(buf,2);
+ }
+- if (dlen <= 128)
++ if ((dlen <= 128) && (response_len < 16384))
+ if (name_num < NAMES) {
+ byte_copy(name[name_num],dlen,d);
+ name_ptr[name_num] = response_len;
+++ /dev/null
---- a/response.c.orig 2009-02-24 21:04:06.000000000 -0800
-+++ b/response.c 2009-02-24 21:04:25.000000000 -0800
-@@ -34,7 +34,7 @@
- uint16_pack_big(buf,49152 + name_ptr[i]);
- return response_addbytes(buf,2);
- }
-- if (dlen <= 128)
-+ if ((dlen <= 128) && (response_len < 16384))
- if (name_num < NAMES) {
- byte_copy(name[name_num],dlen,d);
- name_ptr[name_num] = response_len;
--- /dev/null
+--- a/Makefile
++++ b/Makefile
+@@ -315,11 +315,11 @@ stralloc.h iopause.h taia.h tai.h uint64
+ ./compile dns_txt.c
+
+ dnscache: \
+-load dnscache.o droproot.o okclient.o log.o cache.o query.o \
++load dnscache.o droproot.o okclient.o log.o cache.o query.o qmerge.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
+ ./load dnscache droproot.o okclient.o log.o cache.o \
+- query.o response.o dd.o roots.o iopause.o prot.o dns.a \
++ query.o qmerge.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 \
+ socket.lib`
+
+@@ -340,7 +340,7 @@ compile dnscache.c env.h exit.h scan.h s
+ uint16.h uint64.h socket.h uint16.h dns.h stralloc.h gen_alloc.h \
+ iopause.h taia.h tai.h uint64.h taia.h taia.h byte.h roots.h fmt.h \
+ iopause.h query.h dns.h uint32.h alloc.h response.h uint32.h cache.h \
+-uint32.h uint64.h ndelay.h log.h uint64.h okclient.h droproot.h
++uint32.h uint64.h ndelay.h log.h uint64.h okclient.h droproot.h maxclient.h
+ ./compile dnscache.c
+
+ dnsfilter: \
+@@ -685,11 +685,16 @@ qlog.o: \
+ compile qlog.c buffer.h qlog.h uint16.h
+ ./compile qlog.c
+
++qmerge.o: \
++compile qmerge.c qmerge.h dns.h stralloc.h gen_alloc.h iopause.h \
++taia.h tai.h uint64.h log.h maxclient.h
++ ./compile qmerge.c
++
+ query.o: \
+ compile query.c error.h roots.h log.h uint64.h case.h cache.h \
+ uint32.h uint64.h byte.h dns.h stralloc.h gen_alloc.h iopause.h \
+ taia.h tai.h uint64.h taia.h uint64.h uint32.h uint16.h dd.h alloc.h \
+-response.h uint32.h query.h dns.h uint32.h
++response.h uint32.h query.h dns.h uint32.h qmerge.h
+ ./compile query.c
+
+ random-ip: \
+--- a/dnscache.c
++++ b/dnscache.c
+@@ -20,6 +20,7 @@
+ #include "response.h"
+ #include "cache.h"
+ #include "ndelay.h"
++#include "maxclient.h"
+ #include "log.h"
+ #include "okclient.h"
+ #include "droproot.h"
+@@ -57,7 +58,6 @@ uint64 numqueries = 0;
+
+ static int udp53;
+
+-#define MAXUDP 200
+ static struct udpclient {
+ struct query q;
+ struct taia start;
+@@ -134,7 +134,6 @@ void u_new(void)
+
+ static int tcp53;
+
+-#define MAXTCP 20
+ struct tcpclient {
+ struct query q;
+ struct taia start;
+--- a/log.c
++++ b/log.c
+@@ -151,6 +151,13 @@ void log_tx(const char *q,const char qty
+ line();
+ }
+
++void log_tx_piggyback(const char *q, const char qtype[2], const char *control)
++{
++ string("txpb ");
++ logtype(qtype); space(); name(q); space(); name(control);
++ line();
++}
++
+ void log_cachedanswer(const char *q,const char type[2])
+ {
+ string("cached "); logtype(type); space();
+--- a/log.h
++++ b/log.h
+@@ -20,6 +20,7 @@ extern void log_cachednxdomain(const cha
+ extern void log_cachedns(const char *,const char *);
+
+ extern void log_tx(const char *,const char *,const char *,const char *,unsigned int);
++extern void log_tx_piggyback(const char *,const char *,const char *);
+
+ extern void log_nxdomain(const char *,const char *,unsigned int);
+ extern void log_nodata(const char *,const char *,const char *,unsigned int);
+--- /dev/null
++++ b/maxclient.h
+@@ -0,0 +1,7 @@
++#ifndef MAXCLIENT_H
++#define MAXCLIENT_H
++
++#define MAXUDP 200
++#define MAXTCP 20
++
++#endif /* MAXCLIENT_H */
+--- /dev/null
++++ b/qmerge.c
+@@ -0,0 +1,115 @@
++#include "qmerge.h"
++#include "byte.h"
++#include "log.h"
++#include "maxclient.h"
++
++#define QMERGE_MAX (MAXUDP+MAXTCP)
++struct qmerge inprogress[QMERGE_MAX];
++
++static
++int qmerge_key_init(struct qmerge_key *qmk, const char *q, const char qtype[2],
++ const char *control)
++{
++ if (!dns_domain_copy(&qmk->q, q)) return 0;
++ byte_copy(qmk->qtype, 2, qtype);
++ if (!dns_domain_copy(&qmk->control, control)) return 0;
++ return 1;
++}
++
++static
++int qmerge_key_equal(struct qmerge_key *a, struct qmerge_key *b)
++{
++ return
++ byte_equal(a->qtype, 2, b->qtype) &&
++ dns_domain_equal(a->q, b->q) &&
++ dns_domain_equal(a->control, b->control);
++}
++
++static
++void qmerge_key_free(struct qmerge_key *qmk)
++{
++ dns_domain_free(&qmk->q);
++ dns_domain_free(&qmk->control);
++}
++
++void qmerge_free(struct qmerge **x)
++{
++ struct qmerge *qm;
++
++ qm = *x;
++ *x = 0;
++ if (!qm || !qm->active) return;
++
++ qm->active--;
++ if (!qm->active) {
++ qmerge_key_free(&qm->key);
++ dns_transmit_free(&qm->dt);
++ }
++}
++
++int qmerge_start(struct qmerge **qm, const char servers[64], int flagrecursive,
++ const char *q, const char qtype[2], const char localip[4],
++ const char *control)
++{
++ struct qmerge_key k;
++ int i;
++ int r;
++
++ qmerge_free(qm);
++
++ byte_zero(&k, sizeof k);
++ if (!qmerge_key_init(&k, q, qtype, control)) return -1;
++ for (i = 0; i < QMERGE_MAX; i++) {
++ if (!inprogress[i].active) continue;
++ if (!qmerge_key_equal(&k, &inprogress[i].key)) continue;
++ log_tx_piggyback(q, qtype, control);
++ inprogress[i].active++;
++ *qm = &inprogress[i];
++ qmerge_key_free(&k);
++ return 0;
++ }
++
++ for (i = 0; i < QMERGE_MAX; i++)
++ if (!inprogress[i].active)
++ break;
++ if (i == QMERGE_MAX) return -1;
++
++ log_tx(q, qtype, control, servers, 0);
++ r = dns_transmit_start(&inprogress[i].dt, servers, flagrecursive, q, qtype, localip);
++ if (r == -1) { qmerge_key_free(&k); return -1; }
++ inprogress[i].active++;
++ inprogress[i].state = 0;
++ qmerge_key_free(&inprogress[i].key);
++ byte_copy(&inprogress[i].key, sizeof k, &k);
++ *qm = &inprogress[i];
++ return 0;
++}
++
++void qmerge_io(struct qmerge *qm, iopause_fd *io, struct taia *deadline)
++{
++ if (qm->state == 0) {
++ dns_transmit_io(&qm->dt, io, deadline);
++ qm->state = 1;
++ }
++ else {
++ io->fd = -1;
++ io->events = 0;
++ }
++}
++
++int qmerge_get(struct qmerge **x, const iopause_fd *io, const struct taia *when)
++{
++ int r;
++ struct qmerge *qm;
++
++ qm = *x;
++ if (qm->state == -1) return -1; /* previous error */
++ if (qm->state == 0) return 0; /* no packet */
++ if (qm->state == 2) return 1; /* already got packet */
++
++ r = dns_transmit_get(&qm->dt, io, when);
++ if (r == -1) { qm->state = -1; return -1; } /* error */
++ if (r == 0) { qm->state = 0; return 0; } /* must wait for i/o */
++ if (r == 1) { qm->state = 2; return 1; } /* got packet */
++ return -1; /* bug */
++}
+--- /dev/null
++++ b/qmerge.h
+@@ -0,0 +1,24 @@
++#ifndef QMERGE_H
++#define QMERGE_H
++
++#include "dns.h"
++
++struct qmerge_key {
++ char *q;
++ char qtype[2];
++ char *control;
++};
++
++struct qmerge {
++ int active;
++ struct qmerge_key key;
++ struct dns_transmit dt;
++ int state; /* -1 = error, 0 = need io, 1 = need get, 2 = got packet */
++};
++
++extern int qmerge_start(struct qmerge **,const char *,int,const char *,const char *,const char *,const char *);
++extern void qmerge_io(struct qmerge *,iopause_fd *,struct taia *);
++extern int qmerge_get(struct qmerge **,const iopause_fd *,const struct taia *);
++extern void qmerge_free(struct qmerge **);
++
++#endif /* QMERGE_H */
+--- a/query.c
++++ b/query.c
+@@ -83,7 +83,7 @@ static void cleanup(struct query *z)
+ int j;
+ int k;
+
+- dns_transmit_free(&z->dt);
++ qmerge_free(&z->qm);
+ for (j = 0;j < QUERY_MAXALIAS;++j)
+ dns_domain_free(&z->alias[j]);
+ for (j = 0;j < QUERY_MAXLEVEL;++j) {
+@@ -452,14 +452,8 @@ static int doit(struct query *z,int stat
+ if (j == 64) goto SERVFAIL;
+
+ dns_sortip(z->servers[z->level],64);
+- if (z->level) {
+- log_tx(z->name[z->level],DNS_T_A,z->control[z->level],z->servers[z->level],z->level);
+- if (dns_transmit_start(&z->dt,z->servers[z->level],flagforwardonly,z->name[z->level],DNS_T_A,z->localip) == -1) goto DIE;
+- }
+- else {
+- log_tx(z->name[0],z->type,z->control[0],z->servers[0],0);
+- if (dns_transmit_start(&z->dt,z->servers[0],flagforwardonly,z->name[0],z->type,z->localip) == -1) goto DIE;
+- }
++ dtype = z->level ? DNS_T_A : z->type;
++ if (qmerge_start(&z->qm,z->servers[z->level],flagforwardonly,z->name[z->level],dtype,z->localip,z->control[z->level]) == -1) goto DIE;
+ return 0;
+
+
+@@ -473,10 +467,10 @@ static int doit(struct query *z,int stat
+
+ HAVEPACKET:
+ if (++z->loop == 100) goto DIE;
+- buf = z->dt.packet;
+- len = z->dt.packetlen;
++ buf = z->qm->dt.packet;
++ len = z->qm->dt.packetlen;
+
+- whichserver = z->dt.servers + 4 * z->dt.curserver;
++ whichserver = z->qm->dt.servers + 4 * z->qm->dt.curserver;
+ control = z->control[z->level];
+ d = z->name[z->level];
+ dtype = z->level ? DNS_T_A : z->type;
+@@ -902,7 +896,7 @@ int query_start(struct query *z,char *dn
+
+ int query_get(struct query *z,iopause_fd *x,struct taia *stamp)
+ {
+- switch(dns_transmit_get(&z->dt,x,stamp)) {
++ switch(qmerge_get(&z->qm,x,stamp)) {
+ case 1:
+ return doit(z,1);
+ case -1:
+@@ -913,5 +907,5 @@ int query_get(struct query *z,iopause_fd
+
+ void query_io(struct query *z,iopause_fd *x,struct taia *deadline)
+ {
+- dns_transmit_io(&z->dt,x,deadline);
++ qmerge_io(z->qm,x,deadline);
+ }
+--- a/query.h
++++ b/query.h
+@@ -1,7 +1,7 @@
+ #ifndef QUERY_H
+ #define QUERY_H
+
+-#include "dns.h"
++#include "qmerge.h"
+ #include "uint32.h"
+
+ #define QUERY_MAXLEVEL 5
+@@ -20,7 +20,7 @@ struct query {
+ char localip[4];
+ char type[2];
+ char class[2];
+- struct dns_transmit dt;
++ struct qmerge *qm;
+ } ;
+
+ extern int query_start(struct query *,char *,char *,char *,char *);
+++ /dev/null
-diff --git a/Makefile b/Makefile
-index 1429643..bc047c0 100644
---- a/Makefile
-+++ b/Makefile
-@@ -318,11 +318,11 @@ stralloc.h iopause.h taia.h tai.h uint64.h taia.h
- ./compile dns_txt.c
-
- dnscache: \
--load dnscache.o droproot.o okclient.o log.o cache.o query.o \
-+load dnscache.o droproot.o okclient.o log.o cache.o query.o qmerge.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
- ./load dnscache droproot.o okclient.o log.o cache.o \
-- query.o response.o dd.o roots.o iopause.o prot.o dns.a \
-+ query.o qmerge.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 \
- socket.lib`
-
-@@ -343,7 +343,7 @@ compile dnscache.c env.h exit.h scan.h strerr.h error.h ip4.h \
- uint16.h uint64.h socket.h uint16.h dns.h stralloc.h gen_alloc.h \
- iopause.h taia.h tai.h uint64.h taia.h taia.h byte.h roots.h fmt.h \
- iopause.h query.h dns.h uint32.h alloc.h response.h uint32.h cache.h \
--uint32.h uint64.h ndelay.h log.h uint64.h okclient.h droproot.h
-+uint32.h uint64.h ndelay.h log.h uint64.h okclient.h droproot.h maxclient.h
- ./compile dnscache.c
-
- dnsfilter: \
-@@ -687,11 +687,16 @@ qlog.o: \
- compile qlog.c buffer.h qlog.h uint16.h
- ./compile qlog.c
-
-+qmerge.o: \
-+compile qmerge.c qmerge.h dns.h stralloc.h gen_alloc.h iopause.h \
-+taia.h tai.h uint64.h log.h maxclient.h
-+ ./compile qmerge.c
-+
- query.o: \
- compile query.c error.h roots.h log.h uint64.h case.h cache.h \
- uint32.h uint64.h byte.h dns.h stralloc.h gen_alloc.h iopause.h \
- taia.h tai.h uint64.h taia.h uint64.h uint32.h uint16.h dd.h alloc.h \
--response.h uint32.h query.h dns.h uint32.h
-+response.h uint32.h query.h dns.h uint32.h qmerge.h
- ./compile query.c
-
- random-ip: \
-diff --git a/dnscache.c b/dnscache.c
-index 8c899a3..5ccb16a 100644
---- a/dnscache.c
-+++ b/dnscache.c
-@@ -22,6 +22,7 @@
- #include "log.h"
- #include "okclient.h"
- #include "droproot.h"
-+#include "maxclient.h"
-
- static int packetquery(char *buf,unsigned int len,char **q,char qtype[2],char qclass[2],char id[2])
- {
-@@ -54,7 +55,6 @@ uint64 numqueries = 0;
-
- static int udp53;
-
--#define MAXUDP 200
- static struct udpclient {
- struct query q;
- struct taia start;
-@@ -131,7 +131,6 @@ void u_new(void)
-
- static int tcp53;
-
--#define MAXTCP 20
- struct tcpclient {
- struct query q;
- struct taia start;
-diff --git a/log.c b/log.c
-index c43e8b0..b8cd7ce 100644
---- a/log.c
-+++ b/log.c
-@@ -150,6 +150,13 @@ void log_tx(const char *q,const char qtype[2],const char *control,const char ser
- line();
- }
-
-+void log_tx_piggyback(const char *q, const char qtype[2], const char *control)
-+{
-+ string("txpb ");
-+ logtype(qtype); space(); name(q); space(); name(control);
-+ line();
-+}
-+
- void log_cachedanswer(const char *q,const char type[2])
- {
- string("cached "); logtype(type); space();
-diff --git a/log.h b/log.h
-index fe62fa3..d9a829b 100644
---- a/log.h
-+++ b/log.h
-@@ -18,6 +18,7 @@ extern void log_cachednxdomain(const char *);
- extern void log_cachedns(const char *,const char *);
-
- extern void log_tx(const char *,const char *,const char *,const char *,unsigned int);
-+extern void log_tx_piggyback(const char *,const char *,const char *);
-
- extern void log_nxdomain(const char *,const char *,unsigned int);
- extern void log_nodata(const char *,const char *,const char *,unsigned int);
-diff --git a/maxclient.h b/maxclient.h
-new file mode 100644
-index 0000000..e52fcd1
---- /dev/null
-+++ b/maxclient.h
-@@ -0,0 +1,7 @@
-+#ifndef MAXCLIENT_H
-+#define MAXCLIENT_H
-+
-+#define MAXUDP 200
-+#define MAXTCP 20
-+
-+#endif /* MAXCLIENT_H */
-diff --git a/qmerge.c b/qmerge.c
-new file mode 100644
-index 0000000..7c92299
---- /dev/null
-+++ b/qmerge.c
-@@ -0,0 +1,115 @@
-+#include "qmerge.h"
-+#include "byte.h"
-+#include "log.h"
-+#include "maxclient.h"
-+
-+#define QMERGE_MAX (MAXUDP+MAXTCP)
-+struct qmerge inprogress[QMERGE_MAX];
-+
-+static
-+int qmerge_key_init(struct qmerge_key *qmk, const char *q, const char qtype[2],
-+ const char *control)
-+{
-+ if (!dns_domain_copy(&qmk->q, q)) return 0;
-+ byte_copy(qmk->qtype, 2, qtype);
-+ if (!dns_domain_copy(&qmk->control, control)) return 0;
-+ return 1;
-+}
-+
-+static
-+int qmerge_key_equal(struct qmerge_key *a, struct qmerge_key *b)
-+{
-+ return
-+ byte_equal(a->qtype, 2, b->qtype) &&
-+ dns_domain_equal(a->q, b->q) &&
-+ dns_domain_equal(a->control, b->control);
-+}
-+
-+static
-+void qmerge_key_free(struct qmerge_key *qmk)
-+{
-+ dns_domain_free(&qmk->q);
-+ dns_domain_free(&qmk->control);
-+}
-+
-+void qmerge_free(struct qmerge **x)
-+{
-+ struct qmerge *qm;
-+
-+ qm = *x;
-+ *x = 0;
-+ if (!qm || !qm->active) return;
-+
-+ qm->active--;
-+ if (!qm->active) {
-+ qmerge_key_free(&qm->key);
-+ dns_transmit_free(&qm->dt);
-+ }
-+}
-+
-+int qmerge_start(struct qmerge **qm, const char servers[64], int flagrecursive,
-+ const char *q, const char qtype[2], const char localip[4],
-+ const char *control)
-+{
-+ struct qmerge_key k;
-+ int i;
-+ int r;
-+
-+ qmerge_free(qm);
-+
-+ byte_zero(&k, sizeof k);
-+ if (!qmerge_key_init(&k, q, qtype, control)) return -1;
-+ for (i = 0; i < QMERGE_MAX; i++) {
-+ if (!inprogress[i].active) continue;
-+ if (!qmerge_key_equal(&k, &inprogress[i].key)) continue;
-+ log_tx_piggyback(q, qtype, control);
-+ inprogress[i].active++;
-+ *qm = &inprogress[i];
-+ qmerge_key_free(&k);
-+ return 0;
-+ }
-+
-+ for (i = 0; i < QMERGE_MAX; i++)
-+ if (!inprogress[i].active)
-+ break;
-+ if (i == QMERGE_MAX) return -1;
-+
-+ log_tx(q, qtype, control, servers, 0);
-+ r = dns_transmit_start(&inprogress[i].dt, servers, flagrecursive, q, qtype, localip);
-+ if (r == -1) { qmerge_key_free(&k); return -1; }
-+ inprogress[i].active++;
-+ inprogress[i].state = 0;
-+ qmerge_key_free(&inprogress[i].key);
-+ byte_copy(&inprogress[i].key, sizeof k, &k);
-+ *qm = &inprogress[i];
-+ return 0;
-+}
-+
-+void qmerge_io(struct qmerge *qm, iopause_fd *io, struct taia *deadline)
-+{
-+ if (qm->state == 0) {
-+ dns_transmit_io(&qm->dt, io, deadline);
-+ qm->state = 1;
-+ }
-+ else {
-+ io->fd = -1;
-+ io->events = 0;
-+ }
-+}
-+
-+int qmerge_get(struct qmerge **x, const iopause_fd *io, const struct taia *when)
-+{
-+ int r;
-+ struct qmerge *qm;
-+
-+ qm = *x;
-+ if (qm->state == -1) return -1; /* previous error */
-+ if (qm->state == 0) return 0; /* no packet */
-+ if (qm->state == 2) return 1; /* already got packet */
-+
-+ r = dns_transmit_get(&qm->dt, io, when);
-+ if (r == -1) { qm->state = -1; return -1; } /* error */
-+ if (r == 0) { qm->state = 0; return 0; } /* must wait for i/o */
-+ if (r == 1) { qm->state = 2; return 1; } /* got packet */
-+ return -1; /* bug */
-+}
-diff --git a/qmerge.h b/qmerge.h
-new file mode 100644
-index 0000000..9a58157
---- /dev/null
-+++ b/qmerge.h
-@@ -0,0 +1,24 @@
-+#ifndef QMERGE_H
-+#define QMERGE_H
-+
-+#include "dns.h"
-+
-+struct qmerge_key {
-+ char *q;
-+ char qtype[2];
-+ char *control;
-+};
-+
-+struct qmerge {
-+ int active;
-+ struct qmerge_key key;
-+ struct dns_transmit dt;
-+ int state; /* -1 = error, 0 = need io, 1 = need get, 2 = got packet */
-+};
-+
-+extern int qmerge_start(struct qmerge **,const char *,int,const char *,const char *,const char *,const char *);
-+extern void qmerge_io(struct qmerge *,iopause_fd *,struct taia *);
-+extern int qmerge_get(struct qmerge **,const iopause_fd *,const struct taia *);
-+extern void qmerge_free(struct qmerge **);
-+
-+#endif /* QMERGE_H */
-diff --git a/query.c b/query.c
-index 46cdc00..f091fdd 100644
---- a/query.c
-+++ b/query.c
-@@ -81,7 +81,7 @@ static void cleanup(struct query *z)
- int j;
- int k;
-
-- dns_transmit_free(&z->dt);
-+ qmerge_free(&z->qm);
- for (j = 0;j < QUERY_MAXALIAS;++j)
- dns_domain_free(&z->alias[j]);
- for (j = 0;j < QUERY_MAXLEVEL;++j) {
-@@ -429,14 +429,8 @@ static int doit(struct query *z,int state)
- if (j == 64) goto SERVFAIL;
-
- dns_sortip(z->servers[z->level],64);
-- if (z->level) {
-- log_tx(z->name[z->level],DNS_T_A,z->control[z->level],z->servers[z->level],z->level);
-- if (dns_transmit_start(&z->dt,z->servers[z->level],flagforwardonly,z->name[z->level],DNS_T_A,z->localip) == -1) goto DIE;
-- }
-- else {
-- log_tx(z->name[0],z->type,z->control[0],z->servers[0],0);
-- if (dns_transmit_start(&z->dt,z->servers[0],flagforwardonly,z->name[0],z->type,z->localip) == -1) goto DIE;
-- }
-+ dtype = z->level ? DNS_T_A : z->type;
-+ if (qmerge_start(&z->qm,z->servers[z->level],flagforwardonly,z->name[z->level],dtype,z->localip,z->control[z->level]) == -1) goto DIE;
- return 0;
-
-
-@@ -450,10 +444,10 @@ static int doit(struct query *z,int state)
-
- HAVEPACKET:
- if (++z->loop == 100) goto DIE;
-- buf = z->dt.packet;
-- len = z->dt.packetlen;
-+ buf = z->qm->dt.packet;
-+ len = z->qm->dt.packetlen;
-
-- whichserver = z->dt.servers + 4 * z->dt.curserver;
-+ whichserver = z->qm->dt.servers + 4 * z->qm->dt.curserver;
- control = z->control[z->level];
- d = z->name[z->level];
- dtype = z->level ? DNS_T_A : z->type;
-@@ -836,7 +830,7 @@ int query_start(struct query *z,char *dn,char type[2],char class[2],char localip
-
- int query_get(struct query *z,iopause_fd *x,struct taia *stamp)
- {
-- switch(dns_transmit_get(&z->dt,x,stamp)) {
-+ switch(qmerge_get(&z->qm,x,stamp)) {
- case 1:
- return doit(z,1);
- case -1:
-@@ -847,5 +841,5 @@ int query_get(struct query *z,iopause_fd *x,struct taia *stamp)
-
- void query_io(struct query *z,iopause_fd *x,struct taia *deadline)
- {
-- dns_transmit_io(&z->dt,x,deadline);
-+ qmerge_io(z->qm,x,deadline);
- }
-diff --git a/query.h b/query.h
-index eff68b2..06feab4 100644
---- a/query.h
-+++ b/query.h
-@@ -1,7 +1,7 @@
- #ifndef QUERY_H
- #define QUERY_H
-
--#include "dns.h"
-+#include "qmerge.h"
- #include "uint32.h"
-
- #define QUERY_MAXLEVEL 5
-@@ -20,7 +20,7 @@ struct query {
- char localip[4];
- char type[2];
- char class[2];
-- struct dns_transmit dt;
-+ struct qmerge *qm;
- } ;
-
- extern int query_start(struct query *,char *,char *,char *,char *);
--- /dev/null
+--- a/query.c
++++ b/query.c
+@@ -342,6 +342,29 @@ static int doit(struct query *z,int stat
+ }
+ }
+
++ if (typematch(DNS_T_SOA,dtype)) {
++ byte_copy(key,2,DNS_T_SOA);
++ cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
++ if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) {
++ log_cachedanswer(d,DNS_T_SOA);
++ if (!rqa(z)) goto DIE;
++ pos = 0;
++ while (pos = dns_packet_copy(cached,cachedlen,pos,misc,20)) {
++ pos = dns_packet_getname(cached,cachedlen,pos,&t2);
++ if (!pos) break;
++ pos = dns_packet_getname(cached,cachedlen,pos,&t3);
++ if (!pos) break;
++ if (!response_rstart(d,DNS_T_SOA,ttl)) goto DIE;
++ if (!response_addname(t2)) goto DIE;
++ if (!response_addname(t3)) goto DIE;
++ if (!response_addbytes(misc,20)) goto DIE;
++ response_rfinish(RESPONSE_ANSWER);
++ }
++ cleanup(z);
++ return 1;
++ }
++ }
++
+ if (typematch(DNS_T_A,dtype)) {
+ byte_copy(key,2,DNS_T_A);
+ cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
+@@ -374,7 +397,7 @@ static int doit(struct query *z,int stat
+ }
+ }
+
+- if (!typematch(DNS_T_ANY,dtype) && !typematch(DNS_T_AXFR,dtype) && !typematch(DNS_T_NS,dtype) && !typematch(DNS_T_PTR,dtype) && !typematch(DNS_T_A,dtype) && !typematch(DNS_T_MX,dtype)) {
++ if (!typematch(DNS_T_ANY,dtype) && !typematch(DNS_T_AXFR,dtype) && !typematch(DNS_T_NS,dtype) && !typematch(DNS_T_PTR,dtype) && !typematch(DNS_T_A,dtype) && !typematch(DNS_T_MX,dtype) && !typematch(DNS_T_SOA,dtype)) {
+ byte_copy(key,2,dtype);
+ cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
+ if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) {
+@@ -601,15 +624,24 @@ static int doit(struct query *z,int stat
+ else if (byte_equal(type,2,DNS_T_AXFR))
+ ;
+ else if (byte_equal(type,2,DNS_T_SOA)) {
++ int non_authority = 0;
++ save_start();
+ while (i < j) {
+ pos = dns_packet_skipname(buf,len,records[i]); if (!pos) goto DIE;
+ pos = dns_packet_getname(buf,len,pos + 10,&t2); if (!pos) goto DIE;
+ pos = dns_packet_getname(buf,len,pos,&t3); if (!pos) goto DIE;
+ pos = dns_packet_copy(buf,len,pos,misc,20); if (!pos) goto DIE;
+- if (records[i] < posauthority)
++ if (records[i] < posauthority) {
+ log_rrsoa(whichserver,t1,t2,t3,misc,ttl);
++ save_data(misc,20);
++ save_data(t2,dns_domain_length(t2));
++ save_data(t3,dns_domain_length(t3));
++ non_authority++;
++ }
+ ++i;
+ }
++ if (non_authority)
++ save_finish(DNS_T_SOA,t1,ttl);
+ }
+ else if (byte_equal(type,2,DNS_T_CNAME)) {
+ pos = dns_packet_skipname(buf,len,records[j - 1]); if (!pos) goto DIE;
+++ /dev/null
-diff --git a/query.c b/query.c
-index 46cdc00..4574e97 100644
---- a/query.c
-+++ b/query.c
-@@ -319,6 +319,29 @@ static int doit(struct query *z,int state)
- }
- }
-
-+ if (typematch(DNS_T_SOA,dtype)) {
-+ byte_copy(key,2,DNS_T_SOA);
-+ cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
-+ if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) {
-+ log_cachedanswer(d,DNS_T_SOA);
-+ if (!rqa(z)) goto DIE;
-+ pos = 0;
-+ while (pos = dns_packet_copy(cached,cachedlen,pos,misc,20)) {
-+ pos = dns_packet_getname(cached,cachedlen,pos,&t2);
-+ if (!pos) break;
-+ pos = dns_packet_getname(cached,cachedlen,pos,&t3);
-+ if (!pos) break;
-+ if (!response_rstart(d,DNS_T_SOA,ttl)) goto DIE;
-+ if (!response_addname(t2)) goto DIE;
-+ if (!response_addname(t3)) goto DIE;
-+ if (!response_addbytes(misc,20)) goto DIE;
-+ response_rfinish(RESPONSE_ANSWER);
-+ }
-+ cleanup(z);
-+ return 1;
-+ }
-+ }
-+
- if (typematch(DNS_T_A,dtype)) {
- byte_copy(key,2,DNS_T_A);
- cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
-@@ -351,7 +374,7 @@ static int doit(struct query *z,int state)
- }
- }
-
-- if (!typematch(DNS_T_ANY,dtype) && !typematch(DNS_T_AXFR,dtype) && !typematch(DNS_T_NS,dtype) && !typematch(DNS_T_PTR,dtype) && !typematch(DNS_T_A,dtype) && !typematch(DNS_T_MX,dtype)) {
-+ if (!typematch(DNS_T_ANY,dtype) && !typematch(DNS_T_AXFR,dtype) && !typematch(DNS_T_NS,dtype) && !typematch(DNS_T_PTR,dtype) && !typematch(DNS_T_A,dtype) && !typematch(DNS_T_MX,dtype) && !typematch(DNS_T_SOA,dtype)) {
- byte_copy(key,2,dtype);
- cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
- if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) {
-@@ -585,15 +608,24 @@ static int doit(struct query *z,int state)
- else if (byte_equal(type,2,DNS_T_AXFR))
- ;
- else if (byte_equal(type,2,DNS_T_SOA)) {
-+ int non_authority = 0;
-+ save_start();
- while (i < j) {
- pos = dns_packet_skipname(buf,len,records[i]); if (!pos) goto DIE;
- pos = dns_packet_getname(buf,len,pos + 10,&t2); if (!pos) goto DIE;
- pos = dns_packet_getname(buf,len,pos,&t3); if (!pos) goto DIE;
- pos = dns_packet_copy(buf,len,pos,misc,20); if (!pos) goto DIE;
-- if (records[i] < posauthority)
-+ if (records[i] < posauthority) {
- log_rrsoa(whichserver,t1,t2,t3,misc,ttl);
-+ save_data(misc,20);
-+ save_data(t2,dns_domain_length(t2));
-+ save_data(t3,dns_domain_length(t3));
-+ non_authority++;
-+ }
- ++i;
- }
-+ if (non_authority)
-+ save_finish(DNS_T_SOA,t1,ttl);
- }
- else if (byte_equal(type,2,DNS_T_CNAME)) {
- pos = dns_packet_skipname(buf,len,records[j - 1]); if (!pos) goto DIE;
-