nvt-client 1 user commands nosh
nvt-client noddy Unicode Network Virtual Terminal client
`nvt-client` --local-echo --no-remote-echo --pass-through-overlength-remote-data

## Description

`nvt-client` is a utility that acts as a noddy Unicode NVT (Network Virtual Terminal) client. Per the UCSPI conventions, it expects file descriptors 6 and 7 to be reading from and writing to a network socket, respectively, and uses its standard input and output as the local terminal device underlying the NVT. (tcp-socket-connect 1 can be used to set this process state up.) Standard I/O do not need to actually be a terminal, of course.

Its primary use case is for building noddy automated (anonymous, unauthenticated) clients for servers that speak "line" protocols (derived from the NVT idea) like HTTP, which would otherwise be built with Bernstein addcr 1, delcr 1, and fixcrio 1. It does in one program what addcr 1, delcr 1, and fixcrio 1 did in two; with the advantages that it handles data transfer in both directions simultaneously, handles the connection between the two directions that the TELNET protocol requires, understands UTF-8, understands the UCSPI conventions, and can do local echo.

It enters a loop where it simultaneously:

- writes all data received from the network to its own standard output, until the network closes (or shuts down) its send side; and

- writes all data received from its own standard input to the network, until its standard input signals EOF with a 0 byte read.

EOF from the network with no pending network data remaining to be written to standard output (i.e. the remote to local buffer is fully drained) terminates `nvt-client` normally. EOF from standard input with no pending network data remaining to be written to the network (i.e. the local to remote buffer is fully drained) causes the network write file descriptor to be shut down for writing (if it is actually a TCP socket). It is expected that the server will in turn see EOF and as a consequence close things from its end.

Data received from the network input are first decoded from the RFC 854 (TELNET) protocol, removing all NVT commands and options and acting upon them. Network input is then treated as UTF-8, sanitized, and written to standard output. The NVT newline convention is translated into the POSIX newline convention.

Data received from standard input are treated as UTF-8, sanitized, then encoded using the RFC 854 protocol to escape any IAC characters, and written to network output. The POSIX newline convention is translated into the NVT newline convention.

`nvt-client` has no "escape" characters, command mode, or any kind of interactive local off-line control. It does not send TELNET commands for "special" characters nor act upon any received, and recognizes no input character as "special". It expects the server to handle any special characters, and turns off special character processing by the local line discipline for the duration of its run, if its standard input is a terminal device. If it is sent signals such as `SIGHUP` it ABENDs in the appropriate way.

In order to normally end a `nvt-client` that is being used interactively, it is thus necessary to ask the server end to terminate the connection. This will be either some form of `QUIT` command in whatever line-based protocol is being spoken, or a character such as EOT that the remote end denotes as a "special" terminal character for signalling the end of transmission. One can ABEND it by sending it a signal, of course; but this will have to be done via some other means than via the local line discipline.

### TELNET options

`nvt-client` never initiates an option negotiation, so will not confuse not-fully-NVT line-oriented protocols with junk characters (except for doubling up of the IAC character, which as RFC 5198 explains is not a conflict when UTF-8 is involved). It understands the RFC 856 Binary option, the RFC 857 ECHO option, the RFC 858 Suspend Go Ahead option, the RFC 860 Timing Mark option, and the RFC 1073 NAWS option. All other TELNET options are rejected when requested.

Any responses to TELNET option commands are sent to the network output, when the commands are received from network input, in order. Thus, Timing Mark is trivially supported. 8-bit clean "binary" is effectively always the case anyway, in order to even support UTF-8; and if NAWS is negotiated on, `nvt-client` sends window sizes whenever it receives a `SIGWINCH` signal.

### echoplex and duplex

`nvt-client` operates solely in a modern full-duplex character mode. It has no plethora of line and "edit" modes for (say) old Multics terminals mentioned in RFCs, nor any half-duplex considerations. Indeed, its primary use case is where its standard I/O is not a terminal and it is not even talking to a fully-fledged NVT at the remote end.

It never sends Go Ahead, RFC 854 having permitted clients to never do so since 1983; and allows the remote end to suspend Go Ahead, which like almost everything in the decades since the RFCs were written, it has no need of. This thus does not satisfy the "kludge line mode" heuristic that is used by BSD telnetd 8, which requires Go Ahead to be sent by clients.

Normally, `nvt-client` does no local echo, which is the default per RFC 857. It permits the remote end to negotiate the RFC 857 ECHO option; and if ECHO on is negotiated, the remote end can of course then echo whatever it so chooses, and have its own echo control settings. It never negotiates RFC 857 ECHO for itself; it being a client rather than a server.

The --local-echo command line option is for use with not-fully-NVT line-oriented protocols, where it might be useful to see what is being sent when using `nvt-client` interactively from a terminal as a protocol debugging tool. When that command line option is employed, `nvt-client` does its own local echo using the vis 3 library function in "safe" mode.

Local echo is turned off if the remote end negotiates the ECHO option on and turned back on if the remote end negotiates ECHO off. This may seem confusing, and the confusion originates with RFC 857. Think of it as the remote end negotiating its taking over the handling of echoing all input, including whether it even happens or not. The --no-remote-echo command line option prevents the remote end from being allowed to negotiate ECHO on, keeping the local echo choice at the local end.

### UTF-8

Per RFC 5198, UTF-8 encoding is mostly layered on top of the underlying NVT protocol. (The original, fully 32-bit, UTF-8 encoding is supported.) TELNET command and option sequences are never encoded in UTF-8.

However, also per RFC 5198, the newline convention conversions are layered on top of UTF-8. No action is taken on any control characters other than Line Feed (LF), Carriage Return (CR), and Null (NUL). Moreover, contra RFC 5198, no Unicode normalization is done; no combining characters combined, no character re-orderings in the data stream performed. The actual Unicode data stream, once sanitized, is outwith `nvt-client`'s remit; and is the responsibility of whatever is generating and consuming the data.

`nvt-client` guarantees that it sends valid UTF-8 to the network; although for forwards compatibility it allows all code points, not just the assigned ones at the time of writing. Encoding errors in local data are always silently dropped; but overlength encodings that are otherwise valid are renormalized to their shortest encoding and passed through.

Network input is more strictly sanitized; with both encoding errors and overlength encodings being silently dropped. The --pass-through-overlength-remote-data command line option lifts that latter restriction, permitting overlength encodings in data from the network and causing them to be normalized and passed through.

## Security

`nvt-client` has no security. It should not be used where any form of security or privacy of communication is desired.

It has no encryption, no support for any TELNET authentication methods, and no form of TLS negotiation. All data, passwords or otherwise, are sent over the network as cleartext, and are potentially interceptable by any device on any (bus-style) network over which the data flow between the local and remote ends.

Do not use `nvt-client` with TELNET servers that provide Unix or Unix-like log-on interfaces.

Unix or Unix-like log-on is not within `nvt-client`'s use case, which is unauthenticated, public, and interceptable comunication. Logging on to a "TELNET BBS" as a "guest" or a "visitor" may not per se require a password, but even then other personally identifying information (e.g. a mailbox address, or the host transmitting who it thinks the client is) is not secured and subject to interception.

Pace all of these dire warnings; because `nvt-client` obeys the UCSPI conventions, it is possible to wrap it inside a third-party UCSPI-SSL tool that encrypts the data streams between `nvt-client` and the network transport layer and does certificate authentication for server and client.

Because of its UTF-8 sanitization, `nvt-client` silently prevents attempts to bypass the newline conversions that employ overlong encodings for CR, LF, and NUL. The --pass-through-overlength-remote-data command line option is not the default in order to militate against Gresham' Law, where bad protocol implementations drive up the cost of correct protocol implementations and make bad protocol the cheaper option; and does not open up a hole for characters to bypass character clasification checks.

`nvt-client` does not support either of the two environment TELNET options, nor the terminal type TELNET option. No information from the local process's environment is sent to the network.

## Example

This script downloads the `text/plain` page from the HTTP 1.x server specified as its arguments:

    #!/bin/sh -e
    printf 'GET /%s HTTP/1.0\nHost: %s:%s\nAccept: text/*\n\n' "${2-}" "${1-0}" "${3-80}" |
    tcp-socket-connect -- "${4-${1-0}}" "${3-80}" nvt-client |
    awk '/^$/ { body=1; next } { if (body) print }'

## Author

Jonathan de Boyne Pollard