[eggheads-patches] PATCH1.4: asyncdns.patch

Fabian Knittel fknittel at gmx.de
Sat Oct 9 12:52:30 CST 1999


[ asncydns.patch ]

This patch adds the "dns" module, which provides asynchronous
dns request possibilities. The patch also adds a lookup
abstraction layer, which makes it possible to transparently
switch between non-blocking (with the dns module) and blocking 
mode (using the library functions gethostbyaddr, etc.).

Fabian
-------------- next part --------------
diff -urN eggdrop1.4~/Makefile.in eggdrop1.4/Makefile.in
--- eggdrop1.4~/Makefile.in	Sat Oct  9 18:33:39 1999
+++ eggdrop1.4/Makefile.in	Sat Oct  9 18:40:19 1999
@@ -93,15 +93,16 @@
 	@exit 1
 
 OBJS =	botcmd.o botmsg.o botnet.o chanprog.o cmds.o dcc.o \
-	dccutil.o flags.o language.o main.o mem.o misc.o \
+	dccutil.o dns.o flags.o language.o main.o mem.o misc.o \
 	modules.o net.o rfc1459.o tcl.o tcldcc.o tclhash.o \
 	tclmisc.o tcluser.o userent.o userrec.o users.o md5/md5c.o
 
-GMAKE_STATIC = ${MAKE} 'CC=${CC}' 'LD=${LD}' 'OBJS=${OBJS}'\
-'STRIP=${MOD_STRIP}' 'CFLAGS=${CFLAGS} -DSTATIC' 'XLIBS=@TCL_LIBS@ @LIBS@'
+GMAKE_STATIC = ${MAKE} 'CC=${CC}' 'LD=${LD}' 'OBJS=${OBJS}' \
+'STRIP=${MOD_STRIP}' 'CFLAGS=${CFLAGS} -DSTATIC' 'XLIBS=@TCL_LIBS@ @LIBS@' \
+'RESLIB=@RESLIB@'
 
 GMAKE_SHLIB = ${MAKE} 'CC=${SHLIB_CC}' 'LD=${SHLIB_LD}' \
-'STRIP=${SHLIB_STRIP}' 'CFLAGS=${CFLAGS}'
+'STRIP=${SHLIB_STRIP}' 'CFLAGS=${CFLAGS}' 'RESLIB=@RESLIB@'
 
 GMAKE_MOD = ${MAKE} 'CC=${MOD_CC}' 'LD=${MOD_LD}' 'OBJS=${OBJS}'\
 'CFLAGS=${CFLAGS}' 'XREQ=${XREQ}' \
@@ -114,7 +115,7 @@
 'XLIBS=@TCL_LIBS@ @LIBS@'
 
 DMAKE_SHLIB = ${MAKE} 'CC=${SHLIB_CC}' 'LD=${SHLIB_LD}' \
-'STRIP=touch' 'CFLAGS=-g3 ${CFLAGS} -DEBUG_MEM'
+'STRIP=touch' 'CFLAGS=-g3 ${CFLAGS} -DEBUG_MEM' 'RESLIB=@RESLIB@'
 
 static: eggtest
 	@echo ""
diff -urN eggdrop1.4~/configure eggdrop1.4/configure
--- eggdrop1.4~/configure	Sat Oct  9 18:33:40 1999
+++ eggdrop1.4/configure	Sat Oct  9 18:48:24 1999
@@ -1724,15 +1724,275 @@
   fi
 fi
 
+echo $ac_n "checking for res_init""... $ac_c" 1>&6
+echo "configure:1729: checking for res_init" >&5
+if eval "test \"`echo '$''{'ac_cv_func_res_init'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1734 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char res_init(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char res_init();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_res_init) || defined (__stub___res_init)
+choke me
+#else
+res_init();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1757: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_res_init=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_res_init=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'res_init`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for res_init in -lbind""... $ac_c" 1>&6
+echo "configure:1775: checking for res_init in -lbind" >&5
+ac_lib_var=`echo bind'_'res_init | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lbind  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1783 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char res_init();
+
+int main() {
+res_init()
+; return 0; }
+EOF
+if { (eval echo configure:1794: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  RESLIB="-lbind"
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for res_init in -lresolv""... $ac_c" 1>&6
+echo "configure:1813: checking for res_init in -lresolv" >&5
+ac_lib_var=`echo resolv'_'res_init | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lresolv  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1821 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char res_init();
+
+int main() {
+res_init()
+; return 0; }
+EOF
+if { (eval echo configure:1832: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  RESLIB="-lresolv"
+else
+  echo "$ac_t""no" 1>&6
+{ echo "configure: error: No resolver library found" 1>&2; exit 1; }
+fi
+
+fi
+
+fi
+
+
+echo $ac_n "checking for res_mkquery""... $ac_c" 1>&6
+echo "configure:1859: checking for res_mkquery" >&5
+if eval "test \"`echo '$''{'ac_cv_func_res_mkquery'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1864 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char res_mkquery(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char res_mkquery();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_res_mkquery) || defined (__stub___res_mkquery)
+choke me
+#else
+res_mkquery();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1887: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_res_mkquery=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_res_mkquery=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'res_mkquery`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for res_mkquery in -lbind""... $ac_c" 1>&6
+echo "configure:1905: checking for res_mkquery in -lbind" >&5
+ac_lib_var=`echo bind'_'res_mkquery | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lbind  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1913 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char res_mkquery();
+
+int main() {
+res_mkquery()
+; return 0; }
+EOF
+if { (eval echo configure:1924: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  RESLIB="-lbind"
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for res_mkquery in -lresolv""... $ac_c" 1>&6
+echo "configure:1943: checking for res_mkquery in -lresolv" >&5
+ac_lib_var=`echo resolv'_'res_mkquery | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lresolv  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1951 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char res_mkquery();
+
+int main() {
+res_mkquery()
+; return 0; }
+EOF
+if { (eval echo configure:1962: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  RESLIB="-lresolv"
+else
+  echo "$ac_t""no" 1>&6
+{ echo "configure: error: No resolver library found" 1>&2; exit 1; }
+fi
+
+fi
+
+fi
+
+
 echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6
-echo "configure:1729: checking whether byte ordering is bigendian" >&5
+echo "configure:1989: checking whether byte ordering is bigendian" >&5
 if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   ac_cv_c_bigendian=unknown
 # See if sys/param.h defines the BYTE_ORDER macro.
 cat > conftest.$ac_ext <<EOF
-#line 1736 "configure"
+#line 1996 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/param.h>
@@ -1743,11 +2003,11 @@
 #endif
 ; return 0; }
 EOF
-if { (eval echo configure:1747: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2007: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   # It does; now see whether it defined to BIG_ENDIAN or not.
 cat > conftest.$ac_ext <<EOF
-#line 1751 "configure"
+#line 2011 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/param.h>
@@ -1758,7 +2018,7 @@
 #endif
 ; return 0; }
 EOF
-if { (eval echo configure:1762: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2022: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_c_bigendian=yes
 else
@@ -1778,7 +2038,7 @@
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 1782 "configure"
+#line 2042 "configure"
 #include "confdefs.h"
 main () {
   /* Are we little or big endian?  From Harbison&Steele.  */
@@ -1791,7 +2051,7 @@
   exit (u.c[sizeof (long) - 1] == 1);
 }
 EOF
-if { (eval echo configure:1795: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2055: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_c_bigendian=no
 else
@@ -1815,7 +2075,7 @@
 fi
 
 echo $ac_n "checking size of long""... $ac_c" 1>&6
-echo "configure:1819: checking size of long" >&5
+echo "configure:2079: checking size of long" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_long'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1823,7 +2083,7 @@
   ac_cv_sizeof_long=0
 else
   cat > conftest.$ac_ext <<EOF
-#line 1827 "configure"
+#line 2087 "configure"
 #include "confdefs.h"
 #include <stdio.h>
 main()
@@ -1834,7 +2094,7 @@
   exit(0);
 }
 EOF
-if { (eval echo configure:1838: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2098: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_sizeof_long=`cat conftestval`
 else
@@ -1854,7 +2114,7 @@
 
 
 echo $ac_n "checking size of int""... $ac_c" 1>&6
-echo "configure:1858: checking size of int" >&5
+echo "configure:2118: checking size of int" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1862,7 +2122,7 @@
   ac_cv_sizeof_int=0
 else
   cat > conftest.$ac_ext <<EOF
-#line 1866 "configure"
+#line 2126 "configure"
 #include "confdefs.h"
 #include <stdio.h>
 main()
@@ -1873,7 +2133,7 @@
   exit(0);
 }
 EOF
-if { (eval echo configure:1877: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2137: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_sizeof_int=`cat conftestval`
 else
@@ -1898,12 +2158,12 @@
 do
 ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
-echo "configure:1902: checking for $ac_hdr that defines DIR" >&5
+echo "configure:2162: checking for $ac_hdr that defines DIR" >&5
 if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1907 "configure"
+#line 2167 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <$ac_hdr>
@@ -1911,7 +2171,7 @@
 DIR *dirp = 0;
 ; return 0; }
 EOF
-if { (eval echo configure:1915: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2175: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   eval "ac_cv_header_dirent_$ac_safe=yes"
 else
@@ -1936,7 +2196,7 @@
 # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
 if test $ac_header_dirent = dirent.h; then
 echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
-echo "configure:1940: checking for opendir in -ldir" >&5
+echo "configure:2200: checking for opendir in -ldir" >&5
 ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1944,7 +2204,7 @@
   ac_save_LIBS="$LIBS"
 LIBS="-ldir  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1948 "configure"
+#line 2208 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1955,7 +2215,7 @@
 opendir()
 ; return 0; }
 EOF
-if { (eval echo configure:1959: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2219: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1977,7 +2237,7 @@
 
 else
 echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
-echo "configure:1981: checking for opendir in -lx" >&5
+echo "configure:2241: checking for opendir in -lx" >&5
 ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1985,7 +2245,7 @@
   ac_save_LIBS="$LIBS"
 LIBS="-lx  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1989 "configure"
+#line 2249 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1996,7 +2256,7 @@
 opendir()
 ; return 0; }
 EOF
-if { (eval echo configure:2000: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2260: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -2019,12 +2279,12 @@
 fi
 
 echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6
-echo "configure:2023: checking for sys/wait.h that is POSIX.1 compatible" >&5
+echo "configure:2283: checking for sys/wait.h that is POSIX.1 compatible" >&5
 if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2028 "configure"
+#line 2288 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/wait.h>
@@ -2040,7 +2300,7 @@
 s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
 ; return 0; }
 EOF
-if { (eval echo configure:2044: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2304: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_header_sys_wait_h=yes
 else
@@ -2064,17 +2324,17 @@
 do
 ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:2068: checking for $ac_hdr" >&5
+echo "configure:2328: checking for $ac_hdr" >&5
 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2073 "configure"
+#line 2333 "configure"
 #include "confdefs.h"
 #include <$ac_hdr>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2078: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:2338: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   rm -rf conftest*
@@ -2102,12 +2362,12 @@
 
 
 echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
-echo "configure:2106: checking for ANSI C header files" >&5
+echo "configure:2366: checking for ANSI C header files" >&5
 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2111 "configure"
+#line 2371 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 #include <stdarg.h>
@@ -2115,7 +2375,7 @@
 #include <float.h>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2119: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:2379: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   rm -rf conftest*
@@ -2132,7 +2392,7 @@
 if test $ac_cv_header_stdc = yes; then
   # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 2136 "configure"
+#line 2396 "configure"
 #include "confdefs.h"
 #include <string.h>
 EOF
@@ -2150,7 +2410,7 @@
 if test $ac_cv_header_stdc = yes; then
   # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 2154 "configure"
+#line 2414 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 EOF
@@ -2171,7 +2431,7 @@
   :
 else
   cat > conftest.$ac_ext <<EOF
-#line 2175 "configure"
+#line 2435 "configure"
 #include "confdefs.h"
 #include <ctype.h>
 #define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
@@ -2182,7 +2442,7 @@
 exit (0); }
 
 EOF
-if { (eval echo configure:2186: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2446: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   :
 else
@@ -2206,12 +2466,12 @@
 fi
 
 echo $ac_n "checking for pid_t""... $ac_c" 1>&6
-echo "configure:2210: checking for pid_t" >&5
+echo "configure:2470: checking for pid_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2215 "configure"
+#line 2475 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -2239,12 +2499,12 @@
 fi
 
 echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
-echo "configure:2243: checking whether time.h and sys/time.h may both be included" >&5
+echo "configure:2503: checking whether time.h and sys/time.h may both be included" >&5
 if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2248 "configure"
+#line 2508 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/time.h>
@@ -2253,7 +2513,7 @@
 struct tm *tp;
 ; return 0; }
 EOF
-if { (eval echo configure:2257: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2517: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_header_time=yes
 else
@@ -2274,21 +2534,21 @@
 fi
 
 echo $ac_n "checking for inline""... $ac_c" 1>&6
-echo "configure:2278: checking for inline" >&5
+echo "configure:2538: checking for inline" >&5
 if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   ac_cv_c_inline=no
 for ac_kw in inline __inline__ __inline; do
   cat > conftest.$ac_ext <<EOF
-#line 2285 "configure"
+#line 2545 "configure"
 #include "confdefs.h"
 
 int main() {
 } $ac_kw foo() {
 ; return 0; }
 EOF
-if { (eval echo configure:2292: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2552: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_c_inline=$ac_kw; break
 else
@@ -2317,12 +2577,12 @@
 for ac_func in rename getrusage getdtablesize srandom random sigaction
 do
 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:2321: checking for $ac_func" >&5
+echo "configure:2581: checking for $ac_func" >&5
 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2326 "configure"
+#line 2586 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -2345,7 +2605,7 @@
 
 ; return 0; }
 EOF
-if { (eval echo configure:2349: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2609: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func_$ac_func=yes"
 else
@@ -2372,12 +2632,12 @@
 for ac_func in sigemptyset vsprintf strcasecmp setpgid clock dlopen
 do
 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:2376: checking for $ac_func" >&5
+echo "configure:2636: checking for $ac_func" >&5
 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2381 "configure"
+#line 2641 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -2400,7 +2660,7 @@
 
 ; return 0; }
 EOF
-if { (eval echo configure:2404: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2664: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func_$ac_func=yes"
 else
@@ -2427,12 +2687,12 @@
 for ac_func in dprintf bzero uname vsnprintf
 do
 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:2431: checking for $ac_func" >&5
+echo "configure:2691: checking for $ac_func" >&5
 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2436 "configure"
+#line 2696 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -2455,7 +2715,7 @@
 
 ; return 0; }
 EOF
-if { (eval echo configure:2459: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2719: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func_$ac_func=yes"
 else
@@ -2499,7 +2759,7 @@
 fi
 
 echo $ac_n "checking space left in file database struct""... $ac_c" 1>&6
-echo "configure:2503: checking space left in file database struct" >&5
+echo "configure:2763: checking space left in file database struct" >&5
 cat > abacab.c <<'EOF'
 #include <stdio.h>
 #include <sys/time.h>
@@ -2598,7 +2858,7 @@
 
   # check in common places now
   echo $ac_n "checking for libtcl""... $ac_c" 1>&6
-echo "configure:2602: checking for libtcl" >&5
+echo "configure:2862: checking for libtcl" >&5
   if test ! "x${TCLLIB}" = "x"
   then
     echo "$ac_t""found in $TCLLIB/lib$TCLLIBFN$TCLLIBEXT" 1>&6
@@ -2654,7 +2914,7 @@
 
   # check in common places now
   echo $ac_n "checking for $TCLINCFN""... $ac_c" 1>&6
-echo "configure:2658: checking for $TCLINCFN" >&5
+echo "configure:2918: checking for $TCLINCFN" >&5
   if test ! "x${TCLINC}" = "x"
   then
     echo "$ac_t""found in $TCLINC/$TCLINCFN" 1>&6
@@ -2718,7 +2978,7 @@
 else
 
   echo $ac_n "checking for Tcl version""... $ac_c" 1>&6
-echo "configure:2722: checking for Tcl version" >&5
+echo "configure:2982: checking for Tcl version" >&5
 
   for ver in $tclnames
   do
@@ -2832,6 +3092,7 @@
 
 
 
+
 trap '' 1 2 15
 cat > confcache <<\EOF
 # This file is a shell script that caches the results of configure
@@ -2985,6 +3246,7 @@
 s%@CP2@%$CP2%g
 s%@CP3@%$CP3%g
 s%@EGGEXEC@%$EGGEXEC%g
+s%@RESLIB@%$RESLIB%g
 s%@SHLIB_LD@%$SHLIB_LD%g
 s%@SHLIB_CC@%$SHLIB_CC%g
 s%@SHLIB_STRIP@%$SHLIB_STRIP%g
diff -urN eggdrop1.4~/configure.in eggdrop1.4/configure.in
--- eggdrop1.4~/configure.in	Sat Oct  9 18:33:40 1999
+++ eggdrop1.4/configure.in	Sat Oct  9 18:40:19 1999
@@ -250,6 +250,14 @@
   fi
 fi
 
+AC_CHECK_FUNC(res_init, ,
+  AC_CHECK_LIB(bind, res_init, RESLIB="-lbind",
+   AC_CHECK_LIB(resolv, res_init, RESLIB="-lresolv", AC_MSG_ERROR(No resolver library found))))
+
+AC_CHECK_FUNC(res_mkquery, ,
+  AC_CHECK_LIB(bind, res_mkquery, RESLIB="-lbind",
+   AC_CHECK_LIB(resolv, res_mkquery, RESLIB="-lresolv", AC_MSG_ERROR(No resolver library found))))
+
 AC_C_BIGENDIAN
 AC_CHECK_SIZEOF(long,0)
 AC_CHECK_SIZEOF(int,0)
@@ -599,6 +607,7 @@
 AC_SUBST(CP3)
 AC_SUBST(EGGEXEC)
 AC_SUBST(CC)
+AC_SUBST(RESLIB)
 AC_SUBST(SHLIB_LD)
 AC_SUBST(SHLIB_CC)
 AC_SUBST(SHLIB_STRIP)
diff -urN eggdrop1.4~/eggdrop.conf.dist eggdrop1.4/eggdrop.conf.dist
--- eggdrop1.4~/eggdrop.conf.dist	Sat Oct  9 18:33:40 1999
+++ eggdrop1.4/eggdrop.conf.dist	Sat Oct  9 18:40:20 1999
@@ -358,6 +358,13 @@
 set mod-path "modules/"
 
 
+#### DNS MODULE #####
+
+# this module provides asynchronous dns support. This will avoid long
+# periods where the bot just hangs there, waiting for a hostname to
+# resolve, which often let it timeout on all other connections.
+#loadmodule dns
+
 
 #### CHANNELS MODULE #####
 
diff -urN eggdrop1.4~/src/Makefile eggdrop1.4/src/Makefile
--- eggdrop1.4~/src/Makefile	Sat Oct  9 18:33:50 1999
+++ eggdrop1.4/src/Makefile	Sat Oct  9 18:40:20 1999
@@ -61,6 +61,9 @@
 dccutil.o: dccutil.c
 	${CC} ${CFLAGS} dccutil.c
 
+dns.o: dns.c
+	${CC} ${CFLAGS} dns.c
+
 flags.o: flags.c
 	${CC} ${CFLAGS} flags.c
 
@@ -147,6 +150,8 @@
    chan.h \
    modules.h \
    tandem.h
+dns.o: \
+   main.h
 flags.o: \
    main.h
 language.o: \
diff -urN eggdrop1.4~/src/botnet.c eggdrop1.4/src/botnet.c
--- eggdrop1.4~/src/botnet.c	Sat Oct  9 18:33:51 1999
+++ eggdrop1.4/src/botnet.c	Sat Oct  9 18:49:21 1999
@@ -870,6 +870,9 @@
   return 0;
 }
 
+static void botlink_resolve_success(int);
+static void botlink_resolve_failure(int);
+
 /* link to another bot */
 int botlink(char *linker, int idx, char *nick)
 {
@@ -911,30 +914,58 @@
     } else {
       context;
       correct_handle(nick);
-      i = new_dcc(&DCC_FORK_BOT, sizeof(struct bot_info));
 
-      dcc[i].port = bi->telnet_port;
-      strcpy(dcc[i].nick, nick);
-      strcpy(dcc[i].host, bi->address);
-      dcc[i].timeval = now;
-      strcpy(dcc[i].u.bot->linker, linker);
-      strcpy(dcc[i].u.bot->version, "(primitive bot)");
       if (idx > -2)
 	putlog(LOG_BOTS, "*", "%s %s at %s:%d ...", BOT_LINKING, nick,
 	       bi->address, bi->telnet_port);
-      dcc[i].u.bot->numver = idx;
+
+      i = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info));
       dcc[i].timeval = now;
-      dcc[i].u.bot->port = dcc[i].port;		/* remember where i started */
-      dcc[i].sock = getsock(SOCK_STRONGCONN);
-      dcc[i].user = u;
-      if (open_telnet_raw(dcc[i].sock, bi->address, dcc[i].port) >= 0)
-	return 1;
-      failed_link(i);
+      dcc[i].port = bi->telnet_port;
+      strcpy(dcc[i].nick, nick);
+      strcpy(dcc[i].host, bi->address);
+      dcc[i].u.dns->ibuf = idx;
+      dcc[i].u.dns->cptr = linker;
+      dcc[i].u.dns->host = get_data_ptr(strlen(dcc[i].host) + 1);
+      strcpy(dcc[i].u.dns->host, dcc[i].host);
+      dcc[i].u.dns->dns_success = (Function) botlink_resolve_success;
+      dcc[i].u.dns->dns_failure = (Function) botlink_resolve_failure;
+      dcc[i].u.dns->dns_type = RES_IPBYHOST;
+
+      dns_ipbyhost(bi->address);
     }
   }
   return 0;
 }
 
+static void botlink_resolve_failure(int i)
+{
+  char s[81];
+
+  putlog(LOG_BOTS, "*", DCC_LINKFAIL, dcc[i].nick);
+  strcpy(s, dcc[i].nick);
+  lostdcc(i);
+  autolink_cycle(s);          /* check for more auto-connections */
+}
+
+static void botlink_resolve_success(int i)
+{
+  int idx = dcc[i].u.dns->ibuf;
+  char *linker = dcc[i].u.dns->cptr;
+
+  dcc[i].addr = dcc[i].u.dns->ip;
+  changeover_dcc(i, &DCC_FORK_BOT, sizeof(struct bot_info));
+  dcc[i].timeval = now;
+  strcpy(dcc[i].u.bot->linker, linker);
+  strcpy(dcc[i].u.bot->version, "(primitive bot)");
+  dcc[i].u.bot->numver = idx;
+  dcc[i].u.bot->port = dcc[i].port;		/* remember where i started */
+  dcc[i].sock = getsock(SOCK_STRONGCONN);
+  if (open_telnet_raw(dcc[i].sock, iptostr(my_ntohl(dcc[i].addr)),
+		      dcc[i].port) < 0)
+    failed_link(i);
+}
+
 static void failed_tandem_relay(int idx)
 {
   int uidx = (-1), i;
@@ -968,16 +999,22 @@
   dcc[uidx].u.relay->sock = dcc[idx].sock;
   dcc[idx].port++;
   dcc[idx].timeval = now;
-  if (open_telnet_raw(dcc[idx].sock, dcc[idx].host, dcc[idx].port) < 0)
+  if (open_telnet_raw(dcc[idx].sock, dcc[idx].addr ?
+				     iptostr(my_ntohl(dcc[idx].addr)) :
+				     dcc[idx].host, dcc[idx].port) < 0)
     failed_tandem_relay(idx);
 }
 
+
+static void tandem_relay_resolve_failure(int);
+static void tandem_relay_resolve_success(int);
+
 /* relay to another tandembot */
 void tandem_relay(int idx, char *nick, int i)
 {
-  struct chat_info *ci;
   struct userrec *u;
   struct bot_addr *bi;
+  struct chat_info *ci;
 
   context;
   u = get_user_by_handle(userlist, nick);
@@ -1002,38 +1039,87 @@
     dprintf(idx, "%s\n", DCC_TOOMANYDCCS1);
     return;
   }
-  i = new_dcc(&DCC_FORK_RELAY, sizeof(struct relay_info));
-  dcc[i].u.relay->chat = get_data_ptr(sizeof(struct chat_info));
+  i = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info));
 
   dcc[i].port = bi->relay_port;
-  dcc[i].u.relay->port = dcc[i].port;
   dcc[i].addr = 0L;
   strcpy(dcc[i].nick, nick);
   dcc[i].user = u;
   strcpy(dcc[i].host, bi->address);
-  dcc[i].u.relay->chat->away = NULL;
-  dcc[i].u.relay->old_status = dcc[i].status;
   dcc[i].status = 0;
-  dcc[i].timeval = now;
-  dcc[i].u.relay->chat->msgs_per_sec = 0;
-  dcc[i].u.relay->chat->con_flags = 0;
-  dcc[i].u.relay->chat->buffer = NULL;
-  dcc[i].u.relay->chat->max_line = 0;
-  dcc[i].u.relay->chat->line_count = 0;
-  dcc[i].u.relay->chat->current_lines = 0;
   dprintf(idx, "%s %s @ %s:%d ...\n", BOT_CONNECTINGTO, nick,
 	  bi->address, bi->relay_port);
   dprintf(idx, "%s\n", BOT_BYEINFO1);
+  dcc[idx].type = &DCC_PRE_RELAY;
   ci = dcc[idx].u.chat;
   dcc[idx].u.relay = get_data_ptr(sizeof(struct relay_info));
-
   dcc[idx].u.relay->chat = ci;
-  dcc[idx].type = &DCC_PRE_RELAY;
   dcc[i].sock = getsock(SOCK_STRONGCONN);
   dcc[idx].u.relay->sock = dcc[i].sock;
   dcc[i].u.relay->sock = dcc[idx].sock;
   dcc[i].timeval = now;
-  if (open_telnet_raw(dcc[i].sock, dcc[i].host, dcc[i].port) < 0)
+  dcc[i].u.dns->ibuf = dcc[idx].sock;
+  dcc[i].u.dns->host = get_data_ptr(strlen(bi->address) + 1);
+  strcpy(dcc[i].u.dns->host, bi->address);
+  dcc[i].u.dns->dns_success = (Function) tandem_relay_resolve_success;
+  dcc[i].u.dns->dns_failure = (Function) tandem_relay_resolve_failure;
+  dcc[i].u.dns->dns_type = RES_IPBYHOST;
+
+  dns_ipbyhost(bi->address);
+}
+
+static void tandem_relay_resolve_failure(int idx)
+{
+  struct chat_info *ci;
+  int uidx = (-1), i;
+
+  context;
+  for (i = 0; i < dcc_total; i++)
+    if ((dcc[i].type == &DCC_PRE_RELAY) &&
+	(dcc[i].u.relay->sock == dcc[idx].sock)) {
+      uidx = i;
+      break;
+    }
+  if (uidx < 0) {
+    putlog(LOG_MISC, "*", "%s  %d -> %d", BOT_CANTFINDRELAYUSER,
+	   dcc[idx].sock, dcc[idx].u.relay->sock);
+    killsock(dcc[idx].sock);
+    lostdcc(idx);
+    return;
+  }
+  ci = dcc[uidx].u.relay->chat;
+  dprintf(uidx, "%s %s.\n", BOT_CANTLINKTO, dcc[idx].nick);
+  nfree(dcc[uidx].u.relay);
+  dcc[uidx].u.chat = ci;
+  dcc[uidx].type = &DCC_CHAT;
+  dcc[uidx].status = dcc[uidx].u.relay->old_status;
+  killsock(dcc[idx].sock);
+  lostdcc(idx);
+  context;
+}
+
+static void tandem_relay_resolve_success(int i)
+{
+  int sock = dcc[i].u.dns->ibuf;
+
+  dcc[i].addr = dcc[i].u.dns->ip;
+  changeover_dcc(i, &DCC_FORK_RELAY, sizeof(struct relay_info));
+  dcc[i].u.relay->chat = get_data_ptr(sizeof(struct chat_info));
+
+  dcc[i].u.relay->sock = sock;
+  dcc[i].u.relay->port = dcc[i].port;
+  dcc[i].u.relay->chat->away = NULL;
+  dcc[i].u.relay->old_status = dcc[i].status;
+  dcc[i].status = 0;
+  dcc[i].u.relay->chat->msgs_per_sec = 0;
+  dcc[i].u.relay->chat->con_flags = 0;
+  dcc[i].u.relay->chat->buffer = NULL;
+  dcc[i].u.relay->chat->max_line = 0;
+  dcc[i].u.relay->chat->line_count = 0;
+  dcc[i].u.relay->chat->current_lines = 0;
+  dcc[i].timeval = now;
+  if (open_telnet_raw(dcc[i].sock, iptostr(my_ntohl(dcc[i].addr)),
+		      dcc[i].port) < 0)
     failed_tandem_relay(i);
 }
 
@@ -1045,8 +1131,18 @@
   context;
   for (i = 0; i < dcc_total; i++)
     if ((dcc[i].type == &DCC_FORK_RELAY) &&
-	(dcc[i].u.relay->sock == dcc[idx].sock))
+	(dcc[i].u.relay->sock == dcc[idx].sock)) {
       tidx = i;
+      break;
+    }
+  if (tidx < 0) {
+    for (i = 0; i < dcc_total; i++)
+      if ((dcc[i].type == &DCC_DNSWAIT) &&
+	  (dcc[i].sock == dcc[idx].u.relay->sock)) {
+	tidx = i;
+	break;
+      }
+  }
   if (tidx < 0) {
     putlog(LOG_MISC, "*", "%s  %d -> %d", BOT_CANTFINDRELAYUSER,
 	   dcc[i].sock, dcc[i].u.relay->sock);
@@ -1063,9 +1159,9 @@
     dprintf(idx, "%s %s.\n\n", BOT_ABORTRELAY2, botnetnick);
     putlog(LOG_MISC, "*", "%s %s -> %s", BOT_ABORTRELAY3, dcc[idx].nick,
 	   dcc[tidx].nick);
+    dcc[idx].status = dcc[idx].u.relay->old_status;
     nfree(dcc[idx].u.relay);
     dcc[idx].u.chat = ci;
-    dcc[idx].status = dcc[idx].u.relay->old_status;
     dcc[idx].type = &DCC_CHAT;
     killsock(dcc[tidx].sock);
     lostdcc(tidx);
@@ -1082,13 +1178,24 @@
   context;
   for (i = 0; i < dcc_total; i++)
     if ((dcc[i].type == &DCC_FORK_RELAY) &&
-	(dcc[i].u.relay->sock == dcc[idx].sock))
+	(dcc[i].u.relay->sock == dcc[idx].sock)) {
       tidx = i;
+      break;
+    }
+  if (tidx < 0) {
+    /* Now try to find it among the DNSWAIT sockets instead */
+    for (i = 0; i < dcc_total; i++)
+      if ((dcc[i].type == &DCC_DNSWAIT) &&
+	  (dcc[i].sock == dcc[idx].u.relay->sock)) {
+	tidx = i;
+	break;
+      }
+  }
   if (tidx < 0) {
     putlog(LOG_MISC, "*", "%s  %d -> %d", BOT_CANTFINDRELAYUSER,
-	   dcc[i].sock, dcc[i].u.relay->sock);
-    killsock(dcc[i].sock);
-    lostdcc(i);
+	   dcc[idx].sock, dcc[idx].u.relay->sock);
+    killsock(dcc[idx].sock);
+    lostdcc(idx);
     return;
   }
   putlog(LOG_MISC, "*", "%s [%s]%s/%d",
diff -urN eggdrop1.4~/src/dcc.c eggdrop1.4/src/dcc.c
--- eggdrop1.4~/src/dcc.c	Sat Oct  9 18:33:51 1999
+++ eggdrop1.4/src/dcc.c	Sat Oct  9 18:49:21 1999
@@ -209,7 +209,9 @@
   dcc[idx].sock = getsock(SOCK_STRONGCONN);
   dcc[idx].port++;
   dcc[idx].timeval = now;
-  if (open_telnet_raw(dcc[idx].sock, dcc[idx].host, dcc[idx].port) < 0) {
+  if (open_telnet_raw(dcc[idx].sock, dcc[idx].addr ?
+		      iptostr(my_ntohl(dcc[idx].addr)) : dcc[idx].host,
+		      dcc[idx].port) < 0) {
     failed_link(idx);
   }
 }
@@ -1047,14 +1049,14 @@
   return 0;
 }
 
-static void dcc_telnet_got_ident(int, char *);
+static void dcc_telnet_hostresolved(int);
 
 static void dcc_telnet(int idx, char *buf, int i)
 {
   unsigned long ip;
   unsigned short port;
   int j = 0, sock;
-  char s[UHOSTLEN + 1], s2[UHOSTLEN + 20];
+  char s[UHOSTLEN + 1];
 
   context;
   if (dcc_total + 1 > max_dcc) {
@@ -1092,32 +1094,67 @@
     killsock(sock);
     return;
   }
+  i = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info));
+  dcc[i].sock = sock;
+  dcc[i].addr = ip;
+  dcc[i].port = port;
+  dcc[i].timeval = now;
+  strcpy(dcc[i].nick, "*");
+  dcc[i].u.dns->ip = ip;
+  dcc[i].u.dns->dns_success = (Function) dcc_telnet_hostresolved;
+  dcc[i].u.dns->dns_failure = (Function) dcc_telnet_hostresolved;
+  dcc[i].u.dns->dns_type = RES_HOSTBYIP;
+  dcc[i].u.dns->ibuf = dcc[idx].sock;
+
+  dns_hostbyip(ip);
+}
+
+static void dcc_telnet_got_ident(int, char *);
+
+static void dcc_telnet_hostresolved(int i)
+{
+  int idx;
+  int j = 0, sock;
+  char s[UHOSTLEN + 1], s2[UHOSTLEN + 20];
+
+  strncpy(dcc[i].host, dcc[i].u.dns->host, UHOSTLEN - 1);
+  dcc[i].host[UHOSTLEN - 1] = 0;
+
+  for (idx = 0; idx < dcc_total; idx++)
+    if ((dcc[idx].type == &DCC_TELNET) &&
+        (dcc[idx].sock == dcc[i].u.dns->ibuf)) {
+       break;
+    }
+  if (dcc_total == idx) {
+    putlog(LOG_BOTS, "*", "Lost listening socket while resolving %s",
+	   dcc[i].host);
+    killsock(dcc[i].sock);
+    lostdcc(i);
+    return;
+  }
   if (dcc[idx].host[0] == '@') {
     /* restrict by hostname */
-    if (!wild_match(dcc[idx].host + 1, s)) {
+    if (!wild_match(dcc[idx].host + 1, dcc[i].host)) {
       putlog(LOG_BOTS, "*", DCC_BADHOST, s);
-      killsock(sock);
+      killsock(dcc[i].sock);
+      lostdcc(i);
       return;
     }
   }
   context;
-  sprintf(s2, "telnet!telnet@%s", s);
+  sprintf(s2, "telnet!telnet@%s", dcc[i].host);
   if (match_ignore(s2) || detect_telnet_flood(s2)) {
-    killsock(sock);
+    killsock(dcc[i].sock);
+    lostdcc(i);
     return;
   }
+
   context;
-  i = new_dcc(&DCC_IDENTWAIT, 0);
-  dcc[i].sock = sock;
-  dcc[i].addr = ip;
-  dcc[i].port = port;
+  changeover_dcc(i, &DCC_IDENTWAIT, 0);
   dcc[i].timeval = now;
-  dcc[i].u.ident_sock = dcc[idx].sock;
-  strncpy(dcc[i].host, s, UHOSTLEN - 1);
-  dcc[i].host[UHOSTLEN - 1] = 0;
-  strcpy(dcc[i].nick, "*");
-  sock = open_telnet(s, 113);
-  putlog(LOG_MISC, "*", DCC_TELCONN, s, port);
+  dcc[i].u.ident_sock = dcc[j].sock;
+  sock = open_telnet(iptostr(my_htonl(dcc[i].addr)), 113);
+  putlog(LOG_MISC, "*", DCC_TELCONN, dcc[i].host, dcc[i].port);
   s[0] = 0;
   context;
   if (sock < 0) {
@@ -1142,7 +1179,7 @@
   context;
   dcc[j].sock = sock;
   dcc[j].port = 113;
-  dcc[j].addr = ip;
+  dcc[j].addr = dcc[i].addr;
   strcpy(dcc[j].host, dcc[i].host);
   strcpy(dcc[j].nick, "*");
   dcc[j].u.ident_sock = dcc[i].sock;
diff -urN eggdrop1.4~/src/dccutil.c eggdrop1.4/src/dccutil.c
--- eggdrop1.4~/src/dccutil.c	Sat Oct  9 18:33:51 1999
+++ eggdrop1.4/src/dccutil.c	Sat Oct  9 18:40:20 1999
@@ -410,6 +410,25 @@
 
 }
 
+/* Changes the given dcc entry to another type */
+void changeover_dcc(int i, struct dcc_table *type, int xtra_size)
+{
+  /* free old structure */
+  if (dcc[i].type && dcc[i].type->kill)
+    dcc[i].type->kill(i, dcc[i].u.other);
+  else if (dcc[i].u.other) {
+    nfree(dcc[i].u.other);
+    dcc[i].u.other = NULL;
+  }
+
+  dcc[i].type = type;
+  if (xtra_size) {
+    dcc[i].u.other = nmalloc(xtra_size);
+    bzero(dcc[i].u.other, xtra_size);
+  }
+}
+
+
 int detect_dcc_flood(time_t * timer, struct chat_info *chat, int idx)
 {
   time_t t;
diff -urN eggdrop1.4~/src/dns.c eggdrop1.4/src/dns.c
--- eggdrop1.4~/src/dns.c	Thu Jan  1 01:00:00 1970
+++ eggdrop1.4/src/dns.c	Sat Oct  9 18:40:20 1999
@@ -0,0 +1,191 @@
+/*
+ * dns.c - handles DNS calls. Also provides the code used by the bot
+ * if the DNS module is not loaded.
+ */
+/*
+ * This file is part of the eggdrop source code.
+ *
+ * Copyright (C) 1999  Eggheads
+ * Copyright (C) 1997  Robey Pointer
+ *
+ * Distributed according to the GNU General Public License. For full
+ * details, read the top of 'main.c' or the file called COPYING that
+ * was distributed with this code.
+ */
+/*
+ * Mon Oct 04 22:24:51 1999  Fabian Knittel
+ *     * minor fixes
+ * Sun Oct 03 18:34:41 1999  Fabian Knittel
+ *     * Initial release
+ */
+
+
+#include "main.h"
+#include <netdb.h>
+#include <setjmp.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+extern struct dcc_t *dcc;
+extern int dcc_total;
+extern int resolve_timeout;
+extern time_t now;
+extern jmp_buf alarmret;
+
+
+void dcc_dnswait(int idx, char *buf, int len)
+{
+  /* ignore anything now */
+  context;
+}
+
+void eof_dcc_dnswait(int idx)
+{
+  putlog(LOG_MISC, "*", "Lost connection while resolving hostname [%s/%d]",
+	 iptostr(dcc[idx].addr), dcc[idx].port);
+  killsock(dcc[idx].sock);
+  lostdcc(idx);
+}
+
+static void display_dcc_dnswait(int idx, char *buf)
+{
+  sprintf(buf, "dns   waited %lus", now - dcc[idx].timeval);
+}
+
+static int expmem_dcc_dnswait(void *x)
+{
+  register struct dns_info *p = (struct dns_info *) x;
+  int size = 0;
+
+  if (p) {
+    size = sizeof(struct dns_info);
+    if (p->host)
+      size += strlen(p->host) + 1;
+    if (p->cbuf)
+      size += strlen(p->cbuf) + 1;
+  }
+  return size;
+}
+
+static void kill_dcc_dnswait(int idx, void *x)
+{
+  register struct dns_info *p = (struct dns_info *) x;
+
+  if (p) {
+    if (p->host)
+      nfree(p->host);
+    if (p->cbuf)
+      nfree(p->cbuf);
+    nfree(p);
+  }
+}
+
+struct dcc_table DCC_DNSWAIT =
+{
+  "DNSWAIT",
+  DCT_VALIDIDX,
+  eof_dcc_dnswait,
+  dcc_dnswait,
+  0,
+  0,
+  display_dcc_dnswait,
+  expmem_dcc_dnswait,
+  kill_dcc_dnswait,
+  0
+};
+
+/* Walk through every dcc entry and look for waiting DNS requests
+ * of RES_HOSTBYIP for our IP address */
+void call_hostbyip(IP ip, char *hostn, int ok)
+{
+  int idx;
+  
+  for (idx = 0; idx < dcc_total; idx++) {
+    if ((dcc[idx].type == &DCC_DNSWAIT) &&
+        (dcc[idx].u.dns->dns_type == RES_HOSTBYIP) &&
+        (dcc[idx].u.dns->ip == ip)) {
+      if (dcc[idx].u.dns->host)
+        nfree(dcc[idx].u.dns->host);
+      dcc[idx].u.dns->host = get_data_ptr(strlen(hostn) + 1);
+      strcpy(dcc[idx].u.dns->host, hostn);
+      if (ok)
+        dcc[idx].u.dns->dns_success(idx);
+      else
+        dcc[idx].u.dns->dns_failure(idx);
+    }
+  }
+}
+
+/* Walk through every dcc entry and look for waiting DNS requests
+ * of RES_IPBYHOST for our hostname */
+void call_ipbyhost(char *hostn, IP ip, int ok)
+{
+  int idx;
+  
+  for (idx = 0; idx < dcc_total; idx++) {
+    if ((dcc[idx].type == &DCC_DNSWAIT) &&
+        (dcc[idx].u.dns->dns_type == RES_IPBYHOST) &&
+        !strcmp(dcc[idx].u.dns->host, hostn)) {
+      dcc[idx].u.dns->ip = ip;
+      if (ok)
+        dcc[idx].u.dns->dns_success(idx);
+      else
+        dcc[idx].u.dns->dns_failure(idx);
+    }
+  }
+}
+
+
+/*
+ *    Async DNS emulation
+ */
+
+void block_dns_hostbyip(IP ip)
+{
+  struct hostent *hp;
+  unsigned long addr = htonl(ip);
+  unsigned char *p;
+  static char s[UHOSTLEN];
+
+  /*
+   * This actually copies hostnamefromip(), which is ugly, but there
+   * is no way to determine if the lookup was successful or not, using
+   * that interface.
+   */
+  if (!setjmp(alarmret)) {
+    alarm(resolve_timeout);
+    hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
+    alarm(0);
+  } else {
+    hp = NULL;
+  }
+  if (hp == NULL) {
+    p = (unsigned char *) &addr;
+    sprintf(s, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);
+  } else {
+    strncpy(s, hp->h_name, UHOSTLEN - 1);
+    s[UHOSTLEN - 1] = 0;
+  }
+  /* call hooks */
+  call_hostbyip(ip, s, hp ? 1 : 0);
+}
+
+void block_dns_ipbyhost(char *host)
+{
+  if (!setjmp(alarmret)) {
+    struct hostent *hp;
+    struct in_addr *in;
+    IP ip = 0;
+
+    alarm(resolve_timeout);
+    hp = gethostbyname(host);
+    alarm(0);
+
+    in = (struct in_addr *) (hp->h_addr_list[0]);
+    ip = (IP) (in->s_addr);
+    call_ipbyhost(host, ip, 1);
+  } else {
+    call_ipbyhost(host, 0, 0);
+  }
+}
diff -urN eggdrop1.4~/src/eggdrop.h eggdrop1.4/src/eggdrop.h
--- eggdrop1.4~/src/eggdrop.h	Sat Oct  9 18:33:51 1999
+++ eggdrop1.4/src/eggdrop.h	Sat Oct  9 18:40:20 1999
@@ -173,6 +173,9 @@
 
 /***********************************************************************/
 
+/* it's used in so many places, let's put it here */
+typedef int (*Function) ();
+
 /* public structure for the listening port map */
 struct portmap {
   int realport;
@@ -216,6 +219,7 @@
     struct bot_info *bot;
     struct relay_info *relay;
     struct script_info *script;
+    struct dns_info *dns;
     int ident_sock;
     void *other;
   } u;				/* special use depending on type */
@@ -275,6 +279,22 @@
   char command[121];
 };
 
+struct dns_info {
+  Function dns_success;		/* is called if the dns request succeeds */
+  Function dns_failure;		/* is called if it fails */
+  char *host;			/* hostname */
+  char *cbuf;			/* temporary buffer. Memory will be free'd
+				   as soon as dns_info is free'd */
+  char *cptr;			/* temporary pointer */
+  IP ip;			/* IP address */
+  int ibuf;			/* temporary buffer for one integer */
+  char dns_type;		/* lookup type, e.g. RES_HOSTBYIP */
+};
+
+/* flags for dns_type */
+#define RES_HOSTBYIP  1			/* hostname to IP address */
+#define RES_IPBYHOST  2			/* IP address to hostname */
+
 /* flags about dcc types */
 #define DCT_CHAT      0x00000001	/* this dcc type receives botnet chatter */
 #define DCT_MASTER    0x00000002	/* received master chatter */
@@ -386,14 +406,15 @@
 #define FILEDB_UNSHARE  4
 
 /* socket flags: */
-#define SOCK_UNUSED     0x01	/* empty socket */
-#define SOCK_BINARY     0x02	/* do not buffer input */
-#define SOCK_LISTEN     0x04	/* listening port */
-#define SOCK_CONNECT    0x08	/* connection attempt */
-#define SOCK_NONSOCK    0x10	/* used for file i/o on debug */
-#define SOCK_STRONGCONN 0x20	/* don't report success until sure */
-#define SOCK_EOFD       0x40	/* it EOF'd recently during a write */
-#define SOCK_PROXYWAIT	0x80	/* waiting for SOCKS traversal */
+#define SOCK_UNUSED     0x001	/* empty socket */
+#define SOCK_BINARY     0x002	/* do not buffer input */
+#define SOCK_LISTEN     0x004	/* listening port */
+#define SOCK_CONNECT    0x008	/* connection attempt */
+#define SOCK_NONSOCK    0x010	/* used for file i/o on debug */
+#define SOCK_STRONGCONN 0x020	/* don't report success until sure */
+#define SOCK_EOFD       0x040	/* it EOF'd recently during a write */
+#define SOCK_PROXYWAIT	0x080	/* waiting for SOCKS traversal */
+#define SOCK_PASS	0x100	/* passed on; only notify in case of traffic */
 
 /* fake idx's for dprintf - these should be ridiculously large +ve nums */
 #define DP_STDOUT       0x7FF1
@@ -423,14 +444,11 @@
 #define HELP_TEXT       2
 #define HELP_IRC        16
 
-/* it's used in so many places, let's put it here */
-typedef int (*Function) ();
-
 /* this is used by the net module to keep track of sockets and what's
  * queued on them */
 typedef struct {
   int sock;
-  char flags;
+  short flags;
   char *inbuf;
   char *outbuf;
   unsigned long outbuflen;	/* outbuf could be binary data */
diff -urN eggdrop1.4~/src/main.h eggdrop1.4/src/main.h
--- eggdrop1.4~/src/main.h	Sat Oct  9 18:34:15 1999
+++ eggdrop1.4/src/main.h	Sat Oct  9 18:40:21 1999
@@ -44,7 +44,7 @@
 extern struct dcc_table DCC_CHAT, DCC_BOT, DCC_LOST, DCC_SCRIPT, DCC_BOT_NEW,
  DCC_RELAY, DCC_RELAYING, DCC_FORK_RELAY, DCC_PRE_RELAY, DCC_CHAT_PASS,
  DCC_FORK_BOT, DCC_SOCKET, DCC_TELNET_ID, DCC_TELNET_NEW, DCC_TELNET_PW,
- DCC_TELNET, DCC_IDENT, DCC_IDENTWAIT;
+ DCC_TELNET, DCC_IDENT, DCC_IDENTWAIT, DCC_DNSWAIT;
 
 #endif
 
@@ -60,6 +60,11 @@
 #endif
 #define iptolong(a) (0xffffffff & (long)(swap_long((unsigned long)a)))
 #define fixcolon(x) if (x[0]==':') {x++;} else {x=newsplit(&x);}
+
+#define my_ntohs(sh) swap_short(sh)
+#define my_htons(sh) swap_short(sh)
+#define my_ntohl(ln) swap_long(ln)
+#define my_htonl(ln) swap_long(ln)
 
 /* Stupid Borg Cube crap ;p */
 #ifdef BORGCUBES
diff -urN eggdrop1.4~/src/mod/Makefile eggdrop1.4/src/mod/Makefile
--- eggdrop1.4~/src/mod/Makefile	Sat Oct  9 18:33:43 1999
+++ eggdrop1.4/src/mod/Makefile	Sat Oct  9 18:40:21 1999
@@ -1,6 +1,6 @@
 # Source-make
 
-GMAKE=${MAKE} 'LD=${LD}' 'STRIP=${STRIP}' 'CC=${CC}' 'CFLAGS=${CFLAGS}'
+GMAKE=${MAKE} 'LD=${LD}' 'STRIP=${STRIP}' 'CC=${CC}' 'CFLAGS=${CFLAGS}' 'RESLIB=${RESLIB}'
 
 doofus:
 	@echo ""
diff -urN eggdrop1.4~/src/mod/Makefile.generic eggdrop1.4/src/mod/Makefile.generic
--- eggdrop1.4~/src/mod/Makefile.generic	Sat Oct  9 18:33:43 1999
+++ eggdrop1.4/src/mod/Makefile.generic	Sat Oct  9 18:40:21 1999
@@ -14,7 +14,7 @@
 static: ../${FILENAME}.o
 	
 ../../../${FILENAME}.so: ${FILENAME}.o
-	${LD} -o ../../../${FILENAME}.so ${FILENAME}.o
+	${LD} ${LDFLAGS} -o ../../../${FILENAME}.so ${FILENAME}.o
 	${STRIP} ../../../${FILENAME}.so
        
 ${FILENAME}.o: ${FILENAME}.c ../module.h ../modvals.h ../../eggdrop.h
diff -urN eggdrop1.4~/src/mod/dns.mod/Makefile eggdrop1.4/src/mod/dns.mod/Makefile
--- eggdrop1.4~/src/mod/dns.mod/Makefile	Thu Jan  1 01:00:00 1970
+++ eggdrop1.4/src/mod/dns.mod/Makefile	Sat Oct  9 18:40:21 1999
@@ -0,0 +1,11 @@
+# Source-make
+FILENAME=dns
+LDFLAGS=${RESLIB}
+
+include ../Makefile.generic
+
+dns.o: \
+   ../module.h \
+   dns.h \
+   dns.c \
+   coredns.c
diff -urN eggdrop1.4~/src/mod/dns.mod/coredns.c eggdrop1.4/src/mod/dns.mod/coredns.c
--- eggdrop1.4~/src/mod/dns.mod/coredns.c	Thu Jan  1 01:00:00 1970
+++ eggdrop1.4/src/mod/dns.mod/coredns.c	Sat Oct  9 18:40:21 1999
@@ -0,0 +1,1138 @@
+/*
+ * dnscore.c - This file contains all core functions needed for the
+ * eggdrop dns module. Many of them are only minimaly modified from
+ * the original source.
+ *
+ * Portions copyright (C) 1999  Eggheads
+ * Written by Fabian Knittel <fknittel at gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Borrowed from mtr  --  a network diagnostic tool
+ * Copyright (C) 1997,1998  Matt Kimball <mkimball at xmission.com>
+ * Released under the GPL, as above.
+ *
+ * Non-blocking DNS portion --
+ * Copyright (C) 1998  Simon Kirby <sim at neato.org>
+ * Released under the GPL, as above.
+ */
+
+/*
+ * Tue Oct 05 21:52:03 1999  Fabian
+ *     * #include tweaking
+ * Sun Oct 03 18:34:41 1999  Fabian
+ *     * Initial release
+ */ 
+
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <errno.h>
+
+
+/* Defines */
+
+#define BASH_SIZE	 8192		/* Size of hash tables */
+#define HOSTNAMELEN 	  255		/* From RFC */
+#define RES_RETRYDELAY      3
+#define RES_MAXSENDS        4
+#define RES_FAILEDDELAY  3600		/* Keep failed record for 1 hour */
+#define RES_MAX_TTL     86400		/* Maximum TTL is 1d */
+
+#define RES_ERR "DNS Resolver error: "
+#define RES_MSG "DNS Resolver: "
+#define RES_WRN "DNS Resolver warning: "
+
+#define MAX_PACKETSIZE (PACKETSZ)
+#define MAX_DOMAINLEN (MAXDNAME)
+
+/* Macros */
+
+#define nonull(s) (s) ? s : nullstring
+#define BASH_MODULO(x) ((x) & 8191)	/* Modulo for hash table size */
+
+/* Non-blocking nameserver interface routines */
+
+#define OPCODES_COUNT 3
+char *opcodes[OPCODES_COUNT + 1] = {
+    "standard query",
+    "inverse query",
+    "server status request",
+    "unknown",
+};
+
+#define RESPONSECODES_COUNT 6
+char *responsecodes[RESPONSECODES_COUNT + 1] = {
+    "no error",
+    "format error in query",
+    "server failure",
+    "queried domain name does not exist",
+    "requested query type not implemented",
+    "refused by name server",
+    "unknown error",
+};
+
+#define RESOURCETYPES_COUNT 17
+char *resourcetypes[RESOURCETYPES_COUNT + 1] = {
+    "unknown type",
+    "A: host address",
+    "NS: authoritative name server",
+    "MD: mail destination (OBSOLETE)",
+    "MF: mail forwarder (OBSOLETE)",
+    "CNAME: name alias",
+    "SOA: authority record",
+    "MB: mailbox domain name (EXPERIMENTAL)",
+    "MG: mail group member (EXPERIMENTAL)",
+    "MR: mail rename domain name (EXPERIMENTAL)",
+    "NULL: NULL RR (EXPERIMENTAL)",
+    "WKS: well known service description",
+    "PTR: domain name pointer",
+    "HINFO: host information",
+    "MINFO: mailbox or mail list information",
+    "MX: mail exchange",
+    "TXT: text string",
+    "unknown type",
+};
+
+#define CLASSTYPES_COUNT 5
+char *classtypes[CLASSTYPES_COUNT + 1] = {
+    "unknown class",
+    "IN: the Internet",
+    "CS: CSNET (OBSOLETE)",
+    "CH: CHAOS",
+    "HS: Hesoid [Dyer 87]",
+    "unknown class"
+};
+
+char *rrtypes[] = {
+    "Unknown",
+    "Query",
+    "Answer",
+    "Authority reference",
+    "Resource reference",
+};
+
+enum {
+    RR_UNKNOWN,
+    RR_QUERY,
+    RR_ANSWER,
+    RR_AUTHORITY,
+    RR_RESOURCE,
+};
+
+typedef struct {
+    word id;			/* Packet id */
+    byte databyte_a;
+    /* rd:1           recursion desired
+     * tc:1           truncated message
+     * aa:1           authoritive answer
+     * opcode:4       purpose of message
+     * qr:1           response flag
+     */
+    byte databyte_b;
+    /* rcode:4        response code
+     * unassigned:2   unassigned bits
+     * pr:1           primary server required (non standard)
+     * ra:1           recursion available
+     */
+    word qdcount;		/* Query record count */
+    word ancount;		/* Answer record count */
+    word nscount;		/* Authority reference record count */
+    word arcount;		/* Resource reference record count */
+} packetheader;
+
+#ifndef HFIXEDSZ
+#define HFIXEDSZ (sizeof(packetheader))
+#endif
+
+/*
+ * Byte order independent macros for packetheader
+ */
+#define getheader_rd(x) (x->databyte_a & 1)
+#define getheader_tc(x) ((x->databyte_a >> 1) & 1)
+#define getheader_aa(x) ((x->databyte_a >> 2) & 1)
+#define getheader_opcode(x) ((x->databyte_a >> 3) & 15)
+#define getheader_qr(x) (x->databyte_a >> 7)
+#define getheader_rcode(x) (x->databyte_b & 15)
+#define getheader_pr(x) ((x->databyte_b >> 6) & 1)
+#define getheader_ra(x) (x->databyte_b >> 7)
+
+#define sucknetword(x)  ((x)+=2,((word)  (((x)[-2] <<  8) | ((x)[-1] <<  0))))
+#define sucknetshort(x) ((x)+=2,((short) (((x)[-2] <<  8) | ((x)[-1] <<  0))))
+#define sucknetdword(x) ((x)+=4,((dword) (((x)[-4] << 24) | ((x)[-3] << 16) | \
+                                          ((x)[-2] <<  8) | ((x)[-1] <<  0))))
+#define sucknetlong(x)  ((x)+=4,((long)  (((x)[-4] << 24) | ((x)[-3] << 16) | \
+                                          ((x)[-2] <<  8) | ((x)[-1] <<  0))))
+
+
+dword resrecvbuf[(MAX_PACKETSIZE + 7) >> 2];	/* MUST BE DWORD ALIGNED */
+
+struct resolve *idbash[BASH_SIZE];
+struct resolve *ipbash[BASH_SIZE];
+struct resolve *hostbash[BASH_SIZE];
+struct resolve *expireresolves = NULL;
+
+IP alignedip;
+IP localhost;
+
+long idseed = 0xdeadbeef;
+long aseed;
+
+int resfd;
+
+char tempstring[16384 + 1 + 1];
+char sendstring[1024 + 1];
+char namestring[1024 + 1];
+char stackstring[1024 + 1];
+
+char nullstring[] = "";
+
+
+/*
+ *    Miscellaneous helper functions
+ */
+
+/* Displays the time difference passed in signeddiff */
+static char *strtdiff(char *d, long signeddiff)
+{
+    dword diff;
+    dword seconds, minutes, hours;
+    long day;
+
+    context;
+    if ((diff = labs(signeddiff))) {
+	seconds = diff % 60;
+	diff /= 60;
+	minutes = diff % 60;
+	diff /= 60;
+	hours = diff % 24;
+	day = signeddiff / (60 * 60 * 24);
+	if (day)
+	    sprintf(d, "%lid", day);
+	else
+	    *d = '\0';
+	if (hours)
+	    sprintf(d + strlen(d), "%luh", hours);
+	if (minutes)
+	    sprintf(d + strlen(d), "%lum", minutes);
+	if (seconds)
+	    sprintf(d + strlen(d), "%lus", seconds);
+    } else
+	sprintf(d, "0s");
+    return d;
+}
+
+/* Allocate memory to hold one resolve request structure */
+static struct resolve *allocresolve()
+{
+    struct resolve *rp;
+
+    rp = (struct resolve *) nmalloc(sizeof(struct resolve));
+    bzero(rp, sizeof(struct resolve));
+    return rp;
+}
+
+
+/*
+ *    Hash and linked-list related functions
+ */
+
+/* Return the hash bucket number for id */
+static dword getidbash(word id)
+{
+    return (dword) BASH_MODULO(id);
+}
+
+/* Return the hash bucket number for ip */
+static dword getipbash(IP ip)
+{
+    return (dword) BASH_MODULO(ip);
+}
+
+/* Return the hash bucket number for host */
+static dword gethostbash(char *host)
+{
+    dword bashvalue = 0;
+
+    for (; *host; host++) {
+	bashvalue ^= *host;
+	bashvalue += (*host >> 1) + (bashvalue >> 1);
+    }
+    return BASH_MODULO(bashvalue);
+}
+
+/* Insert request structure addrp into the id hash table */
+static void linkresolveid(struct resolve *addrp)
+{
+    struct resolve *rp;
+    dword bashnum;
+
+    context;
+    bashnum = getidbash(addrp->id);
+    rp = idbash[bashnum];
+    if (rp) {
+	while ((rp->nextid) && (addrp->id > rp->nextid->id))
+	    rp = rp->nextid;
+	while ((rp->previousid) && (addrp->id < rp->previousid->id))
+	    rp = rp->previousid;
+	if (rp->id < addrp->id) {
+	    addrp->previousid = rp;
+	    addrp->nextid = rp->nextid;
+	    if (rp->nextid)
+		rp->nextid->previousid = addrp;
+	    rp->nextid = addrp;
+	} else if (rp->id > addrp->id) {
+	    addrp->previousid = rp->previousid;
+	    addrp->nextid = rp;
+	    if (rp->previousid)
+		rp->previousid->nextid = addrp;
+	    rp->previousid = addrp;
+	} else		/* trying to add the same id */
+	    return;
+    } else
+	addrp->nextid = addrp->previousid = NULL;
+    idbash[bashnum] = addrp;
+}
+
+/* Remove request structure rp from the id hash table */
+static void unlinkresolveid(struct resolve *rp)
+{
+    dword bashnum;
+
+    context;
+    bashnum = getidbash(rp->id);
+    if (idbash[bashnum] == rp) {
+	if (rp->previousid)
+	    idbash[bashnum] = rp->previousid;
+	else
+	    idbash[bashnum] = rp->nextid;
+    }
+    if (rp->nextid)
+	rp->nextid->previousid = rp->previousid;
+    if (rp->previousid)
+	rp->previousid->nextid = rp->nextid;
+}
+
+/* Insert request structure addrp intp the host hash table */
+static void linkresolvehost(struct resolve *addrp)
+{
+    struct resolve *rp;
+    dword bashnum;
+    int ret;
+
+    context;
+    bashnum = gethostbash(addrp->hostn);
+    rp = hostbash[bashnum];
+    if (rp) {
+	while ((rp->nexthost) &&
+	       (strcasecmp(addrp->hostn, rp->nexthost->hostn) < 0))
+	    rp = rp->nexthost;
+	while ((rp->previoushost) &&
+	       (strcasecmp(addrp->hostn, rp->previoushost->hostn) > 0))
+	    rp = rp->previoushost;
+	ret = strcasecmp(addrp->hostn, rp->hostn);
+	if (ret < 0) {
+	    addrp->previoushost = rp;
+	    addrp->nexthost = rp->nexthost;
+	    if (rp->nexthost)
+		rp->nexthost->previoushost = addrp;
+	    rp->nexthost = addrp;
+	} else if (ret > 0) {
+	    addrp->previoushost = rp->previoushost;
+	    addrp->nexthost = rp;
+	    if (rp->previoushost)
+		rp->previoushost->nexthost = addrp;
+	    rp->previoushost = addrp;
+	} else		/* trying to add the same host */
+	    return;
+    } else
+	addrp->nexthost = addrp->previoushost = NULL;
+    hostbash[bashnum] = addrp;
+}
+
+/* Remove request structure rp from the host hash table */
+static void unlinkresolvehost(struct resolve *rp)
+{
+    dword bashnum;
+
+    context;
+    bashnum = gethostbash(rp->hostn);
+    if (hostbash[bashnum] == rp) {
+	if (rp->previoushost)
+	    hostbash[bashnum] = rp->previoushost;
+	else
+	    hostbash[bashnum] = rp->nexthost;
+    }
+    if (rp->nexthost)
+	rp->nexthost->previoushost = rp->previoushost;
+    if (rp->previoushost)
+	rp->previoushost->nexthost = rp->nexthost;
+    nfree(rp->hostn);
+}
+
+/* Insert request structure addrp into the ip hash table */
+static void linkresolveip(struct resolve *addrp)
+{
+    struct resolve *rp;
+    dword bashnum;
+
+    context;
+    bashnum = getipbash(addrp->ip);
+    rp = ipbash[bashnum];
+    if (rp) {
+	while ((rp->nextip) && (addrp->ip > rp->nextip->ip))
+	    rp = rp->nextip;
+	while ((rp->previousip) && (addrp->ip < rp->previousip->ip))
+	    rp = rp->previousip;
+	if (rp->ip < addrp->ip) {
+	    addrp->previousip = rp;
+	    addrp->nextip = rp->nextip;
+	    if (rp->nextip)
+		rp->nextip->previousip = addrp;
+	    rp->nextip = addrp;
+	} else if (rp->ip > addrp->ip) {
+	    addrp->previousip = rp->previousip;
+	    addrp->nextip = rp;
+	    if (rp->previousip)
+		rp->previousip->nextip = addrp;
+	    rp->previousip = addrp;
+	} else		/* trying to add the same ip */
+	    return;
+    } else
+	addrp->nextip = addrp->previousip = NULL;
+    ipbash[bashnum] = addrp;
+}
+
+/* Remove request structure rp from the ip hash table */
+static void unlinkresolveip(struct resolve *rp)
+{
+    dword bashnum;
+
+    context;
+    bashnum = getipbash(rp->ip);
+    if (ipbash[bashnum] == rp) {
+	if (rp->previousip)
+	    ipbash[bashnum] = rp->previousip;
+	else
+	    ipbash[bashnum] = rp->nextip;
+    }
+    if (rp->nextip)
+	rp->nextip->previousip = rp->previousip;
+    if (rp->previousip)
+	rp->previousip->nextip = rp->nextip;
+}
+
+/* Add request structure rp to the expireresolves list. Entries are sorted
+ * by expire time. */
+static void linkresolve(struct resolve *rp)
+{
+    struct resolve *irp;
+
+    context;
+    if (expireresolves) {
+	irp = expireresolves;
+	while ((irp->next) && (rp->expiretime >= irp->expiretime))
+	    irp = irp->next;
+	if (rp->expiretime >= irp->expiretime) {
+	    rp->next = NULL;
+	    rp->previous = irp;
+	    irp->next = rp;
+	} else {
+	    rp->previous = irp->previous;
+	    rp->next = irp;
+	    if (irp->previous)
+		irp->previous->next = rp;
+	    else
+		expireresolves = rp;
+	    irp->previous = rp;
+	}
+    } else {
+	rp->next = NULL;
+	rp->previous = NULL;
+	expireresolves = rp;
+    }
+}
+
+/* Remove reqeust structure rp from the expireresolves list */
+static void untieresolve(struct resolve *rp)
+{
+    context;
+    if (rp->previous)
+	rp->previous->next = rp->next;
+    else
+	expireresolves = rp->next;
+    if (rp->next)
+	rp->next->previous = rp->previous;
+}
+
+/* Remove request structure rp from all lists and hash tables and
+ * then delete and free the structure */
+static void unlinkresolve(struct resolve *rp)
+{
+    context;
+    untieresolve(rp);
+    unlinkresolveid(rp);
+    unlinkresolveip(rp);
+    if (rp->hostn)
+	unlinkresolvehost(rp);
+    nfree(rp);
+    context;
+}
+
+/* Find request structure using the id */
+static struct resolve *findid(word id)
+{
+    struct resolve *rp;
+    int bashnum;
+
+    context;
+    bashnum = getidbash(id);
+    rp = idbash[bashnum];
+    if (rp) {
+	while ((rp->nextid) && (id >= rp->nextid->id))
+	    rp = rp->nextid;
+	while ((rp->previousid) && (id <= rp->previousid->id))
+	    rp = rp->previousid;
+	if (id == rp->id) {
+	    idbash[bashnum] = rp;
+	    return rp;
+	} else
+	    return NULL;
+    }
+    return rp;			/* NULL */
+}
+
+/* Find request structure using the host */
+static struct resolve *findhost(char *hostn)
+{
+    struct resolve *rp;
+    int bashnum;
+
+    context;
+    bashnum = gethostbash(hostn);
+    rp = hostbash[bashnum];
+    if (rp) {
+	while ((rp->nexthost)
+	       && (strcasecmp(hostn, rp->nexthost->hostn) >= 0))
+	    rp = rp->nexthost;
+	while ((rp->previoushost)
+	       && (strcasecmp(hostn, rp->nexthost->hostn) <= 0))
+	    rp = rp->previoushost;
+	if (strcasecmp(hostn, rp->hostn))
+	    return NULL;
+	else {
+	    hostbash[bashnum] = rp;
+	    return rp;
+	}
+    }
+    return rp;			/* NULL */
+}
+
+/* Find request structure using the ip */
+static struct resolve *findip(IP ip)
+{
+    struct resolve *rp;
+    dword bashnum;
+
+    context;
+    bashnum = getipbash(ip);
+    rp = ipbash[bashnum];
+    if (rp) {
+	while ((rp->nextip) && (ip >= rp->nextip->ip))
+	    rp = rp->nextip;
+	while ((rp->previousip) && (ip <= rp->previousip->ip))
+	    rp = rp->previousip;
+	if (ip == rp->ip) {
+	    ipbash[bashnum] = rp;
+	    return rp;
+	} else
+	    return NULL;
+    }
+    return rp;			/* NULL */
+}
+
+
+/*
+ *    Network and resolver related functions
+ */
+
+/* Create packet for the request and send it to all available nameservers */
+static void dorequest(char *s, int type, word id)
+{
+    packetheader *hp;
+    int r, i;
+    char buf[(MAX_PACKETSIZE / sizeof(char)) + 1];
+
+    context;
+    r = res_mkquery(QUERY, s, C_IN, type, NULL, 0, NULL, buf,
+		    MAX_PACKETSIZE);
+    if (r == -1) {
+	debug0(RES_ERR "Query too large.");
+	return;
+    }
+    hp = (packetheader *) buf;
+    hp->id = id;	/* my_htons() deliberately left out (redundant) */
+    for (i = 0; i < _res.nscount; i++)
+	(void) sendto(resfd, buf, r, 0,
+		      (struct sockaddr *) &_res.nsaddr_list[i],
+		      sizeof(struct sockaddr));
+}
+
+/* (Re-)send request with existing id */
+static void resendrequest(struct resolve *rp, int type)
+{
+    context;
+    rp->sends++;
+    /* update expire time */
+    rp->expiretime = now + (RES_RETRYDELAY * rp->sends);
+    /* add (back) to expire list */
+    linkresolve(rp);
+ 
+    if (type == T_A) {
+	dorequest(rp->hostn, type, rp->id);
+	debug1(RES_MSG "Sent domain lookup request for \"%s\".",
+	       rp->hostn);
+    } else if (type == T_PTR) {
+	sprintf(tempstring, "%u.%u.%u.%u.in-addr.arpa",
+		((byte *) & rp->ip)[3],
+		((byte *) & rp->ip)[2],
+		((byte *) & rp->ip)[1], ((byte *) & rp->ip)[0]);
+	dorequest(tempstring, type, rp->id);
+	debug1(RES_MSG "Sent domain lookup request for \"%s\".",
+	       iptostr(rp->ip));
+    }
+}
+
+/* Send request for the first time */
+static void sendrequest(struct resolve *rp, int type)
+{
+    context;
+    /* Create unique id */
+    do {
+	idseed = (((idseed + idseed) | (long) time(NULL))
+		  + idseed - 0x54bad4a) ^ aseed;
+	aseed ^= idseed;
+	rp->id = (word) idseed;
+    } while (findid(rp->id));
+    linkresolveid(rp);		/* Add id to id hash table */
+    resendrequest(rp, type);	/* Send request */
+}
+
+/* Gets called as soon as the request turns out to have failed . Calls
+ * the eggdrop hook. */
+static void failrp(struct resolve *rp)
+{
+    context;
+    if (rp->state == STATE_FINISHED)
+	return;
+    rp->expiretime = now + RES_FAILEDDELAY;
+    rp->state = STATE_FAILED;
+
+    /* expire time was changed, reinsert entry to maintain order */
+    untieresolve(rp);
+    linkresolve(rp);
+
+    debug0(RES_MSG "Lookup failed.");
+    dns_event_failure(rp);
+}
+
+/* Gets called as soon as the request turns out to be successful. Calls
+ * the eggdrop hook. */
+static void passrp(struct resolve *rp, long ttl, int type)
+{
+    context;
+    rp->state = STATE_FINISHED;
+
+    /* Do not cache entries for too long. */
+    if (ttl < RES_MAX_TTL)
+	rp->expiretime = now + (time_t) ttl;
+    else
+	rp->expiretime = now + RES_MAX_TTL;
+
+    /* Expire time was changed, reinsert entry to maintain order */
+    untieresolve(rp);
+    linkresolve(rp);
+
+    debug1(RES_MSG "Lookup successful: %s", rp->hostn);
+    dns_event_success(rp, type);
+}
+
+/* Parses the response packets received */
+static void parserespacket(byte * s, int l)
+{
+    struct resolve *rp;
+    packetheader *hp;
+    byte *eob;
+    byte *c;
+    long ttl;
+    int r, usefulanswer;
+    word rr, datatype, class, qdatatype, qclass;
+    byte rdatalength;
+
+    context;
+    if (l < sizeof(packetheader)) {
+	debug0(RES_ERR "Packet smaller than standard header size.");
+	return;
+    }
+    if (l == sizeof(packetheader)) {
+	debug0(RES_ERR "Packet has empty body.");
+	return;
+    }
+    hp = (packetheader *) s;
+    /* Convert data to host byte order */
+    /* hp->id does not need to be redundantly byte-order flipped, it
+     * is only echoed by nameserver */
+    rp = findid(hp->id);
+    if (!rp)
+	return;
+    if ((rp->state == STATE_FINISHED) || (rp->state == STATE_FAILED))
+	return;
+    hp->qdcount = my_ntohs(hp->qdcount);
+    hp->ancount = my_ntohs(hp->ancount);
+    hp->nscount = my_ntohs(hp->nscount);
+    hp->arcount = my_ntohs(hp->arcount);
+    if (getheader_tc(hp)) {	/* Packet truncated */
+	debug0(RES_ERR "Nameserver packet truncated.");
+	return;
+    }
+    if (!getheader_qr(hp)) {	/* Not a reply */
+	debug0(RES_ERR "Query packet received on nameserver communication socket.");
+	return;
+    }
+    if (getheader_opcode(hp)) {	/* Not opcode 0 (standard query) */
+	debug0(RES_ERR "Invalid opcode in response packet.");
+	return;
+    }
+    eob = s + l;
+    c = s + HFIXEDSZ;
+    context;
+    switch (getheader_rcode(hp)) {
+    case NOERROR:
+	context;
+	if (hp->ancount) {
+	    debug4(RES_MSG
+		   "Received nameserver reply. (qd:%u an:%u ns:%u ar:%u)",
+		   hp->qdcount, hp->ancount, hp->nscount, hp->arcount);
+	    if (hp->qdcount != 1) {
+		debug0(RES_ERR "Reply does not contain one query.");
+		return;
+	    }
+	    if (c > eob) {
+		debug0(RES_ERR "Reply too short.");
+		return;
+	    }
+	    switch (rp->state) {	/* Construct expected query reply */
+	    case STATE_PTRREQ:
+		sprintf(stackstring,
+			"%u.%u.%u.%u.in-addr.arpa",
+			((byte *) & rp->ip)[3],
+			((byte *) & rp->ip)[2],
+			((byte *) & rp->ip)[1], ((byte *) & rp->ip)[0]);
+		break;
+	    case STATE_AREQ:
+		strncpy(stackstring, rp->hostn, 1024);
+	    }
+	    *namestring = '\0';
+	    r = dn_expand(s, s + l, c, namestring, MAXDNAME);
+	    if (r == -1) {
+		debug0(RES_ERR "dn_expand() failed while expanding query domain.");
+		return;
+	    }
+	    namestring[strlen(stackstring)] = '\0';
+	    if (strcasecmp(stackstring, namestring)) {
+		debug2(RES_MSG "Unknown query packet dropped. (\"%s\" does not match \"%s\")", stackstring, namestring);
+		return;
+	    }
+	    debug1(RES_MSG "Queried domain name: \"%s\"", namestring);
+	    c += r;
+	    if (c + 4 > eob) {
+		debug0(RES_ERR "Query resource record truncated.");
+		return;
+	    }
+	    qdatatype = sucknetword(c);
+	    qclass = sucknetword(c);
+	    if (qclass != C_IN) {
+		debug2(RES_ERR "Received unsupported query class: %u (%s)",
+			qclass, qclass < CLASSTYPES_COUNT ?
+					classtypes[qclass] :
+					classtypes[CLASSTYPES_COUNT]);
+	    }
+	    switch (qdatatype) {
+	    case T_PTR:
+		if (!IS_PTR(rp)) {
+		    debug0(RES_WRN "Ignoring response with unexpected query type \"PTR\".");
+		    return;
+		}
+		break;
+	    case T_A:
+		if (!IS_A(rp)) {
+		    debug0(RES_WRN "Ignoring response with unexpected query type \"PTR\".");
+		    return;
+		}
+		break;
+	    default:
+		debug2(RES_ERR "Received unimplemented query type: %u (%s)",
+			qdatatype,
+			qdatatype < RESOURCETYPES_COUNT ?
+				resourcetypes[qdatatype] :
+				resourcetypes[RESOURCETYPES_COUNT]);
+	    }
+	    for (rr = hp->ancount + hp->nscount + hp->arcount; rr; rr--) {
+		context;
+		if (c > eob) {
+		    debug0(RES_ERR "Packet does not contain all specified resouce records.");
+		    return;
+		}
+		*namestring = '\0';
+		r = dn_expand(s, s + l, c, namestring, MAXDNAME);
+		if (r == -1) {
+		    debug0(RES_ERR "dn_expand() failed while expanding answer domain.");
+		    return;
+		}
+		namestring[strlen(stackstring)] = '\0';
+		if (strcasecmp(stackstring, namestring))
+		    usefulanswer = 0;
+		else
+		    usefulanswer = 1;
+		debug1(RES_MSG "answered domain query: \"%s\"", namestring);
+		c += r;
+		if (c + 10 > eob) {
+		    debug0(RES_ERR "Resource record truncated.");
+		    return;
+		}
+		datatype = sucknetword(c);
+		class = sucknetword(c);
+		ttl = sucknetlong(c);
+		rdatalength = sucknetword(c);
+		if (class != qclass) {
+		    debug2(RES_MSG "query class: %u (%s)",
+			    qclass,
+			    qclass < CLASSTYPES_COUNT ?
+				    classtypes[qclass] :
+				    classtypes[CLASSTYPES_COUNT]);
+		    debug2(RES_MSG "rr class: %u (%s)", class,
+			    class < CLASSTYPES_COUNT ?
+				    classtypes[class] :
+				    classtypes[CLASSTYPES_COUNT]);
+		    debug0(RES_ERR "Answered class does not match queried class.");
+		    return;
+		}
+		if (!rdatalength) {
+		    debug0(RES_ERR "Zero size rdata.");
+		    return;
+		}
+		if (c + rdatalength > eob) {
+		    debug0(RES_ERR "Specified rdata length exceeds packet size.");
+		    return;
+		}
+		context;
+		if (datatype == qdatatype) {
+		    debug1(RES_MSG "TTL: %s", strtdiff(sendstring, ttl));
+		    debug1(RES_MSG "TYPE: %s", datatype < RESOURCETYPES_COUNT ?
+			   resourcetypes[datatype] :
+			   resourcetypes[RESOURCETYPES_COUNT]);
+		    if (usefulanswer)
+			switch (datatype) {
+			case T_A:
+			    if (rdatalength != 4) {
+				debug1(RES_ERR "Unsupported rdata format for \"A\" type. (%u bytes)", rdatalength);
+				return;
+			    }
+			    my_memcpy(&rp->ip, (IP *) c, sizeof(IP));
+			    linkresolveip(rp);
+			    passrp(rp, ttl, T_A);
+			    return;
+			case T_PTR:
+			    *namestring = '\0';
+			    r =	dn_expand(s, s + l, c, namestring, MAXDNAME);
+			    if (r == -1) {
+				debug0(RES_ERR "dn_expand() failed while expanding domain in rdata.");
+				return;
+			    }
+			    debug1(RES_MSG "Answered domain: \"%s\"",
+				   namestring);
+			    if (r > HOSTNAMELEN) {
+				debug0(RES_ERR "Domain name too long.");
+				failrp(rp);
+				return;
+			    }
+			    if (!rp->hostn) {
+				rp->hostn = (char *)nmalloc(strlen(namestring) + 1);
+				strcpy(rp->hostn, namestring);
+				linkresolvehost(rp);
+				passrp(rp, ttl, T_PTR);
+				return;
+			    }
+			    break;
+			default:
+			    debug2(RES_ERR "Received unimplemented data type: %u (%s)",
+				    datatype,
+				    datatype < RESOURCETYPES_COUNT ?
+					resourcetypes[datatype] :
+					resourcetypes[RESOURCETYPES_COUNT]);
+			}
+		} else if (datatype == T_CNAME) {
+		    *namestring = '\0';
+		    r =	dn_expand(s, s + l, c, namestring, MAXDNAME);
+		    if (r == -1) {
+			debug0(RES_ERR "dn_expand() failed while expanding domain in rdata.");
+			return;
+		    }
+		    debug1(RES_MSG "answered domain is CNAME for: %s",
+			   namestring);
+		    /* The next responses will be related to the domain
+		     * pointed to by CNAME, so we need to update which
+		     * respones we regard as important. */
+		    strncpy(stackstring, namestring, 1024);
+		} else {
+		    debug2(RES_MSG "Ignoring resource type %u. (%s)",
+			   datatype, datatype < RESOURCETYPES_COUNT ?
+				resourcetypes[datatype] :
+				resourcetypes[RESOURCETYPES_COUNT]);
+		}
+		c += rdatalength;
+	    }
+	} else
+	    debug0(RES_ERR "No error returned but no answers given.");
+	break;
+    case NXDOMAIN:
+	context;
+	debug0(RES_MSG "Host not found.");
+	failrp(rp);
+	break;
+    default:
+	context;
+	debug2(RES_MSG "Received error response %u. (%s)",
+		getheader_rcode(hp),
+		getheader_rcode(hp) < RESPONSECODES_COUNT ?
+			responsecodes[getheader_rcode(hp)] :
+			responsecodes[RESPONSECODES_COUNT]);
+    }
+    context;
+}
+
+/* Read data received on our dns socket. This function should be called
+ * as soon as traffic is detected. */
+static void dns_ack(void)
+{
+    struct sockaddr_in from;
+    int fromlen = sizeof(struct sockaddr_in);
+    int r, i;
+
+    context;
+    r =	recvfrom(resfd, (byte *) resrecvbuf, MAX_PACKETSIZE, 0,
+		 (struct sockaddr *) &from, &fromlen);
+    if (r <= 0) {
+	debug1(RES_MSG "Socket error: %s", strerror(errno));
+	return;
+    }
+    /* Check to see if this server is actually one we sent to */
+    if (from.sin_addr.s_addr == localhost) {
+        for (i = 0; i < _res.nscount; i++)
+	    /* 0.0.0.0 replies as 127.0.0.1 */
+	    if ((_res.nsaddr_list[i].sin_addr.s_addr == from.sin_addr.s_addr)
+		|| (!_res.nsaddr_list[i].sin_addr.s_addr))
+		break;
+    } else {
+        for (i = 0; i < _res.nscount; i++)
+	    if (_res.nsaddr_list[i].sin_addr.s_addr == from.sin_addr.s_addr)
+		break;
+    }
+    if (i == _res.nscount) {
+        debug1(RES_ERR "Received reply from unknown source: %s",
+	       iptostr(from.sin_addr.s_addr));
+    } else
+        parserespacket((byte *) resrecvbuf, r);
+    context;
+}
+
+/* Remove or resend expired requests. Called once a second. */
+static void dns_check_expires(void)
+{
+    struct resolve *rp, *nextrp;
+
+    context;
+    for (rp = expireresolves; (rp) && (now >= rp->expiretime);
+	 rp = nextrp) {
+	nextrp = rp->next;
+	untieresolve(rp);
+	switch (rp->state) {
+	case STATE_FINISHED:	/* TTL has expired */
+	case STATE_FAILED:	/* Fake TTL has expired */
+	    context;
+	    debug4(RES_MSG "Cache record for \"%s\" (%s) has expired. (state: %u)  Marked for expire at: %ld.",
+		   nonull(rp->hostn), iptostr(rp->ip), rp->state,
+		   rp->expiretime);
+	    unlinkresolve(rp);
+	    break;
+	case STATE_PTRREQ:	/* T_PTR send timed out */
+	    context;
+	    if (rp->sends <= RES_MAXSENDS) {
+	      debug1(RES_MSG "Resend #%d for \"PTR\" query...", rp->sends - 1);
+	      resendrequest(rp, T_PTR);
+	    } else {
+	      debug0(RES_MSG "\"PTR\" query timed out.");
+	      failrp(rp);
+	    }
+	    break;
+	case STATE_AREQ:	/* T_A send timed out */
+	    context;
+	    if (rp->sends <= RES_MAXSENDS) {
+	      debug1(RES_MSG "Resend #%d for \"A\" query...", rp->sends - 1);
+	      resendrequest(rp, T_A);
+	    } else {
+	      debug0(RES_MSG "\"A\" query timed out.");
+	      failrp(rp);
+	    }
+	    break;
+	default:		/* Unknown state, let it expire */
+	    debug1(RES_WRN "Unknown request state %d. Request expired.",
+		   rp->state);
+	    failrp(rp);
+	}
+    }
+    context;
+}
+
+/* Start searching for a host-name using it's ip-address */
+static void dns_lookup(IP ip)
+{
+    struct resolve *rp;
+    
+    context;
+    ip = htonl(ip);
+    if ((rp = findip(ip))) {
+	if ((rp->state == STATE_FINISHED)
+	    || (rp->state == STATE_FAILED)) {
+	    if ((rp->state == STATE_FINISHED) && (rp->hostn)) {
+		debug2(RES_MSG "Used cached record: %s == \"%s\".",
+			    iptostr(ip), rp->hostn);
+		dns_event_success(rp, T_PTR);
+	    } else {
+		debug1(RES_MSG "Used failed record: %s == ???", iptostr(ip));
+		dns_event_failure(rp);
+	    }
+	}
+	return;
+    }
+
+    context;
+    debug0(RES_MSG "Creating new record");
+    rp = allocresolve();
+    rp->state = STATE_PTRREQ;
+    rp->sends = 1;
+    rp->ip = ip;
+    linkresolveip(rp);
+    sendrequest(rp, T_PTR);
+    context;
+}
+
+/* Start searching for an ip-address using it's host-name */
+static void dns_forward(char *hostn)
+{
+    struct resolve *rp;
+    
+    context;
+    if ((rp = findhost(hostn))) {
+	if ((rp->state == STATE_FINISHED)
+	    || (rp->state == STATE_FAILED)) {
+	    if ((rp->state == STATE_FINISHED) && (rp->ip)) {
+		debug2(RES_MSG "Used cached record: %s == \"%s\".", hostn,
+		       iptostr(rp->ip));
+		dns_event_success(rp, T_A);
+	    } else {
+		debug1(RES_MSG "Used failed record: %s == ???", hostn);
+		dns_event_failure(rp);
+	    }
+	}
+	return;
+    }
+
+    context;
+    debug0(RES_MSG "Creating new record");
+    rp = allocresolve();
+    rp->state = STATE_AREQ;
+    rp->sends = 1;
+    rp->hostn = (char *)nmalloc(strlen(hostn) + 1);
+    strcpy(rp->hostn, hostn);
+    linkresolvehost(rp);
+    sendrequest(rp, T_A);
+    context;
+}
+
+/* Initialise the network */
+static int init_network(void)
+{
+    int option;
+    struct in_addr inaddr;
+
+    context;
+    resfd = socket(AF_INET, SOCK_DGRAM, 0);
+    if (resfd == -1) {
+	putlog(LOG_MISC, "*",
+		"Unable to allocate socket for nameserver communication: %s",
+		strerror(errno));
+	return 0;
+    }
+    (void) allocsock(resfd, SOCK_PASS);
+    option = 1;
+    if (setsockopt(resfd, SOL_SOCKET, SO_BROADCAST, (char *) &option,
+	 sizeof(option))) {
+	putlog(LOG_MISC, "*",
+		"Unable to setsockopt() on nameserver communication socket: %s",
+		strerror(errno));
+	killsock(resfd);
+	return 0;
+    }
+    
+    inet_aton("127.0.0.1", &inaddr);
+    localhost = inaddr.s_addr;
+    return 1;
+}
+
+/* Initialise the core dns system, returns 1 if all goes well, 0 if not */
+static int dns_open(void)
+{
+    int i;
+
+    context;
+    /* Initialise the resolv library */
+    res_init();
+    if (!_res.nscount) {
+	putlog(LOG_MISC, "*", "No nameservers defined.");
+	return 0;
+    }
+    _res.options |= RES_RECURSE | RES_DEFNAMES | RES_DNSRCH;
+    for (i = 0; i < _res.nscount; i++)
+	_res.nsaddr_list[i].sin_family = AF_INET;
+
+    if (!init_network())
+	return 0;
+
+    context;
+    /* Initialise the hash tables */
+    aseed = time(NULL) ^ (time(NULL) << 3) ^ (dword) getpid();
+    for (i = 0; i < BASH_SIZE; i++) {
+	idbash[i] = NULL;
+	hostbash[i] = NULL;
+    }
+    context;
+    return 1;
+}
diff -urN eggdrop1.4~/src/mod/dns.mod/dns.c eggdrop1.4/src/mod/dns.mod/dns.c
--- eggdrop1.4~/src/mod/dns.mod/dns.c	Thu Jan  1 01:00:00 1970
+++ eggdrop1.4/src/mod/dns.mod/dns.c	Sat Oct  9 18:40:21 1999
@@ -0,0 +1,252 @@
+/*
+ * dns.c - domain lookup glue code for eggdrop 
+ * 
+ * Copyright (C) 1999  Eggheads
+ * Written by Fabian Knittel <fknittel at gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Sun Oct 03 18:34:41 1999  Fabian
+ *     * Initial release
+ */
+
+
+#define MODULE_NAME "dns"
+
+#include "../module.h"
+#include "dns.h"
+
+static void dns_event_success();
+static void dns_event_failure();
+
+
+static Function *global = NULL;
+
+#include "coredns.c"
+
+
+/*
+ *    DNS event related code
+ */
+
+static void dns_event_success(struct resolve *rp, int type)
+{
+  if (!rp)
+    return;
+
+  if (type == T_PTR) {
+    debug2("DNS resolved %s to %s", iptostr(rp->ip), rp->hostn);
+    call_hostbyip(ntohl(rp->ip), rp->hostn, 1);
+  } else if (type == T_A) {
+    debug2("DNS resolved %s to %s", rp->hostn, iptostr(rp->ip));
+    call_ipbyhost(rp->hostn, ntohl(rp->ip), 1);
+  }
+}
+
+static void dns_event_failure(struct resolve *rp)
+{
+  if (!rp)
+    return;
+
+  /* T_PTR */
+  if (rp->ip) {
+    static char s[UHOSTLEN];
+
+    debug1("DNS resolve failed for %s", iptostr(rp->ip));
+    strcpy(s, iptostr(rp->ip));
+    call_hostbyip(ntohl(rp->ip), s, 0);
+  }  
+  /* T_A */
+  else if (rp->hostn) {
+    debug1("DNS resolve failed for %s", rp->hostn);
+    call_ipbyhost(rp->hostn, 0, 0);
+  }
+  return;
+}
+
+
+/*
+ *    DNS Socket related code
+ */
+
+static void eof_dns_socket(int idx)
+{
+  putlog(LOG_MISC, "*", "DNS Error: socket closed.");
+  killsock(dcc[idx].sock);
+  /* try to reopen socket */
+  if (init_network()) {
+    putlog(LOG_MISC, "*", "DNS socket successfully reopened!");
+    dcc[idx].sock = resfd;
+    dcc[idx].timeval = now;
+  } else
+    lostdcc(idx);
+}
+
+static void dns_socket(int idx, char *buf, int len)
+{
+  dns_ack();
+}
+
+static void display_dns_socket(int idx, char *buf)
+{
+  strcpy(buf, "dns   (ready)");
+}
+
+struct dcc_table DCC_DNS =
+{
+  "DNS",
+  DCT_LISTEN,
+  eof_dns_socket,
+  dns_socket,
+  0,
+  0,
+  display_dns_socket,
+  0,
+  0,
+  0
+};
+
+
+/*
+ *    DNS module related code
+ */
+
+static void cmd_resolve(struct userrec *u, int idx, char *par)
+{
+  struct in_addr inaddr;
+
+  context;
+  if (inet_aton(par, &inaddr)) {
+    dns_lookup(my_ntohl(inaddr.s_addr));
+  } else {
+    dns_forward(par);
+  }
+  return;
+}
+
+
+static void dns_free_cache(void)
+{
+  struct resolve *rp = expireresolves, *rpnext;
+
+  context;
+  while (rp) {
+    rpnext = rp->next;
+    if (rp->hostn)
+      nfree(rp->hostn);
+    nfree(rp);
+    rp = rpnext;
+  } 
+  expireresolves = NULL;
+}
+
+static int dns_cache_expmem(void)
+{
+  struct resolve *rp = expireresolves;
+  int size = 0;
+
+  while (rp) {
+    size += sizeof(struct resolve);
+    if (rp->hostn)
+      size += strlen(rp->hostn) + 1;
+    rp = rp->next;
+  } 
+
+  return size;
+}
+
+static int dns_expmem(void)
+{
+  return dns_cache_expmem();
+}
+
+static int dns_report(int idx, int details)
+{
+  dprintf(idx, "    DNS resolver is active.\n");
+  if (details)
+    dprintf(idx, "    (cache uses %d bytes of memory)\n", dns_cache_expmem());
+  return 0;
+}
+
+static cmd_t dns_dcc[] = {
+  {"resolve", "", (Function) cmd_resolve, NULL},
+  {NULL, NULL, NULL, NULL}
+};
+
+static char *dns_close()
+{
+  int i;
+
+  context;
+  del_hook(HOOK_DNS_HOSTBYIP, dns_lookup);
+  del_hook(HOOK_DNS_IPBYHOST, dns_forward);
+  del_hook(HOOK_SECONDLY, dns_check_expires);
+  rem_builtins(H_dcc, dns_dcc);
+
+  context;
+  for (i = 0; i < dcc_total; i++) {
+    if ((dcc[i].type == &DCC_DNS) &&
+	(dcc[i].sock == resfd)) {
+      killsock(dcc[i].sock);
+      lostdcc(i);
+      break;
+    }
+  }
+
+  context;
+  dns_free_cache();
+  context;
+  module_undepend(MODULE_NAME);
+  context;
+  return NULL;
+}
+
+char *dns_start();
+
+static Function dns_table[] =
+{
+  /* 0 - 3 */
+  (Function) dns_start,
+  (Function) dns_close,
+  (Function) dns_expmem,
+  (Function) dns_report,
+  /* 4 - 7 */
+};
+
+char *dns_start(Function * global_funcs)
+{
+  int i;
+  
+  global = global_funcs;
+  context;
+  if (!dns_open())
+    return "DNS initialisation failed.";
+  i = new_dcc(&DCC_DNS, 0);
+  dcc[i].sock = resfd;
+  dcc[i].timeval = now;
+  strcpy(dcc[i].nick, "(dns)");
+
+  context;
+  module_register(MODULE_NAME, dns_table, 1, 0);
+  context;
+  add_hook(HOOK_SECONDLY, dns_check_expires);
+  add_hook(HOOK_DNS_HOSTBYIP, dns_lookup);
+  add_hook(HOOK_DNS_IPBYHOST, dns_forward);
+  add_builtins(H_dcc, dns_dcc);
+  context;
+  return NULL;
+}
diff -urN eggdrop1.4~/src/mod/dns.mod/dns.h eggdrop1.4/src/mod/dns.mod/dns.h
--- eggdrop1.4~/src/mod/dns.mod/dns.h	Thu Jan  1 01:00:00 1970
+++ eggdrop1.4/src/mod/dns.mod/dns.h	Sat Oct  9 18:40:21 1999
@@ -0,0 +1,68 @@
+/*
+ * dns.h - dns module header file
+ *
+ * Copyright (C) 1999  Eggheads
+ * Written by Fabian Knittel <fknittel at gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Borrowed from mtr  --  a network diagnostic tool
+ * Copyright (C) 1997,1998  Matt Kimball <mkimball at xmission.com>
+ * Released under GPL, as above.
+ *
+ * Non-blocking DNS portion --
+ * Copyright (C) 1998  Simon Kirby <sim at neato.org>
+ * Released under GPL, as above.
+ */
+
+#ifndef MOD_DNS_H
+#define MOD_DNS_H
+
+typedef unsigned char byte;
+typedef unsigned short word;
+typedef unsigned long dword;
+typedef unsigned int ip_t;
+
+struct resolve {
+    struct resolve *next;
+    struct resolve *previous;
+    struct resolve *nextid;
+    struct resolve *previousid;
+    struct resolve *nextip;
+    struct resolve *previousip;
+    struct resolve *nexthost;
+    struct resolve *previoushost;
+    time_t expiretime;
+    char *hostn;
+    ip_t ip;
+    word id;
+    byte state;
+    byte sends;
+};
+
+enum {
+    STATE_FINISHED,
+    STATE_FAILED,
+    STATE_PTRREQ,
+    STATE_AREQ,
+};
+
+#define IS_PTR(x) (x->state == STATE_PTRREQ)
+#define IS_A(x)   (x->state == STATE_AREQ)
+
+#endif /* MOD_DNS_H */
+
diff -urN eggdrop1.4~/src/mod/filesys.mod/filesys.c eggdrop1.4/src/mod/filesys.mod/filesys.c
--- eggdrop1.4~/src/mod/filesys.mod/filesys.c	Sat Oct  9 18:33:46 1999
+++ eggdrop1.4/src/mod/filesys.mod/filesys.c	Sat Oct  9 18:40:21 1999
@@ -558,13 +558,16 @@
   out_dcc_files
 };
 
+
+static void filesys_dcc_send_lookupfailure(int);
+static void filesys_dcc_send_lookupsuccess(int);
+	
 /* received a ctcp-dcc */
 static void filesys_dcc_send(char *nick, char *from, struct userrec *u,
 			     char *text)
 {
-  char *param, *ip, *prt, buf[512], s1[512], *msg = buf;
-  FILE *f;
-  int atr = u ? u->flags : 0, i, j;
+  char *param, *ip, *prt, buf[512], *msg = buf;
+  int atr = u ? u->flags : 0, i;
 
   context;
   strcpy(buf, text);
@@ -607,25 +610,62 @@
       /* This looks like a good place for a sanity check. */
       if (!sanitycheck_dcc(nick, from, ip, prt))
 	return;
-      i = new_dcc(&DCC_FORK_SEND, sizeof(struct xfer_info));
+      i = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info));
 
       if (i < 0) {
 	dprintf(DP_HELP, "NOTICE %s :Sorry, too many DCC connections.\n",
 		nick);
 	putlog(LOG_MISC, "*", "DCC connections full: SEND %s (%s!%s)",
 	       param, nick, from);
+	return;
       }
       dcc[i].addr = my_atoul(ip);
       dcc[i].port = atoi(prt);
       dcc[i].sock = -1;
+      dcc[i].user = u;
       strcpy(dcc[i].nick, nick);
       strcpy(dcc[i].host, from);
+      dcc[i].u.dns->cbuf = get_data_ptr(strlen(param) + 1);
+      strcpy(dcc[i].u.dns->cbuf, param);
+      dcc[i].u.dns->ibuf = atoi(msg);
+      dcc[i].u.dns->ip = dcc[i].addr;
+      dcc[i].u.dns->dns_type = RES_HOSTBYIP;
+      dcc[i].u.dns->dns_success = (Function) filesys_dcc_send_lookupsuccess;
+      dcc[i].u.dns->dns_failure = (Function) filesys_dcc_send_lookupfailure;
+      
+      dns_hostbyip(dcc[i].addr);
+    }
+  }
+}
+
+static void filesys_dcc_send_lookupfailure(int i)
+{
+    putlog(LOG_DEBUG, "*", "Reverse lookup failed for %s",
+           iptostr(my_htonl(dcc[i].addr)));
+    lostdcc(i);
+}
+
+static void filesys_dcc_send_lookupsuccess(int i)
+{
+  FILE *f;
+  char s1[512], param[512];
+  int len = dcc[i].u.dns->ibuf, j;
+
+  strncpy(param, dcc[i].u.dns->cbuf, 511);
+  sprintf(s1, "%d", dcc[i].port);
+  if (!hostsanitycheck_dcc(dcc[i].nick, dcc[i].host, dcc[i].addr,
+                           dcc[i].u.dns->host, s1)) {
+    lostdcc(i);
+    return;
+  }
+
+  changeover_dcc(i, &DCC_FORK_SEND, sizeof(struct xfer_info));
       if (param[0] == '.')
 	param[0] = '_';
       strncpy(dcc[i].u.xfer->filename, param, 120);
       dcc[i].u.xfer->filename[120] = 0;
       if (upload_to_cd) {
-	char *p = get_user(&USERENTRY_DCCDIR, u);
+    char *p = get_user(&USERENTRY_DCCDIR, dcc[i].user);
 
 	if (p)
 	  sprintf(dcc[i].u.xfer->dir, "%s%s/", dccdir, p);
@@ -633,13 +673,13 @@
 	  sprintf(dcc[i].u.xfer->dir, "%s", dccdir);
       } else
 	strcpy(dcc[i].u.xfer->dir, dccin);
-      dcc[i].u.xfer->length = atoi(msg);
+  dcc[i].u.xfer->length = len;
       sprintf(s1, "%s%s", dcc[i].u.xfer->dir, param);
       context;      
       f = fopen(s1, "r");
       if (f) {
 	fclose(f);
-	dprintf(DP_HELP, "NOTICE %s :That file already exists.\n", nick);
+    dprintf(DP_HELP, "NOTICE %s :That file already exists.\n", dcc[i].nick);
 	lostdcc(i);
       } else {
 	/* check for dcc-sends in process with the same filename */
@@ -648,8 +688,8 @@
 	    if ((dcc[j].type->flags & (DCT_FILETRAN | DCT_FILESEND))
 		== (DCT_FILETRAN | DCT_FILESEND)) {
 	      if (!strcmp(param, dcc[j].u.xfer->filename)) {
-		dprintf(DP_HELP,
-		  "NOTICE %s :That file is already being sent.\n", nick);
+	    dprintf(DP_HELP, "NOTICE %s :That file is already being sent.\n",
+		    dcc[i].nick);
 		lostdcc(i);
 		return;
 	      }
@@ -661,15 +701,17 @@
 	if (dcc[i].u.xfer->f == NULL) {
 	  dprintf(DP_HELP,
 		  "NOTICE %s :Can't create that file (temp dir error)\n",
-		  nick);
+	      dcc[i].nick);
 	  lostdcc(i);
 	} else {
+      char prt[100], ip[100];
+
 	  dcc[i].timeval = now;
 	  dcc[i].sock = getsock(SOCK_BINARY);
+      sprintf(prt, "%d", dcc[i].port);
+      sprintf(ip, "%lu", iptolong(my_ntohl(dcc[i].addr)));
 	  if (open_telnet_dcc(dcc[i].sock, ip, prt) < 0) {
 	    dcc[i].type->eof(i);
-	  }
-	}
       }
     }
   }
diff -urN eggdrop1.4~/src/mod/module.h eggdrop1.4/src/mod/module.h
--- eggdrop1.4~/src/mod/module.h	Sat Oct  9 18:33:43 1999
+++ eggdrop1.4/src/mod/module.h	Sat Oct  9 18:44:03 1999
@@ -322,6 +322,17 @@
 /* 232 - 235 */
 #define contextnote(note) (global[232](MODULE_NAME, __FILE__, __LINE__, note))
 #define assert_failed (global[233])
+#define allocsock ((int(*)(int sock,int options))global[234])
+#define call_hostbyip ((void(*)(IP, char *, int))global[235])
+/* 236 - 239 */
+#define call_ipbyhost ((void(*)(char *, IP, int))global[236])
+#define iptostr ((char *(*)(IP))global[237])
+#define DCC_DNSWAIT (*(struct dcc_table *)(global[238]))
+#define hostsanitycheck_dcc ((int(*)(char *, char *, IP, char *, char *))global[239])
+/* 240 - 243 */
+#define dns_ipbyhost ((void (*)(char *))(*(Function**)(global[240])))
+#define dns_hostbyip ((void (*)(IP))(*(Function**)(global[241])))
+#define changeover_dcc ((void (*)(int, struct dcc_table *, int))global[242])
 
 #define ASSERT(expr) { if (!(expr)) assert_failed (MODULE_NAME, __FILE__, __LINE__); }
 
diff -urN eggdrop1.4~/src/mod/modvals.h eggdrop1.4/src/mod/modvals.h
--- eggdrop1.4~/src/mod/modvals.h	Sat Oct  9 18:33:43 1999
+++ eggdrop1.4/src/mod/modvals.h	Sat Oct  9 18:46:38 1999
@@ -1,25 +1,27 @@
 /* these *were* something, but changed */
-#define HOOK_GET_FLAGREC         0
-#define HOOK_BUILD_FLAGREC       1
-#define HOOK_SET_FLAGREC         2
-#define HOOK_READ_USERFILE       3
-#define HOOK_REHASH              4
-#define HOOK_MINUTELY            5
-#define HOOK_DAILY               6
-#define HOOK_HOURLY              7
-#define HOOK_USERFILE            8
-#define HOOK_SECONDLY            9
-#define HOOK_PRE_REHASH          10
-#define HOOK_IDLE                11
-#define HOOK_5MINUTELY           12
-#define REAL_HOOKS               13
-#define HOOK_SHAREOUT            105
-#define HOOK_SHAREIN             106
-#define HOOK_ENCRYPT_PASS        107
-#define HOOK_QSERV               108
-#define HOOK_ADD_MODE            109
-#define HOOK_MATCH_NOTEREJ	 110
-#define HOOK_RFC_CASECMP	 111
+#define HOOK_GET_FLAGREC	  0
+#define HOOK_BUILD_FLAGREC	  1
+#define HOOK_SET_FLAGREC	  2
+#define HOOK_READ_USERFILE	  3
+#define HOOK_REHASH		  4
+#define HOOK_MINUTELY		  5
+#define HOOK_DAILY		  6
+#define HOOK_HOURLY		  7
+#define HOOK_USERFILE		  8
+#define HOOK_SECONDLY		  9
+#define HOOK_PRE_REHASH		 10
+#define HOOK_IDLE		 11
+#define HOOK_5MINUTELY		 12
+#define REAL_HOOKS		 13
+#define HOOK_SHAREOUT		105
+#define HOOK_SHAREIN		106
+#define HOOK_ENCRYPT_PASS	107
+#define HOOK_QSERV		108
+#define HOOK_ADD_MODE		109
+#define HOOK_MATCH_NOTEREJ	110
+#define HOOK_RFC_CASECMP	111
+#define HOOK_DNS_HOSTBYIP	112
+#define HOOK_DNS_IPBYHOST	113
 
 /* these are FIXED once they are in a release they STAY
  * well, unless im feeling grumpy ;) */
diff -urN eggdrop1.4~/src/mod/server.mod/server.c eggdrop1.4/src/mod/server.mod/server.c
--- eggdrop1.4~/src/mod/server.mod/server.c	Sat Oct  9 18:33:49 1999
+++ eggdrop1.4/src/mod/server.mod/server.c	Sat Oct  9 18:40:22 1999
@@ -62,6 +62,7 @@
 static int must_be_owner;	/* arthur2 */
 static char connectserver[121];	/* what, if anything, to do before connect
 				 * to the server */
+static int resolvserv = 0;	/* in the process of resolving a server host */
 
 /* allow a msgs being twice in a queue ? */
 static int double_mode;
@@ -697,16 +698,17 @@
   Tcl_UntraceVar(interp,name,TCL_TRACE_READS|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, \
 	       tcl_eggserver,(ClientData)ptr)
 
+static void dcc_chat_failure(int);
+static void dcc_chat_success(int);
 
 /* this only handles CHAT requests, otherwise it's handled in filesys */
 static int ctcp_DCC_CHAT(char *nick, char *from, char *handle,
 			 char *object, char *keyword, char *text)
 {
   char *action, *param, *ip, *prt, buf[512], *msg = buf;
-  int i, sock;
+  int i;
   struct userrec *u = get_user_by_handle(userlist, handle);
-  struct flag_record fr =
-  {FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0};
+  struct flag_record fr = {FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0};
 
   strcpy(msg, text);
   action = newsplit(&msg);
@@ -741,36 +743,74 @@
   } else {
     if (!sanitycheck_dcc(nick, from, ip, prt))
       return 1;
-    sock = getsock(0);
-    if (open_telnet_dcc(sock, ip, prt) < 0) {
+    i = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info));
+
+    if (i < 0) {
+      putlog(LOG_MISC, "*", "DCC connection: CHAT (%s!%s)", dcc[i].nick, ip);
+      return 1;
+    }
+    dcc[i].addr = my_atoul(ip);
+    dcc[i].port = atoi(prt);
+    dcc[i].sock = -1;
+    strcpy(dcc[i].nick, u->handle);
+    strcpy(dcc[i].host, from);
+    dcc[i].timeval = now;
+    dcc[i].user = u;
+    dcc[i].u.dns->ip = dcc[i].addr;
+    dcc[i].u.dns->dns_type = RES_HOSTBYIP;
+    dcc[i].u.dns->dns_success = (Function) dcc_chat_success;
+    dcc[i].u.dns->dns_failure = (Function) dcc_chat_failure;
+
+    dns_hostbyip(dcc[i].addr);
+  }
+  return 1;
+}
+
+static void dcc_chat_failure(int i)
+{
+  putlog(LOG_DEBUG, "*", "Reverse lookup failed %s",
+	 iptostr(my_htonl(dcc[i].addr)));
+  lostdcc(i);
+}
+
+static void dcc_chat_success(int i)
+{
+  char buf[512], ip[512];
+  struct flag_record fr = {FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0};
+
+  sprintf(buf, "%d", dcc[i].port);
+  if (!hostsanitycheck_dcc(dcc[i].nick, dcc[i].host, dcc[i].addr,
+			  dcc[i].u.dns->host, buf)) {
+    lostdcc(i);
+    return;
+  }
+
+  dcc[i].sock = getsock(0);
+  sprintf(ip, "%lu", iptolong(my_ntohl(dcc[i].addr)));
+  if (open_telnet_dcc(dcc[i].sock, ip, buf) < 0) {
       neterror(buf);
       if(!quiet_reject)
-	dprintf(DP_HELP, "NOTICE %s :%s (%s)\n", nick,
+      dprintf(DP_HELP, "NOTICE %s :%s (%s)\n", dcc[i].nick,
 		DCC_CONNECTFAILED1, buf);
       putlog(LOG_MISC, "*", "%s: CHAT (%s!%s)", DCC_CONNECTFAILED2,
-	     nick, from);
+	   dcc[i].nick, dcc[i].host);
       putlog(LOG_MISC, "*", "    (%s)", buf);
-      killsock(sock);
+    killsock(dcc[i].sock);
+    lostdcc(i);
     } else {
-      i = new_dcc(&DCC_CHAT_PASS, sizeof(struct chat_info));
-
-      dcc[i].addr = my_atoul(ip);
-      dcc[i].port = atoi(prt);
-      dcc[i].sock = sock;
-      strcpy(dcc[i].nick, u->handle);
-      strcpy(dcc[i].host, from);
+    changeover_dcc(i, &DCC_CHAT_PASS, sizeof(struct chat_info));
       dcc[i].status = STAT_ECHO;
+    get_user_flagrec(dcc[i].user, &fr, 0);
       if (glob_party(fr))
 	dcc[i].status |= STAT_PARTY;
       strcpy(dcc[i].u.chat->con_chan, chanset ? chanset->name : "*");
       dcc[i].timeval = now;
-      dcc[i].user = u;
       /* ok, we're satisfied with them now: attempt the connect */
-      putlog(LOG_MISC, "*", "DCC connection: CHAT (%s!%s)", nick, from);
+    putlog(LOG_MISC, "*", "DCC connection: CHAT (%s!%s)", dcc[i].nick,
+	   dcc[i].host);
       dprintf(i, "%s\n", DCC_ENTERPASS);
     }
-  }
-  return 1;
+  return;
 }
 
 static void server_secondly()
@@ -778,7 +818,7 @@
   if (cycle_time)
     cycle_time--;
   deq_msg();
-  if (serv < 0)
+  if (!resolvserv && serv < 0)
     connect_server();
 }
 
diff -urN eggdrop1.4~/src/mod/server.mod/servmsg.c eggdrop1.4/src/mod/server.mod/servmsg.c
--- eggdrop1.4~/src/mod/server.mod/servmsg.c	Sat Oct  9 18:33:49 1999
+++ eggdrop1.4/src/mod/server.mod/servmsg.c	Sat Oct  9 18:40:22 1999
@@ -1040,13 +1040,16 @@
   {0, 0, 0, 0}
 };
 
+static void server_resolve_success(int);
+static void server_resolve_failure(int);
+
 /* hook up to a server */
 /* works a little differently now... async i/o is your friend */
 static void connect_server(void)
 {
-  char s[121], pass[121], botserver[UHOSTLEN + 1];
+  char pass[121], botserver[UHOSTLEN + 1];
   static int oldserv = -1;
-  int servidx, botserverport;
+  int servidx, botserverport = 0;
 
   waiting_for_awake = 0;
   trying_server = now;
@@ -1063,29 +1066,67 @@
     newserverport = 0;
     newserverpass[0] = 0;
     oldserv = (-1);
-  }
+  } else
+    pass[0] = 0;
   if (!cycle_time) {
     if (connectserver[0])	/* drummer */
       do_tcl("connect-server", connectserver);
     next_server(&curserv, botserver, &botserverport, pass);
     putlog(LOG_SERV, "*", "%s %s:%d", IRC_SERVERTRY, botserver, botserverport);
-    serv = open_telnet(botserver, botserverport);
+
+    servidx = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info));
+    dcc[servidx].port = botserverport;
+    strcpy(dcc[servidx].nick, "(server)");
+    strncpy(dcc[servidx].host, botserver, UHOSTLEN);
+    dcc[servidx].host[UHOSTLEN] = 0;
+    dcc[servidx].timeval = now;
+    dcc[servidx].u.dns->host = get_data_ptr(strlen(dcc[servidx].host) + 1);
+    strcpy(dcc[servidx].u.dns->host, dcc[servidx].host);
+    dcc[servidx].u.dns->cbuf = get_data_ptr(strlen(pass) + 1);
+    strcpy(dcc[servidx].u.dns->cbuf, pass);
+    dcc[servidx].u.dns->dns_success = (Function) server_resolve_success;
+    dcc[servidx].u.dns->dns_failure = (Function) server_resolve_failure;
+    dcc[servidx].u.dns->dns_type = RES_IPBYHOST;
+
+    resolvserv = 1;
+    dns_ipbyhost(dcc[servidx].host);
+    if (server_cycle_wait)
+      /* back to 1st server & set wait time */
+      /* put it here, just in case the server quits on us quickly */
+      cycle_time = server_cycle_wait;
+  }
+} 
+
+static void server_resolve_failure(int servidx)
+{
+  serv = -1;
+  resolvserv = 0;
+  putlog(LOG_SERV, "*", "%s %s (%s)", IRC_FAILEDCONNECT, dcc[servidx].host,
+	 IRC_DNSFAILED);
+  lostdcc(servidx);
+}
+
+static void server_resolve_success(int servidx)
+{
+  int oldserv = dcc[servidx].u.dns->ibuf;
+  char s[121], pass[121];
+
+  resolvserv = 0;
+  dcc[servidx].addr = dcc[servidx].u.dns->ip;
+  strcpy(pass, dcc[servidx].u.dns->cbuf);
+  changeover_dcc(servidx, &SERVER_SOCKET, 0);
+  serv = open_telnet(iptostr(my_ntohl(dcc[servidx].addr)),
+				    dcc[servidx].port);
     if (serv < 0) {
-      if (serv == (-2))
-	strcpy(s, IRC_DNSFAILED);
-      else
 	neterror(s);
-      putlog(LOG_SERV, "*", "%s %s (%s)", IRC_FAILEDCONNECT, botserver, s);
+    putlog(LOG_SERV, "*", "%s %s (%s)", IRC_FAILEDCONNECT, dcc[servidx].host,
+	   s);
+    lostdcc(servidx);
       if ((oldserv == curserv) && !(never_give_up))
 	fatal("NO SERVERS WILL ACCEPT MY CONNECTION.", 0);
     } else {
-      /* queue standard login */
-      servidx = new_dcc(&SERVER_SOCKET, 0);
       dcc[servidx].sock = serv;
-      dcc[servidx].port = botserverport;
-      strcpy(dcc[servidx].nick, "(server)");
-      strncpy(dcc[servidx].host, botserver, UHOSTLEN);
-      dcc[servidx].host[UHOSTLEN] = 0;
+    /* queue standard login */
       dcc[servidx].timeval = now;
       SERVER_SOCKET.timeout_val = &server_timeout;
       strcpy(botname, origbotname);
@@ -1094,14 +1135,9 @@
       if (pass[0])
 	dprintf(DP_MODE, "PASS %s\n", pass);
       dprintf(DP_MODE, "USER %s %s %s :%s\n",
-	      botuser, bothost, botserver, botrealname);
+	    botuser, bothost, dcc[servidx].host, botrealname);
       cycle_time = 0;
       /* We join channels AFTER getting the 001 -Wild */
       /* wait for async result now */
-    }
-    if (server_cycle_wait)
-      /* back to 1st server & set wait time */
-      /* put it here, just in case the server quits on us quickly */
-      cycle_time = server_cycle_wait;
   }
 }
diff -urN eggdrop1.4~/src/modules.c eggdrop1.4/src/modules.c
--- eggdrop1.4~/src/modules.c	Sat Oct  9 18:33:52 1999
+++ eggdrop1.4/src/modules.c	Sat Oct  9 18:48:15 1999
@@ -128,7 +128,6 @@
     dprintf(idx, "s un Not sharing userfile.\n");
 }
 
-/* these are obscure ones that I hope to neaten eventually :/ */
 void (*encrypt_pass) (char *, char *) = 0;
 void (*shareout) () = null_func;
 void (*sharein) (int, char *) = null_share;
@@ -139,6 +138,8 @@
 int (*rfc_ncasecmp) (const char *, const char *, int) = _rfc_ncasecmp;
 int (*rfc_toupper) (int) = _rfc_toupper;
 int (*rfc_tolower) (int) = _rfc_tolower;
+void (*dns_hostbyip) (IP) = block_dns_hostbyip;
+void (*dns_ipbyhost) (char *) = block_dns_ipbyhost;
 
 module_entry *module_list;
 dependancy *dependancy_list = NULL;
@@ -467,6 +468,17 @@
   /* 232 - 235 */
   (Function) mod_contextnote,
   (Function) assert_failed,
+  (Function) allocsock,
+  (Function) call_hostbyip,
+  /* 236 - 239 */
+  (Function) call_ipbyhost,
+  (Function) iptostr,
+  (Function) & DCC_DNSWAIT,	/* struct dcc_table * */
+  (Function) hostsanitycheck_dcc,
+  /* 240 - 243 */
+  (Function) & dns_ipbyhost,	/* Function * */
+  (Function) & dns_hostbyip,	/* Function * */
+  (Function) changeover_dcc,  
 };
 
 void init_modules(void)
@@ -899,6 +911,14 @@
       if (match_noterej == false_func)
 	match_noterej = func;
       break;
+    case HOOK_DNS_HOSTBYIP:
+      if (dns_hostbyip == block_dns_hostbyip)
+	dns_hostbyip = func;
+      break;
+    case HOOK_DNS_IPBYHOST:
+      if (dns_ipbyhost == block_dns_ipbyhost)
+	dns_ipbyhost = func;
+      break;
     }
 }
 
@@ -945,6 +965,14 @@
     case HOOK_MATCH_NOTEREJ:
       if (match_noterej == func)
 	match_noterej = false_func;
+      break;
+    case HOOK_DNS_HOSTBYIP:
+      if (dns_hostbyip == func)
+	dns_hostbyip = block_dns_hostbyip;
+      break;
+    case HOOK_DNS_IPBYHOST:
+      if (dns_ipbyhost == func)
+	dns_ipbyhost = block_dns_ipbyhost;
       break;
     }
 }
diff -urN eggdrop1.4~/src/net.c eggdrop1.4/src/net.c
--- eggdrop1.4~/src/net.c	Sat Oct  9 18:33:52 1999
+++ eggdrop1.4/src/net.c	Sat Oct  9 18:40:22 1999
@@ -65,11 +65,6 @@
   return ret;
 }
 
-#define my_ntohs(sh) swap_short(sh)
-#define my_htons(sh) swap_short(sh)
-#define my_ntohl(ln) swap_long(ln)
-#define my_htonl(ln) swap_long(ln)
-
 /* i read somewhere that memcpy() is broken on some machines */
 /* it's easy to replace, so i'm not gonna take any chances, because
  * it's pretty important that it work correctly here */
@@ -214,12 +209,12 @@
   }
 }
 
-/* request a normal socket for i/o */
-void setsock(int sock, int options)
+/* return a free entry in the socket entry */
+int allocsock(int sock, int options)
 {
   int i;
-  int parm;
 
+  context;
   for (i = 0; i < MAXSOCKS; i++) {
     if (socklist[i].flags & SOCK_UNUSED) {
       /* yay!  there is table space */
@@ -227,11 +222,23 @@
       socklist[i].outbuflen = 0;
       socklist[i].flags = options;
       socklist[i].sock = sock;
+      return i;
+    }
+  }
+  fatal("Socket table is full!", 0);
+  return -1; /* never reached */
+}
+
+/* request a normal socket for i/o */
+void setsock(int sock, int options)
+{
+  int i = allocsock(sock, options);
+  int parm;
+
       if (((sock != STDOUT) || backgrd) &&
 	  !(socklist[i].flags & SOCK_NONSOCK)) {
 	parm = 1;
-	setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *) &parm,
-		   sizeof(int));
+    setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *) &parm, sizeof(int));
 
 	parm = 0;
 	setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &parm, sizeof(int));
@@ -244,10 +251,6 @@
       }
       /* yay async i/o ! */
       fcntl(sock, F_SETFL, O_NONBLOCK);
-      return;
-    }
-  }
-  fatal("Socket table is full!", 0);
 }
 
 int getsock(int options)
@@ -328,6 +331,11 @@
 }
 
 /* starts a connection attempt to a socket
+ *
+ * If given a normal hostname, this will be resolved to the corresponding
+ * IP address first. PLEASE try to use the non-blocking dns functions
+ * instead and then call this function with the IP address to avoid blocking.
+ *
  * returns <0 if connection refused:
  *   -1  neterror() type error
  *   -2  can't resolve hostname */
@@ -372,6 +380,7 @@
     name.sin_addr.s_addr = inet_addr(host);
   else {
     /* no, must be host.domain */
+    debug0("Warning: open_telnet_raw() is about to block in gethostbyname()!");
     if (!setjmp(alarmret)) {
       alarm(resolve_timeout);
       hp = gethostbyname(host);
@@ -450,14 +459,17 @@
   return sock;
 }
 
-/* given network-style IP address, return hostname */
-/* hostname will be "##.##.##.##" format if there was an error */
+/* Given a network-style IP address, returns the hostname. The hostname
+ * will be in the "##.##.##.##" format if there was an error.
+ * 
+ * NOTE: This function is depreciated. Try using the async dns approach
+ *       instead. */
 char *hostnamefromip(unsigned long ip)
 {
   struct hostent *hp;
   unsigned long addr = ip;
   unsigned char *p;
-  static char s[121];
+  static char s[UHOSTLEN];
 
   if (!setjmp(alarmret)) {
     alarm(resolve_timeout);
@@ -471,11 +483,21 @@
     sprintf(s, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);
     return s;
   }
-  strncpy(s, hp->h_name, 120);
-  s[120] = 0;
+  strncpy(s, hp->h_name, UHOSTLEN - 1);
+  s[UHOSTLEN - 1] = 0;
   return s;
 }
 
+/* returns a given network-style IP address as a string in the
+ * "##.##.##.##" format */
+char *iptostr(IP ip)
+{
+  struct in_addr a;
+
+  a.s_addr = ip;
+  return inet_ntoa(a);
+}
+
 /* short routine to answer a connect received on a socket made previously
  * by open_listen ... returns hostname of the caller & the new socket
  * does NOT dispose of old "public" socket! */
@@ -484,14 +506,18 @@
 {
   int new_sock, addrlen;
   struct sockaddr_in from;
-  addrlen = sizeof(struct sockaddr);
 
+  addrlen = sizeof(struct sockaddr);
   new_sock = accept(sock, (struct sockaddr *) &from, &addrlen);
   if (new_sock < 0)
     return -1;
   if (ip != NULL) {
     *ip = from.sin_addr.s_addr;
-    strncpy(caller, hostnamefromip(*ip), 120);
+    /* This is now done asynchronously. Instead, we just provide the
+     * IP address.
+     * strncpy(caller, hostnamefromip(*ip), 120);
+     */
+    strncpy(caller, iptostr(*ip), 120);
     caller[120] = 0;
     *ip = my_ntohl(*ip);
   }
@@ -589,6 +615,10 @@
 	    *len = 0;
 	    return i;
 	  }
+	} else if (socklist[i].flags & SOCK_PASS) {
+	  s[0] = 0;
+	  *len = 0;
+	  return i;
 	}
 	if ((socklist[i].sock == STDOUT) && !backgrd)
 	  x = read(STDIN, s, grab);
@@ -711,6 +741,7 @@
     return ret;
   }
   /* binary and listening sockets don't get buffered */
+  /* passed on sockets don't get buffered either  (Fabian)*/
   if (socklist[ret].flags & SOCK_CONNECT) {
     if (socklist[ret].flags & SOCK_STRONGCONN) {
       socklist[ret].flags &= ~SOCK_STRONGCONN;
@@ -726,7 +757,8 @@
     my_memcpy(s, xx, *len);
     return socklist[ret].sock;
   }
-  if (socklist[ret].flags & SOCK_LISTEN)
+  if ((socklist[ret].flags & SOCK_LISTEN) ||
+      (socklist[ret].flags & SOCK_PASS))
     return socklist[ret].sock;
   context;
   /* might be necessary to prepend stored-up data! */
@@ -905,6 +937,8 @@
 	strcat(s, " (binary)");
       if (socklist[i].flags & SOCK_LISTEN)
 	strcat(s, " (listen)");
+      if (socklist[i].flags & SOCK_PASS)
+	strcat(s, " (passed on)");
       if (socklist[i].flags & SOCK_CONNECT)
 	strcat(s, " (connecting)");
       if (socklist[i].flags & SOCK_STRONGCONN)
@@ -933,7 +967,7 @@
 {
   /* According to the latest RFC, the clients SHOULD be able to handle
    * DNS names that are up to 255 characters long.  This is not broken.  */
-  char hostname[256], dnsname[256], badaddress[16];
+  char badaddress[16];
   IP ip = my_atoul(ipaddy);
   int prt = atoi(port);
 
@@ -942,23 +976,39 @@
     return 1;
   context;			/* This should be pretty solid, but
 				 * something _might_ break. */
-  sprintf(badaddress, "%u.%u.%u.%u", (ip >> 24) & 0xff, (ip >> 16) & 0xff,
-	  (ip >> 8) & 0xff, ip & 0xff);
   if (prt < 1) {
     putlog(LOG_MISC, "*", "ALERT: (%s!%s) specified an impossible port of %u!",
 	   nick, from, prt);
     return 0;
   }
+  sprintf(badaddress, "%u.%u.%u.%u", (ip >> 24) & 0xff, (ip >> 16) & 0xff,
+	  (ip >> 8) & 0xff, ip & 0xff);
   if (ip < (1 << 24)) {
     putlog(LOG_MISC, "*", "ALERT: (%s!%s) specified an impossible IP of %s!",
 	   nick, from, badaddress);
     return 0;
   }
+  return 1;
+}
+
+int hostsanitycheck_dcc(char *nick, char *from, IP ip, char *dnsname,
+		        char *prt)
+{
+  /* According to the latest RFC, the clients SHOULD be able to handle
+   * DNS names that are up to 255 characters long.  This is not broken.  */
+  char hostname[256], badaddress[16];
+
+  /* It is disabled HERE so we only have to check in *one* spot! */
+  if (!dcc_sanitycheck)
+    return 1;
+  context;			/* This should be pretty solid, but
+				 * something _might_ break. */
+  sprintf(badaddress, "%u.%u.%u.%u", (ip >> 24) & 0xff, (ip >> 16) & 0xff,
+	  (ip >> 8) & 0xff, ip & 0xff);
   /* These should pad like crazy with zeros, since 120 bytes or so is
    * where the routines providing our data currently lose interest. I'm
    * using the n-variant in case someone changes that... */
   strncpy(hostname, extracthostname(from), 256);
-  strncpy(dnsname, hostnamefromip(my_htonl(ip)), 256);
   if (!strcasecmp(hostname, dnsname)) {
     putlog(LOG_DEBUG, "*", "DNS information for submitted IP checks out.");
     return 1;
diff -urN eggdrop1.4~/src/proto.h eggdrop1.4/src/proto.h
--- eggdrop1.4~/src/proto.h	Sat Oct  9 18:33:52 1999
+++ eggdrop1.4/src/proto.h	Sat Oct  9 18:40:22 1999
@@ -128,13 +128,21 @@
 void not_away(int);
 void set_away(int, char *);
 void *_get_data_ptr(int, char *, int);
-
 #define get_data_ptr(x) _get_data_ptr(x,__FILE__,__LINE__)
 void flush_lines(int, struct chat_info *);
 struct dcc_t *find_idx(int);
 int new_dcc(struct dcc_table *, int);
 void del_dcc(int);
 char *add_cr(char *);
+void changeover_dcc(int, struct dcc_table *, int);
+
+/* dns.c */
+extern void (*dns_hostbyip) (IP);
+extern void (*dns_ipbyhost) (char *);
+void block_dns_hostbyip(IP);
+void block_dns_ipbyhost(char *);
+void call_hostbyip(IP, char *, int);
+void call_ipbyhost(char *, IP, int);
 
 /* gotdcc.c */
 void gotdcc(char *, char *, struct userrec *, char *);
@@ -205,7 +213,9 @@
 IP getmyip();
 void neterror(char *);
 void setsock(int, int);
+int allocsock(int, int);
 int getsock(int);
+char *hostnamefromip(unsigned long);
 void killsock(int);
 int answer(int, char *, unsigned long *, unsigned short *, int);
 int open_listen(int *);
@@ -217,6 +227,8 @@
 int sockgets(char *, int *);
 void tell_netdebug(int);
 int sanitycheck_dcc(char *, char *, char *, char *);
+int hostsanitycheck_dcc(char *, char *, IP, char *, char *);
+char *iptostr(IP);
 
 /* tcl.c */
 void protect_tcl();
diff -urN eggdrop1.4~/doc/UPDATES1.4 eggdrop1.4/doc/UPDATES1.4
--- eggdrop1.4~/doc/UPDATES1.4	Sat Oct  9 18:33:36 1999
+++ eggdrop1.4/doc/UPDATES1.4	Sat Oct  9 19:21:55 1999
@@ -5,4 +5,5 @@
 
 1.4.0
 Foundby   Fixedby   What....
-
+	  Fabian    added an asynchronous DNS request module which prevents
+		    the bot from hanging on dns lookups.


More information about the Patches mailing list