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
|
2009-03-15 01:45:28 +00:00
|
|
|
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.
|
|
|
|
|
2009-03-15 01:45:28 +00:00
|
|
|
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,
|
2009-03-15 01:45:28 +00:00
|
|
|
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.
|
|
|
|
|
2009-03-15 01:45:28 +00:00
|
|
|
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
|
2009-03-15 01:45:28 +00:00
|
|
|
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
|
|
|
|
|
2009-03-15 01:45:28 +00:00
|
|
|
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
|
|
|
|
2009-03-15 01:45:28 +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.
|
|
|
|
|
2009-03-15 01:45:28 +00:00
|
|
|
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.
|
|
|
|
|
2009-03-15 01:45:28 +00:00
|
|
|
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.
|
|
|
|
|
2009-03-15 01:45:28 +00:00
|
|
|
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
|
|
|
|
|
2009-03-15 01:45:28 +00:00
|
|
|
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.
|
|
|
|
|
2009-03-15 01:45:28 +00:00
|
|
|
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.
|