summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorGiancarlo Razzolini2016-09-12 00:26:11 -0300
committerGiancarlo Razzolini2016-09-12 00:26:11 -0300
commit38ef69132c807e5b4ff07f07e24576a21fc0d80d (patch)
treee176feffdd5b5aab2c8bab744edf6e896482cd4f
parenta3112cec68a2196f3aea6636ef77bf781f227d92 (diff)
downloadaur-38ef69132c807e5b4ff07f07e24576a21fc0d80d.tar.gz
* Added the ipv6 patch to the AUR git repo.
* Removed armv6h from the arch array.
-rw-r--r--.SRCINFO7
-rw-r--r--.gitignore1
-rw-r--r--PKGBUILD6
-rw-r--r--ucspi-tcp-0.88-ipv6.patch4976
4 files changed, 4982 insertions, 8 deletions
diff --git a/.SRCINFO b/.SRCINFO
index 30ef7db33ecf..4bc3e308d159 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,20 +1,19 @@
# Generated by mksrcinfo v8
-# Mon Feb 29 13:05:01 UTC 2016
+# Mon Sep 12 03:25:43 UTC 2016
pkgbase = ucspi-tcp
pkgdesc = Easy-to-use command-line tools for building TCP client-server applications.
pkgver = 0.88
- pkgrel = 6
+ pkgrel = 7
url = http://cr.yp.to/ucspi-tcp.html
arch = i686
arch = x86_64
- arch = armv6h
license = public-domain
makedepends = gcc
makedepends = make
makedepends = patch
depends = glibc
source = http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz
- source = http://www.bltweb.net/qmail/ucspi-tcp-0.88-ipv6.patch
+ source = ucspi-tcp-0.88-ipv6.patch
source = head-1.patch
sha512sums = 44efbd477dacf31d39fc970e2d2f74526dc815b905742f6127f0d5c80928ecc7e743089eaab0492386a58d5b97905113fbe8bbc7214ae179b7be27966b7566c7
sha512sums = 4180f2e8e0bd23bc345d363b5cfeab321293360203386fc93672bcb5c6fd8145d82c4eedb261abd0faacbce15bcd3180d7b02f2604039db735def7cdcd30abbc
diff --git a/.gitignore b/.gitignore
index c7b924837c5e..d4bfacc639d9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,2 @@
-ucspi-tcp-*.patch
ucspi-tcp-*.tar.gz
ucspi-tcp-*.tar.xz
diff --git a/PKGBUILD b/PKGBUILD
index 168ec9430942..4d6a0358eb30 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -4,15 +4,15 @@
# Contributor: Manolis Tzanidakis
pkgname=ucspi-tcp
pkgver=0.88
-pkgrel=6
+pkgrel=7
pkgdesc="Easy-to-use command-line tools for building TCP client-server applications."
-arch=('i686' 'x86_64' 'armv6h')
+arch=('i686' 'x86_64')
url="http://cr.yp.to/ucspi-tcp.html"
license=('public-domain')
depends=('glibc')
makedepends=('gcc' 'make' 'patch')
source=("http://cr.yp.to/$pkgname/$pkgname-$pkgver.tar.gz"
- "http://www.bltweb.net/qmail/ucspi-tcp-$pkgver-ipv6.patch"
+ "ucspi-tcp-$pkgver-ipv6.patch"
"head-1.patch")
sha512sums=('44efbd477dacf31d39fc970e2d2f74526dc815b905742f6127f0d5c80928ecc7e743089eaab0492386a58d5b97905113fbe8bbc7214ae179b7be27966b7566c7'
'4180f2e8e0bd23bc345d363b5cfeab321293360203386fc93672bcb5c6fd8145d82c4eedb261abd0faacbce15bcd3180d7b02f2604039db735def7cdcd30abbc'
diff --git a/ucspi-tcp-0.88-ipv6.patch b/ucspi-tcp-0.88-ipv6.patch
new file mode 100644
index 000000000000..d83be6a8bc9a
--- /dev/null
+++ b/ucspi-tcp-0.88-ipv6.patch
@@ -0,0 +1,4976 @@
+diff -uNr ucspi-tcp-0.88.orig/FILES ucspi-tcp-0.88/FILES
+--- ucspi-tcp-0.88.orig/FILES 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/FILES 2009-08-04 17:45:59.000000000 -0500
+@@ -216,3 +216,40 @@
+ warn-auto.sh
+ warn-shsgr
+ x86cpuid.c
++dns_ip6.c
++dns_ipq6.c
++dns_nd6.c
++dns_sortip6.c
++fmt_xlong.c
++ip6_fmt.c
++ip6_scan.c
++scan_0x.c
++socket_accept6.c
++socket_bind6.c
++socket_conn6.c
++socket_local6.c
++socket_recv6.c
++socket_remote6.c
++socket_send6.c
++socket_tcp6.c
++timeoutconn6.c
++tryip6.c
++haveip6.h2
++haveip6.h1
++remoteinfo6.c
++addcr.1
++argv0.1
++date@.1
++delcr.1
++finger@.1
++fixcr.1
++http@.1
++mconnect.1
++recordio.1
++tcp-environ.5
++tcpcat.1
++tcpclient.1
++tcprules.1
++tcprulescheck.1
++tcpserver.1
++who@.1
+diff -uNr ucspi-tcp-0.88.orig/Makefile ucspi-tcp-0.88/Makefile
+--- ucspi-tcp-0.88.orig/Makefile 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/Makefile 2009-08-04 17:45:59.000000000 -0500
+@@ -76,12 +76,14 @@
+ makelib byte_chr.o byte_copy.o byte_cr.o byte_diff.o byte_rchr.o \
+ byte_zero.o case_diffb.o case_diffs.o fmt_ulong.o ip4_fmt.o \
+ ip4_scan.o scan_ulong.o str_chr.o str_diff.o str_len.o str_start.o \
+-uint16_pack.o uint16_unpack.o uint32_pack.o uint32_unpack.o
++uint16_pack.o uint16_unpack.o uint32_pack.o uint32_unpack.o \
++ip6_fmt.o scan_ip6.o scan_xlong.o fmt_xlong.o
+ ./makelib byte.a byte_chr.o byte_copy.o byte_cr.o \
+ byte_diff.o byte_rchr.o byte_zero.o case_diffb.o \
+ case_diffs.o fmt_ulong.o ip4_fmt.o ip4_scan.o scan_ulong.o \
+ str_chr.o str_diff.o str_len.o str_start.o uint16_pack.o \
+- uint16_unpack.o uint32_pack.o uint32_unpack.o
++ uint16_unpack.o uint32_pack.o uint32_unpack.o ip6_fmt.o \
++ scan_ip6.o scan_xlong.o fmt_xlong.o
+
+ byte_chr.o: \
+ compile byte_chr.c byte.h
+@@ -181,11 +183,13 @@
+ dns.a: \
+ makelib dns_dfd.o dns_domain.o dns_dtda.o dns_ip.o dns_ipq.o \
+ dns_name.o dns_nd.o dns_packet.o dns_random.o dns_rcip.o dns_rcrw.o \
+-dns_resolve.o dns_sortip.o dns_transmit.o dns_txt.o
++dns_resolve.o dns_sortip.o dns_transmit.o dns_txt.o dns_ip6.o \
++dns_sortip6.o dns_nd6.o dns_ipq6.o
+ ./makelib dns.a dns_dfd.o dns_domain.o dns_dtda.o dns_ip.o \
+ dns_ipq.o dns_name.o dns_nd.o dns_packet.o dns_random.o \
+ dns_rcip.o dns_rcrw.o dns_resolve.o dns_sortip.o \
+- dns_transmit.o dns_txt.o
++ dns_transmit.o dns_txt.o dns_ip6.o dns_sortip6.o dns_nd6.o \
++ dns_ipq6.o
+
+ dns_dfd.o: \
+ compile dns_dfd.c error.h alloc.h byte.h dns.h stralloc.h gen_alloc.h \
+@@ -257,7 +261,7 @@
+ dns_transmit.o: \
+ compile dns_transmit.c socket.h uint16.h alloc.h error.h byte.h \
+ readwrite.h uint16.h dns.h stralloc.h gen_alloc.h iopause.h taia.h \
+-tai.h uint64.h taia.h
++tai.h uint64.h taia.h uint32.h
+ ./compile dns_transmit.c
+
+ dns_txt.o: \
+@@ -498,9 +502,15 @@
+ 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 \
+-stralloc.h gen_alloc.h uint16.h
++stralloc.h gen_alloc.h uint16.h uint32.h
+ ./compile remoteinfo.c
+
++remoteinfo6.o: \
++compile remoteinfo6.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 \
++stralloc.h gen_alloc.h uint16.h uint32.h
++ ./compile remoteinfo6.c
++
+ rts: \
+ warn-auto.sh rts.sh conf-home
+ cat warn-auto.sh rts.sh \
+@@ -557,43 +567,43 @@
+ rm -f trylsock.o trylsock
+
+ socket_accept.o: \
+-compile socket_accept.c byte.h socket.h uint16.h
++compile socket_accept.c byte.h socket.h uint16.h uint32.h
+ ./compile socket_accept.c
+
+ socket_bind.o: \
+-compile socket_bind.c byte.h socket.h uint16.h
++compile socket_bind.c byte.h socket.h uint16.h uint32.h
+ ./compile socket_bind.c
+
+ socket_conn.o: \
+-compile socket_conn.c readwrite.h byte.h socket.h uint16.h
++compile socket_conn.c readwrite.h byte.h socket.h uint16.h uint32.h
+ ./compile socket_conn.c
+
+ socket_delay.o: \
+-compile socket_delay.c socket.h uint16.h
++compile socket_delay.c socket.h uint16.h uint32.h
+ ./compile socket_delay.c
+
+ socket_listen.o: \
+-compile socket_listen.c socket.h uint16.h
++compile socket_listen.c socket.h uint16.h uint32.h
+ ./compile socket_listen.c
+
+ socket_local.o: \
+-compile socket_local.c byte.h socket.h uint16.h
++compile socket_local.c byte.h socket.h uint16.h uint32.h
+ ./compile socket_local.c
+
+ socket_opts.o: \
+-compile socket_opts.c socket.h uint16.h
++compile socket_opts.c socket.h uint16.h uint32.h
+ ./compile socket_opts.c
+
+ socket_remote.o: \
+-compile socket_remote.c byte.h socket.h uint16.h
++compile socket_remote.c byte.h socket.h uint16.h uint32.h
+ ./compile socket_remote.c
+
+ socket_tcp.o: \
+-compile socket_tcp.c ndelay.h socket.h uint16.h
++compile socket_tcp.c ndelay.h socket.h uint16.h uint32.h
+ ./compile socket_tcp.c
+
+ socket_udp.o: \
+-compile socket_udp.c ndelay.h socket.h uint16.h
++compile socket_udp.c ndelay.h socket.h uint16.h uint32.h
+ ./compile socket_udp.c
+
+ str_chr.o: \
+@@ -710,9 +720,9 @@
+ chmod 755 tcpcat
+
+ 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 \
++load tcpclient.o remoteinfo6.o dns.a time.a unix.a \
++byte.a socket.lib byte.h timeoutconn6.o
++ ./load tcpclient remoteinfo6.o timeoutconn6.o dns.a time.a \
+ unix.a byte.a `cat socket.lib`
+
+ tcpclient.o: \
+@@ -720,7 +730,7 @@
+ scan.h str.h ip4.h uint16.h socket.h uint16.h fd.h stralloc.h \
+ gen_alloc.h buffer.h error.h strerr.h pathexec.h timeoutconn.h \
+ uint16.h remoteinfo.h stralloc.h uint16.h dns.h stralloc.h iopause.h \
+-taia.h tai.h uint64.h taia.h
++taia.h tai.h uint64.h taia.h uint32.h
+ ./compile tcpclient.c
+
+ tcprules: \
+@@ -742,9 +752,9 @@
+ ./compile tcprulescheck.c
+
+ tcpserver: \
+-load tcpserver.o rules.o remoteinfo.o timeoutconn.o cdb.a dns.a \
++load tcpserver.o rules.o remoteinfo6.o timeoutconn6.o cdb.a dns.a \
+ time.a unix.a byte.a socket.lib
+- ./load tcpserver rules.o remoteinfo.o timeoutconn.o cdb.a \
++ ./load tcpserver rules.o remoteinfo6.o timeoutconn6.o cdb.a \
+ dns.a time.a unix.a byte.a `cat socket.lib`
+
+ tcpserver.o: \
+@@ -753,7 +763,7 @@
+ alloc.h buffer.h error.h strerr.h sgetopt.h subgetopt.h pathexec.h \
+ 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
++taia.h uint32.h
+ ./compile tcpserver.c
+
+ time.a: \
+@@ -765,9 +775,14 @@
+
+ timeoutconn.o: \
+ compile timeoutconn.c ndelay.h socket.h uint16.h iopause.h taia.h \
+-tai.h uint64.h error.h timeoutconn.h uint16.h
++tai.h uint64.h error.h timeoutconn.h uint16.h uint32.h
+ ./compile timeoutconn.c
+
++timeoutconn6.o: \
++compile timeoutconn6.c ndelay.h socket.h uint16.h iopause.h taia.h \
++tai.h uint64.h error.h timeoutconn.h uint16.h uint32.h
++ ./compile timeoutconn6.c
++
+ uint16_pack.o: \
+ compile uint16_pack.c uint16.h
+ ./compile uint16_pack.c
+@@ -806,7 +821,12 @@
+ socket_opts.o socket_remote.o socket_tcp.o socket_udp.o \
+ stralloc_cat.o stralloc_catb.o stralloc_cats.o stralloc_copy.o \
+ stralloc_eady.o stralloc_opyb.o stralloc_opys.o stralloc_pend.o \
+-strerr_die.o strerr_sys.o subgetopt.o wait_nohang.o wait_pid.o
++strerr_die.o strerr_sys.o subgetopt.o wait_nohang.o wait_pid.o \
++socket_conn6.o socket_bind6.o socket_accept6.o socket_recv6.o \
++socket_send6.o socket_local6.o socket_remote6.o socket_tcp6.o \
++socket_getifname.o socket_getifidx.o socket_v4mappedprefix.o \
++socket_ip4loopback.o socket_v6any.o socket_v6loopback.o \
++socket_udp6.o
+ ./makelib unix.a alloc.o alloc_re.o buffer.o buffer_0.o \
+ buffer_1.o buffer_2.o buffer_copy.o buffer_get.o \
+ buffer_put.o env.o error.o error_str.o fd_copy.o fd_move.o \
+@@ -819,7 +839,12 @@
+ socket_udp.o stralloc_cat.o stralloc_catb.o stralloc_cats.o \
+ stralloc_copy.o stralloc_eady.o stralloc_opyb.o \
+ stralloc_opys.o stralloc_pend.o strerr_die.o strerr_sys.o \
+- subgetopt.o wait_nohang.o wait_pid.o
++ subgetopt.o wait_nohang.o wait_pid.o socket_conn6.o \
++ socket_bind6.o socket_accept6.o socket_recv6.o socket_send6.o \
++ socket_local6.o socket_remote6.o socket_tcp6.o \
++ socket_getifname.o socket_getifidx.o socket_v4mappedprefix.o \
++ socket_ip4loopback.o socket_v6any.o socket_v6loopback.o \
++ socket_udp6.o
+
+ wait_nohang.o: \
+ compile wait_nohang.c haswaitp.h
+@@ -835,3 +860,110 @@
+ | sed s}HOME}"`head -1 conf-home`"}g \
+ > who@
+ chmod 755 who@
++
++socket_conn6.o: \
++compile socket_conn6.c socket.h uint16.h haveip6.h error.h ip6.h \
++uint32.h
++ ./compile socket_conn6.c
++
++socket_bind6.o: \
++compile socket_bind6.c socket.h uint16.h haveip6.h error.h ip6.h \
++uint32.h
++ ./compile socket_bind6.c
++
++socket_accept6.o: \
++compile socket_accept6.c socket.h uint16.h haveip6.h error.h ip6.h \
++uint32.h
++ ./compile socket_accept6.c
++
++socket_recv6.o: \
++compile socket_recv6.c socket.h uint16.h haveip6.h error.h ip6.h \
++uint32.h
++ ./compile socket_recv6.c
++
++socket_send6.o: \
++compile socket_send6.c socket.h uint16.h haveip6.h error.h uint32.h
++ ./compile socket_send6.c
++
++socket_local6.o: \
++compile socket_local6.c socket.h uint16.h haveip6.h error.h uint32.h
++ ./compile socket_local6.c
++
++socket_remote6.o: \
++compile socket_remote6.c socket.h uint16.h haveip6.h error.h uint32.h
++ ./compile socket_remote6.c
++
++dns_sortip6.o: \
++compile dns_sortip6.c byte.h dns.h stralloc.h gen_alloc.h iopause.h \
++taia.h tai.h uint64.h taia.h
++ ./compile dns_sortip6.c
++
++dns_nd6.o: \
++compile dns_nd6.c byte.h fmt.h dns.h stralloc.h gen_alloc.h iopause.h \
++taia.h tai.h uint64.h taia.h
++ ./compile dns_nd6.c
++
++dns_ipq6.o: \
++compile dns_ipq6.c stralloc.h gen_alloc.h case.h byte.h str.h dns.h \
++stralloc.h iopause.h taia.h tai.h uint64.h taia.h ip6.h
++ ./compile dns_ipq6.c
++
++dns_ip6.o: \
++compile dns_ip6.c stralloc.h gen_alloc.h uint16.h byte.h dns.h \
++stralloc.h iopause.h taia.h tai.h uint64.h taia.h
++ ./compile dns_ip6.c
++
++fmt_xlong.o: \
++compile fmt_xlong.c scan.h
++ ./compile fmt_xlong.c
++
++scan_xlong.o: \
++compile scan_xlong.c scan.h
++ ./compile scan_xlong.c
++
++ip6_fmt.o: \
++compile ip6_fmt.c fmt.h ip6.h
++ ./compile ip6_fmt.c
++
++scan_ip6.o: \
++compile scan_ip6.c scan.h ip6.h
++ ./compile scan_ip6.c
++
++socket_tcp6.o: \
++compile socket_tcp6.c ndelay.h socket.h uint16.h haveip6.h uint32.h
++ ./compile socket_tcp6.c
++
++socket_udp6.o: \
++compile socket_udp6.c ndelay.h socket.h uint16.h haveip6.h uint32.h
++ ./compile socket_udp6.c
++
++haveip6.h: \
++tryip6.c choose compile haveip6.h1 haveip6.h2
++ ./choose c tryip6 haveip6.h1 haveip6.h2 > haveip6.h
++
++socket_getifname.o: \
++compile socket_getifname.c socket.h uint16.h uint32.h
++ ./compile socket_getifname.c
++
++socket_getifidx.o: \
++compile socket_getifidx.c socket.h uint16.h uint32.h
++ ./compile socket_getifidx.c
++
++socket_ip4loopback.o: \
++compile socket_ip4loopback.c
++ ./compile socket_ip4loopback.c
++
++socket_v4mappedprefix.o: \
++compile socket_v4mappedprefix.c
++ ./compile socket_v4mappedprefix.c
++
++socket_v6any.o: \
++compile socket_v6any.c
++ ./compile socket_v6any.c
++
++socket_v6loopback.o: \
++compile socket_v6loopback.c
++ ./compile socket_v6loopback.c
++
++clean:
++ rm -f `cat TARGETS`
+diff -uNr ucspi-tcp-0.88.orig/TARGETS ucspi-tcp-0.88/TARGETS
+--- ucspi-tcp-0.88.orig/TARGETS 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/TARGETS 2009-08-04 17:45:59.000000000 -0500
+@@ -169,3 +169,31 @@
+ it
+ setup
+ check
++dns_ip6.o
++dns_ipq6.o
++dns_nd6.o
++dns_sortip6.o
++fmt_xlong.o
++ip6_fmt.o
++ip6_scan.o
++scan_0x.o
++socket_accept6.o
++socket_bind6.o
++socket_conn6.o
++socket_local6.o
++socket_recv6.o
++socket_remote6.o
++socket_send6.o
++socket_tcp6.o
++timeoutconn6.o
++haveip6.h
++remoteinfo6.o
++socket_getifidx.o
++socket_getifname.o
++scan_ip6.o
++scan_xlong.o
++socket_ip4loopback.o
++socket_udp6.o
++socket_v4mappedprefix.o
++socket_v6any.o
++socket_v6loopback.o
+diff -uNr ucspi-tcp-0.88.orig/addcr.1 ucspi-tcp-0.88/addcr.1
+--- ucspi-tcp-0.88.orig/addcr.1 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/addcr.1 2009-08-04 17:45:59.000000000 -0500
+@@ -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),
++fixcr(1)
+diff -uNr ucspi-tcp-0.88.orig/argv0.1 ucspi-tcp-0.88/argv0.1
+--- ucspi-tcp-0.88.orig/argv0.1 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/argv0.1 2009-08-04 17:45:59.000000000 -0500
+@@ -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)
+diff -uNr ucspi-tcp-0.88.orig/date@.1 ucspi-tcp-0.88/date@.1
+--- ucspi-tcp-0.88.orig/date@.1 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/date@.1 2009-08-04 17:45:59.000000000 -0500
+@@ -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)
+diff -uNr ucspi-tcp-0.88.orig/delcr.1 ucspi-tcp-0.88/delcr.1
+--- ucspi-tcp-0.88.orig/delcr.1 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/delcr.1 2009-08-04 17:45:59.000000000 -0500
+@@ -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)
+diff -uNr ucspi-tcp-0.88.orig/dns.h ucspi-tcp-0.88/dns.h
+--- ucspi-tcp-0.88.orig/dns.h 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/dns.h 2009-08-04 17:45:59.000000000 -0500
+@@ -34,51 +34,60 @@
+ unsigned int curserver;
+ struct taia deadline;
+ unsigned int pos;
+- char *servers;
+- char localip[4];
++ const char *servers;
++ char localip[16];
++ unsigned int scope_id;
+ char qtype[2];
+ } ;
+
+-extern void dns_random_init(char *);
++extern void dns_random_init(const char *);
+ extern unsigned int dns_random(unsigned int);
+
+ extern void dns_sortip(char *,unsigned int);
++extern void dns_sortip6(char *,unsigned int);
+
+ extern void dns_domain_free(char **);
+-extern int dns_domain_copy(char **,char *);
+-extern unsigned int dns_domain_length(char *);
+-extern int dns_domain_equal(char *,char *);
+-extern char *dns_domain_suffix(char *,char *);
+-extern int dns_domain_fromdot(char **,char *,unsigned int);
+-extern int dns_domain_todot_cat(stralloc *,char *);
+-
+-extern unsigned int dns_packet_copy(char *,unsigned int,unsigned int,char *,unsigned int);
+-extern unsigned int dns_packet_getname(char *,unsigned int,unsigned int,char **);
+-extern unsigned int dns_packet_skipname(char *,unsigned int,unsigned int);
+-extern int dns_packet_nameequal(char *,unsigned int,unsigned int,char *,unsigned int,unsigned int);
++extern int dns_domain_copy(char **,const char *);
++extern unsigned int dns_domain_length(const char *);
++extern int dns_domain_equal(const char *,const char *);
++extern int dns_domain_suffix(const char *,const char *);
++extern unsigned int dns_domain_suffixpos(const char *,const char *);
++extern int dns_domain_fromdot(char **,const char *,unsigned int);
++extern int dns_domain_todot_cat(stralloc *,const char *);
++
++extern unsigned int dns_packet_copy(const char *,unsigned int,unsigned int,char *,unsigned int);
++extern unsigned int dns_packet_getname(const char *,unsigned int,unsigned int,char **);
++extern unsigned int dns_packet_skipname(const char *,unsigned int,unsigned int);
+
+-extern int dns_transmit_start(struct dns_transmit *,char *,int,char *,char *,char *);
++extern int dns_transmit_start(struct dns_transmit *,const char *,int,const char *,const char *,const char *);
+ extern void dns_transmit_free(struct dns_transmit *);
+ extern void dns_transmit_io(struct dns_transmit *,iopause_fd *,struct taia *);
+-extern int dns_transmit_get(struct dns_transmit *,iopause_fd *,struct taia *);
++extern int dns_transmit_get(struct dns_transmit *,const iopause_fd *,const struct taia *);
+
+ extern int dns_resolvconfip(char *);
+-extern int dns_resolve(char *,char *);
++extern int dns_resolve(const char *,const char *);
+ extern struct dns_transmit dns_resolve_tx;
+
+-extern int dns_ip4_packet(stralloc *,char *,unsigned int);
+-extern int dns_ip4(stralloc *,stralloc *);
+-extern int dns_name_packet(stralloc *,char *,unsigned int);
+-extern void dns_name4_domain(char *,char *);
++extern int dns_ip4_packet(stralloc *,const char *,unsigned int);
++extern int dns_ip4(stralloc *,const stralloc *);
++extern int dns_ip6_packet(stralloc *,const char *,unsigned int);
++extern int dns_ip6(stralloc *,stralloc *);
++extern int dns_name_packet(stralloc *,const char *,unsigned int);
++extern void dns_name4_domain(char *,const char *);
+ #define DNS_NAME4_DOMAIN 31
+-extern int dns_name4(stralloc *,char *);
+-extern int dns_txt_packet(stralloc *,char *,unsigned int);
+-extern int dns_txt(stralloc *,stralloc *);
+-extern int dns_mx_packet(stralloc *,char *,unsigned int);
+-extern int dns_mx(stralloc *,stralloc *);
++extern int dns_name4(stralloc *,const char *);
++extern int dns_txt_packet(stralloc *,const char *,unsigned int);
++extern int dns_txt(stralloc *,const stralloc *);
++extern int dns_mx_packet(stralloc *,const char *,unsigned int);
++extern int dns_mx(stralloc *,const stralloc *);
+
+ extern int dns_resolvconfrewrite(stralloc *);
+-extern int dns_ip4_qualify_rules(stralloc *,stralloc *,stralloc *,stralloc *);
+-extern int dns_ip4_qualify(stralloc *,stralloc *,stralloc *);
++extern int dns_ip4_qualify_rules(stralloc *,stralloc *,const stralloc *,const stralloc *);
++extern int dns_ip4_qualify(stralloc *,stralloc *,const stralloc *);
++extern int dns_ip6_qualify_rules(stralloc *,stralloc *,const stralloc *,const stralloc *);
++extern int dns_ip6_qualify(stralloc *,stralloc *,const stralloc *);
++
++extern int dns_name6_domain(char *,char *);
++#define DNS_NAME6_DOMAIN (4*16+11)
+
+ #endif
+diff -uNr ucspi-tcp-0.88.orig/dns_dfd.c ucspi-tcp-0.88/dns_dfd.c
+--- ucspi-tcp-0.88.orig/dns_dfd.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/dns_dfd.c 2009-08-04 17:45:59.000000000 -0500
+@@ -1,9 +1,10 @@
+-#include "error.h"
+-#include "alloc.h"
++#include <stdlib.h>
++#include <errno.h>
+ #include "byte.h"
+ #include "dns.h"
++#include "error.h"
+
+-int dns_domain_fromdot(char **out,char *buf,unsigned int n)
++int dns_domain_fromdot(char **out,const char *buf,unsigned int n)
+ {
+ char label[63];
+ unsigned int labellen = 0; /* <= sizeof label */
+@@ -59,11 +60,11 @@
+ if (namelen + 1 > sizeof name) return 0;
+ name[namelen++] = 0;
+
+- x = alloc(namelen);
++ x = malloc(namelen);
+ if (!x) return 0;
+ byte_copy(x,namelen,name);
+
+- if (*out) alloc_free(*out);
++ if (*out) free(*out);
+ *out = x;
+ return 1;
+ }
+diff -uNr ucspi-tcp-0.88.orig/dns_domain.c ucspi-tcp-0.88/dns_domain.c
+--- ucspi-tcp-0.88.orig/dns_domain.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/dns_domain.c 2009-08-04 17:45:59.000000000 -0500
+@@ -1,16 +1,15 @@
+-#include "error.h"
+-#include "alloc.h"
++#include <stdlib.h>
+ #include "case.h"
+ #include "byte.h"
+ #include "dns.h"
+
+-unsigned int dns_domain_length(char *dn)
++unsigned int dns_domain_length(const char *dn)
+ {
+- char *x;
++ const char *x;
+ unsigned char c;
+
+ x = dn;
+- while (c = *x++)
++ while ((c = *x++))
+ x += (unsigned int) c;
+ return x - dn;
+ }
+@@ -18,26 +17,26 @@
+ void dns_domain_free(char **out)
+ {
+ if (*out) {
+- alloc_free(*out);
++ free(*out);
+ *out = 0;
+ }
+ }
+
+-int dns_domain_copy(char **out,char *in)
++int dns_domain_copy(char **out,const char *in)
+ {
+ unsigned int len;
+ char *x;
+
+ len = dns_domain_length(in);
+- x = alloc(len);
++ x = malloc(len);
+ if (!x) return 0;
+ byte_copy(x,len,in);
+- if (*out) alloc_free(*out);
++ if (*out) free(*out);
+ *out = x;
+ return 1;
+ }
+
+-int dns_domain_equal(char *dn1,char *dn2)
++int dns_domain_equal(const char *dn1,const char *dn2)
+ {
+ unsigned int len;
+
+@@ -48,12 +47,25 @@
+ return 1;
+ }
+
+-char *dns_domain_suffix(char *big,char *little)
++int dns_domain_suffix(const char *big,const char *little)
++{
++ unsigned char c;
++
++ for (;;) {
++ if (dns_domain_equal(big,little)) return 1;
++ c = *big++;
++ if (!c) return 0;
++ big += c;
++ }
++}
++
++unsigned int dns_domain_suffixpos(const char *big,const char *little)
+ {
++ const char *orig = big;
+ unsigned char c;
+
+ for (;;) {
+- if (dns_domain_equal(big,little)) return big;
++ if (dns_domain_equal(big,little)) return big - orig;
+ c = *big++;
+ if (!c) return 0;
+ big += c;
+diff -uNr ucspi-tcp-0.88.orig/dns_dtda.c ucspi-tcp-0.88/dns_dtda.c
+--- ucspi-tcp-0.88.orig/dns_dtda.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/dns_dtda.c 2009-08-04 17:45:59.000000000 -0500
+@@ -1,7 +1,7 @@
+ #include "stralloc.h"
+ #include "dns.h"
+
+-int dns_domain_todot_cat(stralloc *out,char *d)
++int dns_domain_todot_cat(stralloc *out,const char *d)
+ {
+ char ch;
+ char ch2;
+diff -uNr ucspi-tcp-0.88.orig/dns_ip.c ucspi-tcp-0.88/dns_ip.c
+--- ucspi-tcp-0.88.orig/dns_ip.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/dns_ip.c 2009-08-04 17:45:59.000000000 -0500
+@@ -3,7 +3,7 @@
+ #include "byte.h"
+ #include "dns.h"
+
+-int dns_ip4_packet(stralloc *out,char *buf,unsigned int len)
++int dns_ip4_packet(stralloc *out,const char *buf,unsigned int len)
+ {
+ unsigned int pos;
+ char header[12];
+@@ -36,7 +36,7 @@
+
+ static char *q = 0;
+
+-int dns_ip4(stralloc *out,stralloc *fqdn)
++int dns_ip4(stralloc *out,const stralloc *fqdn)
+ {
+ unsigned int i;
+ char code;
+diff -uNr ucspi-tcp-0.88.orig/dns_ip6.c ucspi-tcp-0.88/dns_ip6.c
+--- ucspi-tcp-0.88.orig/dns_ip6.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/dns_ip6.c 2009-08-04 17:45:59.000000000 -0500
+@@ -0,0 +1,103 @@
++#include "stralloc.h"
++#include "uint16.h"
++#include "byte.h"
++#include "dns.h"
++#include "ip4.h"
++#include "ip6.h"
++
++static int dns_ip6_packet_add(stralloc *out,const char *buf,unsigned int len)
++{
++ unsigned int pos;
++ char header[16];
++ uint16 numanswers;
++ uint16 datalen;
++
++ pos = dns_packet_copy(buf,len,0,header,12); if (!pos) return -1;
++ uint16_unpack_big(header + 6,&numanswers);
++ pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
++ pos += 4;
++
++ while (numanswers--) {
++ pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
++ pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) return -1;
++ uint16_unpack_big(header + 8,&datalen);
++ if (byte_equal(header,2,DNS_T_AAAA)) {
++ if (byte_equal(header + 2,2,DNS_C_IN))
++ if (datalen == 16) {
++ if (!dns_packet_copy(buf,len,pos,header,16)) return -1;
++ if (!stralloc_catb(out,header,16)) return -1;
++ }
++ } else if (byte_equal(header,2,DNS_T_A))
++ if (byte_equal(header + 2,2,DNS_C_IN))
++ if (datalen == 4) {
++ byte_copy(header,12,V4mappedprefix);
++ if (!dns_packet_copy(buf,len,pos,header+12,4)) return -1;
++ if (!stralloc_catb(out,header,16)) return -1;
++ }
++ pos += datalen;
++ }
++
++ dns_sortip6(out->s,out->len);
++ return 0;
++}
++
++int dns_ip6_packet(stralloc *out,const char *buf,unsigned int len) {
++ if (!stralloc_copys(out,"")) return -1;
++ return dns_ip6_packet_add(out,buf,len);
++}
++
++static char *q = 0;
++
++int dns_ip6(stralloc *out,stralloc *fqdn)
++{
++ unsigned int i;
++ char code;
++ char ch;
++ char ip[16];
++
++ if (!stralloc_copys(out,"")) return -1;
++ if (!stralloc_readyplus(fqdn,1)) return -1;
++ fqdn->s[fqdn->len]=0;
++ if ((i=scan_ip6(fqdn->s,ip))) {
++ if (fqdn->s[i]) return -1;
++ stralloc_copyb(out,ip,16);
++ return 0;
++ }
++ code = 0;
++ for (i = 0;i <= fqdn->len;++i) {
++ if (i < fqdn->len)
++ ch = fqdn->s[i];
++ else
++ ch = '.';
++
++ if ((ch == '[') || (ch == ']')) continue;
++ if (ch == '.') {
++ if (!stralloc_append(out,&code)) return -1;
++ code = 0;
++ continue;
++ }
++ if ((ch >= '0') && (ch <= '9')) {
++ code *= 10;
++ code += ch - '0';
++ continue;
++ }
++
++ if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1;
++ if (!stralloc_copys(out,"")) return -1;
++ if (dns_resolve(q,DNS_T_AAAA) != -1)
++ if (dns_ip6_packet_add(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) != -1) {
++ dns_transmit_free(&dns_resolve_tx);
++ dns_domain_free(&q);
++ }
++ if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1;
++ if (dns_resolve(q,DNS_T_A) != -1)
++ if (dns_ip6_packet_add(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) != -1) {
++ dns_transmit_free(&dns_resolve_tx);
++ dns_domain_free(&q);
++ }
++ return out->a>0?0:-1;
++ }
++
++ out->len &= ~3;
++ return 0;
++}
+diff -uNr ucspi-tcp-0.88.orig/dns_ipq.c ucspi-tcp-0.88/dns_ipq.c
+--- ucspi-tcp-0.88.orig/dns_ipq.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/dns_ipq.c 2009-08-04 17:45:59.000000000 -0500
+@@ -4,7 +4,7 @@
+ #include "str.h"
+ #include "dns.h"
+
+-static int doit(stralloc *work,char *rule)
++static int doit(stralloc *work,const char *rule)
+ {
+ char ch;
+ unsigned int colon;
+@@ -30,7 +30,7 @@
+ return stralloc_cats(work,rule + colon + 1);
+ }
+
+-int dns_ip4_qualify_rules(stralloc *out,stralloc *fqdn,stralloc *in,stralloc *rules)
++int dns_ip4_qualify_rules(stralloc *out,stralloc *fqdn,const stralloc *in,const stralloc *rules)
+ {
+ unsigned int i;
+ unsigned int j;
+@@ -63,7 +63,7 @@
+ }
+ }
+
+-int dns_ip4_qualify(stralloc *out,stralloc *fqdn,stralloc *in)
++int dns_ip4_qualify(stralloc *out,stralloc *fqdn,const stralloc *in)
+ {
+ static stralloc rules;
+ if (dns_resolvconfrewrite(&rules) == -1) return -1;
+diff -uNr ucspi-tcp-0.88.orig/dns_ipq6.c ucspi-tcp-0.88/dns_ipq6.c
+--- ucspi-tcp-0.88.orig/dns_ipq6.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/dns_ipq6.c 2009-08-04 17:45:59.000000000 -0500
+@@ -0,0 +1,72 @@
++#include "stralloc.h"
++#include "case.h"
++#include "byte.h"
++#include "str.h"
++#include "dns.h"
++
++static int doit(stralloc *work,const char *rule)
++{
++ char ch;
++ unsigned int colon;
++ unsigned int prefixlen;
++
++ ch = *rule++;
++ if ((ch != '?') && (ch != '=') && (ch != '*') && (ch != '-')) return 1;
++ colon = str_chr(rule,':');
++ if (!rule[colon]) return 1;
++
++ if (work->len < colon) return 1;
++ prefixlen = work->len - colon;
++ if ((ch == '=') && prefixlen) return 1;
++ if (case_diffb(rule,colon,work->s + prefixlen)) return 1;
++ if (ch == '?') {
++ if (byte_chr(work->s,prefixlen,'.') < prefixlen) return 1;
++ if (byte_chr(work->s,prefixlen,':') < prefixlen) return 1;
++ if (byte_chr(work->s,prefixlen,'[') < prefixlen) return 1;
++ if (byte_chr(work->s,prefixlen,']') < prefixlen) return 1;
++ }
++
++ work->len = prefixlen;
++ if (ch == '-') work->len = 0;
++ return stralloc_cats(work,rule + colon + 1);
++}
++
++int dns_ip6_qualify_rules(stralloc *out,stralloc *fqdn,const stralloc *in,const stralloc *rules)
++{
++ unsigned int i;
++ unsigned int j;
++ unsigned int plus;
++ unsigned int fqdnlen;
++
++ if (!stralloc_copy(fqdn,in)) return -1;
++
++ for (j = i = 0;j < rules->len;++j)
++ if (!rules->s[j]) {
++ if (!doit(fqdn,rules->s + i)) return -1;
++ i = j + 1;
++ }
++
++ fqdnlen = fqdn->len;
++ plus = byte_chr(fqdn->s,fqdnlen,'+');
++ if (plus >= fqdnlen)
++ return dns_ip6(out,fqdn);
++
++ i = plus + 1;
++ for (;;) {
++ j = byte_chr(fqdn->s + i,fqdnlen - i,'+');
++ byte_copy(fqdn->s + plus,j,fqdn->s + i);
++ fqdn->len = plus + j;
++ if (dns_ip6(out,fqdn) == -1) return -1;
++ if (out->len) return 0;
++ i += j;
++ if (i >= fqdnlen) return 0;
++ ++i;
++ }
++}
++
++int dns_ip6_qualify(stralloc *out,stralloc *fqdn,const stralloc *in)
++{
++ static stralloc rules;
++ if (dns_resolvconfrewrite(&rules) == -1) return -1;
++ return dns_ip6_qualify_rules(out,fqdn,in,&rules);
++}
+diff -uNr ucspi-tcp-0.88.orig/dns_name.c ucspi-tcp-0.88/dns_name.c
+--- ucspi-tcp-0.88.orig/dns_name.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/dns_name.c 2009-08-04 17:45:59.000000000 -0500
+@@ -2,10 +2,11 @@
+ #include "uint16.h"
+ #include "byte.h"
+ #include "dns.h"
++#include "ip6.h"
+
+ static char *q = 0;
+
+-int dns_name_packet(stralloc *out,char *buf,unsigned int len)
++int dns_name_packet(stralloc *out,const char *buf,unsigned int len)
+ {
+ unsigned int pos;
+ char header[12];
+@@ -35,7 +36,7 @@
+ return 0;
+ }
+
+-int dns_name4(stralloc *out,char ip[4])
++int dns_name4(stralloc *out,const char ip[4])
+ {
+ char name[DNS_NAME4_DOMAIN];
+
+@@ -46,3 +47,17 @@
+ dns_domain_free(&q);
+ return 0;
+ }
++
++int dns_name6(stralloc *out,char ip[16])
++{
++ char name[DNS_NAME6_DOMAIN];
++
++ if (ip6_isv4mapped(ip))
++ return dns_name4(out,ip+12);
++ dns_name6_domain(name,ip);
++ if (dns_resolve(name,DNS_T_PTR) == -1) return -1;
++ if (dns_name_packet(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) == -1) return -1;
++ dns_transmit_free(&dns_resolve_tx);
++ dns_domain_free(&q);
++ return 0;
++}
+diff -uNr ucspi-tcp-0.88.orig/dns_nd.c ucspi-tcp-0.88/dns_nd.c
+--- ucspi-tcp-0.88.orig/dns_nd.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/dns_nd.c 2009-08-04 17:45:59.000000000 -0500
+@@ -2,7 +2,7 @@
+ #include "fmt.h"
+ #include "dns.h"
+
+-void dns_name4_domain(char name[DNS_NAME4_DOMAIN],char ip[4])
++void dns_name4_domain(char name[DNS_NAME4_DOMAIN],const char ip[4])
+ {
+ unsigned int namelen;
+ unsigned int i;
+diff -uNr ucspi-tcp-0.88.orig/dns_nd6.c ucspi-tcp-0.88/dns_nd6.c
+--- ucspi-tcp-0.88.orig/dns_nd6.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/dns_nd6.c 2009-08-04 17:45:59.000000000 -0500
+@@ -0,0 +1,28 @@
++#include "byte.h"
++#include "fmt.h"
++#include "dns.h"
++
++/* RFC1886:
++ * 4321:0:1:2:3:4:567:89ab
++ * ->
++ * b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.IP6.INT.
++ */
++
++static inline char tohex(char c) {
++ return c>=10?c-10+'a':c+'0';
++}
++
++int dns_name6_domain(char name[DNS_NAME6_DOMAIN],char ip[16])
++{
++ unsigned int j;
++
++ for (j=0; j<16; j++) {
++ name[j*4]=1;
++ name[j*4+1]=tohex(ip[15-j] & 15);
++ name[j*4+2]=1;
++ name[j*4+3]=tohex((unsigned char)ip[15-j] >> 4);
++ }
++ byte_copy(name + 4*16,10,"\3ip6\4arpa\0");
++ return 4*16+10;
++}
++
+diff -uNr ucspi-tcp-0.88.orig/dns_packet.c ucspi-tcp-0.88/dns_packet.c
+--- ucspi-tcp-0.88.orig/dns_packet.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/dns_packet.c 2009-08-04 17:45:59.000000000 -0500
+@@ -2,10 +2,11 @@
+ DNS should have used LZ77 instead of its own sophomoric compression algorithm.
+ */
+
+-#include "error.h"
++#include <errno.h>
+ #include "dns.h"
++#include "error.h"
+
+-unsigned int dns_packet_copy(char *buf,unsigned int len,unsigned int pos,char *out,unsigned int outlen)
++unsigned int dns_packet_copy(const char *buf,unsigned int len,unsigned int pos,char *out,unsigned int outlen)
+ {
+ while (outlen) {
+ if (pos >= len) { errno = error_proto; return 0; }
+@@ -15,7 +16,7 @@
+ return pos;
+ }
+
+-unsigned int dns_packet_skipname(char *buf,unsigned int len,unsigned int pos)
++unsigned int dns_packet_skipname(const char *buf,unsigned int len,unsigned int pos)
+ {
+ unsigned char ch;
+
+@@ -32,7 +33,7 @@
+ return 0;
+ }
+
+-unsigned int dns_packet_getname(char *buf,unsigned int len,unsigned int pos,char **d)
++unsigned int dns_packet_getname(const char *buf,unsigned int len,unsigned int pos,char **d)
+ {
+ unsigned int loop = 0;
+ unsigned int state = 0;
+diff -uNr ucspi-tcp-0.88.orig/dns_random.c ucspi-tcp-0.88/dns_random.c
+--- ucspi-tcp-0.88.orig/dns_random.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/dns_random.c 2009-08-04 17:45:59.000000000 -0500
+@@ -1,3 +1,4 @@
++#include <unistd.h>
+ #include "dns.h"
+ #include "taia.h"
+ #include "uint32.h"
+@@ -29,7 +30,7 @@
+ }
+ }
+
+-void dns_random_init(char data[128])
++void dns_random_init(const char data[128])
+ {
+ int i;
+ struct taia t;
+diff -uNr ucspi-tcp-0.88.orig/dns_rcip.c ucspi-tcp-0.88/dns_rcip.c
+--- ucspi-tcp-0.88.orig/dns_rcip.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/dns_rcip.c 2009-08-04 17:45:59.000000000 -0500
+@@ -2,12 +2,13 @@
+ #include "openreadclose.h"
+ #include "byte.h"
+ #include "ip4.h"
+-#include "env.h"
++#include "ip6.h"
+ #include "dns.h"
++#include "env.h"
+
+ static stralloc data = {0};
+
+-static int init(char ip[64])
++static int init(char ip[256])
+ {
+ int i;
+ int j;
+@@ -16,15 +17,16 @@
+
+ x = env_get("DNSCACHEIP");
+ if (x)
+- while (iplen <= 60)
++ while (iplen <= 60) {
+ if (*x == '.')
+ ++x;
+ else {
+- i = ip4_scan(x,ip + iplen);
++ i = scan_ip6(x,ip + iplen);
+ if (!i) break;
+ x += i;
+- iplen += 4;
++ iplen += 16;
+ }
++ }
+
+ if (!iplen) {
+ i = openreadclose("/etc/resolv.conf",&data,64);
+@@ -39,8 +41,9 @@
+ while ((data.s[i] == ' ') || (data.s[i] == '\t'))
+ ++i;
+ if (iplen <= 60)
+- if (ip4_scan(data.s + i,ip + iplen))
+- iplen += 4;
++ if (scan_ip6(data.s + i,ip + iplen)) {
++ iplen += 16;
++ }
+ }
+ i = j + 1;
+ }
+@@ -48,19 +51,19 @@
+ }
+
+ if (!iplen) {
+- byte_copy(ip,4,"\177\0\0\1");
+- iplen = 4;
++ byte_copy(ip,16,"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1");
++ iplen = 16;
+ }
+- byte_zero(ip + iplen,64 - iplen);
++ byte_zero(ip + iplen,256 - iplen);
+ return 0;
+ }
+
+ static int ok = 0;
+ static unsigned int uses;
+ static struct taia deadline;
+-static char ip[64]; /* defined if ok */
++static char ip[256]; /* defined if ok */
+
+-int dns_resolvconfip(char s[64])
++int dns_resolvconfip(char s[256])
+ {
+ struct taia now;
+
+@@ -77,6 +80,6 @@
+ }
+
+ --uses;
+- byte_copy(s,64,ip);
++ byte_copy(s,256,ip);
+ return 0;
+ }
+diff -uNr ucspi-tcp-0.88.orig/dns_rcrw.c ucspi-tcp-0.88/dns_rcrw.c
+--- ucspi-tcp-0.88.orig/dns_rcrw.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/dns_rcrw.c 2009-08-04 17:45:59.000000000 -0500
+@@ -1,16 +1,17 @@
++#include <unistd.h>
+ #include "taia.h"
+-#include "env.h"
+ #include "byte.h"
+ #include "str.h"
+ #include "openreadclose.h"
+ #include "dns.h"
++#include "env.h"
+
+ static stralloc data = {0};
+
+ static int init(stralloc *rules)
+ {
+ char host[256];
+- char *x;
++ const char *x;
+ int i;
+ int j;
+ int k;
+diff -uNr ucspi-tcp-0.88.orig/dns_resolve.c ucspi-tcp-0.88/dns_resolve.c
+--- ucspi-tcp-0.88.orig/dns_resolve.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/dns_resolve.c 2009-08-04 17:45:59.000000000 -0500
+@@ -2,19 +2,20 @@
+ #include "taia.h"
+ #include "byte.h"
+ #include "dns.h"
++#include "ip6.h"
+
+ struct dns_transmit dns_resolve_tx = {0};
+
+-int dns_resolve(char *q,char qtype[2])
++int dns_resolve(const char *q,const char qtype[2])
+ {
+ struct taia stamp;
+ struct taia deadline;
+- char servers[64];
++ char servers[256];
+ iopause_fd x[1];
+ int r;
+
+ if (dns_resolvconfip(servers) == -1) return -1;
+- if (dns_transmit_start(&dns_resolve_tx,servers,1,q,qtype,"\0\0\0\0") == -1) return -1;
++ if (dns_transmit_start(&dns_resolve_tx,servers,1,q,qtype,V6any) == -1) return -1;
+
+ for (;;) {
+ taia_now(&stamp);
+diff -uNr ucspi-tcp-0.88.orig/dns_sortip6.c ucspi-tcp-0.88/dns_sortip6.c
+--- ucspi-tcp-0.88.orig/dns_sortip6.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/dns_sortip6.c 2009-08-04 17:45:59.000000000 -0500
+@@ -0,0 +1,20 @@
++#include "byte.h"
++#include "dns.h"
++
++/* XXX: sort servers by configurable notion of closeness? */
++/* XXX: pay attention to competence of each server? */
++
++void dns_sortip6(char *s,unsigned int n)
++{
++ unsigned int i;
++ char tmp[16];
++
++ n >>= 4;
++ while (n > 1) {
++ i = dns_random(n);
++ --n;
++ byte_copy(tmp,16,s + (i << 4));
++ byte_copy(s + (i << 4),16,s + (n << 4));
++ byte_copy(s + (n << 4),16,tmp);
++ }
++}
+diff -uNr ucspi-tcp-0.88.orig/dns_transmit.c ucspi-tcp-0.88/dns_transmit.c
+--- ucspi-tcp-0.88.orig/dns_transmit.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/dns_transmit.c 2009-08-04 17:45:59.000000000 -0500
+@@ -1,12 +1,15 @@
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <unistd.h>
++#include <stdlib.h>
+ #include "socket.h"
+-#include "alloc.h"
+-#include "error.h"
++#include <errno.h>
+ #include "byte.h"
+-#include "readwrite.h"
+ #include "uint16.h"
+ #include "dns.h"
++#include "ip6.h"
+
+-static int serverwantstcp(char *buf,unsigned int len)
++static int serverwantstcp(const char *buf,unsigned int len)
+ {
+ char out[12];
+
+@@ -15,7 +18,7 @@
+ return 0;
+ }
+
+-static int serverfailed(char *buf,unsigned int len)
++static int serverfailed(const char *buf,unsigned int len)
+ {
+ char out[12];
+ unsigned int rcode;
+@@ -23,11 +26,11 @@
+ if (!dns_packet_copy(buf,len,0,out,12)) return 1;
+ rcode = out[3];
+ rcode &= 15;
+- if (rcode && (rcode != 3)) { errno = error_again; return 1; }
++ if (rcode && (rcode != 3)) { errno = EAGAIN; return 1; }
+ return 0;
+ }
+
+-static int irrelevant(struct dns_transmit *d,char *buf,unsigned int len)
++static int irrelevant(const struct dns_transmit *d,const char *buf,unsigned int len)
+ {
+ char out[12];
+ char *dn;
+@@ -40,8 +43,8 @@
+
+ dn = 0;
+ pos = dns_packet_getname(buf,len,pos,&dn); if (!pos) return 1;
+- if (!dns_domain_equal(dn,d->query + 14)) { alloc_free(dn); return 1; }
+- alloc_free(dn);
++ if (!dns_domain_equal(dn,d->query + 14)) { free(dn); return 1; }
++ free(dn);
+
+ pos = dns_packet_copy(buf,len,pos,out,4); if (!pos) return 1;
+ if (byte_diff(out,2,d->qtype)) return 1;
+@@ -53,14 +56,14 @@
+ static void packetfree(struct dns_transmit *d)
+ {
+ if (!d->packet) return;
+- alloc_free(d->packet);
++ free(d->packet);
+ d->packet = 0;
+ }
+
+ static void queryfree(struct dns_transmit *d)
+ {
+ if (!d->query) return;
+- alloc_free(d->query);
++ free(d->query);
+ d->query = 0;
+ }
+
+@@ -83,9 +86,9 @@
+ int j;
+
+ for (j = 0;j < 10;++j)
+- if (socket_bind4(d->s1 - 1,d->localip,1025 + dns_random(64510)) == 0)
++ if (socket_bind6(d->s1 - 1,d->localip,1025 + dns_random(64510),d->scope_id) == 0)
+ return 0;
+- if (socket_bind4(d->s1 - 1,d->localip,0) == 0)
++ if (socket_bind6(d->s1 - 1,d->localip,0,d->scope_id) == 0)
+ return 0;
+ return -1;
+ }
+@@ -94,22 +97,22 @@
+
+ static int thisudp(struct dns_transmit *d)
+ {
+- char *ip;
++ const char *ip;
+
+ socketfree(d);
+
+ while (d->udploop < 4) {
+ for (;d->curserver < 16;++d->curserver) {
+- ip = d->servers + 4 * d->curserver;
+- if (byte_diff(ip,4,"\0\0\0\0")) {
++ ip = d->servers + 16 * d->curserver;
++ if (byte_diff(ip,16,V6any)) {
+ d->query[2] = dns_random(256);
+ d->query[3] = dns_random(256);
+
+- d->s1 = 1 + socket_udp();
++ d->s1 = 1 + socket_udp6();
+ if (!d->s1) { dns_transmit_free(d); return -1; }
+ if (randombind(d) == -1) { dns_transmit_free(d); return -1; }
+
+- if (socket_connect4(d->s1 - 1,ip,53) == 0)
++ if (socket_connect6(d->s1 - 1,ip,53,d->scope_id) == 0)
+ if (send(d->s1 - 1,d->query + 2,d->querylen - 2,0) == d->querylen - 2) {
+ struct taia now;
+ taia_now(&now);
+@@ -145,29 +148,29 @@
+ static int thistcp(struct dns_transmit *d)
+ {
+ struct taia now;
+- char *ip;
++ const char *ip;
+
+ socketfree(d);
+ packetfree(d);
+
+ for (;d->curserver < 16;++d->curserver) {
+- ip = d->servers + 4 * d->curserver;
+- if (byte_diff(ip,4,"\0\0\0\0")) {
++ ip = d->servers + 16 * d->curserver;
++ if (byte_diff(ip,16,V6any)) {
+ d->query[2] = dns_random(256);
+ d->query[3] = dns_random(256);
+
+- d->s1 = 1 + socket_tcp();
++ d->s1 = 1 + socket_tcp6();
+ if (!d->s1) { dns_transmit_free(d); return -1; }
+ if (randombind(d) == -1) { dns_transmit_free(d); return -1; }
+
+ taia_now(&now);
+ taia_uint(&d->deadline,10);
+ taia_add(&d->deadline,&d->deadline,&now);
+- if (socket_connect4(d->s1 - 1,ip,53) == 0) {
++ if (socket_connect6(d->s1 - 1,ip,53,d->scope_id) == 0) {
+ d->tcpstate = 2;
+ return 0;
+ }
+- if ((errno == error_inprogress) || (errno == error_wouldblock)) {
++ if ((errno == EINPROGRESS) || (errno == EWOULDBLOCK)) {
+ d->tcpstate = 1;
+ return 0;
+ }
+@@ -191,16 +194,16 @@
+ return thistcp(d);
+ }
+
+-int dns_transmit_start(struct dns_transmit *d,char servers[64],int flagrecursive,char *q,char qtype[2],char localip[4])
++int dns_transmit_start(struct dns_transmit *d,const char servers[256],int flagrecursive,const char *q,const char qtype[2],const char localip[16])
+ {
+ unsigned int len;
+
+ dns_transmit_free(d);
+- errno = error_io;
++ errno = EIO;
+
+ len = dns_domain_length(q);
+ d->querylen = len + 18;
+- d->query = alloc(d->querylen);
++ d->query = malloc(d->querylen);
+ if (!d->query) return -1;
+
+ uint16_pack_big(d->query,len + 16);
+@@ -211,7 +214,7 @@
+
+ byte_copy(d->qtype,2,qtype);
+ d->servers = servers;
+- byte_copy(d->localip,4,localip);
++ byte_copy(d->localip,16,localip);
+
+ d->udploop = flagrecursive ? 1 : 0;
+
+@@ -236,19 +239,19 @@
+ *deadline = d->deadline;
+ }
+
+-int dns_transmit_get(struct dns_transmit *d,iopause_fd *x,struct taia *when)
++int dns_transmit_get(struct dns_transmit *d,const iopause_fd *x,const struct taia *when)
+ {
+ char udpbuf[513];
+ unsigned char ch;
+ int r;
+ int fd;
+
+- errno = error_io;
++ errno = EIO;
+ fd = d->s1 - 1;
+
+ if (!x->revents) {
+ if (taia_less(when,&d->deadline)) return 0;
+- errno = error_timeout;
++ errno = ETIMEDOUT;
+ if (d->tcpstate == 0) return nextudp(d);
+ return nexttcp(d);
+ }
+@@ -260,7 +263,7 @@
+ */
+ r = recv(fd,udpbuf,sizeof udpbuf,0);
+ if (r <= 0) {
+- if (d->udploop == 2) return 0;
++ if (errno == ECONNREFUSED) if (d->udploop == 2) return 0;
+ return nextudp(d);
+ }
+ if (r + 1 > sizeof udpbuf) return 0;
+@@ -274,7 +277,7 @@
+ socketfree(d);
+
+ d->packetlen = r;
+- d->packet = alloc(d->packetlen);
++ d->packet = malloc(d->packetlen);
+ if (!d->packet) { dns_transmit_free(d); return -1; }
+ byte_copy(d->packet,d->packetlen,udpbuf);
+ queryfree(d);
+@@ -334,7 +337,7 @@
+ d->packetlen += ch;
+ d->tcpstate = 5;
+ d->pos = 0;
+- d->packet = alloc(d->packetlen);
++ d->packet = malloc(d->packetlen);
+ if (!d->packet) { dns_transmit_free(d); return -1; }
+ return 0;
+ }
+diff -uNr ucspi-tcp-0.88.orig/dns_txt.c ucspi-tcp-0.88/dns_txt.c
+--- ucspi-tcp-0.88.orig/dns_txt.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/dns_txt.c 2009-08-04 17:45:59.000000000 -0500
+@@ -3,7 +3,7 @@
+ #include "byte.h"
+ #include "dns.h"
+
+-int dns_txt_packet(stralloc *out,char *buf,unsigned int len)
++int dns_txt_packet(stralloc *out,const char *buf,unsigned int len)
+ {
+ unsigned int pos;
+ char header[12];
+@@ -48,7 +48,7 @@
+
+ static char *q = 0;
+
+-int dns_txt(stralloc *out,stralloc *fqdn)
++int dns_txt(stralloc *out,const stralloc *fqdn)
+ {
+ if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1;
+ if (dns_resolve(q,DNS_T_TXT) == -1) return -1;
+diff -uNr ucspi-tcp-0.88.orig/error.h ucspi-tcp-0.88/error.h
+--- ucspi-tcp-0.88.orig/error.h 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/error.h 2009-08-04 17:45:59.000000000 -0500
+@@ -1,7 +1,7 @@
+ #ifndef ERROR_H
+ #define ERROR_H
+
+-extern int errno;
++#include <errno.h>
+
+ extern int error_intr;
+ extern int error_nomem;
+diff -uNr ucspi-tcp-0.88.orig/finger@.1 ucspi-tcp-0.88/finger@.1
+--- ucspi-tcp-0.88.orig/finger@.1 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/finger@.1 2009-08-04 17:45:59.000000000 -0500
+@@ -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)
+diff -uNr ucspi-tcp-0.88.orig/fixcr.1 ucspi-tcp-0.88/fixcr.1
+--- ucspi-tcp-0.88.orig/fixcr.1 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/fixcr.1 2009-08-04 17:45:59.000000000 -0500
+@@ -0,0 +1,11 @@
++.TH fixcr 1
++.SH NAME
++fixcr \- make sure that there is a CR before each LF
++.SH SYNOPSIS
++.B fixcr
++.SH DESCRIPTION
++.B fixcr
++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)
+diff -uNr ucspi-tcp-0.88.orig/fmt_xlong.c ucspi-tcp-0.88/fmt_xlong.c
+--- ucspi-tcp-0.88.orig/fmt_xlong.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/fmt_xlong.c 2009-08-04 17:45:59.000000000 -0500
+@@ -0,0 +1,22 @@
++#include "fmt.h"
++
++char tohex(char num) {
++ if (num<10)
++ return num+'0';
++ else if (num<16)
++ return num-10+'a';
++ else
++ return -1;
++}
++
++unsigned int fmt_xlong(register char *s,register unsigned long u)
++{
++ register unsigned int len; register unsigned long q;
++ len = 1; q = u;
++ while (q > 15) { ++len; q /= 16; }
++ if (s) {
++ s += len;
++ do { *--s = tohex(u % 16); u /= 16; } while(u); /* handles u == 0 */
++ }
++ return len;
++}
+diff -uNr ucspi-tcp-0.88.orig/haveip6.h1 ucspi-tcp-0.88/haveip6.h1
+--- ucspi-tcp-0.88.orig/haveip6.h1 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/haveip6.h1 2009-08-04 17:45:59.000000000 -0500
+@@ -0,0 +1 @@
++
+diff -uNr ucspi-tcp-0.88.orig/haveip6.h2 ucspi-tcp-0.88/haveip6.h2
+--- ucspi-tcp-0.88.orig/haveip6.h2 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/haveip6.h2 2009-08-04 17:45:59.000000000 -0500
+@@ -0,0 +1 @@
++#define LIBC_HAS_IP6 1
+diff -uNr ucspi-tcp-0.88.orig/hier.c ucspi-tcp-0.88/hier.c
+--- ucspi-tcp-0.88.orig/hier.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/hier.c 2009-08-04 17:45:59.000000000 -0500
+@@ -4,6 +4,9 @@
+ {
+ h(auto_home,-1,-1,02755);
+ d(auto_home,"bin",-1,-1,02755);
++ d(auto_home,"man",-1,-1,02755);
++ d(auto_home,"man/man1",-1,-1,02755);
++ d(auto_home,"man/man5",-1,-1,02755);
+
+ c(auto_home,"bin","tcpserver",-1,-1,0755);
+ c(auto_home,"bin","tcprules",-1,-1,0755);
+@@ -22,4 +25,20 @@
+ 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","tcpclient.1",-1,-1,0644);
++ c(auto_home,"man/man1","tcpserver.1",-1,-1,0644);
++ c(auto_home,"man/man1","tcprules.1",-1,-1,0644);
++ c(auto_home,"man/man1","tcprulescheck.1",-1,-1,0644);
++ c(auto_home,"man/man1","fixcr.1",-1,-1,0644);
++ c(auto_home,"man/man1","addcr.1",-1,-1,0644);
++ c(auto_home,"man/man1","delcr.1",-1,-1,0644);
++ c(auto_home,"man/man1","who@.1",-1,-1,0644);
++ c(auto_home,"man/man1","date@.1",-1,-1,0644);
++ c(auto_home,"man/man1","finger@.1",-1,-1,0644);
++ c(auto_home,"man/man1","http@.1",-1,-1,0644);
++ c(auto_home,"man/man1","mconnect.1",-1,-1,0644);
++ c(auto_home,"man/man1","argv0.1",-1,-1,0644);
++ c(auto_home,"man/man1","recordio.1",-1,-1,0644);
++ c(auto_home,"man/man5","tcp-environ.5",-1,-1,0644);
+ }
+diff -uNr ucspi-tcp-0.88.orig/http@.1 ucspi-tcp-0.88/http@.1
+--- ucspi-tcp-0.88.orig/http@.1 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/http@.1 2009-08-04 17:45:59.000000000 -0500
+@@ -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)
+diff -uNr ucspi-tcp-0.88.orig/ip4.h ucspi-tcp-0.88/ip4.h
+--- ucspi-tcp-0.88.orig/ip4.h 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/ip4.h 2009-08-04 17:45:59.000000000 -0500
+@@ -6,4 +6,6 @@
+
+ #define IP4_FMT 20
+
++extern const char ip4loopback[4]; /* = {127,0,0,1}; */
++
+ #endif
+diff -uNr ucspi-tcp-0.88.orig/ip6.h ucspi-tcp-0.88/ip6.h
+--- ucspi-tcp-0.88.orig/ip6.h 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/ip6.h 2009-08-04 17:45:59.000000000 -0500
+@@ -0,0 +1,28 @@
++#ifndef IP6_H
++#define IP6_H
++
++#include "byte.h"
++
++extern unsigned int scan_ip6(const char *src,char *ip);
++extern unsigned int fmt_ip6(char *dest,const char *ip);
++
++extern unsigned int scan_ip6_flat(const char *src,char *);
++extern unsigned int fmt_ip6_flat(char *dest,const char *);
++
++/*
++ ip6 address syntax: (h = hex digit), no leading '0' required
++ 1. hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh
++ 2. any number of 0000 may be abbreviated as "::", but only once
++ flat ip6 address syntax:
++ hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
++ */
++
++#define IP6_FMT 40
++
++extern const unsigned char V4mappedprefix[12]; /*={0,0,0,0,0,0,0,0,0,0,0xff,0xff}; */
++extern const unsigned char V6loopback[16]; /*={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; */
++extern const unsigned char V6any[16]; /*={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; */
++
++#define ip6_isv4mapped(ip) (byte_equal(ip,12,V4mappedprefix))
++
++#endif
+diff -uNr ucspi-tcp-0.88.orig/ip6_fmt.c ucspi-tcp-0.88/ip6_fmt.c
+--- ucspi-tcp-0.88.orig/ip6_fmt.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/ip6_fmt.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/mconnect.1 ucspi-tcp-0.88/mconnect.1
+--- ucspi-tcp-0.88.orig/mconnect.1 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/mconnect.1 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/old-rules.c ucspi-tcp-0.88/old-rules.c
+--- ucspi-tcp-0.88.orig/old-rules.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/old-rules.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/pathexec.h ucspi-tcp-0.88/pathexec.h
+--- ucspi-tcp-0.88.orig/pathexec.h 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/pathexec.h 2009-08-04 17:45:59.000000000 -0500
+@@ -2,7 +2,7 @@
+ #define PATHEXEC_H
+
+ extern void pathexec_run(char *,char **,char **);
+-extern int pathexec_env(char *,char *);
++extern int pathexec_env(const char *,const char *);
+ extern void pathexec(char **);
+
+ #endif
+diff -uNr ucspi-tcp-0.88.orig/pathexec_env.c ucspi-tcp-0.88/pathexec_env.c
+--- ucspi-tcp-0.88.orig/pathexec_env.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/pathexec_env.c 2009-08-04 17:45:59.000000000 -0500
+@@ -8,7 +8,7 @@
+ static stralloc plus;
+ static stralloc tmp;
+
+-int pathexec_env(char *s,char *t)
++int pathexec_env(const char *s,const char *t)
+ {
+ if (!s) return 1;
+ if (!stralloc_copys(&tmp,s)) return 0;
+@@ -22,7 +22,6 @@
+
+ void pathexec(char **argv)
+ {
+- char *path;
+ char **e;
+ unsigned int elen;
+ unsigned int i;
+diff -uNr ucspi-tcp-0.88.orig/rblsmtpd.c ucspi-tcp-0.88/rblsmtpd.c
+--- ucspi-tcp-0.88.orig/rblsmtpd.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/rblsmtpd.c 2009-08-04 17:51:17.000000000 -0500
+@@ -25,26 +25,58 @@
+ strerr_die1x(100,"rblsmtpd: usage: rblsmtpd [ -b ] [ -R ] [ -t timeout ] [ -r base ] [ -a base ] smtpd [ arg ... ]");
+ }
+
++char *tcp_proto;
+ char *ip_env;
+ static stralloc ip_reverse;
+
++static inline char tohex(char c) {
++ return c>=10?c-10+'a':c+'0';
++}
++
+ void ip_init(void)
+ {
+ unsigned int i;
+ unsigned int j;
++ unsigned char remoteip[16];
++ char hexval;
+
++ tcp_proto = env_get("PROTO");
++ if (!tcp_proto) tcp_proto = "";
+ ip_env = env_get("TCPREMOTEIP");
+ if (!ip_env) ip_env = "";
+
+ if (!stralloc_copys(&ip_reverse,"")) nomem();
+
+ i = str_len(ip_env);
+- while (i) {
+- for (j = i;j > 0;--j) if (ip_env[j - 1] == '.') break;
+- if (!stralloc_catb(&ip_reverse,ip_env + j,i - j)) nomem();
+- if (!stralloc_cats(&ip_reverse,".")) nomem();
+- if (!j) break;
+- i = j - 1;
++ if (str_diff(tcp_proto, "TCP6") != 0)
++ {
++ // IPv4
++ while (i) {
++ for (j = i;j > 0;--j) if (ip_env[j - 1] == '.') break;
++ if (!stralloc_catb(&ip_reverse,ip_env + j,i - j)) nomem();
++ if (!stralloc_cats(&ip_reverse,".")) nomem();
++ if (!j) break;
++ i = j - 1;
++ }
++ }
++ else
++ {
++ // IPv6
++ if ((i=scan_ip6(ip_env, remoteip))==0)
++ return;
++
++ for (j=16; j>0; j--)
++ {
++ hexval=tohex(remoteip[j-1] & 15);
++ if(!stralloc_catb(&ip_reverse, &hexval, 1)) nomem();
++ if(!stralloc_cats(&ip_reverse, ".")) nomem();
++
++ hexval=tohex(remoteip[j-1] >> 4);
++ if(!stralloc_catb(&ip_reverse, &hexval, 1)) nomem();
++ if(!stralloc_cats(&ip_reverse, ".")) nomem();
++ }
++
++ if(!stralloc_cats(&ip_reverse, "ipv6.")) nomem();
+ }
+ }
+
+@@ -190,7 +222,7 @@
+ argv += optind;
+ if (!*argv) usage();
+
+- if (flagwantdefaultrbl) rbl("rbl.maps.vix.com");
++ if (flagwantdefaultrbl) rbl("zen.spamhaus.org");
+ if (decision >= 2) rblsmtpd();
+
+ pathexec_run(*argv,argv,envp);
+diff -uNr ucspi-tcp-0.88.orig/recordio.1 ucspi-tcp-0.88/recordio.1
+--- ucspi-tcp-0.88.orig/recordio.1 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/recordio.1 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/remoteinfo.h ucspi-tcp-0.88/remoteinfo.h
+--- ucspi-tcp-0.88.orig/remoteinfo.h 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/remoteinfo.h 2009-08-04 17:45:59.000000000 -0500
+@@ -5,5 +5,6 @@
+ #include "uint16.h"
+
+ extern int remoteinfo(stralloc *,char *,uint16,char *,uint16,unsigned int);
++extern int remoteinfo6(stralloc *,char *,uint16,char *,uint16,unsigned int,uint32);
+
+ #endif
+diff -uNr ucspi-tcp-0.88.orig/remoteinfo6.c ucspi-tcp-0.88/remoteinfo6.c
+--- ucspi-tcp-0.88.orig/remoteinfo6.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/remoteinfo6.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/rules.c ucspi-tcp-0.88/rules.c
+--- ucspi-tcp-0.88.orig/rules.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/rules.c 2009-08-04 17:45:59.000000000 -0500
+@@ -64,7 +64,7 @@
+
+ if (!stralloc_copys(&rules_name,ip)) return -1;
+ while (rules_name.len > 0) {
+- if (ip[rules_name.len - 1] == '.') {
++ if (ip[rules_name.len - 1] == '.' || ip[rules_name.len - 1] == ':') {
+ r = dorule(callback);
+ if (r) return r;
+ }
+diff -uNr ucspi-tcp-0.88.orig/scan_ip6.c ucspi-tcp-0.88/scan_ip6.c
+--- ucspi-tcp-0.88.orig/scan_ip6.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/scan_ip6.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/scan_xlong.c ucspi-tcp-0.88/scan_xlong.c
+--- ucspi-tcp-0.88.orig/scan_xlong.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/scan_xlong.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/socket.h ucspi-tcp-0.88/socket.h
+--- ucspi-tcp-0.88.orig/socket.h 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/socket.h 2009-08-04 17:45:59.000000000 -0500
+@@ -2,21 +2,52 @@
+ #define SOCKET_H
+
+ #include "uint16.h"
++#include "uint32.h"
+
+ extern int socket_tcp(void);
+ extern int socket_udp(void);
++extern int socket_tcp6(void);
++extern int socket_udp6(void);
+
+-extern int socket_connect4(int,char *,uint16);
++extern int socket_connect4(int,const char *,uint16);
++extern int socket_connect6(int s,const char *ip,uint16 port,uint32 scope_id);
+ extern int socket_connected(int);
+-extern int socket_bind4(int,char *,uint16);
+-extern int socket_bind4_reuse(int,char *,uint16);
++extern int socket_bind4(int,const char *,uint16);
++extern int socket_bind4_reuse(int,const char *,uint16);
++extern int socket_bind6(int s,const char *ip,uint16 port,uint32 scope_id);
++extern int socket_bind6_reuse(int s,const char *ip,uint16 port,uint32 scope_id);
+ extern int socket_listen(int,int);
+ extern int socket_accept4(int,char *,uint16 *);
++extern int socket_accept6(int s,char *ip,uint16 *port,uint32 *scope_id);
+ extern int socket_recv4(int,char *,int,char *,uint16 *);
+-extern int socket_send4(int,char *,int,char *,uint16);
++extern int socket_send4(int,const char *,int,const char *,uint16);
++extern int socket_recv6(int s,char *buf,unsigned int len,char *ip,uint16 *port,uint32 *scope_id);
++extern int socket_send6(int s,const char *buf,unsigned int len,const char *ip,uint16 port,uint32 scope_id);
+ extern int socket_local4(int,char *,uint16 *);
+ extern int socket_remote4(int,char *,uint16 *);
++extern int socket_local6(int s,char *ip,uint16 *port,uint32 *scope_id);
++extern int socket_remote6(int s,char *ip,uint16 *port,uint32 *scope_id);
++
++/* enable sending udp packets to the broadcast address */
++extern int socket_broadcast(int);
++/* join a multicast group on the given interface */
++extern int socket_mcjoin4(int,char *,char *);
++extern int socket_mcjoin6(int,char *,int);
++/* leave a multicast group on the given interface */
++extern int socket_mcleave4(int,char *);
++extern int socket_mcleave6(int,char *);
++/* set multicast TTL/hop count for outgoing packets */
++extern int socket_mcttl4(int,char);
++extern int socket_mcttl6(int,char);
++/* enable multicast loopback */
++extern int socket_mcloop4(int,char);
++extern int socket_mcloop6(int,char);
++
++extern const char* socket_getifname(uint32 interface);
++extern uint32 socket_getifidx(const char *ifname);
+
+ extern void socket_tryreservein(int,int);
+
++extern int noipv6;
++
+ #endif
+diff -uNr ucspi-tcp-0.88.orig/socket_accept6.c ucspi-tcp-0.88/socket_accept6.c
+--- ucspi-tcp-0.88.orig/socket_accept6.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/socket_accept6.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/socket_bind.c ucspi-tcp-0.88/socket_bind.c
+--- ucspi-tcp-0.88.orig/socket_bind.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/socket_bind.c 2009-08-04 17:45:59.000000000 -0500
+@@ -5,7 +5,7 @@
+ #include "byte.h"
+ #include "socket.h"
+
+-int socket_bind4(int s,char ip[4],uint16 port)
++int socket_bind4(int s,const char ip[4],uint16 port)
+ {
+ struct sockaddr_in sa;
+
+@@ -17,7 +17,7 @@
+ return bind(s,(struct sockaddr *) &sa,sizeof sa);
+ }
+
+-int socket_bind4_reuse(int s,char ip[4],uint16 port)
++int socket_bind4_reuse(int s,const char ip[4],uint16 port)
+ {
+ int opt = 1;
+ setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof opt);
+diff -uNr ucspi-tcp-0.88.orig/socket_bind6.c ucspi-tcp-0.88/socket_bind6.c
+--- ucspi-tcp-0.88.orig/socket_bind6.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/socket_bind6.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/socket_conn.c ucspi-tcp-0.88/socket_conn.c
+--- ucspi-tcp-0.88.orig/socket_conn.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/socket_conn.c 2009-08-04 17:45:59.000000000 -0500
+@@ -6,7 +6,7 @@
+ #include "byte.h"
+ #include "socket.h"
+
+-int socket_connect4(int s,char ip[4],uint16 port)
++int socket_connect4(int s,const char ip[4],uint16 port)
+ {
+ struct sockaddr_in sa;
+
+diff -uNr ucspi-tcp-0.88.orig/socket_conn6.c ucspi-tcp-0.88/socket_conn6.c
+--- ucspi-tcp-0.88.orig/socket_conn6.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/socket_conn6.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/socket_getifidx.c ucspi-tcp-0.88/socket_getifidx.c
+--- ucspi-tcp-0.88.orig/socket_getifidx.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/socket_getifidx.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/socket_getifname.c ucspi-tcp-0.88/socket_getifname.c
+--- ucspi-tcp-0.88.orig/socket_getifname.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/socket_getifname.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/socket_ip4loopback.c ucspi-tcp-0.88/socket_ip4loopback.c
+--- ucspi-tcp-0.88.orig/socket_ip4loopback.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/socket_ip4loopback.c 2009-08-04 17:45:59.000000000 -0500
+@@ -0,0 +1,2 @@
++
++const char ip4loopback[4] = {127,0,0,1};
+diff -uNr ucspi-tcp-0.88.orig/socket_local6.c ucspi-tcp-0.88/socket_local6.c
+--- ucspi-tcp-0.88.orig/socket_local6.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/socket_local6.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/socket_recv6.c ucspi-tcp-0.88/socket_recv6.c
+--- ucspi-tcp-0.88.orig/socket_recv6.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/socket_recv6.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/socket_remote6.c ucspi-tcp-0.88/socket_remote6.c
+--- ucspi-tcp-0.88.orig/socket_remote6.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/socket_remote6.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/socket_send6.c ucspi-tcp-0.88/socket_send6.c
+--- ucspi-tcp-0.88.orig/socket_send6.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/socket_send6.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/socket_tcp6.c ucspi-tcp-0.88/socket_tcp6.c
+--- ucspi-tcp-0.88.orig/socket_tcp6.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/socket_tcp6.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/socket_udp6.c ucspi-tcp-0.88/socket_udp6.c
+--- ucspi-tcp-0.88.orig/socket_udp6.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/socket_udp6.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/socket_v4mappedprefix.c ucspi-tcp-0.88/socket_v4mappedprefix.c
+--- ucspi-tcp-0.88.orig/socket_v4mappedprefix.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/socket_v4mappedprefix.c 2009-08-04 17:45:59.000000000 -0500
+@@ -0,0 +1,2 @@
++
++const unsigned char V4mappedprefix[12]={0,0,0,0,0,0,0,0,0,0,0xff,0xff};
+diff -uNr ucspi-tcp-0.88.orig/socket_v6any.c ucspi-tcp-0.88/socket_v6any.c
+--- ucspi-tcp-0.88.orig/socket_v6any.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/socket_v6any.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/socket_v6loopback.c ucspi-tcp-0.88/socket_v6loopback.c
+--- ucspi-tcp-0.88.orig/socket_v6loopback.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/socket_v6loopback.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/str.h ucspi-tcp-0.88/str.h
+--- ucspi-tcp-0.88.orig/str.h 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/str.h 2009-08-04 17:45:59.000000000 -0500
+@@ -1,13 +1,13 @@
+ #ifndef STR_H
+ #define STR_H
+
+-extern unsigned int str_copy(char *,char *);
+-extern int str_diff(char *,char *);
+-extern int str_diffn(char *,char *,unsigned int);
+-extern unsigned int str_len(char *);
+-extern unsigned int str_chr(char *,int);
+-extern unsigned int str_rchr(char *,int);
+-extern int str_start(char *,char *);
++extern unsigned int str_copy(char *,const char *);
++extern int str_diff(const char *,const char *);
++extern int str_diffn(const char *,const char *,unsigned int);
++extern unsigned int str_len(const char *);
++extern unsigned int str_chr(const char *,int);
++extern unsigned int str_rchr(const char *,int);
++extern int str_start(const char *,const char *);
+
+ #define str_equal(s,t) (!str_diff((s),(t)))
+
+diff -uNr ucspi-tcp-0.88.orig/str_chr.c ucspi-tcp-0.88/str_chr.c
+--- ucspi-tcp-0.88.orig/str_chr.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/str_chr.c 2009-08-04 17:45:59.000000000 -0500
+@@ -1,9 +1,9 @@
+ #include "str.h"
+
+-unsigned int str_chr(register char *s,int c)
++unsigned int str_chr(register const char *s,int c)
+ {
+ register char ch;
+- register char *t;
++ register const char *t;
+
+ ch = c;
+ t = s;
+diff -uNr ucspi-tcp-0.88.orig/str_diff.c ucspi-tcp-0.88/str_diff.c
+--- ucspi-tcp-0.88.orig/str_diff.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/str_diff.c 2009-08-04 17:45:59.000000000 -0500
+@@ -1,6 +1,6 @@
+ #include "str.h"
+
+-int str_diff(register char *s,register char *t)
++int str_diff(register const char *s,register const char *t)
+ {
+ register char x;
+
+diff -uNr ucspi-tcp-0.88.orig/str_len.c ucspi-tcp-0.88/str_len.c
+--- ucspi-tcp-0.88.orig/str_len.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/str_len.c 2009-08-04 17:45:59.000000000 -0500
+@@ -1,8 +1,8 @@
+ #include "str.h"
+
+-unsigned int str_len(char *s)
++unsigned int str_len(const char *s)
+ {
+- register char *t;
++ register const char *t;
+
+ t = s;
+ for (;;) {
+diff -uNr ucspi-tcp-0.88.orig/str_start.c ucspi-tcp-0.88/str_start.c
+--- ucspi-tcp-0.88.orig/str_start.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/str_start.c 2009-08-04 17:45:59.000000000 -0500
+@@ -1,6 +1,6 @@
+ #include "str.h"
+
+-int str_start(register char *s,register char *t)
++int str_start(register const char *s,register const char *t)
+ {
+ register char x;
+
+diff -uNr ucspi-tcp-0.88.orig/stralloc.h ucspi-tcp-0.88/stralloc.h
+--- ucspi-tcp-0.88.orig/stralloc.h 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/stralloc.h 2009-08-04 17:45:59.000000000 -0500
+@@ -9,18 +9,20 @@
+ extern int stralloc_readyplus(stralloc *,unsigned int);
+ extern int stralloc_copy(stralloc *,stralloc *);
+ extern int stralloc_cat(stralloc *,stralloc *);
+-extern int stralloc_copys(stralloc *,char *);
+-extern int stralloc_cats(stralloc *,char *);
+-extern int stralloc_copyb(stralloc *,char *,unsigned int);
+-extern int stralloc_catb(stralloc *,char *,unsigned int);
++extern int stralloc_copys(stralloc *,const char *);
++extern int stralloc_cats(stralloc *,const char *);
++extern int stralloc_copyb(stralloc *,const char *,unsigned int);
++extern int stralloc_catb(stralloc *,const char *,unsigned int);
+ extern int stralloc_append(stralloc *,char *); /* beware: this takes a pointer to 1 char */
+-extern int stralloc_starts(stralloc *,char *);
++extern int stralloc_starts(stralloc *,const char *);
+
+ #define stralloc_0(sa) stralloc_append(sa,"")
+
+ extern int stralloc_catulong0(stralloc *,unsigned long,unsigned int);
+ extern int stralloc_catlong0(stralloc *,long,unsigned int);
+
++extern void stralloc_free(stralloc *);
++
+ #define stralloc_catlong(sa,l) (stralloc_catlong0((sa),(l),0))
+ #define stralloc_catuint0(sa,i,n) (stralloc_catulong0((sa),(i),(n)))
+ #define stralloc_catint0(sa,i,n) (stralloc_catlong0((sa),(i),(n)))
+diff -uNr ucspi-tcp-0.88.orig/stralloc_catb.c ucspi-tcp-0.88/stralloc_catb.c
+--- ucspi-tcp-0.88.orig/stralloc_catb.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/stralloc_catb.c 2009-08-04 17:45:59.000000000 -0500
+@@ -1,7 +1,7 @@
+ #include "stralloc.h"
+ #include "byte.h"
+
+-int stralloc_catb(stralloc *sa,char *s,unsigned int n)
++int stralloc_catb(stralloc *sa,const char *s,unsigned int n)
+ {
+ if (!sa->s) return stralloc_copyb(sa,s,n);
+ if (!stralloc_readyplus(sa,n + 1)) return 0;
+diff -uNr ucspi-tcp-0.88.orig/stralloc_cats.c ucspi-tcp-0.88/stralloc_cats.c
+--- ucspi-tcp-0.88.orig/stralloc_cats.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/stralloc_cats.c 2009-08-04 17:45:59.000000000 -0500
+@@ -2,7 +2,7 @@
+ #include "str.h"
+ #include "stralloc.h"
+
+-int stralloc_cats(stralloc *sa,char *s)
++int stralloc_cats(stralloc *sa,const char *s)
+ {
+ return stralloc_catb(sa,s,str_len(s));
+ }
+diff -uNr ucspi-tcp-0.88.orig/stralloc_opyb.c ucspi-tcp-0.88/stralloc_opyb.c
+--- ucspi-tcp-0.88.orig/stralloc_opyb.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/stralloc_opyb.c 2009-08-04 17:45:59.000000000 -0500
+@@ -1,7 +1,7 @@
+ #include "stralloc.h"
+ #include "byte.h"
+
+-int stralloc_copyb(stralloc *sa,char *s,unsigned int n)
++int stralloc_copyb(stralloc *sa,const char *s,unsigned int n)
+ {
+ if (!stralloc_ready(sa,n + 1)) return 0;
+ byte_copy(sa->s,n,s);
+diff -uNr ucspi-tcp-0.88.orig/stralloc_opys.c ucspi-tcp-0.88/stralloc_opys.c
+--- ucspi-tcp-0.88.orig/stralloc_opys.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/stralloc_opys.c 2009-08-04 17:45:59.000000000 -0500
+@@ -2,7 +2,7 @@
+ #include "str.h"
+ #include "stralloc.h"
+
+-int stralloc_copys(stralloc *sa,char *s)
++int stralloc_copys(stralloc *sa,const char *s)
+ {
+ return stralloc_copyb(sa,s,str_len(s));
+ }
+diff -uNr ucspi-tcp-0.88.orig/tcp-environ.5 ucspi-tcp-0.88/tcp-environ.5
+--- ucspi-tcp-0.88.orig/tcp-environ.5 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/tcp-environ.5 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/tcpcat.1 ucspi-tcp-0.88/tcpcat.1
+--- ucspi-tcp-0.88.orig/tcpcat.1 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/tcpcat.1 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/tcpclient.1 ucspi-tcp-0.88/tcpclient.1
+--- ucspi-tcp-0.88.orig/tcpclient.1 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/tcpclient.1 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/tcpclient.c ucspi-tcp-0.88/tcpclient.c
+--- ucspi-tcp-0.88.orig/tcpclient.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/tcpclient.c 2009-08-04 17:45:59.000000000 -0500
+@@ -9,6 +9,7 @@
+ #include "scan.h"
+ #include "str.h"
+ #include "ip4.h"
++#include "ip6.h"
+ #include "uint16.h"
+ #include "socket.h"
+ #include "fd.h"
+@@ -20,6 +21,7 @@
+ #include "timeoutconn.h"
+ #include "remoteinfo.h"
+ #include "dns.h"
++#include "byte.h"
+
+ #define FATAL "tcpclient: fatal: "
+ #define CONNECT "tcpclient: unable to connect to "
+@@ -31,27 +33,30 @@
+ void usage(void)
+ {
+ strerr_die1x(100,"tcpclient: usage: tcpclient \
+-[ -hHrRdDqQv ] \
++[ -46hHrRdDqQv ] \
+ [ -i localip ] \
+ [ -p localport ] \
+ [ -T timeoutconn ] \
+ [ -l localname ] \
+ [ -t timeoutinfo ] \
++[ -I interface ] \
+ host port program");
+ }
+
++int forcev6 = 0;
+ int verbosity = 1;
+ int flagdelay = 1;
+ int flagremoteinfo = 1;
+ int flagremotehost = 1;
+ unsigned long itimeout = 26;
+ unsigned long ctimeout[2] = { 2, 58 };
++uint32 netif = 0;
+
+-char iplocal[4] = { 0,0,0,0 };
++char iplocal[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
+ uint16 portlocal = 0;
+ char *forcelocal = 0;
+
+-char ipremote[4];
++char ipremote[16];
+ uint16 portremote;
+
+ char *hostname;
+@@ -61,12 +66,13 @@
+ static stralloc tmp;
+ static stralloc fqdn;
+ char strnum[FMT_ULONG];
+-char ipstr[IP4_FMT];
++char ipstr[IP6_FMT];
+
+ char seed[128];
+
+ main(int argc,char **argv)
+ {
++ int fakev4=0;
+ unsigned long u;
+ int opt;
+ char *x;
+@@ -80,8 +86,10 @@
+ close(7);
+ sig_ignore(sig_pipe);
+
+- while ((opt = getopt(argc,argv,"dDvqQhHrRi:p:t:T:l:")) != opteof)
++ while ((opt = getopt(argc,argv,"46dDvqQhHrRi:p:t:T:l:I:")) != opteof)
+ switch(opt) {
++ case '4': noipv6 = 1; break;
++ case '6': forcev6 = 1; break;
+ case 'd': flagdelay = 1; break;
+ case 'D': flagdelay = 0; break;
+ case 'v': verbosity = 2; break;
+@@ -97,7 +105,8 @@
+ if (optarg[j] == '+') ++j;
+ scan_ulong(optarg + j,&ctimeout[1]);
+ break;
+- case 'i': if (!ip4_scan(optarg,iplocal)) usage(); break;
++ case 'i': if (!scan_ip6(optarg,iplocal)) usage(); break;
++ case 'I': netif=socket_getifidx(optarg); break;
+ case 'p': scan_ulong(optarg,&u); portlocal = u; break;
+ default: usage();
+ }
+@@ -108,8 +117,8 @@
+
+ hostname = *argv;
+ if (!hostname) usage();
+- if (str_equal(hostname,"")) hostname = "127.0.0.1";
+- if (str_equal(hostname,"0")) hostname = "127.0.0.1";
++ if (!hostname[0] || str_equal(hostname,"0"))
++ hostname = (noipv6?"127.0.0.1":"::1");
+
+ x = *++argv;
+ if (!x) usage();
+@@ -127,33 +136,36 @@
+ if (!*++argv) usage();
+
+ if (!stralloc_copys(&tmp,hostname)) nomem();
+- if (dns_ip4_qualify(&addresses,&fqdn,&tmp) == -1)
++ if (dns_ip6_qualify(&addresses,&fqdn,&tmp) == -1)
+ strerr_die4sys(111,FATAL,"temporarily unable to figure out IP address for ",hostname,": ");
+- if (addresses.len < 4)
++ if (addresses.len < 16)
+ strerr_die3x(111,FATAL,"no IP address for ",hostname);
+
+- if (addresses.len == 4) {
++ if (addresses.len == 16) {
+ ctimeout[0] += ctimeout[1];
+ ctimeout[1] = 0;
+ }
+
+ for (cloop = 0;cloop < 2;++cloop) {
+ if (!stralloc_copys(&moreaddresses,"")) nomem();
+- for (j = 0;j + 4 <= addresses.len;j += 4) {
+- s = socket_tcp();
++ for (j = 0;j + 16 <= addresses.len;j += 4) {
++ s = socket_tcp6();
+ if (s == -1)
+ strerr_die2sys(111,FATAL,"unable to create socket: ");
+- if (socket_bind4(s,iplocal,portlocal) == -1)
++ if (socket_bind6(s,iplocal,portlocal,netif) == -1)
+ strerr_die2sys(111,FATAL,"unable to bind socket: ");
+- if (timeoutconn(s,addresses.s + j,portremote,ctimeout[cloop]) == 0)
++ if (timeoutconn6(s,addresses.s + j,portremote,ctimeout[cloop],netif) == 0)
+ goto CONNECTED;
+ close(s);
+ if (!cloop && ctimeout[1] && (errno == error_timeout)) {
+- if (!stralloc_catb(&moreaddresses,addresses.s + j,4)) nomem();
++ if (!stralloc_catb(&moreaddresses,addresses.s + j,16)) nomem();
+ }
+ else {
+ strnum[fmt_ulong(strnum,portremote)] = 0;
+- ipstr[ip4_fmt(ipstr,addresses.s + j)] = 0;
++ if (ip6_isv4mapped(addresses.s+j))
++ ipstr[ip4_fmt(ipstr,addresses.s + j + 12)] = 0;
++ else
++ ipstr[ip6_fmt(ipstr,addresses.s + j)] = 0;
+ strerr_warn5(CONNECT,ipstr," port ",strnum,": ",&strerr_sys);
+ }
+ }
+@@ -169,37 +181,46 @@
+ if (!flagdelay)
+ socket_tcpnodelay(s); /* if it fails, bummer */
+
+- if (!pathexec_env("PROTO","TCP")) nomem();
+-
+- if (socket_local4(s,iplocal,&portlocal) == -1)
++ if (socket_local6(s,iplocal,&portlocal,&netif) == -1)
+ strerr_die2sys(111,FATAL,"unable to get local address: ");
+
++ if (!forcev6 && (ip6_isv4mapped(iplocal) || byte_equal(iplocal,16,V6any)))
++ fakev4=1;
++
++ if (!pathexec_env("PROTO",fakev4?"TCP":"TCP6")) nomem();
++
+ strnum[fmt_ulong(strnum,portlocal)] = 0;
+ if (!pathexec_env("TCPLOCALPORT",strnum)) nomem();
+- ipstr[ip4_fmt(ipstr,iplocal)] = 0;
++ if (fakev4)
++ ipstr[ip4_fmt(ipstr,iplocal+12)] = 0;
++ else
++ ipstr[ip6_fmt(ipstr,iplocal)] = 0;
+ if (!pathexec_env("TCPLOCALIP",ipstr)) nomem();
+
+ x = forcelocal;
+ if (!x)
+- if (dns_name4(&tmp,iplocal) == 0) {
++ if (dns_name6(&tmp,iplocal) == 0) {
+ if (!stralloc_0(&tmp)) nomem();
+ x = tmp.s;
+ }
+ if (!pathexec_env("TCPLOCALHOST",x)) nomem();
+
+- if (socket_remote4(s,ipremote,&portremote) == -1)
++ if (socket_remote6(s,ipremote,&portremote,&netif) == -1)
+ strerr_die2sys(111,FATAL,"unable to get remote address: ");
+
+ strnum[fmt_ulong(strnum,portremote)] = 0;
+ if (!pathexec_env("TCPREMOTEPORT",strnum)) nomem();
+- ipstr[ip4_fmt(ipstr,ipremote)] = 0;
++ if (fakev4)
++ ipstr[ip4_fmt(ipstr,ipremote+12)] = 0;
++ else
++ ipstr[ip6_fmt(ipstr,ipremote)] = 0;
+ if (!pathexec_env("TCPREMOTEIP",ipstr)) nomem();
+ if (verbosity >= 2)
+ strerr_warn4("tcpclient: connected to ",ipstr," port ",strnum,0);
+
+ x = 0;
+ if (flagremotehost)
+- if (dns_name4(&tmp,ipremote) == 0) {
++ if (dns_name6(&tmp,ipremote) == 0) {
+ if (!stralloc_0(&tmp)) nomem();
+ x = tmp.s;
+ }
+@@ -207,7 +228,7 @@
+
+ x = 0;
+ if (flagremoteinfo)
+- if (remoteinfo(&tmp,ipremote,portremote,iplocal,portlocal,itimeout) == 0) {
++ if (remoteinfo6(&tmp,ipremote,portremote,iplocal,portlocal,itimeout,netif) == 0) {
+ if (!stralloc_0(&tmp)) nomem();
+ x = tmp.s;
+ }
+diff -uNr ucspi-tcp-0.88.orig/tcprules.1 ucspi-tcp-0.88/tcprules.1
+--- ucspi-tcp-0.88.orig/tcprules.1 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/tcprules.1 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/tcprules.c ucspi-tcp-0.88/tcprules.c
+--- ucspi-tcp-0.88.orig/tcprules.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/tcprules.c 2009-08-04 17:45:59.000000000 -0500
+@@ -123,8 +123,15 @@
+ }
+ line.len = len; /* for die_bad() */
+
+- colon = byte_chr(x,len,':');
+- if (colon == len) continue;
++ colon = 0;
++ for (;;) {
++ int tmp;
++ tmp = byte_chr(x + colon,len - colon,':');
++ colon += tmp;
++ if (colon == len) continue;
++ if (byte_equal(x+colon+1,4,"deny") || byte_equal(x+colon+1,5,"allow")) break;
++ ++colon;
++ }
+
+ if (!stralloc_copyb(&address,x,colon)) nomem();
+ if (!stralloc_copys(&data,"")) nomem();
+diff -uNr ucspi-tcp-0.88.orig/tcprulescheck.1 ucspi-tcp-0.88/tcprulescheck.1
+--- ucspi-tcp-0.88.orig/tcprulescheck.1 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/tcprulescheck.1 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/tcpserver.1 ucspi-tcp-0.88/tcpserver.1
+--- ucspi-tcp-0.88.orig/tcpserver.1 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/tcpserver.1 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/tcpserver.c ucspi-tcp-0.88/tcpserver.c
+--- ucspi-tcp-0.88.orig/tcpserver.c 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/tcpserver.c 2009-08-04 17:45:59.000000000 -0500
+@@ -7,6 +7,7 @@
+ #include "fmt.h"
+ #include "scan.h"
+ #include "ip4.h"
++#include "ip6.h"
+ #include "fd.h"
+ #include "exit.h"
+ #include "env.h"
+@@ -28,6 +29,7 @@
+ #include "sig.h"
+ #include "dns.h"
+
++int forcev6 = 0;
+ int verbosity = 1;
+ int flagkillopts = 1;
+ int flagdelay = 1;
+@@ -36,20 +38,21 @@
+ int flagremotehost = 1;
+ int flagparanoid = 0;
+ unsigned long timeout = 26;
++uint32 netif = 0;
+
+ static stralloc tcpremoteinfo;
+
+ uint16 localport;
+ char localportstr[FMT_ULONG];
+-char localip[4];
+-char localipstr[IP4_FMT];
++char localip[16];
++char localipstr[IP6_FMT];
+ static stralloc localhostsa;
+ char *localhost = 0;
+
+ uint16 remoteport;
+ char remoteportstr[FMT_ULONG];
+-char remoteip[4];
+-char remoteipstr[IP4_FMT];
++char remoteip[16];
++char remoteipstr[IP6_FMT];
+ static stralloc remotehostsa;
+ char *remotehost = 0;
+
+@@ -96,12 +99,12 @@
+ if (ch < 33) ch = '?';
+ if (ch > 126) ch = '?';
+ if (ch == '%') ch = '?'; /* logger stupidity */
+- if (ch == ':') ch = '?';
++/* if (ch == ':') ch = '?'; */
+ append(&ch);
+ }
+ cats("...");
+ }
+-void env(char *s,char *t)
++void env(const char *s,const char *t)
+ {
+ if (!pathexec_env(s,t)) drop_nomem();
+ }
+@@ -135,9 +138,16 @@
+
+ void doit(int t)
+ {
++ int fakev4=0;
+ int j;
++ uint32 scope_id;
+
+- remoteipstr[ip4_fmt(remoteipstr,remoteip)] = 0;
++ if (!forcev6 && ip6_isv4mapped(remoteip))
++ fakev4=1;
++ if (fakev4)
++ remoteipstr[ip4_fmt(remoteipstr,remoteip+12)] = 0;
++ else
++ remoteipstr[ip6_fmt(remoteipstr,remoteip)] = 0;
+
+ if (verbosity >= 2) {
+ strnum[fmt_ulong(strnum,getpid())] = 0;
+@@ -155,30 +165,40 @@
+ strerr_die2sys(111,DROP,"unable to print banner: ");
+ }
+
+- if (socket_local4(t,localip,&localport) == -1)
++ if (socket_local6(t,localip,&localport,&scope_id) == -1)
+ strerr_die2sys(111,DROP,"unable to get local address: ");
+
+- localipstr[ip4_fmt(localipstr,localip)] = 0;
++ if (fakev4)
++ localipstr[ip4_fmt(localipstr,localip+12)] = 0;
++ else
++ localipstr[ip6_fmt(localipstr,localip)] = 0;
+ remoteportstr[fmt_ulong(remoteportstr,remoteport)] = 0;
+
+ if (!localhost)
+- if (dns_name4(&localhostsa,localip) == 0)
++ if (dns_name6(&localhostsa,localip) == 0)
+ if (localhostsa.len) {
+ if (!stralloc_0(&localhostsa)) drop_nomem();
+ localhost = localhostsa.s;
+ }
+- env("PROTO","TCP");
++ env("PROTO",fakev4?"TCP":"TCP6");
+ env("TCPLOCALIP",localipstr);
++ localipstr[ip6_fmt(localipstr,localip)]=0;
++ env("TCP6LOCALIP",localipstr);
++
+ env("TCPLOCALPORT",localportstr);
++ env("TCP6LOCALPORT",localportstr);
+ env("TCPLOCALHOST",localhost);
++ env("TCP6LOCALHOST",localhost);
++ if (!fakev4 && scope_id)
++ env("TCP6INTERFACE",socket_getifname(scope_id));
+
+ if (flagremotehost)
+- if (dns_name4(&remotehostsa,remoteip) == 0)
++ if (dns_name6(&remotehostsa,remoteip) == 0)
+ if (remotehostsa.len) {
+ if (flagparanoid)
+- if (dns_ip4(&tmp,&remotehostsa) == 0)
+- for (j = 0;j + 4 <= tmp.len;j += 4)
+- if (byte_equal(remoteip,4,tmp.s + j)) {
++ if (dns_ip6(&tmp,&remotehostsa) == 0)
++ for (j = 0;j + 16 <= tmp.len;j += 16)
++ if (byte_equal(remoteip,16,tmp.s + j)) {
+ flagparanoid = 0;
+ break;
+ }
+@@ -188,15 +208,20 @@
+ }
+ }
+ env("TCPREMOTEIP",remoteipstr);
++ remoteipstr[ip6_fmt(remoteipstr,remoteip)]=0;
++ env("TCP6REMOTEIP",remoteipstr);
+ env("TCPREMOTEPORT",remoteportstr);
++ env("TCP6REMOTEPORT",remoteportstr);
+ env("TCPREMOTEHOST",remotehost);
++ env("TCP6REMOTEHOST",remotehost);
+
+ if (flagremoteinfo) {
+- if (remoteinfo(&tcpremoteinfo,remoteip,remoteport,localip,localport,timeout) == -1)
++ if (remoteinfo6(&tcpremoteinfo,remoteip,remoteport,localip,localport,timeout,netif) == -1)
+ flagremoteinfo = 0;
+ if (!stralloc_0(&tcpremoteinfo)) drop_nomem();
+ }
+ env("TCPREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0);
++ env("TCP6REMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0);
+
+ if (fnrules) {
+ int fdrules;
+@@ -206,7 +231,15 @@
+ if (!flagallownorules) drop_rules();
+ }
+ else {
+- if (rules(found,fdrules,remoteipstr,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) drop_rules();
++ int fakev4=0;
++ char* temp;
++ if (!forcev6 && ip6_isv4mapped(remoteip))
++ fakev4=1;
++ if (fakev4)
++ temp=remoteipstr+7;
++ else
++ temp=remoteipstr;
++ if (rules(found,fdrules,temp,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) drop_rules();
+ close(fdrules);
+ }
+ }
+@@ -240,7 +273,7 @@
+ {
+ strerr_warn1("\
+ tcpserver: usage: tcpserver \
+-[ -1UXpPhHrRoOdDqQv ] \
++[ -461UXpPhHrRoOdDqQv ] \
+ [ -c limit ] \
+ [ -x rules.cdb ] \
+ [ -B banner ] \
+@@ -249,6 +282,7 @@
+ [ -b backlog ] \
+ [ -l localname ] \
+ [ -t timeout ] \
++[ -I interface ] \
+ host port program",0);
+ _exit(100);
+ }
+@@ -299,8 +333,8 @@
+ unsigned long u;
+ int s;
+ int t;
+-
+- while ((opt = getopt(argc,argv,"dDvqQhHrR1UXx:t:u:g:l:b:B:c:pPoO")) != opteof)
++
++ while ((opt = getopt(argc,argv,"46dDvqQhHrR1UXx:t:u:g:l:b:B:c:I:pPoO")) != opteof)
+ switch(opt) {
+ case 'b': scan_ulong(optarg,&backlog); break;
+ case 'c': scan_ulong(optarg,&limit); break;
+@@ -325,7 +359,10 @@
+ x = env_get("GID"); if (x) scan_ulong(x,&gid); break;
+ case 'u': scan_ulong(optarg,&uid); break;
+ case 'g': scan_ulong(optarg,&gid); break;
++ case 'I': netif=socket_getifidx(optarg); break;
+ case '1': flag1 = 1; break;
++ case '4': noipv6 = 1; break;
++ case '6': forcev6 = 1; break;
+ case 'l': localhost = optarg; break;
+ default: usage();
+ }
+@@ -337,8 +374,7 @@
+
+ hostname = *argv++;
+ if (!hostname) usage();
+- if (str_equal(hostname,"")) hostname = "0.0.0.0";
+- if (str_equal(hostname,"0")) hostname = "0.0.0.0";
++ if (str_equal(hostname,"")) hostname = "0";
+
+ x = *argv++;
+ if (!x) usage();
+@@ -348,7 +384,7 @@
+ se = getservbyname(x,"tcp");
+ if (!se)
+ strerr_die3x(111,FATAL,"unable to figure out port number for ",x);
+- localport = ntohs(se->s_port);
++ uint16_unpack_big((char*)&se->s_port,&localport);
+ }
+
+ if (!*argv) usage();
+@@ -358,20 +394,26 @@
+ sig_catch(sig_term,sigterm);
+ sig_ignore(sig_pipe);
+
+- if (!stralloc_copys(&tmp,hostname))
+- strerr_die2x(111,FATAL,"out of memory");
+- if (dns_ip4_qualify(&addresses,&fqdn,&tmp) == -1)
+- strerr_die4sys(111,FATAL,"temporarily unable to figure out IP address for ",hostname,": ");
+- if (addresses.len < 4)
+- strerr_die3x(111,FATAL,"no IP address for ",hostname);
+- byte_copy(localip,4,addresses.s);
++ if (str_equal(hostname,"0")) {
++ byte_zero(localip,sizeof localip);
++ } else {
++ if (!stralloc_copys(&tmp,hostname))
++ strerr_die2x(111,FATAL,"out of memory");
++ if (dns_ip6_qualify(&addresses,&fqdn,&tmp) == -1)
++ strerr_die4sys(111,FATAL,"temporarily unable to figure out IP address for ",hostname,": ");
++ if (addresses.len < 16)
++ strerr_die3x(111,FATAL,"no IP address for ",hostname);
++ byte_copy(localip,16,addresses.s);
++ if (ip6_isv4mapped(localip))
++ noipv6=1;
++ }
+
+- s = socket_tcp();
++ s = socket_tcp6();
+ if (s == -1)
+ strerr_die2sys(111,FATAL,"unable to create socket: ");
+- if (socket_bind4_reuse(s,localip,localport) == -1)
++ if (socket_bind6_reuse(s,localip,localport,netif) == -1)
+ strerr_die2sys(111,FATAL,"unable to bind: ");
+- if (socket_local4(s,localip,&localport) == -1)
++ if (socket_local6(s,localip,&localport,&netif) == -1)
+ strerr_die2sys(111,FATAL,"unable to get local address: ");
+ if (socket_listen(s,backlog) == -1)
+ strerr_die2sys(111,FATAL,"unable to listen: ");
+@@ -399,7 +441,7 @@
+ while (numchildren >= limit) sig_pause();
+
+ sig_unblock(sig_child);
+- t = socket_accept4(s,remoteip,&remoteport);
++ t = socket_accept6(s,remoteip,&remoteport,&netif);
+ sig_block(sig_child);
+
+ if (t == -1) continue;
+diff -uNr ucspi-tcp-0.88.orig/timeoutconn.h ucspi-tcp-0.88/timeoutconn.h
+--- ucspi-tcp-0.88.orig/timeoutconn.h 2009-08-04 15:19:16.000000000 -0500
++++ ucspi-tcp-0.88/timeoutconn.h 2009-08-04 17:45:59.000000000 -0500
+@@ -2,7 +2,9 @@
+ #define TIMEOUTCONN_H
+
+ #include "uint16.h"
++#include "uint32.h"
+
+ extern int timeoutconn(int,char *,uint16,unsigned int);
++extern int timeoutconn6(int,char *,uint16,unsigned int,uint32);
+
+ #endif
+diff -uNr ucspi-tcp-0.88.orig/timeoutconn6.c ucspi-tcp-0.88/timeoutconn6.c
+--- ucspi-tcp-0.88.orig/timeoutconn6.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/timeoutconn6.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/tryip6.c ucspi-tcp-0.88/tryip6.c
+--- ucspi-tcp-0.88.orig/tryip6.c 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/tryip6.c 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/usr/local/man/man1/tcpclient.1 ucspi-tcp-0.88/usr/local/man/man1/tcpclient.1
+--- ucspi-tcp-0.88.orig/usr/local/man/man1/tcpclient.1 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/usr/local/man/man1/tcpclient.1 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/usr/local/man/man1/tcpserver.1 ucspi-tcp-0.88/usr/local/man/man1/tcpserver.1
+--- ucspi-tcp-0.88.orig/usr/local/man/man1/tcpserver.1 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/usr/local/man/man1/tcpserver.1 2009-08-04 17:45:59.000000000 -0500
+@@ -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 -uNr ucspi-tcp-0.88.orig/who@.1 ucspi-tcp-0.88/who@.1
+--- ucspi-tcp-0.88.orig/who@.1 1969-12-31 18:00:00.000000000 -0600
++++ ucspi-tcp-0.88/who@.1 2009-08-04 17:45:59.000000000 -0500
+@@ -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)