Combining two patches

"Jimmy Spam" <[email protected]>
Newsgroups gmane.mail.qmail.ldap
Message-ID <[email protected]>
I'm trying combine this two patchs (attached) without success. Before
begin the hard task of inspect all code detail, I want know if you have
this patches already combined for your own server.

Thank you very much


______________________________________________________________________
Correo gratis de Pobladores.com
Ahora con 25MB de capacidad. 
http://www.pobladores.com/services/webmail
ucspi-tcp-0.88.tcpserver-limits-2007-12-22.patch (application/octet-stream, 20.5 KB)
The tcpserver limits patch, by Matija Nalis, gives tcpserver the ability to reject connections when the server's 
load average is above a certain number, when more than a certain number of connections are received from the same 
IP address, or when more than a certain number of connections are received from machines in the same class-C block 
(i.e. the "first three numbers" in their IP addresses are the same. "1.2.3.4" and "1.2.3.100" are in the same class-C block.)

The limits are configured by setting the MAXLOAD, MAXCONNIP, and MAXCONNC environment variables before tcpserver runs. 
If you want tcpserver to send a message to the client before dropping their connection, you can configure this by 
setting a DIEMSG environment variable.

The patch I was using, dated 2006-01-26, does work as advertised, and has saved my own server and several of my clients' 
servers from being overloaded by over-zealous attackers (i.e. spammers) over the past few months. However, I did notice
 a few minor cosmetic issues which I thought needed to be fixed, so I updated the patch.

My updates are:

    *

      When MAXCONNIP or MAXCONNC cause a connection to be rejected, tcpserver adds "MAXCONNIP:" or "MAXCONNC:" with the limit
 at the end of the "deny line in the logs. This makes it easy to debug- the error message tells you which environment variable
 caused the connection to be rejected.

      However, when MAXLOAD causes a connection to be rejected, it adds "LOAD:" and the current load average to the log. This
 doesn't match the environment variable, which "feels funny" to me. (I told you it was a minor cosmetic issue.)

      For the sake of consistency, I changed the "LOAD:" label to say "MAXLOAD:", so it matches the environment variable name,
 like the other two messages do.
    *

      The older patch only has a provision for a single DIEMSG variable, whose value is sent to a client whose connection is 
being rejected, regardless of which of the three limits the client triggered. I thought it would be nice to be able to set one 
message which says something like "Server too busy, try again later" and another message which says "Too many connections from 
your IP address".

      I added three new environment variables: DIEMSG_MAXLOAD, DIEMSG_MAXCONNIP, and DIEMSG_MAXCONNC, whose values are used 
instead of the generic DIEMSG message. However, to avoid breaking older scripts, if one of these new variables is not set, the 
DIEMSG value will be used instead.

The original author's web page has a link where you can download the previous versions of the patch. As of the time I'm writing 
this (2007-12-22) the most recent version of his patch is dated 2006-01-26, and is what I used as the starting point for my own 
changes.


diff -ruN ucspi-tcp-0.88-factory/CHANGES.tcpserver-limits-patch ucspi-tcp-0.88-patched/CHANGES.tcpserver-limits-patch
--- ucspi-tcp-0.88-factory/CHANGES.tcpserver-limits-patch	1969-12-31 19:00:00.000000000 -0500
+++ ucspi-tcp-0.88-patched/CHANGES.tcpserver-limits-patch	2007-12-22 02:54:20.000000000 -0500
@@ -0,0 +1,36 @@
+20071222 John Simpson <[email protected]>
+- Changed "LOAD:" log suffix to "MAXLOAD:" so it matches the environment
+  variable which caused the rejection, like the other two messages do.
+- Added DIEMSG_MAXLOAD, DIEMSG_MAXCONNIP, and DIEMSG_MAXCONNC environment
+  variables. If defined, they will be used instead of DIEMSG when that
+  type of denial occurs. Otherwise, DIEMSG will be used as normal.
+- Updated README.tcpserver-limits-patch
+
+20060126 Added support for "always reject" (setting MAXCONNIP and/or
+MAXCONNC to 0) and fixing a bug when sometimes DIEMSG would not be 
+shown (by Mark Powell)
+
+20050903 Added support for Solaris (by Jorge Valdes).
+Moved MAXLOAD code to getprocla(). 
+Modified documentation a little to accommodate recent changes.
+
+20050130 reinstated /proc/loadavg support for those compiling on Linux 
+with dietlibc (see #define NO_GETLOADAVG at top of tcpserver.c). 
+Also, we now compile on 64bit platforms (we avoid including unistd.h if
+using getloadavg(3), so we don't conflict with readwrite.h header file)
+Needed if your compile was breaking with:
+readwrite.h:4: error: syntax error before "read"
+readwrite.h:4: warning: data definition has no type or storage class
+SUMMARY: If 20040725 worked for you, there is no reason to upgrade 
+(no new features of bugfixes)
+
+20040725 adds a sleep(1) before terminating (to prevent too high load from
+many rapid fork()/exit() calls. It also changes the method for checking
+system load to getloadavg(3) instead of parsing /proc/loadavg, therefore
+making it working on *BSD and other non-Linux systems in addition to Linux.
+It also adds DIEMSG="xxx" support.
+
+20040327 fixes a bug in 20040124 related to MAXLOAD (it would not work
+correctly when load was higher than 10.00)
+
+
diff -ruN ucspi-tcp-0.88-factory/README.tcpserver-limits-patch ucspi-tcp-0.88-patched/README.tcpserver-limits-patch
--- ucspi-tcp-0.88-factory/README.tcpserver-limits-patch	1969-12-31 19:00:00.000000000 -0500
+++ ucspi-tcp-0.88-patched/README.tcpserver-limits-patch	2007-12-22 02:49:44.000000000 -0500
@@ -0,0 +1,163 @@
+See CHANGES.tcpserver-limits-patch for changes summary.
+
+:::COMPILING:::
+
+    For MAXLOAD variable to have effect, you have 3 options:
+
+(1) By default the patch assumes that you have working getloadavg(3)
+    (most modern UN*Xoids have, including Linux and FreeBSD). No changes
+    are needed to standard ucspi-tcp compilation procedures.
+
+(2) If you have Solaris system:
+    - conf-cc needs to be modified to include "-DSOLARIS"
+    - Makefile needs to be modified so that tcpserver links with "-lkstat" 
+      (add "-lkstat" to the end of line 748 after "`cat socket.lib`")
+
+(3) If you have a non-Solaris system without getloadavg(3), but with 
+    readable '/proc/loadavg' (in linux-2.4.x/2.6.x syntax); for example 
+    if you're compiling on Linux system with dietlibc:
+    - conf-cc needs to be modified to include "-DNO_GETLOADAVG"
+
+
+:::USING:::
+
+This patch (20060126) makes tcpserver from DJB's ucspi-tcp-0.88 package (see
+http://cr.yp.to/ucspi-tcp.html) to modify its behavior if some environment
+variables are present.
+
+The variables can be preset before starting tcpserver (thus acting as
+default for all connections), or, if you use 'tcpserver -x xxx.cdb', they
+can be set (or overridden) from xxx.cdb. If none of the variables are set,
+tcpserver behaves same as non patched version (except for negligible
+performance loss). Any or all variables can be set, as soon as first limit
+is reached the connection is dropped. I'd recommend using .cdb files
+exclusively though, as you can then modify configuration without killing
+tcpserver.
+
+The variables are:
+
+(1) MAXLOAD 
+    maximum 1-minute load average * 100. For example, if you have line
+    :allow,MAXLOAD="350" 
+    in your rules file from which you created .cdb, the connection will be
+    accepted only if load average is below 3.50
+
+    See COMPILING instructions above for info on supported systems.
+  
+(2) MAXCONNIP
+    maximum connections from one IP address. tcpserver's -c flag defines
+    maximum number of allowed connections, but it can be abused if
+    just one host goes wild and eats all the connections - no other host
+    would be able to connect then. If you created your .cdb with:
+    :allow,MAXCONNIP="5"
+    and run tcpserver -c 50, then each IP address would be able to have at 
+    most 5 concurrent connections, while there still could connect 50
+    clients total.
+    0 is valid value and means 'always reject'
+
+(3) MAXCONNC
+
+    maximum connections from whole C-class (256 addresses). Extension of
+    MAXCONNIP, as sometimes the problematic client has a whole farm of
+    client machines with different IP addresses instead of just one IP
+    address, and they all try to connect. It might have been more useful to
+    be able to specify CIDR block than C-class, but I've decided to KISS.
+
+    for example tcpserver -c 200, and .cdb with:
+    :allow,MAXCONNC="15"
+    will allow at most 15 host from any x.y.z.0/24 address block, while
+    still allowing up to 200 total connections.
+    0 is valid value and means 'always reject'
+
+(4) DIEMSG
+    
+    if set and one of the above limits is exceeded, this is the message 
+    to be sent to client (CRLF is always added to the text) before terminating
+    connection. If unset, the connection simply terminates (after 1 sec delay) 
+    if limit is exceeded.
+
+    For example:
+    DIEMSG="421 example.com Service temporarily not available, closing 
+    transmission channel"
+
+(5) DIEMSG_MAXLOAD
+
+    If set, and a connection is denied because the MAXLOAD limit is exceeded,
+    this value will be used instead of DIEMSG.
+
+    For example:
+    DIEMSG_MAXLOAD="421 example.com Server busy, try again later."
+
+(6) DIEMSG_MAXCONNIP
+
+    If set, and a connection is denied because the MAXCONNIP limit is exceeded,
+    this value will be used instead of DIEMSG.
+
+    For example:
+    DIEMSG_MAXCONNIP="421 example.com Too many connections from your IP."
+
+(7) DIEMSG_MAXCONNC
+
+    If set, and a connection is denied because the MAXCONNC limit is exceeded,
+    this value will be used instead of DIEMSG.
+
+    For example:
+    DIEMSG_MAXCONNC="421 example.com Too many connections from your network."
+
+Notes: 
+
+- if a connection is dropped due to some of those variables set, it will be
+  flagged (if you run tcpserver -v) with "MAXLOAD:", "MAXCONNIP:" or
+  "MAXCONNC:" at the end of the "tcpserver: deny" line. If that bothers you
+  (eg. you have a strict log parsers), don't apply that chunk of the patch.
+
+- the idea for this patch came from my previous experience with xinetd, and
+  need to limit incoming bursts of virus/spam SMTP connections, since I was
+  running qmail-scanner to scan incoming and outgoing messages for viruses
+  and spam.
+
+When you make changes, please check that they work as expected. 
+
+Examples (for tcprules created .cdb)
+(a) 192.168.:allow,MAXLOAD="1000"
+    :allow,MAXCONNIP="3"
+
+    this would allow any connection from your local LAN (192.168.*.*
+    addresses) if system load is less than 10.00. non-LAN connections would
+    be accepted only if clients from that IP address have not already opened
+    more than 2 connections (as your connection would be last allowed -- 3rd)
+
+(b) 192.168.:allow
+    5.6.7.8:allow,MAXCONNIP="3"
+    1.2.:allow,MAXLOAD="500",MAXCONNIP="1",MAXCONNC="5"
+    :allow,MAXLOAD="1000",MAXCONNIP="3",DIEMSG="421 example.com unavailable"
+
+    if client connects from 192.168.*.* (ex: your LAN), it is allowed.
+    if it connects from 5.6.7.8 (ex: little abusive customer of yours),
+     it is allowed unless there are already 3active connections from 5.6.7.8
+     to this service
+    if it connects from 1.2.*.* (ex: some problematic networks which caused
+     you grief in the past) it will connect only if load is less than 5.0,
+     there is less than 5 active connections from whole C class
+     (1.2.*.0/24), and if that specific IP address does not already have
+     connection open.
+    in all other cases, the client will be permitted to connect if load is
+     less than 10.00 and client has 2 or less connections open. If load is
+     higher than 10.00 or there are 3 or more connections open from this
+     client, the message "421 example.com unavailable" will be returned to 
+     the client and connection terminated.
+
+
+Any bugs introduced are ours, do not bother DJB with them.
+If you find any, or have neat ideas, or better documentation, or whatever,
+contact me.
+
+the 2006-01-26 version of the patch can be found at:
+http://linux.voyager.hr/ucspi-tcp/
+
+the 2007-12-22 version of the patch can be found at:
+http://qmail.jms1.net/ucspi-tcp/
+
+Enjoy,
+Matija Nalis < mnalis-tcpserver _at_ voyager.hr >
+John Simpson <[email protected]> (2007-12-22 version)
diff -ruN ucspi-tcp-0.88-factory/tcpserver.c ucspi-tcp-0.88-patched/tcpserver.c
--- ucspi-tcp-0.88-factory/tcpserver.c	2000-03-18 10:18:42.000000000 -0500
+++ ucspi-tcp-0.88-patched/tcpserver.c	2007-12-22 02:41:24.000000000 -0500
@@ -1,6 +1,14 @@
+#ifdef __dietlibc__
+#define NO_GETLOADAVG
+#endif
+
 #include <sys/types.h>
 #include <sys/param.h>
 #include <netdb.h>
+#include <stdlib.h>
+#ifdef NO_GETLOADAVG
+#include <unistd.h>
+#endif
 #include "uint16.h"
 #include "str.h"
 #include "byte.h"
@@ -28,6 +36,18 @@
 #include "sig.h"
 #include "dns.h"
 
+
+#ifdef SOLARIS
+#include <kstat.h>
+static kstat_ctl_t   *kc;
+#ifndef FSCALE
+#define FSHIFT  8               /* bits to right of fixed binary point */
+#define FSCALE  (1<<FSHIFT)
+#endif /* FSCALE */
+
+#define loaddouble(la) ((double)(la) / FSCALE)
+#endif
+
 int verbosity = 1;
 int flagkillopts = 1;
 int flagdelay = 1;
@@ -59,11 +79,22 @@
 static stralloc tmp;
 static stralloc fqdn;
 static stralloc addresses;
+static stralloc diemsg_buf;
+static stralloc diemsg2_buf;
+static stralloc diemsg3_buf;
+static stralloc diemsg4_buf;
 
 char bspace[16];
 buffer b;
 
 
+typedef struct
+{
+  char ip[4];
+  pid_t pid;
+} baby;
+
+baby *child;
 
 /* ---------------------------- child */
 
@@ -72,6 +103,13 @@
 int flagdeny = 0;
 int flagallownorules = 0;
 char *fnrules = 0;
+unsigned long maxload = 0;
+long maxconnip = -1;
+long maxconnc = -1;
+char *diemsg = "";
+char *diemsg2 = "";
+char *diemsg3 = "";
+char *diemsg4 = "";
 
 void drop_nomem(void)
 {
@@ -110,6 +148,8 @@
   strerr_die4sys(111,DROP,"unable to read ",fnrules,": ");
 }
 
+unsigned long limit = 40;
+
 void found(char *data,unsigned int datalen)
 {
   unsigned int next0;
@@ -125,6 +165,29 @@
 	if (data[1 + split] == '=') {
 	  data[1 + split] = 0;
 	  env(data + 1,data + 1 + split + 1);
+	  if (str_diff(data+1, "MAXLOAD") == 0) scan_ulong(data+1+split+1,&maxload);
+	  if (str_diff(data+1, "MAXCONNIP") == 0) scan_ulong(data+1+split+1,&maxconnip);
+	  if (str_diff(data+1, "MAXCONNC") == 0) scan_ulong(data+1+split+1,&maxconnc);
+	  if (str_diff(data+1, "DIEMSG") == 0) {
+	    if (!stralloc_copys(&diemsg_buf,data+1+split+1)) drop_nomem();
+	    if (!stralloc_0(&diemsg_buf)) drop_nomem();
+	    diemsg = diemsg_buf.s;
+	  }
+	  if (str_diff(data+1, "DIEMSG_MAXLOAD") == 0) {
+	    if (!stralloc_copys(&diemsg2_buf,data+1+split+1)) drop_nomem();
+	    if (!stralloc_0(&diemsg2_buf)) drop_nomem();
+	    diemsg2 = diemsg2_buf.s;
+	  }
+	  if (str_diff(data+1, "DIEMSG_MAXCONNIP") == 0) {
+	    if (!stralloc_copys(&diemsg3_buf,data+1+split+1)) drop_nomem();
+	    if (!stralloc_0(&diemsg3_buf)) drop_nomem();
+	    diemsg3 = diemsg3_buf.s;
+	  }
+	  if (str_diff(data+1, "DIEMSG_MAXCONNC") == 0) {
+	    if (!stralloc_copys(&diemsg4_buf,data+1+split+1)) drop_nomem();
+	    if (!stralloc_0(&diemsg4_buf)) drop_nomem();
+	    diemsg4 = diemsg4_buf.s;
+	  }
 	}
 	break;
     }
@@ -133,9 +196,53 @@
   }
 }
 
+unsigned long getprocla(void)
+{
+#ifdef SOLARIS
+  kstat_t       *ksp;
+  kstat_named_t *knp;
+  double lavg;
+  kstat_chain_update(kc);
+  ksp = kstat_lookup(kc, "unix", 0, "system_misc");
+  kstat_read(kc,ksp,NULL);
+  knp = kstat_data_lookup(ksp,"avenrun_1min");
+  lavg = loaddouble(knp->value.ui32);
+  return (unsigned long)(lavg * 100);
+#else
+#ifdef NO_GETLOADAVG
+  int lret;
+  int i;
+  unsigned long u1, u2;
+  char *s;
+  static stralloc loadavg_data = {0};
+
+  lret = openreadclose("/proc/loadavg", &loadavg_data, 10);
+  if (lret != -1) {
+    /* /proc/loadavg format is:
+     * 13.08 3.04 1.00 34/170 14190 */
+    s = loadavg_data.s;
+    i = scan_ulong (s, &u1); s+=i;
+    if ((i>0) && (i<5) && (*s == '.')) { /* load should be < 10000 */
+      i = scan_ulong (s+1,&u2);
+      if (i==2) { /* we require two decimal places */
+        return (u1 * 100 + u2);
+      }
+      return (u1 * 100);
+    }
+  }
+#else
+  double result;
+  if (getloadavg(&result, 1) == 1) {
+    return (result * 100);
+  }
+#endif
+#endif
+}
+
 void doit(int t)
 {
   int j;
+  unsigned long curload = 0;
 
   remoteipstr[ip4_fmt(remoteipstr,remoteip)] = 0;
 
@@ -211,6 +318,26 @@
     }
   }
 
+  if (maxload) {
+    curload = getprocla();
+    if (curload > maxload) flagdeny = 2;
+  }
+  
+  if (!flagdeny && (maxconnip != -1 || maxconnc != -1)) {
+  	unsigned long u;
+  	long c1=0, cc=0;
+  	for (u=0; u < limit; u++) if (child[u].pid != 0) { 
+  		if ((child[u].ip[0] == remoteip[0]) &&
+  		    (child[u].ip[1] == remoteip[1]) &&
+  		    (child[u].ip[2] == remoteip[2]) ) {
+  		    cc++;
+  		    if (child[u].ip[3] == remoteip[3]) c1++;
+  		}
+  	}
+	if (maxconnc != -1 && (cc >= maxconnc)) flagdeny = 4;
+	if (maxconnip != -1 && (c1 >= maxconnip)) flagdeny = 3;
+  }
+
   if (verbosity >= 2) {
     strnum[fmt_ulong(strnum,getpid())] = 0;
     if (!stralloc_copys(&tmp,"tcpserver: ")) drop_nomem();
@@ -223,11 +350,38 @@
     cats(":"); safecats(remoteipstr);
     cats(":"); if (flagremoteinfo) safecats(tcpremoteinfo.s);
     cats(":"); safecats(remoteportstr);
+    if (flagdeny == 2) {
+    	char curloadstr[FMT_ULONG];
+    	curloadstr[fmt_ulong(curloadstr,curload)] = 0;
+    	cats(" "); safecats ("MAXLOAD"); cats(":"); safecats(curloadstr);
+    }
+    if (flagdeny == 3) {
+    	char maxconstr[FMT_ULONG];
+    	maxconstr[fmt_ulong(maxconstr,maxconnip)] = 0;
+    	cats(" "); safecats ("MAXCONNIP"); cats(":"); safecats(maxconstr);
+    }
+    if (flagdeny == 4) {
+    	char maxconstr[FMT_ULONG];
+    	maxconstr[fmt_ulong(maxconstr,maxconnc)] = 0;
+    	cats(" "); safecats ("MAXCONNC"); cats(":"); safecats(maxconstr);
+    }
     cats("\n");
     buffer_putflush(buffer_2,tmp.s,tmp.len);
   }
 
-  if (flagdeny) _exit(100);
+  if (flagdeny) {
+    if ((flagdeny==2) && *diemsg2) diemsg = diemsg2;
+    if ((flagdeny==3) && *diemsg3) diemsg = diemsg3;
+    if ((flagdeny==4) && *diemsg4) diemsg = diemsg4;
+    if (*diemsg) {
+      buffer_init(&b,write,t,bspace,sizeof bspace);
+      buffer_puts(&b,diemsg);
+      if (buffer_putsflush(&b,"\r\n") == -1)
+        strerr_die2sys(111,DROP,"unable to print diemsg: ");
+    }
+    sleep(1);
+    _exit(100);
+  }
 }
 
 
@@ -253,7 +407,6 @@
   _exit(100);
 }
 
-unsigned long limit = 40;
 unsigned long numchildren = 0;
 
 int flag1 = 0;
@@ -278,6 +431,7 @@
 {
   int wstat;
   int pid;
+  unsigned long u;
  
   while ((pid = wait_nohang(&wstat)) > 0) {
     if (verbosity >= 2) {
@@ -286,6 +440,8 @@
       strerr_warn4("tcpserver: end ",strnum," status ",strnum2,0);
     }
     if (numchildren) --numchildren; printstatus();
+    for (u=0; u < limit; u++) if (child[u].pid == pid) { child[u].pid = 0; break; }
+    if (u == limit) strerr_die1x(111,"tcpserver: ERROR: dead child not found?!"); /* never happens */
   }
 }
 
@@ -299,6 +455,7 @@
   unsigned long u;
   int s;
   int t;
+  pid_t pid;
  
   while ((opt = getopt(argc,argv,"dDvqQhHrR1UXx:t:u:g:l:b:B:c:pPoO")) != opteof)
     switch(opt) {
@@ -332,6 +489,14 @@
   argc -= optind;
   argv += optind;
 
+  x = env_get("MAXLOAD"); if (x) scan_ulong(x,&maxload);
+  x = env_get("MAXCONNIP"); if (x) scan_ulong(x,&maxconnip);
+  x = env_get("MAXCONNC"); if (x) scan_ulong(x,&maxconnc);
+  x = env_get("DIEMSG"); if (x) diemsg = x;
+  x = env_get("DIEMSG_MAXLOAD"); if (x) diemsg2 = x;
+  x = env_get("DIEMSG_MAXCONNIP"); if (x) diemsg3 = x;
+  x = env_get("DIEMSG_MAXCONNC"); if (x) diemsg4 = x;
+  
   if (!verbosity)
     buffer_2->fd = -1;
  
@@ -352,6 +517,10 @@
   }
 
   if (!*argv) usage();
+  
+  child = calloc(sizeof(baby),limit);
+  if (!child)
+    strerr_die2x(111,FATAL,"out of memory for MAXCONNIP tracking");
  
   sig_block(sig_child);
   sig_catch(sig_child,sigchld);
@@ -393,6 +562,9 @@
  
   close(0);
   close(1);
+  #ifdef SOLARIS
+  kc = kstat_open();
+  #endif  
   printstatus();
  
   for (;;) {
@@ -405,7 +577,7 @@
     if (t == -1) continue;
     ++numchildren; printstatus();
  
-    switch(fork()) {
+    switch(pid=fork()) {
       case 0:
         close(s);
         doit(t);
@@ -420,6 +592,10 @@
       case -1:
         strerr_warn2(DROP,"unable to fork: ",&strerr_sys);
         --numchildren; printstatus();
+        break;
+      default:
+        for (u=0; u < limit; u++) if (child[u].pid == 0) { byte_copy(child[u].ip,4,remoteip); child[u].pid = pid; break; }
+	if (u == limit) strerr_die1x(111,"tcpserver: ERROR: no empty space for new child?!"); /* never happens */
     }
     close(t);
   }
ucspi-tcp-ssl-20050405.patch (application/octet-stream, 47 KB)
Index: FILES
===================================================================
RCS file: /usr/home/cvs-djbware/CVS/ucspi-tcp/FILES,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -p -r1.1.1.1 -r1.2
--- FILES	14 Jun 2002 08:47:30 -0000	1.1.1.1
+++ FILES	5 Apr 2004 15:34:57 -0000	1.2
@@ -216,3 +216,19 @@ wait_pid.c
 warn-auto.sh
 warn-shsgr
 x86cpuid.c
+addcr.1
+argv0.1
[email protected]
+delcr.1
[email protected]
+fixcrio.1
[email protected]
+mconnect.1
+recordio.1
+tcpcat.1
+tcpclient.1
+tcprules.1
+tcprulescheck.1
+tcpserver.1
[email protected]
+tcp-environ.5
Index: Makefile
===================================================================
RCS file: /usr/home/cvs-djbware/CVS/ucspi-tcp/Makefile,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -u -p -r1.1.1.1 -r1.3
--- Makefile	14 Jun 2002 08:47:30 -0000	1.1.1.1
+++ Makefile	5 Apr 2004 15:34:57 -0000	1.3
@@ -1,13 +1,25 @@
 # Don't edit Makefile! Use conf-* for configuration.
 
+DEFINES=-DWITH_SSL
+#add -DWITH_SSL to enable ssl support
+
+# LIBS for additional libraries and INCS for additional includes
+LIBS=-lcrypto -lssl
+#INCS=-I/usr/local/include
+OPENSSLBIN=openssl
+
 SHELL=/bin/sh
 
-default: it
+default: it man
 
 addcr: \
 load addcr.o unix.a byte.a
 	./load addcr unix.a byte.a 
 
+addcr.0: \
+addcr.1
+	nroff -man addcr.1 > addcr.0
+
 addcr.o: \
 compile addcr.c buffer.h exit.h
 	./compile addcr.c
@@ -24,6 +36,10 @@ argv0: \
 load argv0.o unix.a byte.a
 	./load argv0 unix.a byte.a 
 
+argv0.0: \
+argv0.1
+	nroff -man argv0.1 > argv0.0
+
 argv0.o: \
 compile argv0.c pathexec.h strerr.h
 	./compile argv0.c
@@ -151,6 +167,10 @@ warn-auto.sh choose.sh conf-home
 	> choose
 	chmod 755 choose
 
+clean: \
+TARGETS
+	rm -f `cat TARGETS`
+
 commands.o: \
 compile commands.c buffer.h stralloc.h gen_alloc.h str.h case.h \
 commands.h
@@ -170,10 +190,18 @@ warn-auto.sh [email protected] conf-home
 	> date@
 	chmod 755 date@
 
[email protected]: \
[email protected]
+	nroff -man [email protected] > [email protected]
+
 delcr: \
 load delcr.o unix.a byte.a
 	./load delcr unix.a byte.a 
 
+delcr.0: \
+delcr.1
+	nroff -man delcr.1 > delcr.0
+
 delcr.o: \
 compile delcr.c buffer.h exit.h
 	./compile delcr.c
@@ -292,10 +320,18 @@ warn-auto.sh [email protected] conf-home
 	> finger@
 	chmod 755 finger@
 
[email protected]: \
[email protected]
+	nroff -man [email protected] > [email protected]
+
 fixcrio: \
 load fixcrio.o time.a unix.a byte.a
 	./load fixcrio time.a unix.a byte.a 
 
+fixcrio.0: \
+fixcrio.1
+	nroff -man fixcrio.1 > fixcrio.0
+
 fixcrio.o: \
 compile fixcrio.c sig.h buffer.h strerr.h byte.h readwrite.h exit.h \
 iopause.h taia.h tai.h uint64.h pathexec.h
@@ -346,6 +382,10 @@ warn-auto.sh [email protected] conf-home
 	> http@
 	chmod 755 http@
 
[email protected]: \
[email protected]
+	nroff -man [email protected] > [email protected]
+
 install: \
 load install.o hier.o auto_home.o unix.a byte.a
 	./load install hier.o auto_home.o unix.a byte.a 
@@ -409,6 +449,11 @@ warn-auto.sh systype
 	) > makelib
 	chmod 755 makelib
 
+man: \
+tcpclient.0 tcpserver.0 tcprules.0 tcprulescheck.0 tcp-environ.0 \
[email protected] [email protected] [email protected] [email protected] tcpcat.0 mconnect.0 fixcrio.0 addcr.0 \
+delcr.0 argv0.0 recordio.0
+
 mconnect: \
 warn-auto.sh mconnect.sh conf-home
 	cat warn-auto.sh mconnect.sh \
@@ -425,6 +470,10 @@ compile mconnect-io.c sig.h wait.h fork.
 readwrite.h exit.h
 	./compile mconnect-io.c
 
+mconnect.0: \
+mconnect.1
+	nroff -man mconnect.1 > mconnect.0
+
 ndelay_off.o: \
 compile ndelay_off.c ndelay.h
 	./compile ndelay_off.c
@@ -495,6 +544,10 @@ compile recordio.c sig.h buffer.h strerr
 exit.h fmt.h iopause.h taia.h tai.h uint64.h pathexec.h
 	./compile recordio.c
 
+recordio.0: \
+recordio.1
+	nroff -man recordio.1 > recordio.0
+
 remoteinfo.o: \
 compile remoteinfo.c fmt.h buffer.h socket.h uint16.h error.h \
 iopause.h taia.h tai.h uint64.h timeoutconn.h uint16.h remoteinfo.h \
@@ -702,6 +755,10 @@ taia_uint.o: \
 compile taia_uint.c taia.h tai.h uint64.h
 	./compile taia_uint.c
 
+tcp-environ.0: \
+tcp-environ.5
+	nroff -man tcp-environ.5 > tcp-environ.0
+
 tcpcat: \
 warn-auto.sh tcpcat.sh conf-home
 	cat warn-auto.sh tcpcat.sh \
@@ -709,12 +766,20 @@ warn-auto.sh tcpcat.sh conf-home
 	> tcpcat
 	chmod 755 tcpcat
 
+tcpcat.0: \
+tcpcat.1
+	nroff -man tcpcat.1 > tcpcat.0
+
 tcpclient: \
 load tcpclient.o remoteinfo.o timeoutconn.o dns.a time.a unix.a \
 byte.a socket.lib
 	./load tcpclient remoteinfo.o timeoutconn.o dns.a time.a \
 	unix.a byte.a  `cat socket.lib`
 
+tcpclient.0: \
+tcpclient.1
+	nroff -man tcpclient.1 > tcpclient.0
+
 tcpclient.o: \
 compile tcpclient.c sig.h exit.h sgetopt.h subgetopt.h uint16.h fmt.h \
 scan.h str.h ip4.h uint16.h socket.h uint16.h fd.h stralloc.h \
@@ -727,6 +792,10 @@ tcprules: \
 load tcprules.o cdb.a unix.a byte.a
 	./load tcprules cdb.a unix.a byte.a 
 
+tcprules.0: \
+tcprules.1
+	nroff -man tcprules.1 > tcprules.0
+
 tcprules.o: \
 compile tcprules.c strerr.h stralloc.h gen_alloc.h getln.h buffer.h \
 stralloc.h buffer.h exit.h fmt.h byte.h cdb_make.h buffer.h uint32.h
@@ -736,6 +805,10 @@ tcprulescheck: \
 load tcprulescheck.o rules.o cdb.a unix.a byte.a
 	./load tcprulescheck rules.o cdb.a unix.a byte.a 
 
+tcprulescheck.0: \
+tcprulescheck.1
+	nroff -man tcprulescheck.1 > tcprulescheck.0
+
 tcprulescheck.o: \
 compile tcprulescheck.c byte.h buffer.h strerr.h env.h rules.h \
 stralloc.h gen_alloc.h
@@ -745,7 +818,11 @@ tcpserver: \
 load tcpserver.o rules.o remoteinfo.o timeoutconn.o cdb.a dns.a \
 time.a unix.a byte.a socket.lib
 	./load tcpserver rules.o remoteinfo.o timeoutconn.o cdb.a \
-	dns.a time.a unix.a byte.a  `cat socket.lib`
+	dns.a time.a unix.a byte.a  $(LIBS) `cat socket.lib`
+
+tcpserver.0: \
+tcpserver.1
+	nroff -man tcpserver.1 > tcpserver.0
 
 tcpserver.o: \
 compile tcpserver.c uint16.h str.h byte.h fmt.h scan.h ip4.h fd.h \
@@ -754,7 +831,7 @@ alloc.h buffer.h error.h strerr.h sgetop
 socket.h uint16.h ndelay.h remoteinfo.h stralloc.h uint16.h rules.h \
 stralloc.h sig.h dns.h stralloc.h iopause.h taia.h tai.h uint64.h \
 taia.h
-	./compile tcpserver.c
+	./compile $(DEFINES) $(INCS) tcpserver.c
 
 time.a: \
 makelib iopause.o tai_pack.o taia_add.o taia_approx.o taia_frac.o \
@@ -835,3 +912,22 @@ warn-auto.sh [email protected] conf-home
 	| sed s}HOME}"`head -1 conf-home`"}g \
 	> who@
 	chmod 755 who@
+
[email protected]: \
[email protected]
+	nroff -man [email protected] > [email protected]
+
+cert:
+	${OPENSSLBIN} req -new -x509 -nodes \
+	-out cert.pem -days 366 \
+	-keyout cert.pem
+
+cert-req:
+	${OPENSSLBIN} req -new -nodes \
+	-out req.pem \
+	-keyout cert.pem
+	@echo
+	@echo "Send req.pem to your CA to obtain signed_req.pem, and do:"
+	@echo "cat signed_req.pem >> `head -1 conf-qmail`/control/cert.pem"
+
+
Index: TARGETS
===================================================================
RCS file: /usr/home/cvs-djbware/CVS/ucspi-tcp/TARGETS,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -p -r1.1.1.1 -r1.2
--- TARGETS	14 Jun 2002 08:47:30 -0000	1.1.1.1
+++ TARGETS	5 Apr 2004 15:34:57 -0000	1.2
@@ -169,3 +169,19 @@ instcheck
 it
 setup
 check
+addcr.0
+argv0.0
[email protected]
+delcr.0
[email protected]
+fixcrio.0
[email protected]
+mconnect.0
+recordio.0
+tcp-environ.0
+tcpcat.0
+tcpclient.0
+tcprules.0
+tcprulescheck.0
+tcpserver.0
[email protected]
Index: addcr.1
===================================================================
RCS file: addcr.1
diff -N addcr.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ addcr.1	5 Apr 2004 15:34:57 -0000	1.1
@@ -0,0 +1,22 @@
+.TH addcr 1
+.SH NAME
+addcr \- add a CR before each LF
+.SH SYNOPSIS
+.B addcr 
+.SH DESCRIPTION
+.B addcr
+inserts CR at the end of each line of input.
+It does not insert CR at the end of a partial final line.
+.SH COMPATIBILITY
+Some vendors ship
+.B unix2dos
+or
+.B bsd2dos
+tools similar to
+.BR addcr .
+Those tools often blow up on long lines and nulls.
+.B addcr
+has no trouble with long lines and nulls.
+.SH "SEE ALSO"
+delcr(1),
+fixcrio(1)
Index: argv0.1
===================================================================
RCS file: argv0.1
diff -N argv0.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ argv0.1	5 Apr 2004 15:34:57 -0000	1.1
@@ -0,0 +1,47 @@
+.TH argv0 1
+.SH NAME
+argv0 \- run a program with a specified 0th argument
+.SH SYNOPSIS
+.B argv0
+.I realname
+.I zero
+[
+.I arg ...
+]
+.SH DESCRIPTION
+.B argv0
+runs
+the program stored as
+.I realname
+on disk,
+with the given
+arguments.
+It sets the 0th argument of
+the program to
+.IR zero .
+
+For example,
+
+.EX
+     argv0 /bin/csh -bin/csh
+.EE
+
+runs
+.B /bin/csh
+with a 0th argument of
+.BR -bin/csh .
+.B csh
+will think it is a login shell
+and behave accordingly.
+
+.B argv0
+can be used to run some
+.B inetd
+wrappers under
+.BR tcpserver .
+.SH "SEE ALSO"
+csh(1),
+tcpserver(1),
+execve(2),
+execvp(3),
+inetd(8)
Index: [email protected]
===================================================================
RCS file: [email protected]
diff -N [email protected]
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ [email protected]	5 Apr 2004 15:34:57 -0000	1.1
@@ -0,0 +1,32 @@
+.TH date@ 1
+.SH NAME
+date@ \- print the date on a host
+.SH SYNTAX
+.B date@
+[
+.I host
+]
+.SH DESCRIPTION
+.B date@
+connects to TCP port 13 (Daytime) on
+.I host
+and prints any data it receives.
+It removes CR and converts unprintable characters to a visible format.
+
+If
+.I host
+is not supplied,
+.B date@
+connects to the local host.
+
+Some computers respond to port 13 with a human-readable date.
+For example, they may be running
+
+.EX
+     tcpserver 0 13 date &
+.EE
+.SH "SEE ALSO"
+cat(1),
+delcr(1),
+tcpclient(1),
+tcpserver(1)
Index: delcr.1
===================================================================
RCS file: delcr.1
diff -N delcr.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ delcr.1	5 Apr 2004 15:34:57 -0000	1.1
@@ -0,0 +1,30 @@
+.TH delcr 1
+.SH NAME
+delcr \- remove a CR before each LF
+.SH SYNOPSIS
+.B delcr
+.SH DESCRIPTION
+.B delcr
+removes a CR at the end of each line of input,
+if a CR is present.
+It also removes a CR at the end of a partial final line.
+
+The pipeline
+
+.EX
+     addcr | delcr
+.EE
+
+prints an exact copy of its input.
+.SH COMPATIBILITY
+Some vendors ship
+.B dos2unix
+or
+.B dos2bsd
+tools similar to
+.BR delcr .
+Those tools often blow up on long lines and nulls.
+.B delcr
+has no trouble with long lines and nulls.
+.SH "SEE ALSO"
+addcr(1)
Index: error.h
===================================================================
RCS file: /usr/home/cvs-djbware/CVS/ucspi-tcp/error.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -p -r1.1.1.1 -r1.2
--- error.h	14 Jun 2002 08:47:31 -0000	1.1.1.1
+++ error.h	6 Nov 2003 09:47:05 -0000	1.2
@@ -1,7 +1,7 @@
 #ifndef ERROR_H
 #define ERROR_H
 
-extern int errno;
+#include <errno.h>
 
 extern int error_intr;
 extern int error_nomem;
Index: [email protected]
===================================================================
RCS file: [email protected]
diff -N [email protected]
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ [email protected]	5 Apr 2004 15:34:57 -0000	1.1
@@ -0,0 +1,45 @@
+.TH finger@ 1
+.SH NAME
+finger@ \- get user information from a host
+.SH SYNTAX
+.B finger@
+[
+.I host
+[
+.I user
+]
+]
+.SH DESCRIPTION
+.B finger@
+connects to TCP port 79 (Finger) on
+.IR host ,
+sends
+.I user
+(with an extra CR)
+to
+.IR host ,
+and prints any data it receives.
+It removes CR and converts unprintable characters to a visible format.
+Some computers respond to port 79 with information about
+.IR user .
+
+If
+.I user
+is not supplied,
+.B finger@
+sends a blank line to
+.IR host .
+Some computers respond with information about
+all the users who are logged in.
+
+If
+.I host
+is not supplied,
+.B finger@
+connects to the local host.
+.SH "SEE ALSO"
+addcr(1),
+cat(1),
+delcr(1),
+finger(1),
+tcpclient(1)
Index: fixcrio.1
===================================================================
RCS file: fixcrio.1
diff -N fixcrio.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ fixcrio.1	5 Apr 2004 15:34:57 -0000	1.1
@@ -0,0 +1,15 @@
+.TH fixcrio 1
+.SH NAME
+fixcrio \- make sure that there is a CR before each LF
+.SH SYNOPSIS
+.B fixcrio
+.I program
+[
+.I arg ...
+]
+.SH DESCRIPTION
+.B fixcrio
+inserts CR at the end of each line of input where a CR is not already present.
+It does not insert CR at the end of a partial final line.
+.SH "SEE ALSO"
+addcr(1)
Index: hier.c
===================================================================
RCS file: /usr/home/cvs-djbware/CVS/ucspi-tcp/hier.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -p -r1.1.1.1 -r1.2
--- hier.c	14 Jun 2002 08:47:32 -0000	1.1.1.1
+++ hier.c	5 Apr 2004 15:34:57 -0000	1.2
@@ -2,8 +2,13 @@
 
 void hier()
 {
-  h(auto_home,-1,-1,02755);
-  d(auto_home,"bin",-1,-1,02755);
+  h(auto_home,-1,-1,0755);
+  d(auto_home,"bin",-1,-1,0755);
+  d(auto_home,"man",-1,-1,0755);
+  d(auto_home,"man/man1",-1,-1,0755);
+  d(auto_home,"man/man5",-1,-1,0755);
+  d(auto_home,"man/cat1",-1,-1,0755);
+  d(auto_home,"man/cat5",-1,-1,0755);
 
   c(auto_home,"bin","tcpserver",-1,-1,0755);
   c(auto_home,"bin","tcprules",-1,-1,0755);
@@ -22,4 +27,37 @@ void hier()
   c(auto_home,"bin","delcr",-1,-1,0755);
   c(auto_home,"bin","fixcrio",-1,-1,0755);
   c(auto_home,"bin","rblsmtpd",-1,-1,0755);
+
+  c(auto_home,"man/man1","addcr.1",-1,-1,0644);
+  c(auto_home,"man/cat1","addcr.0",-1,-1,0644);
+  c(auto_home,"man/man1","argv0.1",-1,-1,0644);
+  c(auto_home,"man/cat1","argv0.0",-1,-1,0644);
+  c(auto_home,"man/man1","[email protected]",-1,-1,0644);
+  c(auto_home,"man/cat1","[email protected]",-1,-1,0644);
+  c(auto_home,"man/man1","delcr.1",-1,-1,0644);
+  c(auto_home,"man/cat1","delcr.0",-1,-1,0644);
+  c(auto_home,"man/man1","[email protected]",-1,-1,0644);
+  c(auto_home,"man/cat1","[email protected]",-1,-1,0644);
+  c(auto_home,"man/man1","fixcrio.1",-1,-1,0644);
+  c(auto_home,"man/cat1","fixcrio.0",-1,-1,0644);
+  c(auto_home,"man/man1","[email protected]",-1,-1,0644);
+  c(auto_home,"man/cat1","[email protected]",-1,-1,0644);
+  c(auto_home,"man/man1","mconnect.1",-1,-1,0644);
+  c(auto_home,"man/cat1","mconnect.0",-1,-1,0644);
+  c(auto_home,"man/man1","recordio.1",-1,-1,0644);
+  c(auto_home,"man/cat1","recordio.0",-1,-1,0644);
+  c(auto_home,"man/man1","tcpcat.1",-1,-1,0644);
+  c(auto_home,"man/cat1","tcpcat.0",-1,-1,0644);
+  c(auto_home,"man/man1","tcpclient.1",-1,-1,0644);
+  c(auto_home,"man/cat1","tcpclient.0",-1,-1,0644);
+  c(auto_home,"man/man1","tcprules.1",-1,-1,0644);
+  c(auto_home,"man/cat1","tcprules.0",-1,-1,0644);
+  c(auto_home,"man/man1","tcprulescheck.1",-1,-1,0644);
+  c(auto_home,"man/cat1","tcprulescheck.0",-1,-1,0644);
+  c(auto_home,"man/man1","tcpserver.1",-1,-1,0644);
+  c(auto_home,"man/cat1","tcpserver.0",-1,-1,0644);
+  c(auto_home,"man/man1","[email protected]",-1,-1,0644);
+  c(auto_home,"man/cat1","[email protected]",-1,-1,0644);
+  c(auto_home,"man/man5","tcp-environ.5",-1,-1,0644);
+  c(auto_home,"man/cat5","tcp-environ.0",-1,-1,0644);
 }
Index: [email protected]
===================================================================
RCS file: [email protected]
diff -N [email protected]
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ [email protected]	5 Apr 2004 15:34:57 -0000	1.1
@@ -0,0 +1,52 @@
+.TH http@ 1
+.SH NAME
+http@ \- get a web page from a host through HTTP
+.SH SYNTAX
+.B http@
+[
+.I host
+[
+.I page
+[
+.I port
+]
+]
+]
+.SH DESCRIPTION
+.B http@
+connects to
+.I port
+on
+.IR host ,
+sends
+.B GET /\fIpage
+(with an extra CR)
+to
+.IR host ,
+and prints any data it receives,
+removing CR from the end of each line.
+
+If
+.I port
+is not supplied,
+.B http@
+uses port 80 (HTTP).
+
+If
+.I page
+is not supplied,
+.B http@
+sends
+.B GET /
+to
+.IR host .
+
+If
+.I host
+is not supplied,
+.B http@
+connects to the local host.
+.SH "SEE ALSO"
+addcr(1),
+delcr(1),
+tcpclient(1)
Index: mconnect.1
===================================================================
RCS file: mconnect.1
diff -N mconnect.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ mconnect.1	5 Apr 2004 15:34:57 -0000	1.1
@@ -0,0 +1,36 @@
+.TH mconnect 1
+.SH NAME
+mconnect \- connect to the SMTP server on a host
+.SH SYNTAX
+.B mconnect
+[
+.I host
+[
+.I port
+]
+]
+.SH DESCRIPTION
+.B mconnect
+connects to
+.I port
+on
+.IR host .
+It sends its input to
+.IR host ,
+adding a CR to each line.
+Meanwhile it prints anything it receives from
+.IR host .
+
+If
+.I port
+is not supplied,
+.B mconnect
+uses port 25 (SMTP).
+
+If
+.I host
+is not supplied,
+.B mconnect
+connects to the local host.
+.SH "SEE ALSO"
+tcpclient(1)
Index: recordio.1
===================================================================
RCS file: recordio.1
diff -N recordio.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ recordio.1	5 Apr 2004 15:34:57 -0000	1.1
@@ -0,0 +1,75 @@
+.TH recordio 1
+.SH NAME
+recordio \- record the input and output of a program
+.SH SYNTAX
+.B recordio
+.I program
+[
+.I arg ...
+]
+.SH DESCRIPTION
+.B recordio
+runs
+.I program
+with the given arguments.
+It prints lines to stderr
+showing the input and output of
+.IR program .
+
+At the beginning of each line on stderr,
+.B recordio
+inserts the
+.I program
+process ID,
+along with
+.B <
+for input or
+.B >
+for output.
+At the end of each line it inserts a space, a plus sign, or [EOF];
+a space indicates that there was a newline in the input or output,
+and [EOF] indicates the end of input or output.
+
+.B recordio
+prints every packet of input and output immediately.
+It does not attempt to combine packets into coherent stderr lines.
+For example,
+
+.EX
+     recordio sh -c 'cat /dev/fd/8 2>&1' > /dev/null
+.EE
+
+could produce
+
+.EX
+     5135 > cat: /dev/fd/8: Bad file descriptor 
+.br
+     5135 > [EOF]
+.EE
+
+or
+
+.EX
+     5135 > cat: +
+.br
+     5135 > /dev/fd/8+
+.br
+     5135 > : +
+.br
+     5135 > Bad file descriptor 
+.br
+     5135 > [EOF]
+.EE
+
+.B recordio
+uses several lines for long packets
+to guarantee that each line is printed atomically to stderr.
+
+.B recordio
+runs as a child of
+.IR program .
+It exits when it sees the end of
+.IR program 's
+output.
+.SH "SEE ALSO"
+tcpserver(1)
Index: tcp-environ.5
===================================================================
RCS file: tcp-environ.5
diff -N tcp-environ.5
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tcp-environ.5	5 Apr 2004 15:34:57 -0000	1.1
@@ -0,0 +1,62 @@
+.TH tcp-environ 5
+.SH NAME
+tcp-environ \- TCP-related environment variables
+.SH DESCRIPTION
+The following environment variables
+describe a TCP connection.
+They are set up by
+.BR tcp-env ,
+.BR tcpclient ,
+and
+.BR tcpserver .
+Note that
+.BR TCPLOCALHOST ,
+.BR TCPREMOTEHOST ,
+and
+.B TCPREMOTEINFO
+can contain arbitrary characters.
+.TP 5
+PROTO
+The string
+.BR TCP .
+.TP 5
+TCPLOCALHOST
+The domain name of the local host,
+with uppercase letters converted to lowercase.
+If there is no currently available domain name
+for the local IP address,
+.B TCPLOCALHOST
+is not set.
+.TP 5
+TCPLOCALIP
+The IP address of the local host, in dotted-decimal form.
+.TP 5
+TCPLOCALPORT
+The local TCP port number, in decimal.
+.TP 5
+TCPREMOTEHOST
+The domain name of the remote host,
+with uppercase letters converted to lowercase.
+If there is no currently available domain name
+for the remote IP address,
+.B TCPREMOTEHOST
+is not set.
+.TP 5
+TCPREMOTEINFO
+A connection-specific string, perhaps a username,
+supplied by the remote host
+via 931/1413/IDENT/TAP.
+If the remote host did not supply connection information,
+.B TCPREMOTEINFO
+is not set.
+.TP 5
+TCPREMOTEIP
+The IP address of the remote host.
+.TP 5
+TCPREMOTEPORT
+The remote TCP port number.
+.SH "SEE ALSO"
+tcpclient(1),
+tcpserver(1),
+tcp-env(1),
+tcp(4)
Index: tcpcat.1
===================================================================
RCS file: tcpcat.1
diff -N tcpcat.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tcpcat.1	5 Apr 2004 15:34:57 -0000	1.1
@@ -0,0 +1,20 @@
+.TH tcpcat 1
+.SH NAME
+tcpcat \- print data from a TCP port
+.SH SYNTAX
+.B tcpcat
+.I host
+.I port
+.SH DESCRIPTION
+.B tcpcat
+connects to
+.I port
+on
+.I host
+and prints any data it receives.
+
+.B tcpcat
+can be used to transfer binary data.
+It does no conversions.
+.SH "SEE ALSO"
+tcpclient(1)
Index: tcpclient.1
===================================================================
RCS file: tcpclient.1
diff -N tcpclient.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tcpclient.1	5 Apr 2004 15:34:57 -0000	1.1
@@ -0,0 +1,151 @@
+.TH tcpclient 1
+.SH NAME
+tcpclient \- create an outgoing TCP connection
+.SH SYNOPSIS
+.B tcpclient
+[
+.B \-hHrRdDqQv
+]
+[
+.B \-i\fIlocalip
+]
+[
+.B \-p\fIlocalport
+]
+[
+.B \-T\fItimeoutconn
+]
+[
+.B \-l\fIlocalname
+]
+[
+.B \-t\fItimeoutinfo
+]
+.I host
+.I port
+.I program
+[
+.I arg ...
+]
+.SH DESCRIPTION
+.B tcpclient
+attempts to connect to a TCP server.
+If it is successful, it runs
+.I program
+with the given arguments,
+with descriptor 6 reading from the network
+and descriptor 7 writing to the network.
+
+The server's address is given by
+.I host
+and
+.IR port .
+.I host
+may be 0, referring to the local machine,
+or a dotted-decimal IP address,
+or a host name;
+if a host has several IP addresses,
+.B tcpclient
+tries each in turn.
+.I port
+may be a numeric port number
+or a port name.
+
+.B tcpclient
+sets up several environment variables,
+as described in
+.B tcp-environ(5).
+.SH OPTIONS
+.TP
+.B \-i\fIlocalip
+Use
+.I localip
+as the IP address for the local side of the connection;
+quit if
+.I localip
+is not available.
+.TP
+.B \-p\fIlocalport
+Use
+.I localport
+as the port number for the local side of the connection;
+quit if
+.I localport
+is not available.
+.TP
+.B \-T\fItimeoutconn
+Give up on the
+connection attempt
+after
+.I timeoutconn
+seconds. Default: 60.
+This timeout applies to each IP address tried.
+.TP
+.B \-d
+(Default.)
+Delay sending data for a fraction of a second whenever the
+remote host is responding slowly,
+to make better use of the network.
+.TP
+.B \-D
+Never delay sending data;
+enable TCP_NODELAY.
+This is appropriate for interactive connections.
+.TP
+.B \-q
+Quiet.
+Do not print any messages.
+.TP
+.B \-Q
+(Default.)
+Print error messages.
+.TP
+.B \-v
+Verbose.
+Print all available messages.
+.SH "DATA-GATHERING OPTIONS"
+.TP
+.B \-h
+(Default.)
+Look up the remote host name for
+.BR TCPREMOTEHOST .
+.TP
+.B \-H
+Do not look up the remote host name;
+unset
+.BR TCPREMOTEHOST .
+.TP
+.B \-l\fIlocalname
+Do not look up the local host name;
+use
+.I localname
+for
+.BR TCPLOCALHOST .
+.TP
+.B \-r
+(Default.)
+Attempt to obtain
+.B TCPREMOTEINFO
+from the remote host.
+.TP
+.B \-R
+Do not attempt to obtain
+.B TCPREMOTEINFO
+from the remote host.
+.TP
+.B \-t\fItimeoutinfo
+Give up on the 
+.B TCPREMOTEINFO
+connection attempt
+after
+.I timeoutinfo
+seconds. Default: 26.
+.SH "SEE ALSO"
+date@(1),
+finger@(1),
+http@(1),
+mconnect(1),
+tcpcat(1),
+tcpserver(1),
+who@(1),
+tcp-environ(5)
Index: tcprules.1
===================================================================
RCS file: tcprules.1
diff -N tcprules.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tcprules.1	5 Apr 2004 15:34:57 -0000	1.1
@@ -0,0 +1,208 @@
+.TH tcprules 1
+.SH NAME
+tcprules \- compile rules for tcpserver
+.SH SYNOPSIS
+.B tcprules
+.I rules.cdb
+.I rules.tmp
+.SH OVERVIEW
+.B tcpserver
+optionally follows rules to decide whether a TCP connection is acceptable.
+For example, a rule of
+
+.EX
+   18.23.0.32:deny
+.EE
+
+prohibits connections from IP address 18.23.0.32.
+
+.B tcprules
+reads rules from its standard input
+and writes them into
+.I rules.cdb
+in a binary format suited
+for quick access by
+.BR tcpserver .
+
+.B tcprules
+can be used while
+.B tcpserver
+is running:
+it ensures that
+.I rules.cdb
+is updated atomically.
+It does this by first writing the rules to
+.I rules.tmp
+and then moving
+.I rules.tmp
+on top of
+.IR rules.cdb .
+If
+.I rules.tmp
+already exists, it is destroyed.
+The directories containing
+.I rules.cdb
+and
+.I rules.tmp
+must be writable to
+.BR tcprules ;
+they must also be on the same filesystem.
+
+If there is a problem with the input,
+.B tcprules
+complains and leaves
+.I rules.cdb
+alone.
+
+The binary
+.I rules.cdb
+format is portable across machines.
+.SH "RULE FORMAT"
+A rule takes up one line.
+A file containing rules
+may also contain comments: lines beginning with # are ignored.
+
+Each rule contains an
+.BR address ,
+a colon,
+and a list of
+.BR instructions ,
+with no extra spaces.
+When
+.B tcpserver
+receives a connection from that address,
+it follows the instructions.
+.SH "ADDRESSES"
+.B tcpserver
+starts by looking for a rule with address
+.IR TCPREMOTEINFO\fB@\fITCPREMOTEIP .
+If it doesn't find one, or if
+.I TCPREMOTEINFO
+is not set, it tries the address
+.IR TCPREMOTEIP .
+If that doesn't work, it tries shorter and shorter prefixes of
+.I TCPREMOTEIP
+ending with a dot.
+If none of them work, it tries the empty string.
+
+For example, here are some rules:
+
+.EX
+   [email protected]:first
+.br
+   18.23.0.32:second
+.br
+   127.:third
+.br
+   :fourth
+.EE
+
+If
+.I TCPREMOTEIP
+is
+.BR 10.119.75.38 ,
+.B tcpserver
+will follow the
+.B fourth
+instructions.
+
+If
+.I TCPREMOTEIP
+is
+.BR 18.23.0.32 ,
+.B tcpserver
+will follow the
+.B second
+instructions.
+
+If
+.I TCPREMOTEINFO
+is
+.B bill
+and
+.I TCPREMOTEIP
+is
+.BR 127.0.0.1 ,
+.B tcpserver
+will follow the
+.B third
+instructions.
+
+If
+.I TCPREMOTEINFO
+is
+.B joe
+and
+.I TCPREMOTEIP
+is
+.BR 127.0.0.1 ,
+.B tcpserver
+will follow the
+.B first
+instructions.
+.SH "ADDRESS RANGES"
+.B tcprules
+treats
+.B 1.2.3.37-53:ins
+as an abbreviation
+for the rules
+.BR 1.2.3.37:ins ,
+.BR 1.2.3.38:ins ,
+and so on up through
+.BR 1.2.3.53:ins .
+Similarly,
+.BR 10.2-3.:ins
+is an abbreviation for
+.B 10.2.:ins
+and
+.BR 10.3.:ins .
+.SH "INSTRUCTIONS"
+The instructions in a rule must begin with either
+.B allow
+or
+.BR deny .
+.B deny
+tells
+.B tcpserver
+to drop the connection without running anything.
+For example, the rule
+
+.EX
+   :deny
+.EE
+
+tells
+.B tcpserver
+to drop all connections that aren't handled by more specific rules.
+
+The instructions may continue with some environment variables,
+in the format
+.IR ,VAR="VALUE" .
+.B tcpserver
+adds
+.I VAR=VALUE
+to the current environment.
+For example,
+
+.EX
+   10.0.:allow,RELAYCLIENT="@fix.me"
+.EE
+
+adds
+.B [email protected]
+to the environment.
+The quotes here may be replaced by any repeated character:
+
+.EX
+   10.0.:allow,RELAYCLIENT=/@fix.me/
+.EE
+
+Any number of variables may be listed:
+
+.EX
+   127.0.0.1:allow,RELAYCLIENT="",TCPLOCALHOST="movie.edu"
+.EE
+.SH "SEE ALSO"
+tcprulescheck(1),
+tcpserver(1),
+tcp-environ(5)
Index: tcprules.c
===================================================================
RCS file: /usr/home/cvs-djbware/CVS/ucspi-tcp/tcprules.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -p -r1.1.1.1 -r1.2
--- tcprules.c	14 Jun 2002 08:47:30 -0000	1.1.1.1
+++ tcprules.c	16 Mar 2004 15:12:26 -0000	1.2
@@ -94,6 +94,7 @@ main(int argc,char **argv)
   int len;
   int fd;
   int i;
+  int e;
   char ch;
 
   fn = argv[1];
@@ -144,8 +145,16 @@ main(int argc,char **argv)
     while (len)
       switch(*x) {
         case ',':
+	  e = byte_chr(x + 1,len - 1,',');
           i = byte_chr(x,len,'=');
-          if (i == len) die_bad();
+          if (i > e) {
+	    if (e < 2 || x[1] != '!') die_bad();
+	    if (!stralloc_catb(&data,"-",1)) nomem();
+	    if (!stralloc_catb(&data,x + 2,e - 1)) nomem();
+	    if (!stralloc_0(&data)) nomem();
+	    x += e + 1; len -= e + 1;
+	    break;
+	  }
           if (!stralloc_catb(&data,"+",1)) nomem();
           if (!stralloc_catb(&data,x + 1,i)) nomem();
           x += i + 1; len -= i + 1;
Index: tcprulescheck.1
===================================================================
RCS file: tcprulescheck.1
diff -N tcprulescheck.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tcprulescheck.1	5 Apr 2004 15:34:57 -0000	1.1
@@ -0,0 +1,25 @@
+.TH tcprulescheck 1
+.SH NAME
+tcprulescheck \- try out rules for tcpserver
+.SH SYNTAX
+.B tcprulescheck
+.I rules.cdb
+.I tcpremoteip
+[
+.I tcpremoteinfo
+]
+.SH DESCRIPTION
+.B tcprulescheck
+says what
+.B tcpserver
+will do with a connection from
+IP address
+.IR tcpremoteip ,
+following the rules compiled into
+.I rules.cdb
+by
+.BR tcprules .
+.SH "SEE ALSO"
+tcprules(1),
+tcpserver(1),
+tcp-environ(5)
Index: tcprulescheck.c
===================================================================
RCS file: /usr/home/cvs-djbware/CVS/ucspi-tcp/tcprulescheck.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -p -r1.1.1.1 -r1.2
--- tcprulescheck.c	14 Jun 2002 08:47:30 -0000	1.1.1.1
+++ tcprulescheck.c	16 Mar 2004 15:12:27 -0000	1.2
@@ -22,6 +22,11 @@ void found(char *data,unsigned int datal
 	buffer_puts(buffer_1,data + 1);
 	buffer_puts(buffer_1,"\n");
 	break;
+      case '-':
+	buffer_puts(buffer_1,"unset environment variable ");
+	buffer_puts(buffer_1,data + 1);
+	buffer_puts(buffer_1,"\n");
+	break;
     }
     ++next0;
     data += next0; datalen -= next0;
Index: tcpserver.1
===================================================================
RCS file: tcpserver.1
diff -N tcpserver.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tcpserver.1	6 Apr 2004 11:49:45 -0000	1.2
@@ -0,0 +1,318 @@
+.TH tcpserver 1
+.SH NAME
+tcpserver \- accept incoming TCP connections
+.SH SYNOPSIS
+.B tcpserver
+[
+.B \-1UXpPhHrRoOdDqQsSv
+]
+[
+.B \-c\fIlimit
+]
+[
+.B \-C\fI[address[/len]:]limit
+]
+[
+.B \-e\fIname=[var]
+]
+[
+.B \-x\fIrules.cdb
+]
+[
+.B \-B\fIbanner
+]
+[
+.B \-g\fIgid
+]
+[
+.B \-u\fIuid
+]
+[
+.B \-b\fIbacklog
+]
+[
+.B \-l\fIlocalname
+]
+[
+.B \-t\fItimeout
+]
+[
+.B \-n\fIcertfile
+]
+.I host
+.I port
+.I program
+[
+.I arg ...
+]
+.SH DESCRIPTION
+.B tcpserver
+waits for connections from TCP clients.
+For each connection, it runs
+.I program
+with the given arguments,
+with descriptor 0 reading from the network
+and descriptor 1 writing to the network.
+
+The server's address is given by
+.I host
+and
+.IR port .
+.I host
+can be 0, allowing connections from any host;
+or a particular IP address,
+allowing connections only to that address;
+or a host name, allowing connections to the first IP address
+for that host.
+.I port
+may be a numeric port number
+or a port name.
+If
+.I port
+is 0,
+.B tcpserver
+will choose a free port.
+
+.B tcpserver
+sets up several environment variables,
+as described in
+.B tcp-environ(5).
+
+.B tcpserver
+exits when it receives SIGTERM.
+.SH "OPTIONS"
+.TP
+.B \-c\fIlimit
+Do not handle more than
+.I limit
+simultaneous connections.
+If there are
+.I limit
+simultaneous copies of
+.I program
+running, defer acceptance of a new connection
+until one copy finishes.
+.I limit
+must be a positive integer.
+Default: 40.
+.TP
+.B \-C\fI[address[/len]:]limit
+Do not handle more than
+.I limit
+connections from the specified address or prefix.
+If there is no address specified a generic per IP
+.I limit
+is enforced.
+It is possible to specify multiple
+.IR limits .
+These limits are evaluated in sequential order, from first to last.
+The first matching
+.I limit
+decides what action is taken.
+The only exception is the generic per IP
+.I limit
+which is always evaluated last.
+.TP
+.B \-e\fIname=[var]
+If a per address limit is hit instead of dropping the connection set the
+environment variable
+.I name
+with
+.I var
+as optional data.
+This may be handy with the qmail-ldap patched qmail-smtpd where setting
+the environment 421GREETING will result in a restricted SMTP session always
+returning a temporary error.
+.TP
+.B \-x\fIrules.cdb
+Follow the rules compiled into
+.I rules.cdb
+by
+.BR tcprules .
+These rules may specify setting environment variables
+or rejecting connections from bad sources.
+
+.B tcpserver
+does not read
+.I rules.cdb
+into memory;
+you can rerun
+.B tcprules
+to change
+.BR tcpserver 's
+behavior on the fly.
+.TP
+.B \-B\fIbanner
+Write
+.I banner
+to the network immediately after each connection is made.
+.B tcpserver
+writes
+.I banner
+before looking up
+.BR TCPREMOTEHOST ,
+before looking up
+.BR TCPREMOTEINFO ,
+and before checking
+.IR rules.cdb .
+
+This feature can be used to reduce latency in protocols
+where the client waits for a greeting from the server.
+.TP
+.B \-g\fIgid
+Switch group ID to
+.I gid
+after preparing to receive connections.
+.I gid
+must be a positive integer.
+.TP
+.B \-u\fIuid
+Switch user ID to 
+.I uid
+after preparing to receive connections.
+.I uid
+must be a positive integer.
+.TP
+.B \-U
+Same as
+.B \-g\fI$GID
+.BR \-u\fI$UID .
+Typically
+.I $GID
+and
+.I $UID
+are set by envuidgid.
+.TP
+.B \-1
+After preparing to receive connections,
+print the local port number to standard output.
+.TP
+.B \-b\fIbacklog
+Allow up to
+.I backlog
+simultaneous SYN_RECEIVEDs.
+Default: 20.
+On some systems,
+.I backlog
+is silently limited to 5.
+See
+.BR listen (2)
+for more details.
+.TP
+.B \-o
+Leave IP options alone.
+If the client is sending packets along an IP source route,
+send packets back along the same route.
+.TP
+.B \-O
+(Default.)
+Kill IP options.
+A client can still use source routing to connect and to send data,
+but packets will be sent back along the default route.
+.TP
+.B \-d
+(Default.)
+Delay sending data for a fraction of a second whenever the
+remote host is responding slowly,
+to make better use of the network.
+.TP
+.B \-D
+Never delay sending data;
+enable TCP_NODELAY.
+This is appropriate for interactive connections.
+.TP
+.B \-q
+Quiet.
+Do not print any messages.
+.TP
+.B \-Q
+(Default.)
+Print error messages.
+.TP
+.B \-s
+Enable SSL/TLS mode. This modus needs a SSL enabled build and a certificat.
+.TP
+.B \-S
+(Default.)
+Don't enable SSL/TLS mode.
+.TP
+.B \-n\fIcertfile
+Instead of the default ./cert.pem certificate us the specified
+.IR certfile .
+.TP
+.B \-v
+Verbose.
+Print all available messages.
+.TP
+.B \-X
+With
+.BR -x\fIcdb ,
+allow connections even if
+.I cdb
+does not exist.
+Normally the connection gets dropped.
+.SH "DATA-GATHERING OPTIONS"
+.TP
+.B \-p
+Paranoid.
+After looking up the remote host name,
+look up the IP addresses for that name,
+and make sure one of them matches
+.BR TCPREMOTEIP .
+If none of them do,
+unset
+.BR TCPREMOTEHOST .
+.TP
+.B \-P
+(Default.)
+Not paranoid.
+.TP
+.B \-h
+(Default.)
+Look up the remote host name and set
+.BR TCPREMOTEHOST .
+.TP
+.B \-H
+Do not look up the remote host name.
+.TP
+.B \-l\fIlocalname
+Do not look up the local host name;
+use
+.I localname
+for
+.BR TCPLOCALHOST .
+.TP
+.B \-r
+(Default.)
+Attempt to obtain
+.B TCPREMOTEINFO
+from the remote host.
+.TP
+.B \-R
+Do not attempt to obtain
+.B TCPREMOTEINFO
+from the remote host.
+.TP
+.B \-t\fItimeout
+Give up on the 
+.B TCPREMOTEINFO
+connection attempt
+after
+.I timeout
+seconds. Default: 26.
+.SH ENVIRONMENT
+.TP
+.B SSL_CIPHER
+Specifies the ciphers that should be used in SSL/TLS mode.
+See
+.I openssl(1)
+for more information.
+.SH "SEE ALSO"
+argv0(1),
+fixcr(1),
+recordio(1),
+tcpclient(1),
+tcprules(1),
+listen(2),
+tcp-environ(5),
+openssl(1)
Index: tcpserver.c
===================================================================
RCS file: /usr/home/cvs-djbware/CVS/ucspi-tcp/tcpserver.c,v
retrieving revision 1.1.1.1
retrieving revision 1.8
diff -u -p -r1.1.1.1 -r1.8
--- tcpserver.c	14 Jun 2002 08:47:30 -0000	1.1.1.1
+++ tcpserver.c	1 Apr 2005 15:13:15 -0000	1.8
@@ -1,6 +1,7 @@
 #include <sys/types.h>
 #include <sys/param.h>
 #include <netdb.h>
+#include <openssl/ssl.h>
 #include "uint16.h"
 #include "str.h"
 #include "byte.h"
@@ -36,6 +37,13 @@ int flagremoteinfo = 1;
 int flagremotehost = 1;
 int flagparanoid = 0;
 unsigned long timeout = 26;
+#ifdef WITH_SSL
+int flagssl = 0;
+struct stralloc certfile = {0};
+#define CERTFILE "./cert.pem"
+
+void translate(SSL*, int, int, unsigned int);
+#endif
 
 static stralloc tcpremoteinfo;
 
@@ -127,6 +135,9 @@ void found(char *data,unsigned int datal
 	  env(data + 1,data + 1 + split + 1);
 	}
 	break;
+      case '-':
+	env(data + 1, (char *)0);
+	break;
     }
     ++next0;
     data += next0; datalen -= next0;
@@ -238,10 +249,28 @@ void doit(int t)
 
 void usage(void)
 {
+#ifndef WITH_SSL
   strerr_warn1("\
 tcpserver: usage: tcpserver \
 [ -1UXpPhHrRoOdDqQv ] \
 [ -c limit ] \
+[ -C [address[/len]:]limit ] \
+[ -e name=var ] \
+[ -x rules.cdb ] \
+[ -B banner ] \
+[ -g gid ] \
+[ -u uid ] \
+[ -b backlog ] \
+[ -l localname ] \
+[ -t timeout ] \
+host port program",0);
+#else
+  strerr_warn1("\
+tcpserver: usage: tcpserver \
+[ -1UXpPhHrRoOdDqQsSv ] \
+[ -c limit ] \
+[ -C [address[/len]:]limit ] \
+[ -e name=var ] \
 [ -x rules.cdb ] \
 [ -B banner ] \
 [ -g gid ] \
@@ -249,7 +278,9 @@ tcpserver: usage: tcpserver \
 [ -b backlog ] \
 [ -l localname ] \
 [ -t timeout ] \
+[ -n certfile ] \
 host port program",0);
+#endif
   _exit(100);
 }
 
@@ -274,12 +305,106 @@ void sigterm()
   _exit(0);
 }
 
+struct conn {
+  int pid;
+  char remoteip[4];
+} *conns;
+
+struct ip_limelt {
+  char ip[4];
+  char mask[4];
+  unsigned long limit;
+  unsigned long count;
+};
+
+#include "gen_alloc.h"
+#include "gen_allocdefs.h"
+GEN_ALLOC_typedef(ip_limit,struct ip_limelt,l,len,a)
+GEN_ALLOC_readyplus(ip_limit, struct ip_limelt,l,len,a,i,n,x,10,
+  ip_limit_rp)
+
+ip_limit ipl = {0};
+unsigned long limit_ip = 0;
+
+void
+ip_limit_add(char *str)
+{
+  unsigned int n, len;
+  unsigned long ul = 0;
+  struct ip_limelt lim;
+
+  byte_zero(&lim, sizeof(lim));
+  n = str_chr(str, ':');
+  if (str[n] == ':') {
+    str[n] = 0;
+    scan_ulong(str + n + 1, &ul);
+    lim.limit = ul;
+    /* parse ip */
+    ul = 32;
+    n = str_chr(str, '/');
+    if (str[n] == '/')
+      scan_ulong(str + n + 1, &ul);
+    if (ul > 32)
+      strerr_die2x(111,FATAL,"ip prefix len > 32");
+    if (ip4_scan(str, lim.ip) == 0)
+      strerr_die2x(111,FATAL,"bad ip address");
+    for (n = 0; n < 4; n++)
+      if (ul > 8) {
+	lim.mask[n] = 0xff;
+	ul -= 8;
+      } else {
+	lim.mask[n] = 0xff << (8 - ul);
+	ul = 0;
+      }
+    if (!ip_limit_rp(&ipl,1))
+      strerr_die2x(111,FATAL,"out of memory");
+    ipl.l[ipl.len++] = lim;
+  } else {
+    scan_ulong(str, &ul);
+    limit_ip = ul;
+  }
+}
+
+int
+ip_limit_check(char ip[4], int d)
+{
+  unsigned long c;
+  unsigned int l;
+  int i;
+
+  for (l = 0; l < ipl.len; l++)
+    if ((ip[0] & ipl.l[l].mask[0]) == (ipl.l[l].ip[0] & ipl.l[l].mask[0]) &&
+        (ip[1] & ipl.l[l].mask[1]) == (ipl.l[l].ip[1] & ipl.l[l].mask[1]) &&
+        (ip[2] & ipl.l[l].mask[2]) == (ipl.l[l].ip[2] & ipl.l[l].mask[2]) &&
+        (ip[3] & ipl.l[l].mask[3]) == (ipl.l[l].ip[3] & ipl.l[l].mask[3])) {
+      if (ipl.l[l].count + d > ipl.l[l].limit)
+	return 1;
+      ipl.l[l].count += d;
+      return 0;
+    }
+
+  /* global per ip limit */
+  for (l = 0, c= 0; l < limit; l++)
+    if (!byte_diff(conns[l].remoteip, sizeof(ip), ip))
+      c++;
+  if (limit_ip != 0 && c + d > limit_ip)
+    return 1;
+
+  return 0;
+}
+
 void sigchld()
 {
   int wstat;
   int pid;
- 
+  unsigned int i;
+
   while ((pid = wait_nohang(&wstat)) > 0) {
+    for (i = 0; i < limit; i++)
+      if (conns[i].pid == pid) {
+	ip_limit_check(conns[i].remoteip, -1);
+	byte_zero(&conns[i], sizeof(struct conn));
+      }
     if (verbosity >= 2) {
       strnum[fmt_ulong(strnum,pid)] = 0;
       strnum2[fmt_ulong(strnum2,wstat)] = 0;
@@ -296,14 +421,31 @@ main(int argc,char **argv)
   int opt;
   struct servent *se;
   char *x;
+  char *iplimenv;
+  int flagiplim;
   unsigned long u;
   int s;
   int t;
- 
-  while ((opt = getopt(argc,argv,"dDvqQhHrR1UXx:t:u:g:l:b:B:c:pPoO")) != opteof)
+  unsigned int i;
+  int pid;
+#ifdef WITH_SSL
+  BIO *sbio;
+  SSL *ssl;
+  SSL_CTX *ctx;
+  int pi2c[2], pi4c[2];
+
+  ctx = NULL;
+
+  if (!stralloc_copys(&certfile, CERTFILE) || !stralloc_0(&certfile) )
+    strerr_die2x(111,FATAL,"out of memory");
+  while ((opt = getopt(argc,argv,"dDvqQhHrRsS1UXx:t:u:g:l:b:B:c:C:e:n:pPoO")) != opteof)
+#else
+  while ((opt = getopt(argc,argv,"dDvqQhHrR1UXx:t:u:g:l:b:B:c:C:e:pPoO")) != opteof)
+#endif
     switch(opt) {
       case 'b': scan_ulong(optarg,&backlog); break;
       case 'c': scan_ulong(optarg,&limit); break;
+      case 'C': ip_limit_add(optarg); break;
       case 'X': flagallownorules = 1; break;
       case 'x': fnrules = optarg; break;
       case 'B': banner = optarg; break;
@@ -327,6 +469,18 @@ main(int argc,char **argv)
       case 'g': scan_ulong(optarg,&gid); break;
       case '1': flag1 = 1; break;
       case 'l': localhost = optarg; break;
+      case 'e': iplimenv = optarg;
+		if (iplimenv[str_chr(iplimenv, '=')] != '=')
+		  strerr_die2x(100,FATAL, "no '=' in ip limit env-var");
+		break;
+#ifdef WITH_SSL
+      case 's': flagssl = 1; break;
+      case 'S': flagssl = 0; break;
+      case 'n': if (!stralloc_copys(&certfile, optarg) ||
+		    !stralloc_0(&certfile) )
+		  strerr_die2x(111,FATAL,"out of memory");
+		break;
+#endif
       default: usage();
     }
   argc -= optind;
@@ -334,6 +488,15 @@ main(int argc,char **argv)
 
   if (!verbosity)
     buffer_2->fd = -1;
+
+  if (limit == 0)
+    strerr_die2x(100,FATAL,"limit may not be set to 0");
+  if (limit > 65000)
+    strerr_die2x(100,FATAL,"limit way to high");
+  conns = (struct conn *)alloc(limit * sizeof(struct conn));
+  if (!conns)
+    strerr_die2x(111,FATAL,"out of memory");
+  byte_zero(conns, limit * sizeof(struct conn));
  
   hostname = *argv++;
   if (!hostname) usage();
@@ -366,6 +529,25 @@ main(int argc,char **argv)
     strerr_die3x(111,FATAL,"no IP address for ",hostname);
   byte_copy(localip,4,addresses.s);
 
+#ifdef WITH_SSL
+  if (flagssl == 1) {
+    /* setup SSL context (load key and cert into ctx) */
+    SSL_library_init();
+    ctx=SSL_CTX_new(SSLv23_server_method());
+    if (!ctx) strerr_die2x(111,FATAL,"unable to create SSL context");
+
+    /* set prefered ciphers */
+    if (env_get("SSL_CIPHER"))
+      if (SSL_CTX_set_cipher_list(ctx, env_get("SSL_CIPHER")) == 0)
+	strerr_die2x(111,FATAL,"unable to set cipher list");
+
+    if(SSL_CTX_use_RSAPrivateKey_file(ctx, certfile.s, SSL_FILETYPE_PEM) != 1)
+      strerr_die2x(111,FATAL,"unable to load RSA private key");
+    if(SSL_CTX_use_certificate_chain_file(ctx, certfile.s) != 1)
+      strerr_die2x(111,FATAL,"unable to load certificate");
+  }
+#endif
+  
   s = socket_tcp();
   if (s == -1)
     strerr_die2sys(111,FATAL,"unable to create socket: ");
@@ -404,9 +586,31 @@ main(int argc,char **argv)
 
     if (t == -1) continue;
     ++numchildren; printstatus();
+
+    /* per ip handling */
+    flagiplim = 0;
+    if (ip_limit_check(remoteip, 1)) {
+      remoteipstr[ip4_fmt(remoteipstr,remoteip)] = 0;
+      if (iplimenv) {
+        strerr_warn4(DROP,"too many conections from ",remoteipstr,
+	    " only flagged",0);
+	flagiplim = 1;
+      } else {
+        strerr_warn3(DROP,"too many conections from ",remoteipstr,0);
+        --numchildren; printstatus();
+        close(t);
+        continue;
+      }
+    }
  
-    switch(fork()) {
+    switch(pid = fork()) {
       case 0:
+	if (flagiplim) {
+          int split;
+      	  split = str_chr(iplimenv,'=');
+	  iplimenv[split] = 0;
+	  env(iplimenv,iplimenv + split + 1);
+	}
         close(s);
         doit(t);
         if ((fd_move(0,t) == -1) || (fd_copy(1,0) == -1))
@@ -415,12 +619,159 @@ main(int argc,char **argv)
         sig_unblock(sig_child);
         sig_uncatch(sig_term);
         sig_uncatch(sig_pipe);
+#ifdef WITH_SSL
+	if (flagssl == 1) {
+	  if (pipe(pi2c) != 0)
+	    strerr_die2sys(111,DROP,"unable to create pipe: ");
+	  if (pipe(pi4c) != 0)
+	    strerr_die2sys(111,DROP,"unable to create pipe: ");
+	  switch(fork()) {
+	    case 0:
+	      close(0); close(1);
+	      close(pi2c[1]);
+	      close(pi4c[0]);
+	      if ((fd_move(0,pi2c[0]) == -1) || (fd_move(1,pi4c[1]) == -1))
+		strerr_die2sys(111,DROP,"unable to set up descriptors: ");
+	      /* signals are allready set in the parent */
+	      pathexec(argv);
+	      strerr_die4sys(111,DROP,"unable to run ",*argv,": ");
+	    case -1:
+	      strerr_die2sys(111,DROP,"unable to fork: ");
+	    default:
+	      ssl = SSL_new(ctx);
+	      if (!ssl)
+		strerr_die2x(111,DROP,"unable to set up SSL session");
+	      sbio = BIO_new_socket(0,BIO_NOCLOSE);
+	      if (!sbio)
+		strerr_die2x(111,DROP,"unable to set up BIO socket");
+	      SSL_set_bio(ssl,sbio,sbio);
+	      close(pi2c[0]);
+	      close(pi4c[1]);
+	      translate(ssl, pi2c[1], pi4c[0], 3600);
+	      _exit(0);
+	  }
+	}
+#endif
         pathexec(argv);
 	strerr_die4sys(111,DROP,"unable to run ",*argv,": ");
       case -1:
         strerr_warn2(DROP,"unable to fork: ",&strerr_sys);
         --numchildren; printstatus();
+	break;
+      default:
+	for (i = 0; i < limit; i++)
+	  if (conns[i].pid == 0) {
+	    conns[i].pid = pid;
+	    byte_copy(conns[i].remoteip, sizeof(remoteip), remoteip);
+	    break;
+	  }
     }
     close(t);
   }
 }
+
+#ifdef WITH_SSL
+static int allwrite(int fd, char *buf, int len)
+{
+  int w;
+
+  while (len) {
+    w = write(fd,buf,len);
+    if (w == -1) {
+      if (errno == error_intr) continue;
+      return -1; /* note that some data may have been written */
+    }
+    if (w == 0) ; /* luser's fault */
+    buf += w;
+    len -= w;
+  }
+  return 0;
+}
+
+static int allwritessl(SSL* ssl, char *buf, int len)
+{
+  int w;
+
+  while (len) {
+    w = SSL_write(ssl,buf,len);
+    if (w == -1) {
+      if (errno == error_intr) continue;
+      return -1; /* note that some data may have been written */
+    }
+    if (w == 0) ; /* luser's fault */
+    buf += w;
+    len -= w;
+  }
+  return 0;
+}
+
+char tbuf[2048];
+
+void translate(SSL* ssl, int clearout, int clearin, unsigned int iotimeout)
+{
+  struct taia now;
+  struct taia deadline;
+  iopause_fd iop[2];
+  int flagexitasap;
+  int iopl;
+  int sslout, sslin;
+  int n, r;
+
+  sslin = SSL_get_fd(ssl);
+  sslout = SSL_get_fd(ssl);
+  if (sslin == -1 || sslout == -1)
+    strerr_die2x(111,DROP,"unable to set up SSL connection");
+  
+  flagexitasap = 0;
+
+  if (SSL_accept(ssl)<=0)
+    strerr_die2x(111,DROP,"unable to accept SSL connection");
+
+  while (!flagexitasap) {
+    taia_now(&now);
+    taia_uint(&deadline,iotimeout);
+    taia_add(&deadline,&now,&deadline);
+
+    /* fill iopause struct */
+    iopl = 2;
+    iop[0].fd = sslin;
+    iop[0].events = IOPAUSE_READ;
+    iop[1].fd = clearin;
+    iop[1].events = IOPAUSE_READ;
+
+    /* do iopause read */
+    iopause(iop,iopl,&deadline,&now);
+    if (iop[0].revents) {
+      do {
+        /* data on sslin */
+        n = SSL_read(ssl, tbuf, sizeof(tbuf));
+        if ( n < 0 )
+	  strerr_die2sys(111,DROP,"unable to read form network: ");
+        if ( n == 0 )
+	  flagexitasap = 1;
+        r = allwrite(clearout, tbuf, n);
+        if ( r < 0 )
+	  strerr_die2sys(111,DROP,"unable to write to client: ");
+	/*
+	 * if the data payload was longer than sizeof(tbuf) then SSL will have
+	 * bytes processed and pending. We need to pick them up and write them
+	 * to clearout.
+	 */
+      } while (SSL_pending(ssl));
+    }
+    if (iop[1].revents) {
+      /* data on clearin */
+      n = read(clearin, tbuf, sizeof(tbuf));
+      if ( n < 0 )
+	strerr_die2sys(111,DROP,"unable to read form client: ");
+      if ( n == 0 )
+	flagexitasap = 1;
+      r = allwritessl(ssl, tbuf, n);
+      if ( r < 0 )
+	strerr_die2sys(111,DROP,"unable to write to network: ");
+    }
+    if (!iop[0].revents && !iop[1].revents)
+      strerr_die2x(0, DROP,"timeout reached without input");
+  }
+}
+#endif
Index: [email protected]
===================================================================
RCS file: [email protected]
diff -N [email protected]
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ [email protected]	5 Apr 2004 15:34:57 -0000	1.1
@@ -0,0 +1,32 @@
+.TH who@ 1
+.SH NAME
+who@ \- print list of active users on a host
+.SH SYNTAX
+.B who@
+[
+.I host
+]
+.SH DESCRIPTION
+.B who@
+connects to TCP port 11 (Systat) on
+.I host
+and prints any data it receives.
+It removes CR and converts unprintable characters to a visible format.
+
+If
+.I host
+is not supplied,
+.B who@
+connects to the local host.
+
+Some computers respond to port 11 with a list of active users.
+For example, they may be running
+
+.EX
+     tcpserver 0 11 who &
+.EE
+.SH "SEE ALSO"
+cat(1),
+delcr(1),
+tcpclient(1),
+tcpserver(1)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.