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
|
|
|
|
libtelnet_*_cb() functions.
|
|
|
|
|
|
|
|
The libtelnet_*_cb() functions (callback fuctions from here out) are
|
|
|
|
not actually implemented by libtelnet, but are used by it. The
|
|
|
|
libtelnet.h header includes declarations for the functions but it is
|
|
|
|
the application's responsibility to provide implementations of these
|
|
|
|
functions.
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
void libtelnet_init(struct libtelnet_t *telnet,
|
|
|
|
enum libtelnet_mode_t mode);
|
|
|
|
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 mode parameter must be one of LIBTELNET_MODE_SERVER or
|
|
|
|
LIBTELNET_MODE_CLIENT. 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.
|
|
|
|
|
|
|
|
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 libtelnet_send_cb() callback function. The user_data parameter
|
|
|
|
to each of these functions is passed through to the callback.
|
|
|
|
|
|
|
|
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 application is responsible for implementing these functions.
|
|
|
|
The function definitions are included in libtelnet.h. If any of
|
|
|
|
these functions are not implemented and linked into the application
|
|
|
|
then libtelnet.o will generate linker errors for undefined symbols.
|
|
|
|
|
|
|
|
void libtelnet_data_cb(struct libtelnet_t *telnet,
|
|
|
|
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_send_cb(struct libtelnet_t *telnet,
|
|
|
|
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_command_cb(struct libtelnet_t *telnet,
|
|
|
|
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_negotiate_cb(struct libtelnet_t *telnet,
|
|
|
|
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_subnegotiation_cb(struct libtelnet_t *telnet,
|
|
|
|
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_compress_cb(struct libtelnet_t *telnet,
|
|
|
|
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.
|
|
|
|
|
|
|
|
To run telnet-proxy, you simply give it the server's IP address
|
|
|
|
(telnet-proxy does not support hostname resolution, nor IPv6), the
|
|
|
|
server's port number, and the port number that telnet-proxy should
|
|
|
|
listen on. For example, to connect to the server on 209.85.171.100
|
|
|
|
port 7800 and to listen on port 5000, run:
|
|
|
|
|
|
|
|
$ ./telnet-proxy 209.85.171.100 7800 5000
|
|
|
|
|
|
|
|
You can then connect to the host telnet-proxy is running on (e.g.
|
|
|
|
127.0.0.1, or the machine's public IP) on port 500 and you will
|
|
|
|
automatically be proxied into 209.85.171.100.
|
|
|
|
|
|
|
|
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.
|