Download | Plain Text | No Line Numbers
- --- FILES 14 Jun 2002 08:47:30 -0000 1.1.1.1
- +++ FILES 5 Apr 2004 15:34:57 -0000 1.2
- @@ -216,3 +216,19 @@
- warn-auto.sh
- warn-shsgr
- x86cpuid.c
- +addcr.1
- +argv0.1
- +date@.1
- +delcr.1
- +finger@.1
- +fixcrio.1
- +http@.1
- +mconnect.1
- +recordio.1
- +tcpcat.1
- +tcpclient.1
- +tcprules.1
- +tcprulescheck.1
- +tcpserver.1
- +who@.1
- +tcp-environ.5
- --- Makefile 14 Jun 2002 08:47:30 -0000 1.1.1.1
- +++ Makefile 5 Apr 2004 15:34:57 -0000 1.3
- @@ -1,5 +1,13 @@
- # Don't edit Makefile! Use conf-* for configuration.
-
- +DEFINES=-DWITH_SSL
- +#add -DWITH_SSL to enable ssl support
- +
- +# LIBS for additional libraries and INCS for additional includes
- +LIBS=-lcrypto -lssl
- +#INCS=-I/usr/local/include
- +OPENSSLBIN=openssl
- +
- SHELL=/bin/sh
-
- default: it
- @@ -745,7 +753,7 @@
- load tcpserver.o rules.o remoteinfo.o timeoutconn.o cdb.a dns.a \
- time.a unix.a byte.a socket.lib
- ./load tcpserver rules.o remoteinfo.o timeoutconn.o cdb.a \
- - dns.a time.a unix.a byte.a `cat socket.lib`
- + dns.a time.a unix.a byte.a $(LIBS) `cat socket.lib`
-
- tcpserver.o: \
- compile tcpserver.c uint16.h str.h byte.h fmt.h scan.h ip4.h fd.h \
- @@ -754,7 +762,7 @@
- socket.h uint16.h ndelay.h remoteinfo.h stralloc.h uint16.h rules.h \
- stralloc.h sig.h dns.h stralloc.h iopause.h taia.h tai.h uint64.h \
- taia.h
- - ./compile tcpserver.c
- + ./compile $(DEFINES) $(INCS) tcpserver.c
-
- time.a: \
- makelib iopause.o tai_pack.o taia_add.o taia_approx.o taia_frac.o \
- @@ -835,3 +843,21 @@
- | sed s}HOME}"`head -1 conf-home`"}g \
- > who@
- chmod 755 who@
- +
- +clean:
- + rm -f `cat TARGETS`
- +
- +cert:
- + ${OPENSSLBIN} req -new -x509 -nodes \
- + -out cert.pem -days 366 \
- + -keyout cert.pem
- +
- +cert-req:
- + ${OPENSSLBIN} req -new -nodes \
- + -out req.pem \
- + -keyout cert.pem
- + @echo
- + @echo "Send req.pem to your CA to obtain signed_req.pem, and do:"
- + @echo "cat signed_req.pem >> `head -1 conf-qmail`/control/cert.pem"
- +
- +
- --- /dev/null 1 Jan 1970 00:00:00 -0000
- +++ addcr.1 5 Apr 2004 15:34:57 -0000 1.1
- @@ -0,0 +1,22 @@
- +.TH addcr 1
- +.SH NAME
- +addcr \- add a CR before each LF
- +.SH SYNOPSIS
- +.B addcr
- +.SH DESCRIPTION
- +.B addcr
- +inserts CR at the end of each line of input.
- +It does not insert CR at the end of a partial final line.
- +.SH COMPATIBILITY
- +Some vendors ship
- +.B unix2dos
- +or
- +.B bsd2dos
- +tools similar to
- +.BR addcr .
- +Those tools often blow up on long lines and nulls.
- +.B addcr
- +has no trouble with long lines and nulls.
- +.SH "SEE ALSO"
- +delcr(1),
- +fixcrio(1)
- --- /dev/null 1 Jan 1970 00:00:00 -0000
- +++ argv0.1 5 Apr 2004 15:34:57 -0000 1.1
- @@ -0,0 +1,47 @@
- +.TH argv0 1
- +.SH NAME
- +argv0 \- run a program with a specified 0th argument
- +.SH SYNOPSIS
- +.B argv0
- +.I realname
- +.I zero
- +[
- +.I arg ...
- +]
- +.SH DESCRIPTION
- +.B argv0
- +runs
- +the program stored as
- +.I realname
- +on disk,
- +with the given
- +arguments.
- +It sets the 0th argument of
- +the program to
- +.IR zero .
- +
- +For example,
- +
- +.EX
- + argv0 /bin/csh -bin/csh
- +.EE
- +
- +runs
- +.B /bin/csh
- +with a 0th argument of
- +.BR -bin/csh .
- +.B csh
- +will think it is a login shell
- +and behave accordingly.
- +
- +.B argv0
- +can be used to run some
- +.B inetd
- +wrappers under
- +.BR tcpserver .
- +.SH "SEE ALSO"
- +csh(1),
- +tcpserver(1),
- +execve(2),
- +execvp(3),
- +inetd(8)
- --- /dev/null 1 Jan 1970 00:00:00 -0000
- +++ date@.1 5 Apr 2004 15:34:57 -0000 1.1
- @@ -0,0 +1,32 @@
- +.TH date@ 1
- +.SH NAME
- +date@ \- print the date on a host
- +.SH SYNTAX
- +.B date@
- +[
- +.I host
- +]
- +.SH DESCRIPTION
- +.B date@
- +connects to TCP port 13 (Daytime) on
- +.I host
- +and prints any data it receives.
- +It removes CR and converts unprintable characters to a visible format.
- +
- +If
- +.I host
- +is not supplied,
- +.B date@
- +connects to the local host.
- +
- +Some computers respond to port 13 with a human-readable date.
- +For example, they may be running
- +
- +.EX
- + tcpserver 0 13 date &
- +.EE
- +.SH "SEE ALSO"
- +cat(1),
- +delcr(1),
- +tcpclient(1),
- +tcpserver(1)
- --- /dev/null 1 Jan 1970 00:00:00 -0000
- +++ delcr.1 5 Apr 2004 15:34:57 -0000 1.1
- @@ -0,0 +1,30 @@
- +.TH delcr 1
- +.SH NAME
- +delcr \- remove a CR before each LF
- +.SH SYNOPSIS
- +.B delcr
- +.SH DESCRIPTION
- +.B delcr
- +removes a CR at the end of each line of input,
- +if a CR is present.
- +It also removes a CR at the end of a partial final line.
- +
- +The pipeline
- +
- +.EX
- + addcr | delcr
- +.EE
- +
- +prints an exact copy of its input.
- +.SH COMPATIBILITY
- +Some vendors ship
- +.B dos2unix
- +or
- +.B dos2bsd
- +tools similar to
- +.BR delcr .
- +Those tools often blow up on long lines and nulls.
- +.B delcr
- +has no trouble with long lines and nulls.
- +.SH "SEE ALSO"
- +addcr(1)
- --- error.h 14 Jun 2002 08:47:31 -0000 1.1.1.1
- +++ error.h 6 Nov 2003 09:47:05 -0000 1.2
- @@ -1,7 +1,7 @@
- #ifndef ERROR_H
- #define ERROR_H
-
- -extern int errno;
- +#include <errno.h>
-
- extern int error_intr;
- extern int error_nomem;
- --- /dev/null 1 Jan 1970 00:00:00 -0000
- +++ finger@.1 5 Apr 2004 15:34:57 -0000 1.1
- @@ -0,0 +1,45 @@
- +.TH finger@ 1
- +.SH NAME
- +finger@ \- get user information from a host
- +.SH SYNTAX
- +.B finger@
- +[
- +.I host
- +[
- +.I user
- +]
- +]
- +.SH DESCRIPTION
- +.B finger@
- +connects to TCP port 79 (Finger) on
- +.IR host ,
- +sends
- +.I user
- +(with an extra CR)
- +to
- +.IR host ,
- +and prints any data it receives.
- +It removes CR and converts unprintable characters to a visible format.
- +Some computers respond to port 79 with information about
- +.IR user .
- +
- +If
- +.I user
- +is not supplied,
- +.B finger@
- +sends a blank line to
- +.IR host .
- +Some computers respond with information about
- +all the users who are logged in.
- +
- +If
- +.I host
- +is not supplied,
- +.B finger@
- +connects to the local host.
- +.SH "SEE ALSO"
- +addcr(1),
- +cat(1),
- +delcr(1),
- +finger(1),
- +tcpclient(1)
- --- /dev/null 1 Jan 1970 00:00:00 -0000
- +++ fixcrio.1 5 Apr 2004 15:34:57 -0000 1.1
- @@ -0,0 +1,15 @@
- +.TH fixcrio 1
- +.SH NAME
- +fixcrio \- make sure that there is a CR before each LF
- +.SH SYNOPSIS
- +.B fixcrio
- +.I program
- +[
- +.I arg ...
- +]
- +.SH DESCRIPTION
- +.B fixcrio
- +inserts CR at the end of each line of input where a CR is not already present.
- +It does not insert CR at the end of a partial final line.
- +.SH "SEE ALSO"
- +addcr(1)
- --- hier.c 14 Jun 2002 08:47:32 -0000 1.1.1.1
- +++ hier.c 5 Apr 2004 15:34:57 -0000 1.2
- @@ -2,8 +2,11 @@
-
- void hier()
- {
- - h(auto_home,-1,-1,02755);
- - d(auto_home,"bin",-1,-1,02755);
- + h(auto_home,-1,-1,0755);
- + d(auto_home,"bin",-1,-1,0755);
- + d(auto_home,"man",-1,-1,0755);
- + d(auto_home,"man/man1",-1,-1,0755);
- + d(auto_home,"man/man5",-1,-1,0755);
-
- c(auto_home,"bin","tcpserver",-1,-1,0755);
- c(auto_home,"bin","tcprules",-1,-1,0755);
- @@ -22,4 +27,21 @@
- c(auto_home,"bin","delcr",-1,-1,0755);
- c(auto_home,"bin","fixcrio",-1,-1,0755);
- c(auto_home,"bin","rblsmtpd",-1,-1,0755);
- +
- + c(auto_home,"man/man1","addcr.1",-1,-1,0644);
- + c(auto_home,"man/man1","argv0.1",-1,-1,0644);
- + c(auto_home,"man/man1","date@.1",-1,-1,0644);
- + c(auto_home,"man/man1","delcr.1",-1,-1,0644);
- + c(auto_home,"man/man1","finger@.1",-1,-1,0644);
- + c(auto_home,"man/man1","fixcrio.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","recordio.1",-1,-1,0644);
- + c(auto_home,"man/man1","tcpcat.1",-1,-1,0644);
- + c(auto_home,"man/man1","tcpclient.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","tcpserver.1",-1,-1,0644);
- + c(auto_home,"man/man1","who@.1",-1,-1,0644);
- + c(auto_home,"man/man5","tcp-environ.5",-1,-1,0644);
- }
- --- /dev/null 1 Jan 1970 00:00:00 -0000
- +++ http@.1 5 Apr 2004 15:34:57 -0000 1.1
- @@ -0,0 +1,52 @@
- +.TH http@ 1
- +.SH NAME
- +http@ \- get a web page from a host through HTTP
- +.SH SYNTAX
- +.B http@
- +[
- +.I host
- +[
- +.I page
- +[
- +.I port
- +]
- +]
- +]
- +.SH DESCRIPTION
- +.B http@
- +connects to
- +.I port
- +on
- +.IR host ,
- +sends
- +.B GET /\fIpage
- +(with an extra CR)
- +to
- +.IR host ,
- +and prints any data it receives,
- +removing CR from the end of each line.
- +
- +If
- +.I port
- +is not supplied,
- +.B http@
- +uses port 80 (HTTP).
- +
- +If
- +.I page
- +is not supplied,
- +.B http@
- +sends
- +.B GET /
- +to
- +.IR host .
- +
- +If
- +.I host
- +is not supplied,
- +.B http@
- +connects to the local host.
- +.SH "SEE ALSO"
- +addcr(1),
- +delcr(1),
- +tcpclient(1)
- --- /dev/null 1 Jan 1970 00:00:00 -0000
- +++ mconnect.1 5 Apr 2004 15:34:57 -0000 1.1
- @@ -0,0 +1,36 @@
- +.TH mconnect 1
- +.SH NAME
- +mconnect \- connect to the SMTP server on a host
- +.SH SYNTAX
- +.B mconnect
- +[
- +.I host
- +[
- +.I port
- +]
- +]
- +.SH DESCRIPTION
- +.B mconnect
- +connects to
- +.I port
- +on
- +.IR host .
- +It sends its input to
- +.IR host ,
- +adding a CR to each line.
- +Meanwhile it prints anything it receives from
- +.IR host .
- +
- +If
- +.I port
- +is not supplied,
- +.B mconnect
- +uses port 25 (SMTP).
- +
- +If
- +.I host
- +is not supplied,
- +.B mconnect
- +connects to the local host.
- +.SH "SEE ALSO"
- +tcpclient(1)
- --- /dev/null 1 Jan 1970 00:00:00 -0000
- +++ recordio.1 5 Apr 2004 15:34:57 -0000 1.1
- @@ -0,0 +1,75 @@
- +.TH recordio 1
- +.SH NAME
- +recordio \- record the input and output of a program
- +.SH SYNTAX
- +.B recordio
- +.I program
- +[
- +.I arg ...
- +]
- +.SH DESCRIPTION
- +.B recordio
- +runs
- +.I program
- +with the given arguments.
- +It prints lines to stderr
- +showing the input and output of
- +.IR program .
- +
- +At the beginning of each line on stderr,
- +.B recordio
- +inserts the
- +.I program
- +process ID,
- +along with
- +.B <
- +for input or
- +.B >
- +for output.
- +At the end of each line it inserts a space, a plus sign, or [EOF];
- +a space indicates that there was a newline in the input or output,
- +and [EOF] indicates the end of input or output.
- +
- +.B recordio
- +prints every packet of input and output immediately.
- +It does not attempt to combine packets into coherent stderr lines.
- +For example,
- +
- +.EX
- + recordio sh -c 'cat /dev/fd/8 2>&1' > /dev/null
- +.EE
- +
- +could produce
- +
- +.EX
- + 5135 > cat: /dev/fd/8: Bad file descriptor
- +.br
- + 5135 > [EOF]
- +.EE
- +
- +or
- +
- +.EX
- + 5135 > cat: +
- +.br
- + 5135 > /dev/fd/8+
- +.br
- + 5135 > : +
- +.br
- + 5135 > Bad file descriptor
- +.br
- + 5135 > [EOF]
- +.EE
- +
- +.B recordio
- +uses several lines for long packets
- +to guarantee that each line is printed atomically to stderr.
- +
- +.B recordio
- +runs as a child of
- +.IR program .
- +It exits when it sees the end of
- +.IR program 's
- +output.
- +.SH "SEE ALSO"
- +tcpserver(1)
- --- /dev/null 1 Jan 1970 00:00:00 -0000
- +++ tcp-environ.5 5 Apr 2004 15:34:57 -0000 1.1
- @@ -0,0 +1,62 @@
- +.TH tcp-environ 5
- +.SH NAME
- +tcp-environ \- TCP-related environment variables
- +.SH DESCRIPTION
- +The following environment variables
- +describe a TCP connection.
- +They are set up by
- +.BR tcp-env ,
- +.BR tcpclient ,
- +and
- +.BR tcpserver .
- +Note that
- +.BR TCPLOCALHOST ,
- +.BR TCPREMOTEHOST ,
- +and
- +.B TCPREMOTEINFO
- +can contain arbitrary characters.
- +.TP 5
- +PROTO
- +The string
- +.BR TCP .
- +.TP 5
- +TCPLOCALHOST
- +The domain name of the local host,
- +with uppercase letters converted to lowercase.
- +If there is no currently available domain name
- +for the local IP address,
- +.B TCPLOCALHOST
- +is not set.
- +.TP 5
- +TCPLOCALIP
- +The IP address of the local host, in dotted-decimal form.
- +.TP 5
- +TCPLOCALPORT
- +The local TCP port number, in decimal.
- +.TP 5
- +TCPREMOTEHOST
- +The domain name of the remote host,
- +with uppercase letters converted to lowercase.
- +If there is no currently available domain name
- +for the remote IP address,
- +.B TCPREMOTEHOST
- +is not set.
- +.TP 5
- +TCPREMOTEINFO
- +A connection-specific string, perhaps a username,
- +supplied by the remote host
- +via 931/1413/IDENT/TAP.
- +If the remote host did not supply connection information,
- +.B TCPREMOTEINFO
- +is not set.
- +.TP 5
- +TCPREMOTEIP
- +The IP address of the remote host.
- +.TP 5
- +TCPREMOTEPORT
- +The remote TCP port number.
- +.SH "SEE ALSO"
- +tcpclient(1),
- +tcpserver(1),
- +tcp-env(1),
- +tcp(4)
- --- /dev/null 1 Jan 1970 00:00:00 -0000
- +++ tcpcat.1 5 Apr 2004 15:34:57 -0000 1.1
- @@ -0,0 +1,20 @@
- +.TH tcpcat 1
- +.SH NAME
- +tcpcat \- print data from a TCP port
- +.SH SYNTAX
- +.B tcpcat
- +.I host
- +.I port
- +.SH DESCRIPTION
- +.B tcpcat
- +connects to
- +.I port
- +on
- +.I host
- +and prints any data it receives.
- +
- +.B tcpcat
- +can be used to transfer binary data.
- +It does no conversions.
- +.SH "SEE ALSO"
- +tcpclient(1)
- --- /dev/null 1 Jan 1970 00:00:00 -0000
- +++ tcpclient.1 5 Apr 2004 15:34:57 -0000 1.1
- @@ -0,0 +1,151 @@
- +.TH tcpclient 1
- +.SH NAME
- +tcpclient \- create an outgoing TCP connection
- +.SH SYNOPSIS
- +.B tcpclient
- +[
- +.B \-hHrRdDqQv
- +]
- +[
- +.B \-i\fIlocalip
- +]
- +[
- +.B \-p\fIlocalport
- +]
- +[
- +.B \-T\fItimeoutconn
- +]
- +[
- +.B \-l\fIlocalname
- +]
- +[
- +.B \-t\fItimeoutinfo
- +]
- +.I host
- +.I port
- +.I program
- +[
- +.I arg ...
- +]
- +.SH DESCRIPTION
- +.B tcpclient
- +attempts to connect to a TCP server.
- +If it is successful, it runs
- +.I program
- +with the given arguments,
- +with descriptor 6 reading from the network
- +and descriptor 7 writing to the network.
- +
- +The server's address is given by
- +.I host
- +and
- +.IR port .
- +.I host
- +may be 0, referring to the local machine,
- +or a dotted-decimal IP address,
- +or a host name;
- +if a host has several IP addresses,
- +.B tcpclient
- +tries each in turn.
- +.I port
- +may be a numeric port number
- +or a port name.
- +
- +.B tcpclient
- +sets up several environment variables,
- +as described in
- +.B tcp-environ(5).
- +.SH OPTIONS
- +.TP
- +.B \-i\fIlocalip
- +Use
- +.I localip
- +as the IP address for the local side of the connection;
- +quit if
- +.I localip
- +is not available.
- +.TP
- +.B \-p\fIlocalport
- +Use
- +.I localport
- +as the port number for the local side of the connection;
- +quit if
- +.I localport
- +is not available.
- +.TP
- +.B \-T\fItimeoutconn
- +Give up on the
- +connection attempt
- +after
- +.I timeoutconn
- +seconds. Default: 60.
- +This timeout applies to each IP address tried.
- +.TP
- +.B \-d
- +(Default.)
- +Delay sending data for a fraction of a second whenever the
- +remote host is responding slowly,
- +to make better use of the network.
- +.TP
- +.B \-D
- +Never delay sending data;
- +enable TCP_NODELAY.
- +This is appropriate for interactive connections.
- +.TP
- +.B \-q
- +Quiet.
- +Do not print any messages.
- +.TP
- +.B \-Q
- +(Default.)
- +Print error messages.
- +.TP
- +.B \-v
- +Verbose.
- +Print all available messages.
- +.SH "DATA-GATHERING OPTIONS"
- +.TP
- +.B \-h
- +(Default.)
- +Look up the remote host name for
- +.BR TCPREMOTEHOST .
- +.TP
- +.B \-H
- +Do not look up the remote host name;
- +unset
- +.BR TCPREMOTEHOST .
- +.TP
- +.B \-l\fIlocalname
- +Do not look up the local host name;
- +use
- +.I localname
- +for
- +.BR TCPLOCALHOST .
- +.TP
- +.B \-r
- +(Default.)
- +Attempt to obtain
- +.B TCPREMOTEINFO
- +from the remote host.
- +.TP
- +.B \-R
- +Do not attempt to obtain
- +.B TCPREMOTEINFO
- +from the remote host.
- +.TP
- +.B \-t\fItimeoutinfo
- +Give up on the
- +.B TCPREMOTEINFO
- +connection attempt
- +after
- +.I timeoutinfo
- +seconds. Default: 26.
- +.SH "SEE ALSO"
- +date@(1),
- +finger@(1),
- +http@(1),
- +mconnect(1),
- +tcpcat(1),
- +tcpserver(1),
- +who@(1),
- +tcp-environ(5)
- --- /dev/null 1 Jan 1970 00:00:00 -0000
- +++ tcprules.1 5 Apr 2004 15:34:57 -0000 1.1
- @@ -0,0 +1,208 @@
- +.TH tcprules 1
- +.SH NAME
- +tcprules \- compile rules for tcpserver
- +.SH SYNOPSIS
- +.B tcprules
- +.I rules.cdb
- +.I rules.tmp
- +.SH OVERVIEW
- +.B tcpserver
- +optionally follows rules to decide whether a TCP connection is acceptable.
- +For example, a rule of
- +
- +.EX
- + 18.23.0.32:deny
- +.EE
- +
- +prohibits connections from IP address 18.23.0.32.
- +
- +.B tcprules
- +reads rules from its standard input
- +and writes them into
- +.I rules.cdb
- +in a binary format suited
- +for quick access by
- +.BR tcpserver .
- +
- +.B tcprules
- +can be used while
- +.B tcpserver
- +is running:
- +it ensures that
- +.I rules.cdb
- +is updated atomically.
- +It does this by first writing the rules to
- +.I rules.tmp
- +and then moving
- +.I rules.tmp
- +on top of
- +.IR rules.cdb .
- +If
- +.I rules.tmp
- +already exists, it is destroyed.
- +The directories containing
- +.I rules.cdb
- +and
- +.I rules.tmp
- +must be writable to
- +.BR tcprules ;
- +they must also be on the same filesystem.
- +
- +If there is a problem with the input,
- +.B tcprules
- +complains and leaves
- +.I rules.cdb
- +alone.
- +
- +The binary
- +.I rules.cdb
- +format is portable across machines.
- +.SH "RULE FORMAT"
- +A rule takes up one line.
- +A file containing rules
- +may also contain comments: lines beginning with # are ignored.
- +
- +Each rule contains an
- +.BR address ,
- +a colon,
- +and a list of
- +.BR instructions ,
- +with no extra spaces.
- +When
- +.B tcpserver
- +receives a connection from that address,
- +it follows the instructions.
- +.SH "ADDRESSES"
- +.B tcpserver
- +starts by looking for a rule with address
- +.IR TCPREMOTEINFO\fB@\fITCPREMOTEIP .
- +If it doesn't find one, or if
- +.I TCPREMOTEINFO
- +is not set, it tries the address
- +.IR TCPREMOTEIP .
- +If that doesn't work, it tries shorter and shorter prefixes of
- +.I TCPREMOTEIP
- +ending with a dot.
- +If none of them work, it tries the empty string.
- +
- +For example, here are some rules:
- +
- +.EX
- + joe@127.0.0.1:first
- +.br
- + 18.23.0.32:second
- +.br
- + 127.:third
- +.br
- + :fourth
- +.EE
- +
- +If
- +.I TCPREMOTEIP
- +is
- +.BR 10.119.75.38 ,
- +.B tcpserver
- +will follow the
- +.B fourth
- +instructions.
- +
- +If
- +.I TCPREMOTEIP
- +is
- +.BR 18.23.0.32 ,
- +.B tcpserver
- +will follow the
- +.B second
- +instructions.
- +
- +If
- +.I TCPREMOTEINFO
- +is
- +.B bill
- +and
- +.I TCPREMOTEIP
- +is
- +.BR 127.0.0.1 ,
- +.B tcpserver
- +will follow the
- +.B third
- +instructions.
- +
- +If
- +.I TCPREMOTEINFO
- +is
- +.B joe
- +and
- +.I TCPREMOTEIP
- +is
- +.BR 127.0.0.1 ,
- +.B tcpserver
- +will follow the
- +.B first
- +instructions.
- +.SH "ADDRESS RANGES"
- +.B tcprules
- +treats
- +.B 1.2.3.37-53:ins
- +as an abbreviation
- +for the rules
- +.BR 1.2.3.37:ins ,
- +.BR 1.2.3.38:ins ,
- +and so on up through
- +.BR 1.2.3.53:ins .
- +Similarly,
- +.BR 10.2-3.:ins
- +is an abbreviation for
- +.B 10.2.:ins
- +and
- +.BR 10.3.:ins .
- +.SH "INSTRUCTIONS"
- +The instructions in a rule must begin with either
- +.B allow
- +or
- +.BR deny .
- +.B deny
- +tells
- +.B tcpserver
- +to drop the connection without running anything.
- +For example, the rule
- +
- +.EX
- + :deny
- +.EE
- +
- +tells
- +.B tcpserver
- +to drop all connections that aren't handled by more specific rules.
- +
- +The instructions may continue with some environment variables,
- +in the format
- +.IR ,VAR="VALUE" .
- +.B tcpserver
- +adds
- +.I VAR=VALUE
- +to the current environment.
- +For example,
- +
- +.EX
- + 10.0.:allow,RELAYCLIENT="@fix.me"
- +.EE
- +
- +adds
- +.B 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)
- --- tcprules.c 14 Jun 2002 08:47:30 -0000 1.1.1.1
- +++ tcprules.c 16 Mar 2004 15:12:26 -0000 1.2
- @@ -94,6 +94,7 @@
- int len;
- int fd;
- int i;
- + int e;
- char ch;
-
- fn = argv[1];
- @@ -144,8 +145,16 @@
- while (len)
- switch(*x) {
- case ',':
- + e = byte_chr(x + 1,len - 1,',');
- i = byte_chr(x,len,'=');
- - if (i == len) die_bad();
- + if (i > e) {
- + if (e < 2 || x[1] != '!') die_bad();
- + if (!stralloc_catb(&data,"-",1)) nomem();
- + if (!stralloc_catb(&data,x + 2,e - 1)) nomem();
- + if (!stralloc_0(&data)) nomem();
- + x += e + 1; len -= e + 1;
- + break;
- + }
- if (!stralloc_catb(&data,"+",1)) nomem();
- if (!stralloc_catb(&data,x + 1,i)) nomem();
- x += i + 1; len -= i + 1;
- --- /dev/null 1 Jan 1970 00:00:00 -0000
- +++ tcprulescheck.1 5 Apr 2004 15:34:57 -0000 1.1
- @@ -0,0 +1,25 @@
- +.TH tcprulescheck 1
- +.SH NAME
- +tcprulescheck \- try out rules for tcpserver
- +.SH SYNTAX
- +.B tcprulescheck
- +.I rules.cdb
- +.I tcpremoteip
- +[
- +.I tcpremoteinfo
- +]
- +.SH DESCRIPTION
- +.B tcprulescheck
- +says what
- +.B tcpserver
- +will do with a connection from
- +IP address
- +.IR tcpremoteip ,
- +following the rules compiled into
- +.I rules.cdb
- +by
- +.BR tcprules .
- +.SH "SEE ALSO"
- +tcprules(1),
- +tcpserver(1),
- +tcp-environ(5)
- diff -u -p -r1.1.1.1 -r1.2
- --- tcprulescheck.c 14 Jun 2002 08:47:30 -0000 1.1.1.1
- +++ tcprulescheck.c 16 Mar 2004 15:12:27 -0000 1.2
- @@ -22,6 +22,11 @@
- buffer_puts(buffer_1,data + 1);
- buffer_puts(buffer_1,"\n");
- break;
- + case '-':
- + buffer_puts(buffer_1,"unset environment variable ");
- + buffer_puts(buffer_1,data + 1);
- + buffer_puts(buffer_1,"\n");
- + break;
- }
- ++next0;
- data += next0; datalen -= next0;
- --- /dev/null 1 Jan 1970 00:00:00 -0000
- +++ tcpserver.1 6 Apr 2004 11:49:45 -0000 1.2
- @@ -0,0 +1,284 @@
- +.TH tcpserver 1
- +.SH NAME
- +tcpserver \- accept incoming TCP connections
- +.SH SYNOPSIS
- +.B tcpserver
- +[
- +.B \-1UXpPhHrRoOdDqQsSv
- +]
- +[
- +.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 \-n\fIcertfile
- +]
- +.I host
- +.I port
- +.I program
- +[
- +.I arg ...
- +]
- +.SH DESCRIPTION
- +.B tcpserver
- +waits for connections from TCP clients.
- +For each connection, it runs
- +.I program
- +with the given arguments,
- +with descriptor 0 reading from the network
- +and descriptor 1 writing to the network.
- +
- +The server's address is given by
- +.I host
- +and
- +.IR port .
- +.I host
- +can be 0, allowing connections from any host;
- +or a particular IP address,
- +allowing connections only to that address;
- +or a host name, allowing connections to the first IP address
- +for that host.
- +.I port
- +may be a numeric port number
- +or a port name.
- +If
- +.I port
- +is 0,
- +.B tcpserver
- +will choose a free port.
- +
- +.B tcpserver
- +sets up several environment variables,
- +as described in
- +.B tcp-environ(5).
- +
- +.B tcpserver
- +exits when it receives SIGTERM.
- +.SH "OPTIONS"
- +.TP
- +.B \-c\fIlimit
- +Do not handle more than
- +.I limit
- +simultaneous connections.
- +If there are
- +.I limit
- +simultaneous copies of
- +.I program
- +running, defer acceptance of a new connection
- +until one copy finishes.
- +.I limit
- +must be a positive integer.
- +Default: 40.
- +.TP
- +.B \-x\fIrules.cdb
- +Follow the rules compiled into
- +.I rules.cdb
- +by
- +.BR tcprules .
- +These rules may specify setting environment variables
- +or rejecting connections from bad sources.
- +
- +.B tcpserver
- +does not read
- +.I rules.cdb
- +into memory;
- +you can rerun
- +.B tcprules
- +to change
- +.BR tcpserver 's
- +behavior on the fly.
- +.TP
- +.B \-B\fIbanner
- +Write
- +.I banner
- +to the network immediately after each connection is made.
- +.B tcpserver
- +writes
- +.I banner
- +before looking up
- +.BR TCPREMOTEHOST ,
- +before looking up
- +.BR TCPREMOTEINFO ,
- +and before checking
- +.IR rules.cdb .
- +
- +This feature can be used to reduce latency in protocols
- +where the client waits for a greeting from the server.
- +.TP
- +.B \-g\fIgid
- +Switch group ID to
- +.I gid
- +after preparing to receive connections.
- +.I gid
- +must be a positive integer.
- +.TP
- +.B \-u\fIuid
- +Switch user ID to
- +.I uid
- +after preparing to receive connections.
- +.I uid
- +must be a positive integer.
- +.TP
- +.B \-U
- +Same as
- +.B \-g\fI$GID
- +.BR \-u\fI$UID .
- +Typically
- +.I $GID
- +and
- +.I $UID
- +are set by envuidgid.
- +.TP
- +.B \-1
- +After preparing to receive connections,
- +print the local port number to standard output.
- +.TP
- +.B \-b\fIbacklog
- +Allow up to
- +.I backlog
- +simultaneous SYN_RECEIVEDs.
- +Default: 20.
- +On some systems,
- +.I backlog
- +is silently limited to 5.
- +See
- +.BR listen (2)
- +for more details.
- +.TP
- +.B \-o
- +Leave IP options alone.
- +If the client is sending packets along an IP source route,
- +send packets back along the same route.
- +.TP
- +.B \-O
- +(Default.)
- +Kill IP options.
- +A client can still use source routing to connect and to send data,
- +but packets will be sent back along the default route.
- +.TP
- +.B \-d
- +(Default.)
- +Delay sending data for a fraction of a second whenever the
- +remote host is responding slowly,
- +to make better use of the network.
- +.TP
- +.B \-D
- +Never delay sending data;
- +enable TCP_NODELAY.
- +This is appropriate for interactive connections.
- +.TP
- +.B \-q
- +Quiet.
- +Do not print any messages.
- +.TP
- +.B \-Q
- +(Default.)
- +Print error messages.
- +.TP
- +.B \-s
- +Enable SSL/TLS mode. This modus needs a SSL enabled build and a certificat.
- +.TP
- +.B \-S
- +(Default.)
- +Don't enable SSL/TLS mode.
- +.TP
- +.B \-n\fIcertfile
- +Instead of the default ./cert.pem certificate us the specified
- +.IR certfile .
- +.TP
- +.B \-v
- +Verbose.
- +Print all available messages.
- +.TP
- +.B \-X
- +With
- +.BR -x\fIcdb ,
- +allow connections even if
- +.I cdb
- +does not exist.
- +Normally the connection gets dropped.
- +.SH "DATA-GATHERING OPTIONS"
- +.TP
- +.B \-p
- +Paranoid.
- +After looking up the remote host name,
- +look up the IP addresses for that name,
- +and make sure one of them matches
- +.BR TCPREMOTEIP .
- +If none of them do,
- +unset
- +.BR TCPREMOTEHOST .
- +.TP
- +.B \-P
- +(Default.)
- +Not paranoid.
- +.TP
- +.B \-h
- +(Default.)
- +Look up the remote host name and set
- +.BR TCPREMOTEHOST .
- +.TP
- +.B \-H
- +Do not look up the remote host name.
- +.TP
- +.B \-l\fIlocalname
- +Do not look up the local host name;
- +use
- +.I localname
- +for
- +.BR TCPLOCALHOST .
- +.TP
- +.B \-r
- +(Default.)
- +Attempt to obtain
- +.B TCPREMOTEINFO
- +from the remote host.
- +.TP
- +.B \-R
- +Do not attempt to obtain
- +.B TCPREMOTEINFO
- +from the remote host.
- +.TP
- +.B \-t\fItimeout
- +Give up on the
- +.B TCPREMOTEINFO
- +connection attempt
- +after
- +.I timeout
- +seconds. Default: 26.
- +.SH ENVIRONMENT
- +.TP
- +.B SSL_CIPHER
- +Specifies the ciphers that should be used in SSL/TLS mode.
- +See
- +.I openssl(1)
- +for more information.
- +.SH "SEE ALSO"
- +argv0(1),
- +fixcr(1),
- +recordio(1),
- +tcpclient(1),
- +tcprules(1),
- +listen(2),
- +tcp-environ(5),
- +openssl(1)
- --- tcpserver.c 14 Jun 2002 08:47:30 -0000 1.1.1.1
- +++ tcpserver.c 1 Apr 2005 15:13:15 -0000 1.8
- @@ -1,6 +1,8 @@
- #include <sys/types.h>
- #include <sys/param.h>
- #include <netdb.h>
- +#include <openssl/ssl.h>
- +#include <fcntl.h>
- #include "uint16.h"
- #include "str.h"
- #include "byte.h"
- @@ -36,6 +37,13 @@
- int flagremotehost = 1;
- int flagparanoid = 0;
- unsigned long timeout = 26;
- +#ifdef WITH_SSL
- +int flagssl = 0;
- +struct stralloc certfile = {0};
- +#define CERTFILE "./cert.pem"
- +
- +void translate(SSL*, int, int, unsigned int);
- +#endif
-
- static stralloc tcpremoteinfo;
-
- @@ -127,6 +135,9 @@
- env(data + 1,data + 1 + split + 1);
- }
- break;
- + case '-':
- + env(data + 1, (char *)0);
- + break;
- }
- ++next0;
- data += next0; datalen -= next0;
- @@ -238,6 +249,7 @@
-
- void usage(void)
- {
- +#ifndef WITH_SSL
- strerr_warn1("\
- tcpserver: usage: tcpserver \
- [ -1UXpPhHrRoOdDqQv ] \
- @@ -250,6 +262,21 @@
- [ -l localname ] \
- [ -t timeout ] \
- host port program",0);
- +#else
- + strerr_warn1("\
- +tcpserver: usage: tcpserver \
- +[ -1UXpPhHrRoOdDqQsSv ] \
- +[ -c limit ] \
- +[ -x rules.cdb ] \
- +[ -B banner ] \
- +[ -g gid ] \
- +[ -u uid ] \
- +[ -b backlog ] \
- +[ -l localname ] \
- +[ -t timeout ] \
- +[ -n certfile ] \
- +host port program",0);
- +#endif
- _exit(100);
- }
-
- @@ -300,7 +327,20 @@
- int s;
- int t;
-
- +#ifdef WITH_SSL
- + BIO *sbio;
- + SSL *ssl;
- + SSL_CTX *ctx;
- + int pi2c[2], pi4c[2];
- +
- + ctx = NULL;
- +
- + if (!stralloc_copys(&certfile, CERTFILE) || !stralloc_0(&certfile) )
- + strerr_die2x(111,FATAL,"out of memory");
- + while ((opt = getopt(argc,argv,"dDvqQhHrRsS1UXx:t:u:g:l:b:B:c:n:pPoO")) != opteof)
- +#else
- while ((opt = getopt(argc,argv,"dDvqQhHrR1UXx:t:u:g:l:b:B:c:pPoO")) != opteof)
- +#endif
- switch(opt) {
- case 'b': scan_ulong(optarg,&backlog); break;
- case 'c': scan_ulong(optarg,&limit); break;
- @@ -327,6 +367,14 @@
- case 'g': scan_ulong(optarg,&gid); break;
- case '1': flag1 = 1; break;
- case 'l': localhost = optarg; break;
- +#ifdef WITH_SSL
- + case 's': flagssl = 1; break;
- + case 'S': flagssl = 0; break;
- + case 'n': if (!stralloc_copys(&certfile, optarg) ||
- + !stralloc_0(&certfile) )
- + strerr_die2x(111,FATAL,"out of memory");
- + break;
- +#endif
- default: usage();
- }
- argc -= optind;
- @@ -334,6 +382,11 @@
-
- if (!verbosity)
- buffer_2->fd = -1;
- +
- + if (limit == 0)
- + strerr_die2x(100,FATAL,"limit may not be set to 0");
- + if (limit > 65000)
- + strerr_die2x(100,FATAL,"limit way to high");
-
- hostname = *argv++;
- if (!hostname) usage();
- @@ -366,6 +419,25 @@
- strerr_die3x(111,FATAL,"no IP address for ",hostname);
- byte_copy(localip,4,addresses.s);
-
- +#ifdef WITH_SSL
- + if (flagssl == 1) {
- + /* setup SSL context (load key and cert into ctx) */
- + SSL_library_init();
- + ctx=SSL_CTX_new(SSLv23_server_method());
- + if (!ctx) strerr_die2x(111,FATAL,"unable to create SSL context");
- +
- + /* set prefered ciphers */
- + if (env_get("SSL_CIPHER"))
- + if (SSL_CTX_set_cipher_list(ctx, env_get("SSL_CIPHER")) == 0)
- + strerr_die2x(111,FATAL,"unable to set cipher list");
- +
- + if(SSL_CTX_use_RSAPrivateKey_file(ctx, certfile.s, SSL_FILETYPE_PEM) != 1)
- + strerr_die2x(111,FATAL,"unable to load RSA private key");
- + if(SSL_CTX_use_certificate_chain_file(ctx, certfile.s) != 1)
- + strerr_die2x(111,FATAL,"unable to load certificate");
- + }
- +#endif
- +
- s = socket_tcp();
- if (s == -1)
- strerr_die2sys(111,FATAL,"unable to create socket: ");
- @@ -415,6 +487,39 @@
- sig_unblock(sig_child);
- sig_uncatch(sig_term);
- sig_uncatch(sig_pipe);
- +#ifdef WITH_SSL
- + if (flagssl == 1) {
- + if (pipe(pi2c) != 0)
- + strerr_die2sys(111,DROP,"unable to create pipe: ");
- + if (pipe(pi4c) != 0)
- + strerr_die2sys(111,DROP,"unable to create pipe: ");
- + switch(fork()) {
- + case 0:
- + close(0); close(1);
- + close(pi2c[1]);
- + close(pi4c[0]);
- + if ((fd_move(0,pi2c[0]) == -1) || (fd_move(1,pi4c[1]) == -1))
- + strerr_die2sys(111,DROP,"unable to set up descriptors: ");
- + /* signals are allready set in the parent */
- + pathexec(argv);
- + strerr_die4sys(111,DROP,"unable to run ",*argv,": ");
- + case -1:
- + strerr_die2sys(111,DROP,"unable to fork: ");
- + default:
- + ssl = SSL_new(ctx);
- + if (!ssl)
- + strerr_die2x(111,DROP,"unable to set up SSL session");
- + sbio = BIO_new_socket(0,BIO_NOCLOSE);
- + if (!sbio)
- + strerr_die2x(111,DROP,"unable to set up BIO socket");
- + SSL_set_bio(ssl,sbio,sbio);
- + close(pi2c[0]);
- + close(pi4c[1]);
- + translate(ssl, pi2c[1], pi4c[0], 3600);
- + _exit(0);
- + }
- + }
- +#endif
- pathexec(argv);
- strerr_die4sys(111,DROP,"unable to run ",*argv,": ");
- case -1:
- @@ -424,3 +529,186 @@
- close(t);
- }
- }
- +
- +#ifdef WITH_SSL
- +int ssl_timeoutio(int (*func)(), long t, int rfd, int wfd, SSL *ssl, char *buf, int len)
- +{
- + int n;
- + const long end = t + time(NULL);
- +
- + do {
- + fd_set fds;
- + struct timeval tv;
- +
- + const int r = buf ? func(ssl, buf, len) : func(ssl);
- + if (r > 0)
- + return r;
- +
- + t = end - time(NULL);
- + if (t < 0)
- + break;
- + tv.tv_sec = t;
- + tv.tv_usec = 0;
- +
- + FD_ZERO(&fds);
- + switch (SSL_get_error(ssl, r))
- + {
- + default:
- + return r; /* some other error */
- + case SSL_ERROR_WANT_READ:
- + FD_SET(rfd, &fds);
- + n = select(rfd + 1, &fds, NULL, NULL, &tv);
- + break;
- + case SSL_ERROR_WANT_WRITE:
- + FD_SET(wfd, &fds);
- + n = select(wfd + 1, NULL, &fds, NULL, &tv);
- + break;
- + }
- +
- + /* n is the number of descriptors that changed status */
- + }
- + while (n > 0);
- +
- + if (n != -1) errno = error_timeout;
- + return -1;
- +}
- +
- +int ssl_timeoutaccept(long t, int rfd, int wfd, SSL *ssl)
- +{
- + int r;
- +
- + /* if connection is established, keep NDELAY */
- + if (ndelay_on(rfd) == -1 || ndelay_on(wfd) == -1)
- + return -1;
- + r = ssl_timeoutio(SSL_accept, t, rfd, wfd, ssl, NULL, 0);
- +
- + if (r <= 0) {
- + ndelay_off(rfd);
- + ndelay_off(wfd);
- + }
- + else
- + SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
- +
- + return r;
- +}
- +
- +int ssl_timeoutread(long t, int rfd, int wfd, SSL *ssl, char *buf, int len)
- +{
- + if (!buf)
- + return 0;
- + if (SSL_pending(ssl))
- + return SSL_read(ssl, buf, len);
- + return ssl_timeoutio(SSL_read, t, rfd, wfd, ssl, buf, len);
- +}
- +
- +int ssl_timeoutwrite(long t, int rfd, int wfd, SSL *ssl, char *buf, int len)
- +{
- + if (!buf)
- + return 0;
- + return ssl_timeoutio(SSL_write, t, rfd, wfd, ssl, buf, len);
- +}
- +
- +static int allwrite(int fd, char *buf, int len)
- +{
- + int w;
- +
- + while (len) {
- + w = write(fd,buf,len);
- + if (w == -1) {
- + if (errno == error_intr) continue;
- + return -1; /* note that some data may have been written */
- + }
- + if (w == 0) ; /* luser's fault */
- + buf += w;
- + len -= w;
- + }
- + return 0;
- +}
- +
- +static int allwritessl(long t, int rfd, int wfd, SSL* ssl, char *buf, int len)
- +{
- + int w;
- +
- + while (len) {
- + w = ssl_timeoutwrite(t, rfd, wfd, ssl, buf, len);
- + if (w == -1) {
- + if (errno == error_intr) continue;
- + return -1; /* note that some data may have been written */
- + }
- + if (w == 0) ; /* luser's fault */
- + buf += w;
- + len -= w;
- + }
- + return 0;
- +}
- +
- +char tbuf[2048];
- +
- +void translate(SSL* ssl, int clearout, int clearin, unsigned int iotimeout)
- +{
- + struct taia now;
- + struct taia deadline;
- + iopause_fd iop[2];
- + int flagexitasap;
- + int iopl;
- + int sslout, sslin;
- + int n, r;
- +
- + sslin = SSL_get_fd(ssl);
- + sslout = SSL_get_fd(ssl);
- + if (sslin == -1 || sslout == -1)
- + strerr_die2x(111,DROP,"unable to set up SSL connection");
- +
- + flagexitasap = 0;
- +
- + if (ssl_timeoutaccept(timeout, sslin, sslout, ssl) <= 0)
- + strerr_die2x(111,DROP,"unable to accept SSL connection");
- +
- + while (!flagexitasap) {
- + taia_now(&now);
- + taia_uint(&deadline,iotimeout);
- + taia_add(&deadline,&now,&deadline);
- +
- + /* fill iopause struct */
- + iopl = 2;
- + iop[0].fd = sslin;
- + iop[0].events = IOPAUSE_READ;
- + iop[1].fd = clearin;
- + iop[1].events = IOPAUSE_READ;
- +
- + /* do iopause read */
- + iopause(iop,iopl,&deadline,&now);
- + if (iop[0].revents) {
- + do {
- + /* data on sslin */
- + n = ssl_timeoutread(iotimeout, sslin, sslout, ssl, tbuf, sizeof(tbuf));
- + if ( n < 0 )
- + strerr_die2sys(111,DROP,"unable to read form network: ");
- + if ( n == 0 )
- + flagexitasap = 1;
- + r = allwrite(clearout, tbuf, n);
- + if ( r < 0 )
- + strerr_die2sys(111,DROP,"unable to write to client: ");
- + /*
- + * if the data payload was longer than sizeof(tbuf) then SSL will have
- + * bytes processed and pending. We need to pick them up and write them
- + * to clearout.
- + */
- + } while (SSL_pending(ssl));
- + }
- + if (iop[1].revents) {
- + /* data on clearin */
- + n = read(clearin, tbuf, sizeof(tbuf));
- + if ( n < 0 )
- + strerr_die2sys(111,DROP,"unable to read form client: ");
- + if ( n == 0 )
- + flagexitasap = 1;
- + r = allwritessl(iotimeout, sslin, sslout, ssl, tbuf, n);
- + if ( r < 0 )
- + strerr_die2sys(111,DROP,"unable to write to network: ");
- + }
- + if (!iop[0].revents && !iop[1].revents)
- + strerr_die2x(0, DROP,"timeout reached without input");
- + }
- +}
- +#endif
- --- /dev/null 1 Jan 1970 00:00:00 -0000
- +++ who@.1 5 Apr 2004 15:34:57 -0000 1.1
- @@ -0,0 +1,32 @@
- +.TH who@ 1
- +.SH NAME
- +who@ \- print list of active users on a host
- +.SH SYNTAX
- +.B who@
- +[
- +.I host
- +]
- +.SH DESCRIPTION
- +.B who@
- +connects to TCP port 11 (Systat) on
- +.I host
- +and prints any data it receives.
- +It removes CR and converts unprintable characters to a visible format.
- +
- +If
- +.I host
- +is not supplied,
- +.B who@
- +connects to the local host.
- +
- +Some computers respond to port 11 with a list of active users.
- +For example, they may be running
- +
- +.EX
- + tcpserver 0 11 who &
- +.EE
- +.SH "SEE ALSO"
- +cat(1),
- +delcr(1),
- +tcpclient(1),
- +tcpserver(1)
-