diff -u orig/tcprules.1 ./tcprules.1
--- orig/tcprules.1	Sun Jan 18 02:17:43 1998
+++ ./tcprules.1	Mon May  4 23:48:31 1998
@@ -156,6 +156,13 @@
 .B 10.2.:ins
 and
 .BR 10.3.:ins .
+.SH "HOST NAMES"
+.B tcprules
+can contain domains as well as addresses; search for a
+match is based on do.ma.in,
+ .ma.in,
+ .in,
+ .  (period used as 'default')
 .SH "INSTRUCTIONS"
 The instructions in a rule must begin with either
 .B allow
diff -u orig/tcprules.c ./tcprules.c
--- orig/tcprules.c	Sun Jan 18 02:17:43 1998
+++ ./tcprules.c	Tue May  5 11:00:02 1998
@@ -58,7 +58,16 @@
   unsigned long bot;
   unsigned long top;
 
-  if (byte_chr(address.s,address.len,'@') == address.len) {
+  for (i = 0; i < address.len; i++) {
+    if (address.s[i] == '-') continue;
+    if (address.s[i] == '.') continue;
+    if (address.s[i] == '@') continue;
+    if (address.s[i] >= '0')
+      if (address.s[i] <= '9') continue;
+    i = address.len + 1;
+  }
+
+  if (i == address.len) {
     i = byte_chr(address.s,address.len,'-');
     if (i < address.len) {
       left = byte_rchr(address.s,i,'.');
diff -u orig/tcpserver.1 ./tcpserver.1
--- orig/tcpserver.1	Sun Jan 18 02:17:43 1998
+++ ./tcpserver.1	Mon May  4 23:48:35 1998
@@ -7,6 +7,9 @@
 .B \-qQvdDoOpPhHrR1
 ]
 [
+.B \-NnAa
+]
+[
 .B \-c\fIlimit
 ]
 [
@@ -179,6 +182,25 @@
 .B \-P
 (Default.)
 Not paranoid.
+.TP
+.B \-a
+'deny' connections from an address with no hostname
+.TP
+.B \-A
+'deny' connections from an address which is 'paranoid'
+The environment variable
+.BR TCPPARANOID
+is set if the connection is
+considered to be 'paranoid' (allows programs to tell the difference
+when
+.BR TCPREMOTEHOST
+is not set).
+.TP
+.B \-n
+Do domain name lookups in tcprules file after ip lookup.
+.TP
+.B \-N
+Do domain name lookups in tcprules file before IP lookup
 .TP
 .B \-h
 (Default.)
diff -u orig/tcpserver.c ./tcpserver.c
--- orig/tcpserver.c	Sun Jan 18 02:17:43 1998
+++ ./tcpserver.c	Mon May  4 23:22:21 1998
@@ -27,6 +27,9 @@
 #include "env.h"
 #include "cdb.h"
 
+#define TCPPARANOID /* if TCPPARANOID options are to be used */
+#define TCPREMOTEHOSTRULES /* if want remote host checked in rules() */
+
 #define FATAL "tcpserver: fatal: "
 #define DROP "tcpserver: warning: dropping connection, "
 int verbosity = 1;
@@ -90,6 +93,16 @@
 char *fnrules = 0;
 int flagdeny = 0;
 
+#ifdef TCPREMOTEHOSTRULES
+stralloc tcpremotehost = {0};
+int domainchecking = 0;
+#endif
+#ifdef TCPPARANOID
+char *connectionstatus;
+int blockingparanoid = 0;
+int blockingnohost = 0;
+#endif
+
 void printenv()
 {
   char *tcplocalhost;
@@ -101,10 +114,17 @@
   tcpremotehost = env_get("TCPREMOTEHOST");
 
   if (!tcplocalhost) tcplocalhost = "";
+#ifdef TCPPARANOID
+  if (!tcpremotehost) tcpremotehost = env_get("TCPPARANOID");
+#endif
   if (!tcpremotehost) tcpremotehost = "";
 
   if (!stralloc_copys(&tmp,"tcpserver: ")) drop_nomem();
+#ifdef TCPPARANOID
+  if (!stralloc_cats(&tmp,connectionstatus)) drop_nomem();
+#else
   if (!stralloc_cats(&tmp,flagdeny ? "deny " : "ok ")) drop_nomem();
+#endif
   if (!stralloc_catb(&tmp,strnum,fmt_ulong(strnum,getpid()))) drop_nomem();
   if (!stralloc_cats(&tmp," ")) drop_nomem();
   safeappend(&tmp,tcplocalhost);
@@ -184,7 +204,11 @@
 
   while ((next0 = byte_chr(data,datalen,0)) < datalen) {
     switch(data[0]) {
+#ifdef TCPPARANOID
+      case 'D': connectionstatus = "deny "; flagdeny = 1; break;
+#else
       case 'D': flagdeny = 1; break;
+#endif
       case '+': if (!env_put(data + 1)) drop_nomem(); break;
     }
     data += next0 + 1; datalen -= next0 + 1;
@@ -192,6 +216,36 @@
   return 1;
 }
 
+#ifdef TCPREMOTEHOSTRULES
+int tcp_domain_check()
+{
+  if (tcpremotehost.len) {
+    unsigned int i = 0;
+
+    if (tcpremoteinfo) {
+      if (!stralloc_copys(&tmp,tcpremoteinfo)) drop_nomem();
+      if (!stralloc_cats(&tmp,"@")) drop_nomem();
+      if (!stralloc_cats(&tmp,tcpremotehost.s)) drop_nomem();
+      if (dorule()) return 1;
+    }
+
+    if (!stralloc_copys(&tmp,tcpremotehost.s)) drop_nomem();
+    if (dorule()) return 1;
+    while (++i < tcpremotehost.len)
+      if (tcpremotehost.s[i] == '.') {
+        if (!stralloc_copys(&tmp,tcpremotehost.s+i))
+           drop_nomem();
+        if (dorule()) return 1;
+      }
+    }
+  /* We use .' to indicate a valid host default (blank for IP address) */
+  /* so that if the host isn't set we can act differently on an IP address */
+  if (!stralloc_copys(&tmp, ".")) drop_nomem();
+  if (dorule()) return 1;
+  return 0;
+}
+#endif
+
 void rules()
 {
   if (!fnrules) return;
@@ -199,6 +253,10 @@
   fdrules = open_read(fnrules);
   if (fdrules == -1) drop_rules();
 
+#ifdef TCPREMOTEHOSTRULES
+  if (domainchecking == -1) tcp_domain_check();
+#endif
+
   if (tcpremoteinfo) {
     if (!stralloc_copys(&tmp,tcpremoteinfo)) drop_nomem();
     if (!stralloc_cats(&tmp,"@")) drop_nomem();
@@ -214,6 +272,11 @@
     --tmp.len;
   }
 
+#ifdef TCPREMOTEHOSTRULES
+  if (domainchecking == 1) tcp_domain_check();
+  tmp.len = 0;
+#endif
+
   dorule();
 
   done:
@@ -246,7 +309,12 @@
   struct servent *se;
   int j;
  
+#if defined(TCPREMOTEHOSTS) || defined(TCPPARANOID)
+  /* okay the defines mean the options might not actually work - so what? */
+  while ((opt = getopt(argc,argv,"dDvqQhHrR1x:t:u:g:l:b:c:pPoOnNaA")) != opteof)
+#else
   while ((opt = getopt(argc,argv,"dDvqQhHrR1x:t:u:g:l:b:c:pPoO")) != opteof)
+#endif
     switch(opt) {
       case 'b': scan_ulong(optarg,&backlog); break;
       case 'c': scan_ulong(optarg,&limit); break;
@@ -269,6 +337,14 @@
       case 'u': scan_ulong(optarg,&uid); break;
       case '1': flag1 = 1; break;
       case 'l': forcelocal = optarg; break;
+#ifdef TCPREMOTEHOSTRULES
+      case 'n': domainchecking = 1; break;
+      case 'N': domainchecking = -1; break;
+#endif
+#ifdef TCPPARANOID
+      case 'a': blockingnohost = 1; break;
+      case 'A': blockingparanoid = 1; break;
+#endif
       default: usage();
     }
   argc -= optind;
@@ -362,6 +438,9 @@
   if (!env_unset("TCPLOCALHOST")) die_nomem();
   if (!env_unset("TCPREMOTEHOST")) die_nomem();
   if (!env_unset("TCPREMOTEINFO")) die_nomem();
+#ifdef TCPPARANOID
+  if (!env_unset("TCPPARANOID")) die_nomem();
+#endif
  
   if (forcelocal)
     if (!env_put2("TCPLOCALHOST",forcelocal)) die_nomem();
@@ -376,6 +455,9 @@
   sig_childblock();
  
   for (;;) {
+#ifdef TCPPARANOID
+    int tcpremotehostset = 0;
+#endif
     while (numchildren >= limit) sig_pause();
     sig_childunblock();
  
@@ -433,6 +515,9 @@
           }
  
         if (flagremotehost)
+#ifdef TCPREMOTEHOSTRULES
+#define tmp tcpremotehost
+#endif
           switch(dns_ptr(&tmp,&ipremote)) {
             case DNS_MEM: drop_nomem();
             case 0:
@@ -447,6 +532,11 @@
               if (!stralloc_0(&tmp)) drop_nomem();
               case_lowers(tmp.s);
               if (!env_put2("TCPREMOTEHOST",tmp.s)) drop_nomem();
+#ifdef TCPPARANOID
+              tcpremotehostset = 1;
+              break;
+            default: tmp.len = 0; /* reset it, for nohost checking */
+#endif
           }
         if (flagremoteinfo) {
           tcpremoteinfo = remoteinfo_get(&ipremote,portremote,&iplocal,portlocal,(int) timeout);
@@ -454,6 +544,23 @@
             if (!env_put2("TCPREMOTEINFO",tcpremoteinfo)) drop_nomem();
         }
 
+#ifdef TCPPARANOID
+        connectionstatus = "ok ";
+        if (!tcpremotehostset) 
+          if (tmp.len) {
+            if (!stralloc_0(&tmp)) drop_nomem();
+            case_lowers(tmp.s);
+            if (!env_put2("TCPPARANOID", tmp.s)) drop_nomem();
+            if (blockingparanoid) connectionstatus = "deny-paranoid ";
+            else connectionstatus = "ok-paranoid ";
+            }
+          else if (blockingnohost) connectionstatus = "deny-nohost ";
+
+        if (str_diffn(connectionstatus, "ok", 2)) flagdeny = 1; else
+#endif
+#ifdef TCPREMOTEHOSTRULES
+#undef tmp
+#endif
 	rules();
 	printenv();
 	if (flagdeny) _exit(100);

