summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Denker <jsd@av8n.com>2012-07-31 22:34:58 -0700
committerJohn Denker <jsd@av8n.com>2012-07-31 22:36:28 -0700
commitef6722750b4518fcb29bf983755b5f02451ef224 (patch)
tree966e94ffd01cd8abb59e16a6992e142db345aa9f
parentb95f5ec1d83519c603f6e2145865c14932c4a813 (diff)
a bunch of files added by the ipv6 patch
-rw-r--r--ucspi-tcp-0.88/ip6_fmt.c64
-rw-r--r--ucspi-tcp-0.88/mconnect.136
-rw-r--r--ucspi-tcp-0.88/old-rules.c101
-rw-r--r--ucspi-tcp-0.88/recordio.175
-rw-r--r--ucspi-tcp-0.88/remoteinfo6.c98
-rw-r--r--ucspi-tcp-0.88/scan_ip6.c87
-rw-r--r--ucspi-tcp-0.88/scan_xlong.c23
-rw-r--r--ucspi-tcp-0.88/socket_accept6.c44
-rw-r--r--ucspi-tcp-0.88/socket_bind6.c45
-rw-r--r--ucspi-tcp-0.88/socket_conn6.c38
-rw-r--r--ucspi-tcp-0.88/socket_getifidx.c8
-rw-r--r--ucspi-tcp-0.88/socket_getifname.c14
-rw-r--r--ucspi-tcp-0.88/socket_ip4loopback.c2
-rw-r--r--ucspi-tcp-0.88/socket_local6.c39
-rw-r--r--ucspi-tcp-0.88/socket_recv6.c44
-rw-r--r--ucspi-tcp-0.88/socket_remote6.c39
-rw-r--r--ucspi-tcp-0.88/socket_send6.c40
-rw-r--r--ucspi-tcp-0.88/socket_tcp6.c44
-rw-r--r--ucspi-tcp-0.88/socket_udp6.c38
-rw-r--r--ucspi-tcp-0.88/socket_v4mappedprefix.c2
-rw-r--r--ucspi-tcp-0.88/socket_v6any.c2
-rw-r--r--ucspi-tcp-0.88/socket_v6loopback.c2
-rw-r--r--ucspi-tcp-0.88/tcp-environ.566
-rw-r--r--ucspi-tcp-0.88/tcpcat.120
-rw-r--r--ucspi-tcp-0.88/tcpclient.1173
-rw-r--r--ucspi-tcp-0.88/tcprules.1221
-rw-r--r--ucspi-tcp-0.88/tcprulescheck.125
-rw-r--r--ucspi-tcp-0.88/tcpserver.1266
-rw-r--r--ucspi-tcp-0.88/timeoutconn6.c34
-rw-r--r--ucspi-tcp-0.88/tryip6.c8
-rw-r--r--ucspi-tcp-0.88/usr/local/man/man1/tcpclient.1173
-rw-r--r--ucspi-tcp-0.88/usr/local/man/man1/tcpserver.1266
-rw-r--r--ucspi-tcp-0.88/who@.132
33 files changed, 2169 insertions, 0 deletions
diff --git a/ucspi-tcp-0.88/ip6_fmt.c b/ucspi-tcp-0.88/ip6_fmt.c
new file mode 100644
index 0000000..d7c010a
--- /dev/null
+++ b/ucspi-tcp-0.88/ip6_fmt.c
@@ -0,0 +1,64 @@
+#include "fmt.h"
+#include "byte.h"
+#include "ip4.h"
+#include "ip6.h"
+
+unsigned int ip6_fmt(char *s,char ip[16])
+{
+ unsigned long len,temp, k, pos0=0,len0=0, pos1=0, compr=0;
+
+ for (k=0; k<16; k+=2) {
+ if (ip[k]==0 && ip[k+1]==0) {
+ if (!compr) {
+ compr=1;
+ pos1=k;
+ }
+ if (k==14) { k=16; goto last; }
+ } else if (compr) {
+ last:
+ if ((temp=k-pos1) > len0) {
+ len0=temp;
+ pos0=pos1;
+ }
+ compr=0;
+ }
+ }
+
+ for (len=0,k=0; k<16; k+=2) {
+ if (k==12 && ip6_isv4mapped(ip)) {
+ len += ip4_fmt(s,ip+12);
+ break;
+ }
+ if (pos0==k && len0) {
+ if (k==0) { ++len; if (s) *s++ = ':'; }
+ ++len; if (s) *s++ = ':';
+ k += len0-2;
+ continue;
+ }
+ temp = ((unsigned long) (unsigned char) ip[k] << 8) +
+ (unsigned long) (unsigned char) ip[k+1];
+ temp = fmt_xlong(s,temp); len += temp; if (s) s += temp;
+ if (k<14) { ++len; if (s) *s++ = ':'; }
+ }
+
+ return len;
+}
+
+static char tohex(char num) {
+ if (num<10)
+ return num+'0';
+ else if (num<16)
+ return num-10+'a';
+ else
+ return -1;
+}
+
+unsigned int ip6_fmt_flat(char *s,char ip[16])
+{
+ int i;
+ for (i=0; i<16; i++) {
+ *s++=tohex((unsigned char)ip[i] >> 4);
+ *s++=tohex((unsigned char)ip[i] & 15);
+ }
+ return 32;
+}
diff --git a/ucspi-tcp-0.88/mconnect.1 b/ucspi-tcp-0.88/mconnect.1
new file mode 100644
index 0000000..6648367
--- /dev/null
+++ b/ucspi-tcp-0.88/mconnect.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)
diff --git a/ucspi-tcp-0.88/old-rules.c b/ucspi-tcp-0.88/old-rules.c
new file mode 100644
index 0000000..7225115
--- /dev/null
+++ b/ucspi-tcp-0.88/old-rules.c
@@ -0,0 +1,101 @@
+#include "alloc.h"
+#include "stralloc.h"
+#include "open.h"
+#include "cdb.h"
+#include "rules.h"
+
+stralloc rules_name = {0};
+
+static struct cdb c;
+
+static int dorule(void (*callback)(char *,unsigned int))
+{
+ char *data;
+ unsigned int datalen;
+
+ switch(cdb_find(&c,rules_name.s,rules_name.len)) {
+ case -1: return -1;
+ case 0: return 0;
+ }
+
+ datalen = cdb_datalen(&c);
+ data = alloc(datalen);
+ if (!data) return -1;
+ if (cdb_read(&c,data,datalen,cdb_datapos(&c)) == -1) {
+ alloc_free(data);
+ return -1;
+ }
+
+ callback(data,datalen);
+ alloc_free(data);
+ return 1;
+}
+
+static int doit(void (*callback)(char *,unsigned int),char *ip,char *host,char *info)
+{
+ int r;
+
+ if (info) {
+ if (!stralloc_copys(&rules_name,info)) return -1;
+ if (!stralloc_cats(&rules_name,"@")) return -1;
+ if (!stralloc_cats(&rules_name,ip)) return -1;
+ r = dorule(callback);
+ if (r) return r;
+
+ if (host) {
+ if (!stralloc_copys(&rules_name,info)) return -1;
+ if (!stralloc_cats(&rules_name,"@=")) return -1;
+ if (!stralloc_cats(&rules_name,host)) return -1;
+ r = dorule(callback);
+ if (r) return r;
+ }
+ }
+
+ if (!stralloc_copys(&rules_name,ip)) return -1;
+ r = dorule(callback);
+ if (r) return r;
+
+ if (host) {
+ if (!stralloc_copys(&rules_name,"=")) return -1;
+ if (!stralloc_cats(&rules_name,host)) return -1;
+ r = dorule(callback);
+ if (r) return r;
+ }
+
+ if (!stralloc_copys(&rules_name,ip)) return -1;
+ while (rules_name.len > 0) {
+ if (ip[rules_name.len - 1] == '.' ||
+ (ip[rules_name.len-1]==':' && rules_name.len>1)) {
+ r = dorule(callback);
+ if (r) return r;
+ }
+ --rules_name.len;
+ }
+
+ if (host) {
+ while (*host) {
+ if (*host == '.') {
+ if (!stralloc_copys(&rules_name,"=")) return -1;
+ if (!stralloc_cats(&rules_name,host)) return -1;
+ r = dorule(callback);
+ if (r) return r;
+ }
+ ++host;
+ }
+ if (!stralloc_copys(&rules_name,"=")) return -1;
+ r = dorule(callback);
+ if (r) return r;
+ }
+
+ rules_name.len = 0;
+ return dorule(callback);
+}
+
+int rules(void (*callback)(char *,unsigned int),int fd,char *ip,char *host,char *info)
+{
+ int r;
+ cdb_init(&c,fd);
+ r = doit(callback,ip,host,info);
+ cdb_free(&c);
+ return r;
+}
diff --git a/ucspi-tcp-0.88/recordio.1 b/ucspi-tcp-0.88/recordio.1
new file mode 100644
index 0000000..e056776
--- /dev/null
+++ b/ucspi-tcp-0.88/recordio.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)
diff --git a/ucspi-tcp-0.88/remoteinfo6.c b/ucspi-tcp-0.88/remoteinfo6.c
new file mode 100644
index 0000000..cf3b7c1
--- /dev/null
+++ b/ucspi-tcp-0.88/remoteinfo6.c
@@ -0,0 +1,98 @@
+#include "fmt.h"
+#include "buffer.h"
+#include "socket.h"
+#include "error.h"
+#include "iopause.h"
+#include "timeoutconn.h"
+#include "remoteinfo.h"
+
+static struct taia now;
+static struct taia deadline;
+
+static int mywrite(int fd,char *buf,int len)
+{
+ iopause_fd x;
+
+ x.fd = fd;
+ x.events = IOPAUSE_WRITE;
+ for (;;) {
+ taia_now(&now);
+ iopause(&x,1,&deadline,&now);
+ if (x.revents) break;
+ if (taia_less(&deadline,&now)) {
+ errno = error_timeout;
+ return -1;
+ }
+ }
+ return write(fd,buf,len);
+}
+
+static int myread(int fd,char *buf,int len)
+{
+ iopause_fd x;
+
+ x.fd = fd;
+ x.events = IOPAUSE_READ;
+ for (;;) {
+ taia_now(&now);
+ iopause(&x,1,&deadline,&now);
+ if (x.revents) break;
+ if (taia_less(&deadline,&now)) {
+ errno = error_timeout;
+ return -1;
+ }
+ }
+ return read(fd,buf,len);
+}
+
+static int doit(stralloc *out,int s,char ipremote[16],uint16 portremote,char iplocal[16],uint16 portlocal,unsigned int timeout,uint32 netif)
+{
+ buffer b;
+ char bspace[128];
+ char strnum[FMT_ULONG];
+ int numcolons;
+ char ch;
+
+ if (socket_bind6(s,iplocal,0,netif) == -1) return -1;
+ if (timeoutconn6(s,ipremote,113,timeout,netif) == -1) return -1;
+
+ buffer_init(&b,mywrite,s,bspace,sizeof bspace);
+ buffer_put(&b,strnum,fmt_ulong(strnum,portremote));
+ buffer_put(&b," , ",3);
+ buffer_put(&b,strnum,fmt_ulong(strnum,portlocal));
+ buffer_put(&b,"\r\n",2);
+ if (buffer_flush(&b) == -1) return -1;
+
+ buffer_init(&b,myread,s,bspace,sizeof bspace);
+ numcolons = 0;
+ for (;;) {
+ if (buffer_get(&b,&ch,1) != 1) return -1;
+ if ((ch == ' ') || (ch == '\t') || (ch == '\r')) continue;
+ if (ch == '\n') return 0;
+ if (numcolons < 3) {
+ if (ch == ':') ++numcolons;
+ }
+ else {
+ if (!stralloc_append(out,&ch)) return -1;
+ if (out->len > 256) return 0;
+ }
+ }
+}
+
+int remoteinfo6(stralloc *out,char ipremote[16],uint16 portremote,char iplocal[16],uint16 portlocal,unsigned int timeout,uint32 netif)
+{
+ int s;
+ int r;
+
+ if (!stralloc_copys(out,"")) return -1;
+
+ taia_now(&now);
+ taia_uint(&deadline,timeout);
+ taia_add(&deadline,&now,&deadline);
+
+ s = socket_tcp6();
+ if (s == -1) return -1;
+ r = doit(out,s,ipremote,portremote,iplocal,portlocal,timeout,netif);
+ close(s);
+ return r;
+}
diff --git a/ucspi-tcp-0.88/scan_ip6.c b/ucspi-tcp-0.88/scan_ip6.c
new file mode 100644
index 0000000..ee239fd
--- /dev/null
+++ b/ucspi-tcp-0.88/scan_ip6.c
@@ -0,0 +1,87 @@
+#include "scan.h"
+#include "ip4.h"
+#include "ip6.h"
+
+/*
+ * IPv6 addresses are really ugly to parse.
+ * Syntax: (h = hex digit)
+ * 1. hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh
+ * 2. any number of 0000 may be abbreviated as "::", but only once
+ * 3. The last two words may be written as IPv4 address
+ */
+
+unsigned int scan_ip6(const char *s,char ip[16])
+{
+ unsigned int i;
+ unsigned int len=0;
+ unsigned long u;
+
+ char suffix[16];
+ int prefixlen=0;
+ int suffixlen=0;
+
+ if ((i=ip4_scan((char*)s,ip+12))) {
+ for (len=0; len<12; ++len) ip[len]=V4mappedprefix[len];
+ return i;
+ }
+ for (i=0; i<16; i++) ip[i]=0;
+ for (;;) {
+ if (*s == ':') {
+ len++;
+ if (s[1] == ':') { /* Found "::", skip to part 2 */
+ s+=2;
+ len++;
+ break;
+ }
+ s++;
+ }
+ i = scan_xlong((char*)s,&u);
+ if (!i) return 0;
+ if (prefixlen==12 && s[i]=='.') {
+ /* the last 4 bytes may be written as IPv4 address */
+ i=ip4_scan((char*)s,ip+12);
+ if (i)
+ return i+len;
+ else
+ return 0;
+ }
+ ip[prefixlen++] = (u >> 8);
+ ip[prefixlen++] = (u & 255);
+ s += i; len += i;
+ if (prefixlen==16)
+ return len;
+ }
+
+/* part 2, after "::" */
+ for (;;) {
+ if (*s == ':') {
+ if (suffixlen==0)
+ break;
+ s++;
+ len++;
+ } else if (suffixlen!=0)
+ break;
+ i = scan_xlong((char*)s,&u);
+ if (!i) {
+ len--;
+ break;
+ }
+ if (suffixlen+prefixlen<=12 && s[i]=='.') {
+ int j=ip4_scan((char*)s,suffix+suffixlen);
+ if (j) {
+ suffixlen+=4;
+ len+=j;
+ break;
+ } else
+ prefixlen=12-suffixlen; /* make end-of-loop test true */
+ }
+ suffix[suffixlen++] = (u >> 8);
+ suffix[suffixlen++] = (u & 255);
+ s += i; len += i;
+ if (prefixlen+suffixlen==16)
+ break;
+ }
+ for (i=0; i<suffixlen; i++)
+ ip[16-suffixlen+i] = suffix[i];
+ return len;
+}
diff --git a/ucspi-tcp-0.88/scan_xlong.c b/ucspi-tcp-0.88/scan_xlong.c
new file mode 100644
index 0000000..6e46d74
--- /dev/null
+++ b/ucspi-tcp-0.88/scan_xlong.c
@@ -0,0 +1,23 @@
+#include "scan.h"
+
+static int fromhex(unsigned char c) {
+ if (c>='0' && c<='9')
+ return c-'0';
+ else if (c>='A' && c<='F')
+ return c-'A'+10;
+ else if (c>='a' && c<='f')
+ return c-'a'+10;
+ return -1;
+}
+
+unsigned int scan_xlong(char *src,unsigned long *dest) {
+ register const char *tmp=src;
+ register int l=0;
+ register unsigned char c;
+ while ((c=fromhex(*tmp))<16) {
+ l=(l<<4)+c;
+ ++tmp;
+ }
+ *dest=l;
+ return tmp-src;
+}
diff --git a/ucspi-tcp-0.88/socket_accept6.c b/ucspi-tcp-0.88/socket_accept6.c
new file mode 100644
index 0000000..a8a9a07
--- /dev/null
+++ b/ucspi-tcp-0.88/socket_accept6.c
@@ -0,0 +1,44 @@
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "byte.h"
+#include "socket.h"
+#include "ip6.h"
+#include "haveip6.h"
+#include "error.h"
+
+int socket_accept6(int s,char ip[16],uint16 *port,uint32 *scope_id)
+{
+#ifdef LIBC_HAS_IP6
+ struct sockaddr_in6 sa;
+#else
+ struct sockaddr_in sa;
+#endif
+ unsigned int dummy = sizeof sa;
+ int fd;
+
+ fd = accept(s,(struct sockaddr *) &sa,&dummy);
+ if (fd == -1) return -1;
+
+#ifdef LIBC_HAS_IP6
+ if (sa.sin6_family==AF_INET) {
+ struct sockaddr_in *sa4=(struct sockaddr_in*)&sa;
+ byte_copy(ip,12,V4mappedprefix);
+ byte_copy(ip+12,4,(char *) &sa4->sin_addr);
+ uint16_unpack_big((char *) &sa4->sin_port,port);
+ return fd;
+ }
+ byte_copy(ip,16,(char *) &sa.sin6_addr);
+ uint16_unpack_big((char *) &sa.sin6_port,port);
+ if (scope_id) *scope_id=sa.sin6_scope_id;
+
+ return fd;
+#else
+ byte_copy(ip,12,V4mappedprefix);
+ byte_copy(ip+12,4,(char *) &sa.sin_addr);
+ uint16_unpack_big((char *) &sa.sin_port,port);
+ if (scope_id) *scope_id=0;
+ return fd;
+#endif
+}
diff --git a/ucspi-tcp-0.88/socket_bind6.c b/ucspi-tcp-0.88/socket_bind6.c
new file mode 100644
index 0000000..8a5a7cd
--- /dev/null
+++ b/ucspi-tcp-0.88/socket_bind6.c
@@ -0,0 +1,45 @@
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "byte.h"
+#include "socket.h"
+#include "ip6.h"
+#include "haveip6.h"
+#include "error.h"
+
+int socket_bind6(int s,const char ip[16],uint16 port,uint32 scope_id)
+{
+#ifdef LIBC_HAS_IP6
+ struct sockaddr_in6 sa;
+
+ if (noipv6) {
+#endif
+ int i;
+ for (i=0; i<16; i++)
+ if (ip[i]!=0) break;
+ if (i==16 || ip6_isv4mapped(ip))
+ return socket_bind4(s,ip+12,port);
+#ifdef LIBC_HAS_IP6
+ }
+ byte_zero(&sa,sizeof sa);
+ sa.sin6_family = AF_INET6;
+ uint16_pack_big((char *) &sa.sin6_port,port);
+/* implicit: sa.sin6_flowinfo = 0; */
+ byte_copy((char *) &sa.sin6_addr,16,ip);
+ sa.sin6_scope_id=scope_id;
+
+ return bind(s,(struct sockaddr *) &sa,sizeof sa);
+#else
+ errno=error_proto;
+ return -1;
+#endif
+}
+
+int socket_bind6_reuse(int s,const char ip[16],uint16 port,uint32 scope_id)
+{
+ int opt = 1;
+ setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof opt);
+ return socket_bind6(s,ip,port,scope_id);
+}
+
diff --git a/ucspi-tcp-0.88/socket_conn6.c b/ucspi-tcp-0.88/socket_conn6.c
new file mode 100644
index 0000000..0ad886d
--- /dev/null
+++ b/ucspi-tcp-0.88/socket_conn6.c
@@ -0,0 +1,38 @@
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include "byte.h"
+#include "socket.h"
+#include "ip6.h"
+#include "haveip6.h"
+#include "uint32.h"
+#include "ip4.h"
+
+int socket_connect6(int s,const char ip[16],uint16 port,uint32 scope_id)
+{
+#ifdef LIBC_HAS_IP6
+ struct sockaddr_in6 sa;
+
+ if (noipv6) {
+#endif
+ if (ip6_isv4mapped(ip))
+ return socket_connect4(s,ip+12,port);
+ if (byte_equal(ip,16,V6loopback))
+ return socket_connect4(s,ip4loopback,port);
+#ifdef LIBC_HAS_IP6
+ }
+ byte_zero(&sa,sizeof sa);
+ sa.sin6_family = PF_INET6;
+ uint16_pack_big((char *) &sa.sin6_port,port);
+ sa.sin6_flowinfo = 0;
+ sa.sin6_scope_id = scope_id;
+ byte_copy((char *) &sa.sin6_addr,16,ip);
+
+ return connect(s,(struct sockaddr *) &sa,sizeof sa);
+#else
+ errno=EPROTONOSUPPORT;
+ return -1;
+#endif
+}
diff --git a/ucspi-tcp-0.88/socket_getifidx.c b/ucspi-tcp-0.88/socket_getifidx.c
new file mode 100644
index 0000000..452d6d7
--- /dev/null
+++ b/ucspi-tcp-0.88/socket_getifidx.c
@@ -0,0 +1,8 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include "socket.h"
+
+uint32 socket_getifidx(const char* ifname) {
+ return if_nametoindex(ifname);
+}
diff --git a/ucspi-tcp-0.88/socket_getifname.c b/ucspi-tcp-0.88/socket_getifname.c
new file mode 100644
index 0000000..77edff9
--- /dev/null
+++ b/ucspi-tcp-0.88/socket_getifname.c
@@ -0,0 +1,14 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include "socket.h"
+
+static char ifname[IFNAMSIZ];
+
+const char* socket_getifname(uint32 interface) {
+ char *tmp=if_indextoname(interface,ifname);
+ if (tmp)
+ return tmp;
+ else
+ return "[unknown]";
+}
diff --git a/ucspi-tcp-0.88/socket_ip4loopback.c b/ucspi-tcp-0.88/socket_ip4loopback.c
new file mode 100644
index 0000000..1bbbe95
--- /dev/null
+++ b/ucspi-tcp-0.88/socket_ip4loopback.c
@@ -0,0 +1,2 @@
+
+const char ip4loopback[4] = {127,0,0,1};
diff --git a/ucspi-tcp-0.88/socket_local6.c b/ucspi-tcp-0.88/socket_local6.c
new file mode 100644
index 0000000..23427c3
--- /dev/null
+++ b/ucspi-tcp-0.88/socket_local6.c
@@ -0,0 +1,39 @@
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "byte.h"
+#include "socket.h"
+#include "ip6.h"
+#include "haveip6.h"
+#include "error.h"
+
+int socket_local6(int s,char ip[16],uint16 *port,uint32 *scope_id)
+{
+#ifdef LIBC_HAS_IP6
+ struct sockaddr_in6 sa;
+#else
+ struct sockaddr_in sa;
+#endif
+ unsigned int dummy = sizeof sa;
+
+ if (getsockname(s,(struct sockaddr *) &sa,&dummy) == -1) return -1;
+#ifdef LIBC_HAS_IP6
+ if (sa.sin6_family==AF_INET) {
+ struct sockaddr_in *sa4=(struct sockaddr_in*)&sa;
+ byte_copy(ip,12,V4mappedprefix);
+ byte_copy(ip+12,4,(char *) &sa4->sin_addr);
+ uint16_unpack_big((char *) &sa4->sin_port,port);
+ return 0;
+ }
+ byte_copy(ip,16,(char *) &sa.sin6_addr);
+ uint16_unpack_big((char *) &sa.sin6_port,port);
+ if (scope_id) *scope_id=sa.sin6_scope_id;
+#else
+ byte_copy(ip,12,V4mappedprefix);
+ byte_copy(ip+12,4,(char *) &sa.sin_addr);
+ uint16_unpack_big((char *) &sa.sin_port,port);
+ if (scope_id) *scope_id=0;
+#endif
+ return 0;
+}
diff --git a/ucspi-tcp-0.88/socket_recv6.c b/ucspi-tcp-0.88/socket_recv6.c
new file mode 100644
index 0000000..a86ca96
--- /dev/null
+++ b/ucspi-tcp-0.88/socket_recv6.c
@@ -0,0 +1,44 @@
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "byte.h"
+#include "socket.h"
+#include "ip6.h"
+#include "haveip6.h"
+#include "error.h"
+
+int socket_recv6(int s,char *buf,unsigned int len,char ip[16],uint16 *port,uint32 *scope_id)
+{
+#ifdef LIBC_HAS_IP6
+ struct sockaddr_in6 sa;
+#else
+ struct sockaddr_in sa;
+#endif
+ unsigned int dummy = sizeof sa;
+ int r;
+
+ byte_zero(&sa,dummy);
+ r = recvfrom(s,buf,len,0,(struct sockaddr *) &sa,&dummy);
+ if (r == -1) return -1;
+
+#ifdef LIBC_HAS_IP6
+ if (noipv6) {
+ struct sockaddr_in *sa4=(struct sockaddr_in *)&sa;
+ byte_copy(ip,12,V4mappedprefix);
+ byte_copy(ip+12,4,(char *) &sa4->sin_addr);
+ uint16_unpack_big((char *) &sa4->sin_port,port);
+ return r;
+ }
+ byte_copy(ip,16,(char *) &sa.sin6_addr);
+ uint16_unpack_big((char *) &sa.sin6_port,port);
+ if (scope_id) *scope_id=sa.sin6_scope_id;
+#else
+ byte_copy(ip,12,(char *)V4mappedprefix);
+ byte_copy(ip+12,4,(char *) &sa.sin_addr);
+ uint16_unpack_big((char *) &sa.sin_port,port);
+ if (scope_id) *scope_id=0;
+#endif
+
+ return r;
+}
diff --git a/ucspi-tcp-0.88/socket_remote6.c b/ucspi-tcp-0.88/socket_remote6.c
new file mode 100644
index 0000000..e60a539
--- /dev/null
+++ b/ucspi-tcp-0.88/socket_remote6.c
@@ -0,0 +1,39 @@
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "byte.h"
+#include "socket.h"
+#include "ip6.h"
+#include "haveip6.h"
+#include "error.h"
+
+int socket_remote6(int s,char ip[16],uint16 *port,uint32 *scope_id)
+{
+#ifdef LIBC_HAS_IP6
+ struct sockaddr_in6 sa;
+#else
+ struct sockaddr_in sa;
+#endif
+ unsigned int dummy = sizeof sa;
+
+ if (getpeername(s,(struct sockaddr *) &sa,&dummy) == -1) return -1;
+#ifdef LIBC_HAS_IP6
+ if (sa.sin6_family==AF_INET) {
+ struct sockaddr_in *sa4=(struct sockaddr_in*)&sa;
+ byte_copy(ip,12,V4mappedprefix);
+ byte_copy(ip+12,4,(char *) &sa4->sin_addr);
+ uint16_unpack_big((char *) &sa4->sin_port,port);
+ return 0;
+ }
+ byte_copy(ip,16,(char *) &sa.sin6_addr);
+ uint16_unpack_big((char *) &sa.sin6_port,port);
+ if (scope_id) *scope_id=sa.sin6_scope_id;
+#else
+ byte_copy(ip,12,V4mappedprefix);
+ byte_copy(ip+12,4,(char *) &sa.sin_addr);
+ uint16_unpack_big((char *) &sa.sin_port,port);
+ if (scope_id) *scope_id=0;
+#endif
+ return 0;
+}
diff --git a/ucspi-tcp-0.88/socket_send6.c b/ucspi-tcp-0.88/socket_send6.c
new file mode 100644
index 0000000..4b2d1e8
--- /dev/null
+++ b/ucspi-tcp-0.88/socket_send6.c
@@ -0,0 +1,40 @@
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "byte.h"
+#include "socket.h"
+#include "ip4.h"
+#include "ip6.h"
+#include "haveip6.h"
+#include "error.h"
+
+int socket_send6(int s,const char *buf,unsigned int len,const char ip[16],uint16 port,uint32 scope_id)
+{
+#ifdef LIBC_HAS_IP6
+ struct sockaddr_in6 sa;
+#else
+ struct sockaddr_in sa;
+#endif
+
+ byte_zero(&sa,sizeof sa);
+#ifdef LIBC_HAS_IP6
+ if (noipv6) {
+#endif
+ if (ip6_isv4mapped(ip))
+ return socket_send4(s,buf,len,ip+12,port);
+ if (byte_equal(ip,16,V6loopback))
+ return socket_send4(s,buf,len,ip4loopback,port);
+#ifdef LIBC_HAS_IP6
+ errno=error_proto;
+ return -1;
+ }
+ sa.sin6_family = AF_INET6;
+ uint16_pack_big((char *) &sa.sin6_port,port);
+ byte_copy((char *) &sa.sin6_addr,16,ip);
+ return sendto(s,buf,len,0,(struct sockaddr *) &sa,sizeof sa);
+#else
+ errno=error_proto;
+ return -1;
+#endif
+}
diff --git a/ucspi-tcp-0.88/socket_tcp6.c b/ucspi-tcp-0.88/socket_tcp6.c
new file mode 100644
index 0000000..74099e2
--- /dev/null
+++ b/ucspi-tcp-0.88/socket_tcp6.c
@@ -0,0 +1,44 @@
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include "ndelay.h"
+#include "socket.h"
+#include "haveip6.h"
+#include "error.h"
+
+#ifdef LIBC_HAS_IP6
+int noipv6=0;
+#else
+int noipv6=1;
+#endif
+
+int socket_tcp6(void)
+{
+#ifdef LIBC_HAS_IP6
+ int s;
+
+ if (noipv6) goto compat;
+ s = socket(PF_INET6,SOCK_STREAM,0);
+ if (s == -1) {
+ if (errno == EINVAL || errno == EAFNOSUPPORT) {
+compat:
+ s=socket(AF_INET,SOCK_STREAM,0);
+ noipv6=1;
+ if (s==-1) return -1;
+ } else
+ return -1;
+ }
+ if (ndelay_on(s) == -1) { close(s); return -1; }
+#ifdef IPV6_V6ONLY
+ {
+ int zero=0;
+ setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&zero,sizeof(zero));
+ }
+#endif
+ return s;
+#else
+ return socket_tcp();
+#endif
+}
diff --git a/ucspi-tcp-0.88/socket_udp6.c b/ucspi-tcp-0.88/socket_udp6.c
new file mode 100644
index 0000000..3769b1d
--- /dev/null
+++ b/ucspi-tcp-0.88/socket_udp6.c
@@ -0,0 +1,38 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include "haveip6.h"
+#include "socket.h"
+
+#ifndef EAFNOSUPPORT
+#define EAFNOSUPPORT EINVAL
+#endif
+
+int socket_udp6(void)
+{
+#ifdef LIBC_HAS_IP6
+ int s;
+
+ if (noipv6) goto compat;
+ s = socket(PF_INET6,SOCK_DGRAM,0);
+ if (s == -1) {
+ if (errno == EINVAL || errno == EAFNOSUPPORT) {
+compat:
+ s=socket(AF_INET,SOCK_DGRAM,0);
+ noipv6=1;
+ if (s==-1) return -1;
+ } else
+ return -1;
+ }
+#ifdef IPV6_V6ONLY
+ {
+ int zero=0;
+ setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&zero,sizeof(zero));
+ }
+#endif
+ return s;
+#else
+ return socket_udp();
+#endif
+}
diff --git a/ucspi-tcp-0.88/socket_v4mappedprefix.c b/ucspi-tcp-0.88/socket_v4mappedprefix.c
new file mode 100644
index 0000000..dbed824
--- /dev/null
+++ b/ucspi-tcp-0.88/socket_v4mappedprefix.c
@@ -0,0 +1,2 @@
+
+const unsigned char V4mappedprefix[12]={0,0,0,0,0,0,0,0,0,0,0xff,0xff};
diff --git a/ucspi-tcp-0.88/socket_v6any.c b/ucspi-tcp-0.88/socket_v6any.c
new file mode 100644
index 0000000..c6d0cbb
--- /dev/null
+++ b/ucspi-tcp-0.88/socket_v6any.c
@@ -0,0 +1,2 @@
+
+const unsigned char V6any[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
diff --git a/ucspi-tcp-0.88/socket_v6loopback.c b/ucspi-tcp-0.88/socket_v6loopback.c
new file mode 100644
index 0000000..b81ee65
--- /dev/null
+++ b/ucspi-tcp-0.88/socket_v6loopback.c
@@ -0,0 +1,2 @@
+
+const unsigned char V6loopback[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
diff --git a/ucspi-tcp-0.88/tcp-environ.5 b/ucspi-tcp-0.88/tcp-environ.5
new file mode 100644
index 0000000..fecad70
--- /dev/null
+++ b/ucspi-tcp-0.88/tcp-environ.5
@@ -0,0 +1,66 @@
+.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.
+.TP 5
+TCPINTERFACE
+The interface name ("eth0") for IPv6 connections using link-local
+addresses.
+.SH "SEE ALSO"
+tcpclient(1),
+tcpserver(1),
+tcp-env(1),
+tcp(4)
diff --git a/ucspi-tcp-0.88/tcpcat.1 b/ucspi-tcp-0.88/tcpcat.1
new file mode 100644
index 0000000..4c51ed5
--- /dev/null
+++ b/ucspi-tcp-0.88/tcpcat.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)
diff --git a/ucspi-tcp-0.88/tcpclient.1 b/ucspi-tcp-0.88/tcpclient.1
new file mode 100644
index 0000000..f82f6b3
--- /dev/null
+++ b/ucspi-tcp-0.88/tcpclient.1
@@ -0,0 +1,173 @@
+.TH tcpclient 1
+.SH NAME
+tcpclient \- create an outgoing TCP connection
+.SH SYNOPSIS
+.B tcpclient
+[
+.B \-46hHrRdDqQv
+]
+[
+.B \-i\fIlocalip
+]
+[
+.B \-p\fIlocalport
+]
+[
+.B \-T\fItimeoutconn
+]
+[
+.B \-l\fIlocalname
+]
+[
+.B \-t\fItimeoutinfo
+]
+[
+.B \-I\fIinterface
+]
+.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 \-I\fIinterface
+Use
+.I interface
+as the local network interface. This is only defined for IPv6 sockets
+and needed if you use link-local IPv6 addresses.
+.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.
+.TP
+.B \-4
+Fall back to IPv4 sockets. This is necessary for terminally broken
+systems like OpenBSD which will not let IPv6 sockets connect to
+V4-mapped IPv6 addresses. Please note that this also applies to DNS
+lookups, so you will have to use an DNS resolver with an IPv6 address to
+connect to IPv6 systems. Use \fBDNSCACHEIP\fR to set the DNS resolver
+IP dynamically.
+.TP
+.B \-6
+Force IPv6 mode in UCSPI environment variables, even for
+IPv4 connections. This will set \fB$PROTO\fR to \fBTCP6\fR and put
+IPv4-mapped IPv6 addresses in \fBTCPLOCALIP\fR and \fBTCPREMOTEIP\fR.
+.SH "SEE ALSO"
+date@(1),
+finger@(1),
+http@(1),
+mconnect(1),
+tcpcat(1),
+tcpserver(1),
+who@(1),
+tcp-environ(5)
diff --git a/ucspi-tcp-0.88/tcprules.1 b/ucspi-tcp-0.88/tcprules.1
new file mode 100644
index 0000000..084165b
--- /dev/null
+++ b/ucspi-tcp-0.88/tcprules.1
@@ -0,0 +1,221 @@
+.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
+ joe@127.0.0.1:first
+.br
+ 18.23.0.32:second
+.br
+ 127.:third
+.br
+ :fourth
+.br
+ ::1:fifth
+.EE
+
+If
+.I TCPREMOTEIP
+is
+.BR 10.119.75.38 ,
+.B tcpserver
+will follow the
+.B fourth
+instructions.
+
+If
+.I TCPREMOTEIP
+is
+.BR ::1 ,
+.B tcpserver
+will follow the
+.B fifth
+instructions. Note that you cannot detect IPv4 mapped addresses by
+matching "::ffff", as those addresses will be converted to IPv4 before
+looking at the rules.
+
+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 RELAYCLIENT=@fix.me
+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)
diff --git a/ucspi-tcp-0.88/tcprulescheck.1 b/ucspi-tcp-0.88/tcprulescheck.1
new file mode 100644
index 0000000..3f0de24
--- /dev/null
+++ b/ucspi-tcp-0.88/tcprulescheck.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)
diff --git a/ucspi-tcp-0.88/tcpserver.1 b/ucspi-tcp-0.88/tcpserver.1
new file mode 100644
index 0000000..72c5ca0
--- /dev/null
+++ b/ucspi-tcp-0.88/tcpserver.1
@@ -0,0 +1,266 @@
+.TH tcpserver 1
+.SH NAME
+tcpserver \- accept incoming TCP connections
+.SH SYNOPSIS
+.B tcpserver
+[
+.B \-146jpPhHrRoOdDqQv
+]
+[
+.B \-c\fIlimit
+]
+[
+.B \-x\fIrules.cdb
+]
+[
+.B \-B\fIbanner
+]
+[
+.B \-g\fIgid
+]
+[
+.B \-u\fIuid
+]
+[
+.B \-b\fIbacklog
+]
+[
+.B \-l\fIlocalname
+]
+[
+.B \-t\fItimeout
+]
+[
+.B \-I\fIinterface
+]
+.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 \-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 \-1
+After preparing to receive connections,
+print the local port number to standard output.
+.TP
+.B \-4
+Fall back to IPv4 sockets. This is necessary for terminally broken
+systems like OpenBSD which will not let IPv6 sockets connect to
+V4-mapped IPv6 addresses. Please note that this also applies to DNS
+lookups, so you will have to use an DNS resolver with an IPv6 address to
+accept IPv6 connections. Use \fBDNSCACHEIP\fR to set the DNS resolver
+IP dynamically.
+.TP
+.B \-6
+Force IPv6 mode in UCSPI environment variables, even for
+IPv4 connections. This will set \fB$PROTO\fR to \fBTCP6\fR and put
+IPv4-mapped IPv6 addresses in \fBTCPLOCALIP\fR and \fBTCPREMOTEIP\fR.
+.TP
+.B \-I\fIinterface
+Bind to the network interface
+.I interface
+("eth0" on Linux, for example). This is only defined and needed for
+IPv6 link-local addresses.
+.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 \-v
+Verbose.
+Print all available messages.
+.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 "SEE ALSO"
+argv0(1),
+fixcr(1),
+recordio(1),
+tcpclient(1),
+tcprules(1),
+listen(2),
+tcp-environ(5)
diff --git a/ucspi-tcp-0.88/timeoutconn6.c b/ucspi-tcp-0.88/timeoutconn6.c
new file mode 100644
index 0000000..75e9f5a
--- /dev/null
+++ b/ucspi-tcp-0.88/timeoutconn6.c
@@ -0,0 +1,34 @@
+#include "ndelay.h"
+#include "socket.h"
+#include "iopause.h"
+#include "error.h"
+#include "timeoutconn.h"
+
+int timeoutconn6(int s,char ip[16],uint16 port,unsigned int timeout,uint32 netif)
+{
+ struct taia now;
+ struct taia deadline;
+ iopause_fd x;
+
+ if (socket_connect6(s,ip,port,netif) == -1) {
+ if ((errno != error_wouldblock) && (errno != error_inprogress)) return -1;
+ x.fd = s;
+ x.events = IOPAUSE_WRITE;
+ taia_now(&now);
+ taia_uint(&deadline,timeout);
+ taia_add(&deadline,&now,&deadline);
+ for (;;) {
+ taia_now(&now);
+ iopause(&x,1,&deadline,&now);
+ if (x.revents) break;
+ if (taia_less(&deadline,&now)) {
+ errno = error_timeout; /* note that connect attempt is continuing */
+ return -1;
+ }
+ }
+ if (!socket_connected(s)) return -1;
+ }
+
+ if (ndelay_off(s) == -1) return -1;
+ return 0;
+}
diff --git a/ucspi-tcp-0.88/tryip6.c b/ucspi-tcp-0.88/tryip6.c
new file mode 100644
index 0000000..e0d7cfb
--- /dev/null
+++ b/ucspi-tcp-0.88/tryip6.c
@@ -0,0 +1,8 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+main() {
+ struct sockaddr_in6 sa;
+ sa.sin6_family = PF_INET6;
+}
diff --git a/ucspi-tcp-0.88/usr/local/man/man1/tcpclient.1 b/ucspi-tcp-0.88/usr/local/man/man1/tcpclient.1
new file mode 100644
index 0000000..f82f6b3
--- /dev/null
+++ b/ucspi-tcp-0.88/usr/local/man/man1/tcpclient.1
@@ -0,0 +1,173 @@
+.TH tcpclient 1
+.SH NAME
+tcpclient \- create an outgoing TCP connection
+.SH SYNOPSIS
+.B tcpclient
+[
+.B \-46hHrRdDqQv
+]
+[
+.B \-i\fIlocalip
+]
+[
+.B \-p\fIlocalport
+]
+[
+.B \-T\fItimeoutconn
+]
+[
+.B \-l\fIlocalname
+]
+[
+.B \-t\fItimeoutinfo
+]
+[
+.B \-I\fIinterface
+]
+.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 \-I\fIinterface
+Use
+.I interface
+as the local network interface. This is only defined for IPv6 sockets
+and needed if you use link-local IPv6 addresses.
+.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.
+.TP
+.B \-4
+Fall back to IPv4 sockets. This is necessary for terminally broken
+systems like OpenBSD which will not let IPv6 sockets connect to
+V4-mapped IPv6 addresses. Please note that this also applies to DNS
+lookups, so you will have to use an DNS resolver with an IPv6 address to
+connect to IPv6 systems. Use \fBDNSCACHEIP\fR to set the DNS resolver
+IP dynamically.
+.TP
+.B \-6
+Force IPv6 mode in UCSPI environment variables, even for
+IPv4 connections. This will set \fB$PROTO\fR to \fBTCP6\fR and put
+IPv4-mapped IPv6 addresses in \fBTCPLOCALIP\fR and \fBTCPREMOTEIP\fR.
+.SH "SEE ALSO"
+date@(1),
+finger@(1),
+http@(1),
+mconnect(1),
+tcpcat(1),
+tcpserver(1),
+who@(1),
+tcp-environ(5)
diff --git a/ucspi-tcp-0.88/usr/local/man/man1/tcpserver.1 b/ucspi-tcp-0.88/usr/local/man/man1/tcpserver.1
new file mode 100644
index 0000000..72c5ca0
--- /dev/null
+++ b/ucspi-tcp-0.88/usr/local/man/man1/tcpserver.1
@@ -0,0 +1,266 @@
+.TH tcpserver 1
+.SH NAME
+tcpserver \- accept incoming TCP connections
+.SH SYNOPSIS
+.B tcpserver
+[
+.B \-146jpPhHrRoOdDqQv
+]
+[
+.B \-c\fIlimit
+]
+[
+.B \-x\fIrules.cdb
+]
+[
+.B \-B\fIbanner
+]
+[
+.B \-g\fIgid
+]
+[
+.B \-u\fIuid
+]
+[
+.B \-b\fIbacklog
+]
+[
+.B \-l\fIlocalname
+]
+[
+.B \-t\fItimeout
+]
+[
+.B \-I\fIinterface
+]
+.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 \-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 \-1
+After preparing to receive connections,
+print the local port number to standard output.
+.TP
+.B \-4
+Fall back to IPv4 sockets. This is necessary for terminally broken
+systems like OpenBSD which will not let IPv6 sockets connect to
+V4-mapped IPv6 addresses. Please note that this also applies to DNS
+lookups, so you will have to use an DNS resolver with an IPv6 address to
+accept IPv6 connections. Use \fBDNSCACHEIP\fR to set the DNS resolver
+IP dynamically.
+.TP
+.B \-6
+Force IPv6 mode in UCSPI environment variables, even for
+IPv4 connections. This will set \fB$PROTO\fR to \fBTCP6\fR and put
+IPv4-mapped IPv6 addresses in \fBTCPLOCALIP\fR and \fBTCPREMOTEIP\fR.
+.TP
+.B \-I\fIinterface
+Bind to the network interface
+.I interface
+("eth0" on Linux, for example). This is only defined and needed for
+IPv6 link-local addresses.
+.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 \-v
+Verbose.
+Print all available messages.
+.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 "SEE ALSO"
+argv0(1),
+fixcr(1),
+recordio(1),
+tcpclient(1),
+tcprules(1),
+listen(2),
+tcp-environ(5)
diff --git a/ucspi-tcp-0.88/who@.1 b/ucspi-tcp-0.88/who@.1
new file mode 100644
index 0000000..0c13f84
--- /dev/null
+++ b/ucspi-tcp-0.88/who@.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)