libtelnet/README

308 lines
12 KiB
Plaintext
Raw Normal View History

2009-03-13 03:33:27 +00:00
=====================================================================
libtelnet - TELNET protocol handling library
=====================================================================
2009-03-14 17:39:07 +00:00
http://github.com/elanthis/libtelnet
Sean Middleditch
sean@sourcemud.org
2009-03-13 03:33:27 +00:00
---------------------------------------------------------------------
The author or authors of this code dedicate any and all copyright
interest in this code to the public domain. We make this dedication
for the benefit of the public at large and to the detriment of our
heirs and successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
code under copyright law.
---------------------------------------------------------------------
2009-03-14 09:24:56 +00:00
*** TODO ***
- RFC 1143 option negotiation algorithm
- automatic MCCP2 handling (controllable by host app)
- efficient one-byte sub-requests
? MCCP1
? ZMP parsing
? MSSP parsing
? ENVIRON/NEW-ENVIRON parsing
? telnet-status testing tool
? few options to make telnet-proxy even more useful
2009-03-13 03:33:27 +00:00
I. INTRODUCTION
=====================================================================
libtelnet provides safe and correct handling of the core TELNET
protocol. It does not include any "smarts," and all use of the
protocol (such as deciding which options to support, enabling
and disabling options, or processing subrequests) must be implemented
by the application author.
2009-03-14 17:39:07 +00:00
For more information on the TELNET protocol, see:
http://www.faqs.org/rfcs/rfc854.html
2009-03-13 03:33:27 +00:00
II. LIBTELNET API
=====================================================================
2009-03-14 17:39:07 +00:00
The libtelnet API contains several distinct parts. The first part is
the basic initialization and deinitialization routines. The second
part is a single function for pushing received data into the
libtelnet processor. The third part is the libtelnet_send_*()
functions, which generate TELNET commands and ensure data is properly
formatted before sending over the wire. The final part is the
callback structure libtelnet_cb_t.
2009-03-14 17:39:07 +00:00
IIa. Initialization
struct libtelnet_t;
This structure represents the state of the TELNET protocol for a
single connection. Each connection utilizing TELNET must have
its own libtelnet_t structure, which is passed to all libtelnet
API calls.
struct libtelnet_cb_t;
An instance of this structure must be initialized and have all
mandatory and desired optional callbacks set. See section IId
for more information.
2009-03-14 17:39:07 +00:00
void libtelnet_init(struct libtelnet_t *telnet,
struct libtelnet_cb_t *cb, enum libtelnet_mode_t mode);
2009-03-14 17:39:07 +00:00
The libtelnet_init() function is responsible for initializing
the data in a libtelnet_t structure. It must be called
immediately after establishing a connection and before any other
libtelnet API calls are made.
The cb parameter must be a pointer to a fully initialized
instance of libtelnet_cb_t. A single instance of the structure
can be shared between any number of libtelnet_t instances.
2009-03-15 15:54:07 +00:00
The mode parameter must be one of LIBTELNET_MODE_SERVER,
LIBTELNET_MODE_CLIENT, or LIBTELNET_MODE_PROXY. These slightly
alter the behavior of libtelnet in certain instances. If you are
implementing a TELNET server, use the SERVER mode. If you are
implementing a client, use the CLIENT mode. The PROXY mode
enables special behavior for telnet-proxy (or similar
applications).
2009-03-14 17:39:07 +00:00
boid libtelnet_free(struct libtelnet_t *telnet);
Releases any internal memory allocated by libtelnet. This must
be called whenever a connection is closed, or you will incur
memory leaks.
IIb. Receiving Data
void libtelnet_push(struct libtelnet_t *telnet,
unsigned char *buffer, unsigned int size, void *user_data);
When your application receives data over the socket from the
remote end, it must pass the received bytes into this function.
Callback functions will be invoked as the buffer is processed,
and the user_data parameter will be passed to each callback.
IIc. Sending Data
Note that all of the libtelnet_send_*() functions will invoke
the send callback function attached to the libtelnet_t instance.
The user_data parameter to each of these functions is passed
through to the callback.
2009-03-14 17:39:07 +00:00
void libtelnet_send_command(struct libtelnet_t *telnet,
unsigned char cmd, void *user_data);
Sends a single "simple" TELNET command, such as the GO-AHEAD
commands (255 249).
void libtelnet_send_negotiate(struct libtelnet_t *telnet,
unsigned char cmd, unsigned char opt, void *user_data);
Sends a TELNET negotiation command. The cmd parameter must be
one of LIBTELNET_WILL, LIBTELNET_DONT, LIBTELNET_DO, or
LIBTELNET_DONT. The opt parameter is the option to
negotiate.
void libtelnet_send_data(struct libtelnet_t *telnet,
unsigned char *buffer, unsigned int size, void *user_data);
Sends raw data, which would be either the process output from
a server or the user input from a client.
void libtelnet_send_subnegotiation(struct libtelnet_t *telnet,
unsigned char opt, unsigned char *buffer, unsigned int size,
void *user_data);
Sends a TELNET sub-negotiation command. The opt parameter
is the sub-negotiation option.
IId. Callbacks
The libtelnet_cb_t structure containers a number of callback
entry points. Of these, only the send and data callbacks are
absolutely required. All others are optional. The declarations
below show the signature of the callback functions.
An example of initializing a libtelnet_cb_t structure:
/* illustrative data callback */
void my_data_cb(libtelnet_t *telnet, unsigned char *buffer,
unsigned int size, void *user_data) {
/* print number of bytes received and then show the
* whole buffer */
printf("RECV(%d): %.*s\n", size, size, buffer);
}
/* illustrative variable definitions */
libtelnet_t conn;
libtelnet_cb_t callbacks;
/* clear all callbacks and set just the ones we want */
memset(&callbacks, 0, sizeof(callbacks));
callbacks->send = my_send_cb;
callbacks->data = my_data_cb;
/* initialize the connection with our callbacks */
libtelnet_init(&conn, &callbacks, LIBTELNET_MODE_SERVER);
Remember that a single libtelnet_cb_t structure can be shared
between any number of libtelnet_t instances. There is no reason
to make multiple copies of the data if all of your connections
use the same callback functions.
2009-03-14 17:39:07 +00:00
void libtelnet_cb_t->data(struct libtelnet_t *telnet,
2009-03-14 17:39:07 +00:00
unsigned char *buffer, unsigned int size, void *user_data);
Regular data has been received by the remote end. For a server,
this would be input typed by the client; for a client, this is
process output generated by the server.
Note that data is not line-buffered by libtelnet. A single
line of input may be broken into pieces and given to
consecutive calls to libtelnet_data_cb(). If you are doing
line-based processing of data, it is your responsibility to
buffer data and find the line breaks.
void libtelnet_cb_t->send(struct libtelnet_t *telnet,
2009-03-14 17:39:07 +00:00
unsigned char *buffer, unsigned int size, void *user_data);
This is called whenever libtelnet has generated output to be
send to the remote end of the connection. In most cases this
will be a simple wrapper arround your applications network
output buffering/transmission code.
You can pass socket information through the user_data
parameter to libtelnet calls so that it is available in this
callback.
void libtelnet_cb_t->command(struct libtelnet_t *telnet,
2009-03-14 17:39:07 +00:00
unsigned char cmd, void *user_data);
Called whenever a "simpler" TELNET command has arrived, such
as GO-AHEAD commands (255 249). The necessary processing
depends on the specific commands; see the TELNET RFC for
more information.
void libtelnet_cb_t->negotiate(struct libtelnet_t *telnet,
2009-03-14 17:39:07 +00:00
unsigned char cmd, unsigned char opt, void *user_data);
This function is called whenever a TELNET negotiation command
has been received. The cmd parameter will be one of
LIBTELNET_WILL, LIBTELNET_WONT, LIBTELNET_DO, or LIBTELNET_DONT.
The opt parameter is the option being negotiated.
libtelnet does not currently manage negotiation for you. For
best practice in implementing TELNET negotiation, see:
http://www.faqs.org/rfcs/rfc1143.html
void libtelnet_cb_t->subnegotiation(struct libtelnet_t *telnet,
2009-03-14 17:39:07 +00:00
unsigned char opt, unsigned char *data, unsigned int size,
void *user_data);
Called whenever a TELNET sub-negotiation has been received.
Sub-negotiations include the NAWS option for communicating
terminal size to a server, the NEW-ENVIRON and TTYPE options
for negotiating terminal features, and MUD-centric protocols
such as ZMP, MSSP, and MCCP2.
The opt parameter is the option under sub-negotiation. The
remaining data (if any) is passed in the buffer.
void libtelnet_cb_t->compress(struct libtelnet_t *telnet,
2009-03-14 17:39:07 +00:00
char enabled, void *user_data);
The callback is invoked whenever the COMPRESS2 (MCCP2)
feature is enabled or disabled. For servers, this is called
immediately after beginning compression after a client accepts
the COMPRESS2 option. For clients, this is called immediately
after a compress stream begin or ends.
The enabled parameter is 1 if compression has begun and 0 if
compression has ended.
2009-03-13 03:33:27 +00:00
III. INTEGRATING LIBTELNET
=====================================================================
FIXME: fill in notes about implementing the libtelnet_*_cb functions
2009-03-14 17:39:07 +00:00
IV. SAFETY AND CORRECTNESS CONSIDERATIONS
2009-03-13 03:33:27 +00:00
=====================================================================
2009-03-14 17:39:07 +00:00
Your existing application may make heavy use of its own output
buffering and transmission commands, including hand-made routines
for sending TELNET commands and sub-negotiation requests. There are
at times subtle issues that need to be handled when communication
over the TELNET protocol, not least of which is the need to escape
any byte value 0xFF with a special TELNET command.
2009-03-13 03:33:27 +00:00
2009-03-14 17:39:07 +00:00
For these reasons, it is very important that applications making use
of libtelnet always make use of the libtelnet_send_*() family of
functions for all data being sent over the TELNET connection.
V. MCCP2 COMPRESSION
2009-03-13 03:33:27 +00:00
=====================================================================
2009-03-14 17:39:07 +00:00
The MCCP2 (COMPRESS2) TELNET extension allows for the compression of
all traffic sent from server to client. For more information:
http://www.mudbytes.net/index.php?a=articles&s=mccp
libtelnet transparently supports MCCP2. For a server to support
MCCP2, the application must begin negotiation of the COMPRESS2
option using libtelnet_send_negotiate(), for example:
libtelnet_send_negotiate(&telnet, LIBTELNET_WILL,
LIBTELNET_OPTION_COMPRESS2, user_data);
libtelnet will automatically detect if the client responds favoribly
and will begin compressing data. For clients, no action must be
taken, as libtelnet will automatically handle the requests.
NOTE: libtelnet will still invoke the callback functions for
negotiation and sub-negotiation commands relating to MCCP2. Do not
respond to these.
In order for libtelnet to support MCCP2, zlib must be installed and
enabled when compiling libtelnet. Use -DHAVE_ZLIB to enable zlib
when compiling libtelnet.c and pass -lz to the linker to link in the
zlib shared library.
VI. TELNET PROXY UTILITY
=====================================================================
The telnet-proxy utility is a small application that serves both as
a testbed for libtelnet and as a powerful debugging tool for TELNET
servers and clients.
To use telnet-proxy, you must first compile it using:
$ make
If you do not have zlib installed and wish to disable MCCP2 support
then you must first edit the Makefile and remove the -DHAVE_ZLIB and
the -lz from the compile flags.
2009-03-15 05:06:17 +00:00
To run telnet-proxy, you simply give it the server's host name or
IP address, the server's port number, and the port number that
telnet-proxy should listen on. For example, to connect to the server
on mud.example.com port 7800 and to listen on port 5000, run:
2009-03-14 17:39:07 +00:00
2009-03-15 05:06:17 +00:00
$ ./telnet-proxy mud.example.com 7800 5000
2009-03-14 17:39:07 +00:00
You can then connect to the host telnet-proxy is running on (e.g.
2009-03-15 05:06:17 +00:00
127.0.0.1) on port 500 and you will automatically be proxied into
mud.example.com.
2009-03-14 17:39:07 +00:00
telnet-proxy will display status information about the data
passing through both ends of the tunnel. Once either end
disconnects, telnet-proxy will close. telnet-proxy can only
support a single tunnel at a time and must be restarted for each
connection.