remove the lib/LIB from identifier prefixes; also, swap printf and printf2 so the more common one is the one with the shorter name

This commit is contained in:
Sean Middleditch 2009-03-19 02:32:04 -04:00
parent 156f5862a6
commit f65f27d77d
5 changed files with 543 additions and 545 deletions

357
README
View File

@ -29,8 +29,8 @@ I. INTRODUCTION
libtelnet provides safe and correct handling of the core TELNET libtelnet provides safe and correct handling of the core TELNET
protocol. In addition to the base TELNET protocol, libtelnet also protocol. In addition to the base TELNET protocol, libtelnet also
implements the Q method of TELNET option negotiation. libtelnet implements the Q method of TELNET option negotiation. libtelnet can
can be used for writing servers, clients, or proxies. be used for writing servers, clients, or proxies.
For more information on the TELNET protocol, see: For more information on the TELNET protocol, see:
@ -42,65 +42,65 @@ II. LIBTELNET API
The libtelnet API contains several distinct parts. The first part is The libtelnet API contains several distinct parts. The first part is
the basic initialization and deinitialization routines. The second the basic initialization and deinitialization routines. The second
part is a single function for pushing received data into the part is a single function for pushing received data into the telnet
libtelnet processor. The third part is the libtelnet_send_*() processor. The third part is the telnet_send_*() functions, which
functions, which generate TELNET commands and ensure data is properly generate TELNET commands and ensure data is properly formatted before
formatted before sending over the wire. The final part is the event sending over the wire. The final part is the event handler
handler interface. interface.
IIa. Initialization IIa. Initialization
struct libtelnet_t; struct telnet_t;
This structure represents the state of the TELNET protocol for a This structure represents the state of the TELNET protocol for a
single connection. Each connection utilizing TELNET must have single connection. Each connection utilizing TELNET must have its
its own libtelnet_t structure, which is passed to all libtelnet own telnet_t structure, which is passed to all libtelnet API
API calls. calls.
void libtelnet_init(libtelnet_t *telnet, libtelnet_event_handler_t handler, void telnet_init(telnet_t *telnet, telnet_event_handler_t handler,
unsigned char flags, void *user_data); unsigned char flags, void *user_data);
The libtelnet_init() function is responsible for initializing The telnet_init() function is responsible for initializing the
the data in a libtelnet_t structure. It must be called data in a telnet_t structure. It must be called immediately after
immediately after establishing a connection and before any other establishing a connection and before any other libtelnet API calls
libtelnet API calls are made. are made.
The handler parameter must be a function matching the The handler parameter must be a function matching the
libtelnet_event_handler_t definition. More information about telnet_event_handler_t definition. More information about events
events can be found in section IId. can be found in section IId.
The user_data parameter is passed to the event handler whenver it The user_data parameter is passed to the event handler whenver it
is invoked. This will usually be a structure container is invoked. This will usually be a structure container
information about the connection, including a socket descriptor information about the connection, including a socket descriptor
for implementing LIBTELNET_EV_SEND event handling. for implementing TELNET_EV_SEND event handling.
The flags parameter can be any of the following flag constants The flags parameter can be any of the following flag constants
bit-or'd together, or 0 to leave all options disabled. bit-or'd together, or 0 to leave all options disabled.
LIBTELNET_FLAG_PROXY TELNET_FLAG_PROXY
Operate in proxy mode. This disables the RFC1143 support and Operate in proxy mode. This disables the RFC1143 support and
enables automatic detection of COMPRESS2 streams. enables automatic detection of COMPRESS2 streams.
boid libtelnet_free(libtelnet_t *telnet); boid telnet_free(telnet_t *telnet);
Releases any internal memory allocated by libtelnet. This must Releases any internal memory allocated by libtelnet. This must be
be called whenever a connection is closed, or you will incur called whenever a connection is closed, or you will incur memory
memory leaks. leaks.
IIb. Receiving Data IIb. Receiving Data
void libtelnet_push(libtelnet_t *telnet, void telnet_push(telnet_t *telnet,
const char *buffer, unsigned int size, void *user_data); const char *buffer, unsigned int size, void *user_data);
When your application receives data over the socket from the When your application receives data over the socket from the
remote end, it must pass the received bytes into this function. remote end, it must pass the received bytes into this function.
As the TELNET stream is parsed, events will be generated and As the TELNET stream is parsed, events will be generated and
passed to the event handler given to libtelnet_init(). Of passed to the event handler given to telnet_init(). Of particular
particular interest for data receiving is the LIBTELNET_EV_DATA interest for data receiving is the TELNET_EV_DATA event, which is
event, which is triggered for any regular data such as user triggered for any regular data such as user input or server
input or server process output. process output.
IIc. Sending Data IIc. Sending Data
All of the libtelnet_send_*() functions will invoke the All of the telnet_send_*() functions will invoke the TELNET_EV_SEND
LIBTELNET_EV_SEND event. event.
Note: it is very important that ALL data sent to the remote end of Note: it is very important that ALL data sent to the remote end of
the connection be passed through libtelnet. All user input or the connection be passed through libtelnet. All user input or
@ -108,186 +108,185 @@ IIc. Sending Data
to one of the following functions. Do NOT send or buffer to one of the following functions. Do NOT send or buffer
unprocessed output data directly! unprocessed output data directly!
void libtelnet_send_command(libtelnet_t *telnet, unsigned char cmd); void telnet_send_command(telnet_t *telnet, unsigned char cmd);
Sends a single "simple" TELNET command, such as the GO-AHEAD Sends a single "simple" TELNET command, such as the GO-AHEAD
commands (255 249). commands (255 249).
void libtelnet_send_command(libtelnet_t *telnet, unsigned char cmd, void telnet_send_telopt(telnet_t *telnet, unsigned char cmd,
unsigned char telopt); unsigned char telopt);
Sends a TELNET command with an option code following. This is Sends a TELNET command with an option code following. This is
only useful for the WILL, WONT, DO, DONT, and SB commands. only useful for the WILL, WONT, DO, DONT, and SB commands.
void libtelnet_send_negotiate(libtelnet_t *telnet, void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
unsigned char cmd, unsigned char opt); unsigned char opt);
Sends a TELNET negotiation command. The cmd parameter must be Sends a TELNET negotiation command. The cmd parameter must be one
one of LIBTELNET_WILL, LIBTELNET_DONT, LIBTELNET_DO, or of TELNET_WILL, TELNET_DONT, TELNET_DO, or TELNET_DONT. The opt
LIBTELNET_DONT. The opt parameter is the option to parameter is the option to negotiate.
negotiate.
void libtelnet_send_data(libtelnet_t *telnet, Unless in PROXY mode, the RFC1143 support may delay or ellide the
const char *buffer, unsigned int size); request entirely, as appropriate. It will ignore duplicate
Sends raw data, which would be either the process output from invocations, such as asking for WILL NAWS when NAWS is already on
a server or the user input from a client. or is currently awaiting response from the remote end.
void libtelnet_send_subnegotiation(libtelnet_t *telnet, void telnet_send_data(telnet_t *telnet, const char *buffer,
unsigned char telopt, const char *buffer,
unsigned int size); unsigned int size);
Sends a TELNET sub-negotiation command. The telopt parameter Sends raw data, which would be either the process output from a
is the sub-negotiation option. server or the user input from a client.
For sending regular text is may be more convenient to use
telnet_printf().
void telnet_send_subnegotiation(telnet_t *telnet,
unsigned char telopt, const char *buffer, unsigned int size);
Sends a TELNET sub-negotiation command. The telopt parameter is
the sub-negotiation option.
Note that the above function is just a shorthand for: Note that the above function is just a shorthand for:
libtelnet_send_telopt(telnet, LIBTELNET_SB, telopt); telnet_send_telopt(telnet, TELNET_SB, telopt);
libtelnet_send_data(telnet, buffer, size); telnet_send_data(telnet, buffer, size);
libtelnet_send_command(telnet, LIBTELNET_SE); telnet_send_command(telnet, TELNET_SE);
For some subnegotiations that involve a lot of complex formatted For some subnegotiations that involve a lot of complex formatted
data to be sent, it may be easier to manually send the SB telopt data to be sent, it may be easier to manually send the SB telopt
header and SE footer around mulitple calls to send_data. header and SE footer around mulitple calls to send_data.
NOTE: libtelnet_send_subnegotiation() does have special behavior NOTE: telnet_send_subnegotiation() does have special behavior in
in PROXY mode, as in that mode this function will automatically PROXY mode, as in that mode this function will automatically
detect the COMPRESS2 marker and enable zlib compression. detect the COMPRESS2 marker and enable zlib compression.
int libtelnet_printf(libtelnet_t *telnet, const char *fmt, ...); int telnet_printf(telnet_t *telnet, const char *fmt, ...);
This functions very similarly to fprintf, except that output This functions very similarly to fprintf, except that output is
is sent through libtelnet for processing. This is equivalent sent through libtelnet for processing. IAC bytes are properly
to using snprintf() to format data into a buffer and then escaped, C newlines (\n) are translated into CR LF, and C carriage
sending the buffer to libtelnet_send_data(). The return code returns (\r) are translated into CR NUL, all as required by
is the length of the formatted text. RFC854. The return code is the length of the formatted text.
NOTE: due to an internal implementation detail, the maximum NOTE: due to an internal implementation detail, the maximum
lenth of the formatted text is 4096 characters. lenth of the formatted text is 4096 characters.
int libtelnet_printf2(libtelnet_T *telnet, const char *fmt, ...); int telnet_printf2(telnet_t *telnet, const char *fmt, ...);
Identical to libtelnet_print(), except that this variant will Identical to telnet_printf() except that \r and \n are not
also translate C newlines (\n) into a CRLF and translates translated. This should be used if you are attempting to send
carriage returns (\r) into CRNUL, as required by TELNET. raw data inside a subnegotiation or if you have already manually
escaped newlines.
NOTE: this function should only be used for regular data such
as user input (in client applications) or process output (in
server applications). If you are formatting data that is part
of a subnegotiation, you should always use libtelnet_printf()
instead, as you will rarely want newline translation inside of
subnegotiations.
IId. Event Handling IId. Event Handling
libtelnet relies on an event-handling mechanism for processing libtelnet relies on an event-handling mechanism for processing the
the parsed TELNET protocol stream as well as for buffering and parsed TELNET protocol stream as well as for buffering and sending
sending output data. output data.
When you initialize a libtelnet_t structure with libtelnet_init() When you initialize a telnet_t structure with telnet_init() you had
you had to pass in an event handler function. This function must to pass in an event handler function. This function must meet the
meet the following prototype: following prototype:
void (libtelnet_t *telnet, libtelnet_event_t *event, void (telnet_t *telnet, telnet_event_t *event, void *user_data);
void *user_data);
The event structure is detailed below. The user_data value is the The event structure is detailed below. The user_data value is the
pointer passed to libtelnet_init(). pointer passed to telnet_init().
struct libtelnet_event_t { struct telnet_event_t {
const char *buffer; const char *buffer;
unsigned int size; unsigned int size;
libtelnet_event_type_t type; telnet_event_type_t type;
unsigned char command; unsigned char command;
unsigned char telopt; unsigned char telopt;
unsigned char accept; unsigned char accept;
}; };
The enumeration values of libtelnet_event_type_t are described in The enumeration values of telnet_event_type_t are described in
detail below. Whenever the the event handler is invoked, the detail below. Whenever the the event handler is invoked, the
application must look at the event->type value and do any application must look at the event->type value and do any necessary
necessary processing. processing.
The only event that MUST be implemented is LIBTELNET_EV_SEND. The only event that MUST be implemented is TELNET_EV_SEND. Most
Most applications will also always want to implement the event applications will also always want to implement the event
LIBTELNET_EV_DATA. TELNET_EV_DATA.
Here is an example event handler implementation which includes Here is an example event handler implementation which includes
handlers for several important events. handlers for several important events.
void my_event_handler(libtelnet_t *telnet, libtelnet_event_t *ev, void my_event_handler(telnet_t *telnet, telnet_event_t *ev,
void *user_data) { void *user_data) {
struct user_info *user = (struct user_info *)user_data; struct user_info *user = (struct user_info *)user_data;
switch (ev->type) { switch (ev->type) {
case LIBTELNET_EV_DATA: case TELNET_EV_DATA:
process_user_input(user, event->buffer, event->size); process_user_input(user, event->buffer, event->size);
break; break;
case LIBTELNET_EV_SEND: case TELNET_EV_SEND:
write_to_descriptor(user, event->buffer, event->size); write_to_descriptor(user, event->buffer, event->size);
break; break;
case LIBTELNET_EV_ERROR: case TELNET_EV_ERROR:
fatal_error("TELNET error: %s", event->buffer); fatal_error("TELNET error: %s", event->buffer);
break; break;
} }
} }
LIBTELNET_EV_DATA: TELNET_EV_DATA:
The DATA event is triggered whenever regular data (not part of The DATA event is triggered whenever regular data (not part of any
any special TELNET command) is received. For a client, this special TELNET command) is received. For a client, this will be
will be process output from the server. For a server, this will process output from the server. For a server, this will be input
be input typed by the user. typed by the user.
The event->buffer value will contain the bytes received and the The event->buffer value will contain the bytes received and the
event->size value will contain the number of bytes received. event->size value will contain the number of bytes received. Note
Note that event->buffer is not NUL terminated! that event->buffer is not NUL terminated!
NOTE: there is no guarantee that user input or server output NOTE: there is no guarantee that user input or server output
will be received in whole lines. If you wish to process data will be received in whole lines. If you wish to process data
a line at a time, you are responsible for buffering the data and a line at a time, you are responsible for buffering the data and
checking for line terminators yourself! checking for line terminators yourself!
LIBTELNET_EV_SEND: TELNET_EV_SEND:
This event is sent whenever libtelnet has generated data that This event is sent whenever libtelnet has generated data that must
must be sent over the wire to the remove end. Generally that be sent over the wire to the remove end. Generally that means
means calling send() or adding the data to your application's calling send() or adding the data to your application's output
output buffer. buffer.
The event->buffer value will contain the bytes to send and the The event->buffer value will contain the bytes to send and the
event->size value will contain the number of bytes to send. event->size value will contain the number of bytes to send. Note
Note that event->buffer is not NUL terminated, and may include that event->buffer is not NUL terminated, and may include NUL
NUL characters in its data, so always use event->size! characters in its data, so always use event->size!
NOTE: Your SEND event handler must send or buffer the data in NOTE: Your SEND event handler must send or buffer the data in
its raw form as provided by libtelnet. If you wish to perform its raw form as provided by libtelnet. If you wish to perform
any kind of preprocessing on data you want to send to the other any kind of preprocessing on data you want to send to the other
LIBTELNET_EV_IAC: TELNET_EV_IAC:
The IAC event is triggered whenever a simple IAC command is The IAC event is triggered whenever a simple IAC command is
received, such as the IAC EOR (end of record, also called received, such as the IAC EOR (end of record, also called go ahead
go ahead or GA) command. or GA) command.
The command received is in the event->command value. The command received is in the event->command value.
The necessary processing depends on the specific commands; see The necessary processing depends on the specific commands; see
the TELNET RFC for more information. the TELNET RFC for more information.
LIBTELNET_EV_WILL: TELNET_EV_WILL:
LIBTELNET_EV_DO: TELNET_EV_DO:
The WILL and DO events are sent when a TELNET negotiation The WILL and DO events are sent when a TELNET negotiation command
command of the same name is received. of the same name is received.
WILL events are sent by the remote end when they wish to be WILL events are sent by the remote end when they wish to be
allowed to turn an option on on their end, or in confirmation allowed to turn an option on on their end, or in confirmation
after you have sent a DO command to them. after you have sent a DO command to them.
DO events are sent by the remote end when they wish for you DO events are sent by the remote end when they wish for you to
to turn on an option on your end, or in confirmation after you turn on an option on your end, or in confirmation after you have
have sent a WILL command to them. sent a WILL command to them.
In either case, the TELNET option under negotiation will be in In either case, the TELNET option under negotiation will be in
event->telopt field. event->telopt field.
If you support the option and wish for it to be enabled you If you support the option and wish for it to be enabled you must
must set the event->accept field to 1, unless this event is set the event->accept field to 1, unless this event is a
a confirmation for a previous WILL/DO command you sent to the confirmation for a previous WILL/DO command you sent to the remote
remote end. If you do not set event->field to 1 then end. If you do not set event->field to 1 then libtelnet will send
libtelnet will send a rejection command back to the other end. a rejection command back to the other end.
libtelnet manages some of the pecularities of negotiation for libtelnet manages some of the pecularities of negotiation for you.
you. For information on libtelnet's negotiation method, see: For information on libtelnet's negotiation method, see:
http://www.faqs.org/rfcs/rfc1143.html http://www.faqs.org/rfcs/rfc1143.html
@ -309,12 +308,12 @@ IId. Event Handling
Note that in PROXY mode libtelnet will do no processing of its Note that in PROXY mode libtelnet will do no processing of its
own for you. own for you.
LIBTELNET_EV_WONT: TELNET_EV_WONT:
LIBTELNET_EV_DONT: TELNET_EV_DONT:
The WONT and DONT events are sent when the remote end of the The WONT and DONT events are sent when the remote end of the
connection wishes to disable an option, when they are connection wishes to disable an option, when they are refusing to
refusing to a support an option that you have asked for, or a support an option that you have asked for, or in confirmation of
in confirmation of an option you have asked to be disabled. an option you have asked to be disabled.
Most commonly WONT and DONT events are sent as rejections of Most commonly WONT and DONT events are sent as rejections of
features you requested by sending DO or WILL events. Receiving features you requested by sending DO or WILL events. Receiving
@ -334,27 +333,27 @@ IId. Event Handling
Note that in PROXY mode libtelnet will do no processing of its Note that in PROXY mode libtelnet will do no processing of its
own for you. own for you.
LIBTELNET_EV_SUBNEGOTIATION: TELNET_EV_SUBNEGOTIATION:
Triggered whenever a TELNET sub-negotiation has been received. Triggered whenever a TELNET sub-negotiation has been received.
Sub-negotiations include the NAWS option for communicating Sub-negotiations include the NAWS option for communicating
terminal size to a server, the NEW-ENVIRON and TTYPE options terminal size to a server, the NEW-ENVIRON and TTYPE options for
for negotiating terminal features, and MUD-centric protocols negotiating terminal features, and MUD-centric protocols such as
such as ZMP, MSSP, and MCCP2. ZMP, MSSP, and MCCP2.
The event->telopt value is the option under sub-negotiation. The event->telopt value is the option under sub-negotiation. The
The remaining data (if any) is passed in event->buffer and remaining data (if any) is passed in event->buffer and
event->size. Note that most subnegotiation commands can event->size. Note that most subnegotiation commands can include
include embedded NUL bytes in the subnegotiation data, and embedded NUL bytes in the subnegotiation data, and the data
the data event->buffer is not NUL terminated, so always use event->buffer is not NUL terminated, so always use the event->size
the event->size value! value!
The meaning and necessary processing for subnegotiations are The meaning and necessary processing for subnegotiations are
defined in various TELNET RFCs and other informal defined in various TELNET RFCs and other informal specifications.
specifications. A subnegotiation should never be sent unless A subnegotiation should never be sent unless the specific option
the specific option has been enabled through the use of the has been enabled through the use of the telnet negotiation
telnet negotiation feature. feature.
LIBTELNET_EV_COMPRESS TELNET_EV_COMPRESS
The COMPRESS event notifies the app that COMPRESS2/MCCP2 The COMPRESS event notifies the app that COMPRESS2/MCCP2
compression has begun or ended. Only servers can send compressed compression has begun or ended. Only servers can send compressed
data, and hence only clients will receive compressed data. data, and hence only clients will receive compressed data.
@ -362,25 +361,24 @@ IId. Event Handling
The event->command value will be 1 if compression has started and The event->command value will be 1 if compression has started and
will be 0 if compression has ended. will be 0 if compression has ended.
LIBTELNET_EV_WARNING TELNET_EV_WARNING
The WARNING event is sent whenever something has gone wrong The WARNING event is sent whenever something has gone wrong inside
inside of libtelnet (possibly due to malformed data sent by the of libtelnet (possibly due to malformed data sent by the other
other end) but which recovery is (likely) possible. It may be end) but which recovery is (likely) possible. It may be safe to
safe to continue using the connection, but some data may have continue using the connection, but some data may have been lost or
been lost or incorrectly interpreted. incorrectly interpreted.
The event->buffer value will contain a NUL terminated string The event->buffer value will contain a NUL terminated string
explaining the error, and the event->size value containers the explaining the error, and the event->size value containers the
length of the string. length of the string.
LIBTELNET_EV_ERROR TELNET_EV_ERROR
Similar to the WARNING event, the ERROR event is sent whenever Similar to the WARNING event, the ERROR event is sent whenever
something has gone wrong. ERROR events are non-recoverable, something has gone wrong. ERROR events are non-recoverable,
however, and the application should immediately close the however, and the application should immediately close the
connection. Whatever has happened is likely going only to connection. Whatever has happened is likely going only to result
result in garbage from libtelnet. This is most likely to in garbage from libtelnet. This is most likely to happen when a
happen when a COMPRESS2 stream fails, but other problems can COMPRESS2 stream fails, but other problems can occur.
occur.
The event->buffer value will contain a NUL terminated string The event->buffer value will contain a NUL terminated string
explaining the error, and the event->size value containers the explaining the error, and the event->size value containers the
@ -396,30 +394,30 @@ IV. SAFETY AND CORRECTNESS CONSIDERATIONS
===================================================================== =====================================================================
Your existing application may make heavy use of its own output Your existing application may make heavy use of its own output
buffering and transmission commands, including hand-made routines buffering and transmission commands, including hand-made routines for
for sending TELNET commands and sub-negotiation requests. There are sending TELNET commands and sub-negotiation requests. There are at
at times subtle issues that need to be handled when communication times subtle issues that need to be handled when communication over
over the TELNET protocol, not least of which is the need to escape the TELNET protocol, not least of which is the need to escape any
any byte value 0xFF with a special TELNET command. byte value 0xFF with a special TELNET command.
For these reasons, it is very important that applications making use For these reasons, it is very important that applications making use
of libtelnet always make use of the libtelnet_send_*() family of of libtelnet always make use of the telnet_send_*() family of
functions for all data being sent over the TELNET connection. functions for all data being sent over the TELNET connection.
In particular, if you are writing a client, all user input must be In particular, if you are writing a client, all user input must be
passed through to libtelnet_send_data(). This also includes any passed through to telnet_send_data(). This also includes any input
input generated automatically by scripts, triggers, or macros. generated automatically by scripts, triggers, or macros.
For a server, any and all output -- including ANSI/VT100 escape For a server, any and all output -- including ANSI/VT100 escape
codes, regular text, newlines, and so on -- must be passed through codes, regular text, newlines, and so on -- must be passed through to
to libtelnet_send_data(). telnet_send_data().
Any TELNET commands that are to be sent must be given to one of the Any TELNET commands that are to be sent must be given to one of the
following: libtelnet_send_command, libtelnet_send_negotiate, or following: telnet_send_command, telnet_send_negotiate, or
libtelnet_send_subnegotiation(). telnet_send_subnegotiation().
If you are attempting to enable COMPRESS2/MCCP2, you must use the If you are attempting to enable COMPRESS2/MCCP2, you must use the
libtelnet_begin_compress2() function. telnet_begin_compress2() function.
V. MCCP2 COMPRESSION V. MCCP2 COMPRESSION
===================================================================== =====================================================================
@ -435,15 +433,15 @@ when compiling libtelnet.c and pass -lz to the linker to link in the
zlib shared library. zlib shared library.
libtelnet transparently supports MCCP2. For a server to support libtelnet transparently supports MCCP2. For a server to support
MCCP2, the application must begin negotiation of the COMPRESS2 MCCP2, the application must begin negotiation of the COMPRESS2 option
option using libtelnet_send_negotiate(), for example: using telnet_send_negotiate(), for example:
libtelnet_send_negotiate(&telnet, LIBTELNET_WILL, telnet_send_negotiate(&telnet, TELNET_WILL,
LIBTELNET_OPTION_COMPRESS2, user_data); TELNET_OPTION_COMPRESS2, user_data);
If a favorable DO COMPRESS2 is sent back from the client then the If a favorable DO COMPRESS2 is sent back from the client then the
server application can begin compression at any time by calling server application can begin compression at any time by calling
libtelnet_begin_compress2(). telnet_begin_compress2().
If a connection is in PROXY mode and COMPRESS2 support is enabled If a connection is in PROXY mode and COMPRESS2 support is enabled
then libtelnet will automatically detect the start of a COMPRESS2 then libtelnet will automatically detect the start of a COMPRESS2
@ -452,8 +450,8 @@ stream, in either the sending or receiving direction.
VI. TELNET PROXY UTILITY VI. TELNET PROXY UTILITY
===================================================================== =====================================================================
The telnet-proxy utility is a small application that serves both as The telnet-proxy utility is a small application that serves both as a
a testbed for libtelnet and as a powerful debugging tool for TELNET testbed for libtelnet and as a powerful debugging tool for TELNET
servers and clients. servers and clients.
To use telnet-proxy, you must first compile it using: To use telnet-proxy, you must first compile it using:
@ -464,8 +462,8 @@ 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 then you must first edit the Makefile and remove the -DHAVE_ZLIB and
the -lz from the compile flags. the -lz from the compile flags.
To run telnet-proxy, you simply give it the server's host name or To run telnet-proxy, you simply give it the server's host name or IP
IP address, the server's port number, and the port number that address, the server's port number, and the port number that
telnet-proxy should listen on. For example, to connect to the server 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: on mud.example.com port 7800 and to listen on port 5000, run:
@ -475,8 +473,7 @@ You can then connect to the host telnet-proxy is running on (e.g.
127.0.0.1) on port 500 and you will automatically be proxied into 127.0.0.1) on port 500 and you will automatically be proxied into
mud.example.com. mud.example.com.
telnet-proxy will display status information about the data telnet-proxy will display status information about the data passing
passing through both ends of the tunnel. telnet-proxy can only through both ends of the tunnel. telnet-proxy can only support a
support a single tunnel at a time. It will continue running until single tunnel at a time. It will continue running until an error
an error occurs or a terminating signal is sent to the proxy occurs or a terminating signal is sent to the proxy process.
process.

View File

@ -47,10 +47,10 @@ static const size_t _buffer_sizes_count = sizeof(_buffer_sizes) /
/* event dispatch helper; return value is value of the accept field of the /* event dispatch helper; return value is value of the accept field of the
* event struct after dispatch; used for the funky REQUEST event */ * event struct after dispatch; used for the funky REQUEST event */
static int _event(libtelnet_t *telnet, libtelnet_event_type_t type, static int _event(telnet_t *telnet, telnet_event_type_t type,
unsigned char command, unsigned char telopt, unsigned char command, unsigned char telopt,
const char *buffer, size_t size) { const char *buffer, size_t size) {
libtelnet_event_t ev; telnet_event_t ev;
ev.buffer = buffer; ev.buffer = buffer;
ev.size = size; ev.size = size;
ev.type = type; ev.type = type;
@ -64,8 +64,8 @@ static int _event(libtelnet_t *telnet, libtelnet_event_type_t type,
} }
/* error generation function */ /* error generation function */
static libtelnet_error_t _error(libtelnet_t *telnet, unsigned line, static telnet_error_t _error(telnet_t *telnet, unsigned line,
const char* func, libtelnet_error_t err, int fatal, const char *fmt, const char* func, telnet_error_t err, int fatal, const char *fmt,
...) { ...) {
char buffer[512]; char buffer[512];
va_list va; va_list va;
@ -78,7 +78,7 @@ static libtelnet_error_t _error(libtelnet_t *telnet, unsigned line,
fmt, va); fmt, va);
va_end(va); va_end(va);
_event(telnet, fatal ? LIBTELNET_EV_ERROR : LIBTELNET_EV_WARNING, err, _event(telnet, fatal ? TELNET_EV_ERROR : TELNET_EV_WARNING, err,
0, (char *)buffer, strlen(buffer)); 0, (char *)buffer, strlen(buffer));
return err; return err;
@ -87,52 +87,52 @@ static libtelnet_error_t _error(libtelnet_t *telnet, unsigned line,
#ifdef HAVE_ZLIB #ifdef HAVE_ZLIB
/* initialize the zlib box for a telnet box; if deflate is non-zero, it /* initialize the zlib box for a telnet box; if deflate is non-zero, it
* initializes zlib for delating (compression), otherwise for inflating * initializes zlib for delating (compression), otherwise for inflating
* (decompression). returns LIBTELNET_EOK on success, something else on * (decompression). returns TELNET_EOK on success, something else on
* failure. * failure.
*/ */
libtelnet_error_t _init_zlib(libtelnet_t *telnet, int deflate, int err_fatal) { telnet_error_t _init_zlib(telnet_t *telnet, int deflate, int err_fatal) {
z_stream *z; z_stream *z;
int rs; int rs;
/* if compression is already enabled, fail loudly */ /* if compression is already enabled, fail loudly */
if (telnet->z != 0) if (telnet->z != 0)
return _error(telnet, __LINE__, __func__, LIBTELNET_EBADVAL, return _error(telnet, __LINE__, __func__, TELNET_EBADVAL,
err_fatal, "cannot initialize compression twice"); err_fatal, "cannot initialize compression twice");
/* allocate zstream box */ /* allocate zstream box */
if ((z= (z_stream *)calloc(1, sizeof(z_stream))) == 0) if ((z= (z_stream *)calloc(1, sizeof(z_stream))) == 0)
return _error(telnet, __LINE__, __func__, LIBTELNET_ENOMEM, err_fatal, return _error(telnet, __LINE__, __func__, TELNET_ENOMEM, err_fatal,
"malloc() failed: %s", strerror(errno)); "malloc() failed: %s", strerror(errno));
/* initialize */ /* initialize */
if (deflate) { if (deflate) {
if ((rs = deflateInit(z, Z_DEFAULT_COMPRESSION)) != Z_OK) { if ((rs = deflateInit(z, Z_DEFAULT_COMPRESSION)) != Z_OK) {
free(z); free(z);
return _error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS, return _error(telnet, __LINE__, __func__, TELNET_ECOMPRESS,
err_fatal, "deflateInit() failed: %s", zError(rs)); err_fatal, "deflateInit() failed: %s", zError(rs));
} }
telnet->flags |= LIBTELNET_PFLAG_DEFLATE; telnet->flags |= TELNET_PFLAG_DEFLATE;
} else { } else {
if ((rs = inflateInit(z)) != Z_OK) { if ((rs = inflateInit(z)) != Z_OK) {
free(z); free(z);
return _error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS, return _error(telnet, __LINE__, __func__, TELNET_ECOMPRESS,
err_fatal, "inflateInit() failed: %s", zError(rs)); err_fatal, "inflateInit() failed: %s", zError(rs));
} }
telnet->flags &= ~LIBTELNET_PFLAG_DEFLATE; telnet->flags &= ~TELNET_PFLAG_DEFLATE;
} }
telnet->z = z; telnet->z = z;
return LIBTELNET_EOK; return TELNET_EOK;
} }
#endif #endif
/* push bytes out, compressing them first if need be */ /* push bytes out, compressing them first if need be */
static void _send(libtelnet_t *telnet, const char *buffer, static void _send(telnet_t *telnet, const char *buffer,
size_t size) { size_t size) {
#ifdef HAVE_ZLIB #ifdef HAVE_ZLIB
/* if we have a deflate (compression) zlib box, use it */ /* if we have a deflate (compression) zlib box, use it */
if (telnet->z != 0 && telnet->flags & LIBTELNET_PFLAG_DEFLATE) { if (telnet->z != 0 && telnet->flags & TELNET_PFLAG_DEFLATE) {
char deflate_buffer[1024]; char deflate_buffer[1024];
int rs; int rs;
@ -146,7 +146,7 @@ static void _send(libtelnet_t *telnet, const char *buffer,
while (telnet->z->avail_in > 0 || telnet->z->avail_out == 0) { while (telnet->z->avail_in > 0 || telnet->z->avail_out == 0) {
/* compress */ /* compress */
if ((rs = deflate(telnet->z, Z_SYNC_FLUSH)) != Z_OK) { if ((rs = deflate(telnet->z, Z_SYNC_FLUSH)) != Z_OK) {
_error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS, 1, _error(telnet, __LINE__, __func__, TELNET_ECOMPRESS, 1,
"deflate() failed: %s", zError(rs)); "deflate() failed: %s", zError(rs));
deflateEnd(telnet->z); deflateEnd(telnet->z);
free(telnet->z); free(telnet->z);
@ -154,7 +154,7 @@ static void _send(libtelnet_t *telnet, const char *buffer,
break; break;
} }
_event(telnet, LIBTELNET_EV_SEND, 0, 0, deflate_buffer, _event(telnet, TELNET_EV_SEND, 0, 0, deflate_buffer,
sizeof(deflate_buffer) - telnet->z->avail_out); sizeof(deflate_buffer) - telnet->z->avail_out);
/* prepare output buffer for next run */ /* prepare output buffer for next run */
@ -165,12 +165,12 @@ static void _send(libtelnet_t *telnet, const char *buffer,
/* COMPRESS2 is not negotiated, just send */ /* COMPRESS2 is not negotiated, just send */
} else } else
#endif /* HAVE_ZLIB */ #endif /* HAVE_ZLIB */
_event(telnet, LIBTELNET_EV_SEND, 0, 0, buffer, size); _event(telnet, TELNET_EV_SEND, 0, 0, buffer, size);
} }
/* retrieve RFC1143 option state */ /* retrieve RFC1143 option state */
libtelnet_rfc1143_t _get_rfc1143(libtelnet_t *telnet, unsigned char telopt) { telnet_rfc1143_t _get_rfc1143(telnet_t *telnet, unsigned char telopt) {
static const libtelnet_rfc1143_t empty = { 0, 0, 0}; static const telnet_rfc1143_t empty = { 0, 0, 0};
int i; int i;
/* search for entry */ /* search for entry */
@ -183,8 +183,8 @@ libtelnet_rfc1143_t _get_rfc1143(libtelnet_t *telnet, unsigned char telopt) {
} }
/* save RFC1143 option state */ /* save RFC1143 option state */
void _set_rfc1143(libtelnet_t *telnet, libtelnet_rfc1143_t q) { void _set_rfc1143(telnet_t *telnet, telnet_rfc1143_t q) {
libtelnet_rfc1143_t *qtmp; telnet_rfc1143_t *qtmp;
int i; int i;
/* search for entry */ /* search for entry */
@ -198,9 +198,9 @@ void _set_rfc1143(libtelnet_t *telnet, libtelnet_rfc1143_t q) {
/* we're going to need to track state for it, so grow the queue /* we're going to need to track state for it, so grow the queue
* and put the telopt into it; bail on allocation error * and put the telopt into it; bail on allocation error
*/ */
if ((qtmp = (libtelnet_rfc1143_t *)malloc(sizeof( if ((qtmp = (telnet_rfc1143_t *)malloc(sizeof(
libtelnet_rfc1143_t) * (telnet->q_size + 1))) == 0) { telnet_rfc1143_t) * (telnet->q_size + 1))) == 0) {
_error(telnet, __LINE__, __func__, LIBTELNET_ENOMEM, 0, _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
"malloc() failed: %s", strerror(errno)); "malloc() failed: %s", strerror(errno));
return; return;
} }
@ -209,24 +209,24 @@ void _set_rfc1143(libtelnet_t *telnet, libtelnet_rfc1143_t q) {
} }
/* negotiation handling magic for RFC1143 */ /* negotiation handling magic for RFC1143 */
static void _negotiate(libtelnet_t *telnet, unsigned char cmd, static void _negotiate(telnet_t *telnet, unsigned char cmd,
unsigned char telopt) { unsigned char telopt) {
libtelnet_rfc1143_t q; telnet_rfc1143_t q;
/* in PROXY mode, just pass it thru and do nothing */ /* in PROXY mode, just pass it thru and do nothing */
if (telnet->flags & LIBTELNET_FLAG_PROXY) { if (telnet->flags & TELNET_FLAG_PROXY) {
switch (cmd) { switch (cmd) {
case LIBTELNET_WILL: case TELNET_WILL:
_event(telnet, LIBTELNET_EV_WILL, 0, telopt, 0, 0); _event(telnet, TELNET_EV_WILL, 0, telopt, 0, 0);
break; break;
case LIBTELNET_WONT: case TELNET_WONT:
_event(telnet, LIBTELNET_EV_WONT, 0, telopt, 0, 0); _event(telnet, TELNET_EV_WONT, 0, telopt, 0, 0);
break; break;
case LIBTELNET_DO: case TELNET_DO:
_event(telnet, LIBTELNET_EV_DO, 0, telopt, 0, 0); _event(telnet, TELNET_EV_DO, 0, telopt, 0, 0);
break; break;
case LIBTELNET_DONT: case TELNET_DONT:
_event(telnet, LIBTELNET_EV_DONT, 0, telopt, 0, 0); _event(telnet, TELNET_EV_DONT, 0, telopt, 0, 0);
break; break;
} }
return; return;
@ -238,28 +238,28 @@ static void _negotiate(libtelnet_t *telnet, unsigned char cmd,
/* start processing... */ /* start processing... */
switch (cmd) { switch (cmd) {
/* request to enable option on remote end or confirm DO */ /* request to enable option on remote end or confirm DO */
case LIBTELNET_WILL: case TELNET_WILL:
switch (q.him) { switch (q.him) {
case RFC1143_NO: case RFC1143_NO:
if (_event(telnet, LIBTELNET_EV_WILL, cmd, telopt, 0, 0) == 1) { if (_event(telnet, TELNET_EV_WILL, cmd, telopt, 0, 0) == 1) {
q.him = RFC1143_YES; q.him = RFC1143_YES;
_set_rfc1143(telnet, q); _set_rfc1143(telnet, q);
libtelnet_send_telopt(telnet, LIBTELNET_DO, telopt); telnet_send_telopt(telnet, TELNET_DO, telopt);
} else } else
libtelnet_send_telopt(telnet, LIBTELNET_DONT, telopt); telnet_send_telopt(telnet, TELNET_DONT, telopt);
break; break;
case RFC1143_YES: case RFC1143_YES:
break; break;
case RFC1143_WANTNO: case RFC1143_WANTNO:
q.him = RFC1143_NO; q.him = RFC1143_NO;
_set_rfc1143(telnet, q); _set_rfc1143(telnet, q);
_error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0, _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
"DONT answered by WILL"); "DONT answered by WILL");
break; break;
case RFC1143_WANTNO_OP: case RFC1143_WANTNO_OP:
q.him = RFC1143_YES; q.him = RFC1143_YES;
_set_rfc1143(telnet, q); _set_rfc1143(telnet, q);
_error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0, _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
"DONT answered by WILL"); "DONT answered by WILL");
break; break;
case RFC1143_WANTYES: case RFC1143_WANTYES:
@ -269,33 +269,33 @@ static void _negotiate(libtelnet_t *telnet, unsigned char cmd,
case RFC1143_WANTYES_OP: case RFC1143_WANTYES_OP:
q.him = RFC1143_WANTNO; q.him = RFC1143_WANTNO;
_set_rfc1143(telnet, q); _set_rfc1143(telnet, q);
libtelnet_send_telopt(telnet, LIBTELNET_DONT, telopt); telnet_send_telopt(telnet, TELNET_DONT, telopt);
break; break;
} }
break; break;
/* request to disable option on remote end, confirm DONT, reject DO */ /* request to disable option on remote end, confirm DONT, reject DO */
case LIBTELNET_WONT: case TELNET_WONT:
switch (q.him) { switch (q.him) {
case RFC1143_NO: case RFC1143_NO:
break; break;
case RFC1143_YES: case RFC1143_YES:
q.him = RFC1143_NO; q.him = RFC1143_NO;
_set_rfc1143(telnet, q); _set_rfc1143(telnet, q);
libtelnet_send_telopt(telnet, LIBTELNET_DONT, telopt); telnet_send_telopt(telnet, TELNET_DONT, telopt);
_event(telnet, LIBTELNET_EV_WONT, 0, telopt, _event(telnet, TELNET_EV_WONT, 0, telopt,
0, 0); 0, 0);
break; break;
case RFC1143_WANTNO: case RFC1143_WANTNO:
q.him = RFC1143_NO; q.him = RFC1143_NO;
_set_rfc1143(telnet, q); _set_rfc1143(telnet, q);
_event(telnet, LIBTELNET_EV_WONT, 0, telopt, _event(telnet, TELNET_EV_WONT, 0, telopt,
0, 0); 0, 0);
break; break;
case RFC1143_WANTNO_OP: case RFC1143_WANTNO_OP:
q.him = RFC1143_WANTYES; q.him = RFC1143_WANTYES;
_set_rfc1143(telnet, q); _set_rfc1143(telnet, q);
_event(telnet, LIBTELNET_EV_DO, 0, telopt, _event(telnet, TELNET_EV_DO, 0, telopt,
0, 0); 0, 0);
break; break;
case RFC1143_WANTYES: case RFC1143_WANTYES:
@ -307,28 +307,28 @@ static void _negotiate(libtelnet_t *telnet, unsigned char cmd,
break; break;
/* request to enable option on local end or confirm WILL */ /* request to enable option on local end or confirm WILL */
case LIBTELNET_DO: case TELNET_DO:
switch (q.us) { switch (q.us) {
case RFC1143_NO: case RFC1143_NO:
if (_event(telnet, LIBTELNET_EV_DO, cmd, telopt, 0, 0) == 1) { if (_event(telnet, TELNET_EV_DO, cmd, telopt, 0, 0) == 1) {
q.us = RFC1143_YES; q.us = RFC1143_YES;
_set_rfc1143(telnet, q); _set_rfc1143(telnet, q);
libtelnet_send_telopt(telnet, LIBTELNET_WILL, telopt); telnet_send_telopt(telnet, TELNET_WILL, telopt);
} else } else
libtelnet_send_telopt(telnet, LIBTELNET_WONT, telopt); telnet_send_telopt(telnet, TELNET_WONT, telopt);
break; break;
case RFC1143_YES: case RFC1143_YES:
break; break;
case RFC1143_WANTNO: case RFC1143_WANTNO:
q.us = RFC1143_NO; q.us = RFC1143_NO;
_set_rfc1143(telnet, q); _set_rfc1143(telnet, q);
_error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0, _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
"WONT answered by DO"); "WONT answered by DO");
break; break;
case RFC1143_WANTNO_OP: case RFC1143_WANTNO_OP:
q.us = RFC1143_YES; q.us = RFC1143_YES;
_set_rfc1143(telnet, q); _set_rfc1143(telnet, q);
_error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0, _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
"WONT answered by DO"); "WONT answered by DO");
break; break;
case RFC1143_WANTYES: case RFC1143_WANTYES:
@ -338,31 +338,31 @@ static void _negotiate(libtelnet_t *telnet, unsigned char cmd,
case RFC1143_WANTYES_OP: case RFC1143_WANTYES_OP:
q.us = RFC1143_WANTNO; q.us = RFC1143_WANTNO;
_set_rfc1143(telnet, q); _set_rfc1143(telnet, q);
libtelnet_send_telopt(telnet, LIBTELNET_WONT, telopt); telnet_send_telopt(telnet, TELNET_WONT, telopt);
break; break;
} }
break; break;
/* request to disable option on local end, confirm WONT, reject WILL */ /* request to disable option on local end, confirm WONT, reject WILL */
case LIBTELNET_DONT: case TELNET_DONT:
switch (q.us) { switch (q.us) {
case RFC1143_NO: case RFC1143_NO:
break; break;
case RFC1143_YES: case RFC1143_YES:
q.us = RFC1143_NO; q.us = RFC1143_NO;
_set_rfc1143(telnet, q); _set_rfc1143(telnet, q);
libtelnet_send_telopt(telnet, LIBTELNET_WONT, telopt); telnet_send_telopt(telnet, TELNET_WONT, telopt);
_event(telnet, LIBTELNET_EV_DONT, 0, telopt, 0, 0); _event(telnet, TELNET_EV_DONT, 0, telopt, 0, 0);
break; break;
case RFC1143_WANTNO: case RFC1143_WANTNO:
q.us = RFC1143_NO; q.us = RFC1143_NO;
_set_rfc1143(telnet, q); _set_rfc1143(telnet, q);
_event(telnet, LIBTELNET_EV_WONT, 0, telopt, 0, 0); _event(telnet, TELNET_EV_WONT, 0, telopt, 0, 0);
break; break;
case RFC1143_WANTNO_OP: case RFC1143_WANTNO_OP:
q.us = RFC1143_WANTYES; q.us = RFC1143_WANTYES;
_set_rfc1143(telnet, q); _set_rfc1143(telnet, q);
_event(telnet, LIBTELNET_EV_WILL, 0, telopt, 0, 0); _event(telnet, TELNET_EV_WILL, 0, telopt, 0, 0);
break; break;
case RFC1143_WANTYES: case RFC1143_WANTYES:
case RFC1143_WANTYES_OP: case RFC1143_WANTYES_OP:
@ -375,16 +375,16 @@ static void _negotiate(libtelnet_t *telnet, unsigned char cmd,
} }
/* initialize a telnet state tracker */ /* initialize a telnet state tracker */
void libtelnet_init(libtelnet_t *telnet, libtelnet_event_handler_t eh, void telnet_init(telnet_t *telnet, telnet_event_handler_t eh,
unsigned char flags, void *user_data) { unsigned char flags, void *user_data) {
memset(telnet, 0, sizeof(libtelnet_t)); memset(telnet, 0, sizeof(telnet_t));
telnet->ud = user_data; telnet->ud = user_data;
telnet->eh = eh; telnet->eh = eh;
telnet->flags = flags; telnet->flags = flags;
} }
/* free up any memory allocated by a state tracker */ /* free up any memory allocated by a state tracker */
void libtelnet_free(libtelnet_t *telnet) { void telnet_free(telnet_t *telnet) {
/* free sub-request buffer */ /* free sub-request buffer */
if (telnet->buffer != 0) { if (telnet->buffer != 0) {
free(telnet->buffer); free(telnet->buffer);
@ -396,7 +396,7 @@ void libtelnet_free(libtelnet_t *telnet) {
#ifdef HAVE_ZLIB #ifdef HAVE_ZLIB
/* free zlib box */ /* free zlib box */
if (telnet->z != 0) { if (telnet->z != 0) {
if (telnet->flags & LIBTELNET_PFLAG_DEFLATE) if (telnet->flags & TELNET_PFLAG_DEFLATE)
deflateEnd(telnet->z); deflateEnd(telnet->z);
else else
inflateEnd(telnet->z); inflateEnd(telnet->z);
@ -414,7 +414,7 @@ void libtelnet_free(libtelnet_t *telnet) {
} }
/* push a byte into the telnet buffer */ /* push a byte into the telnet buffer */
static libtelnet_error_t _buffer_byte(libtelnet_t *telnet, static telnet_error_t _buffer_byte(telnet_t *telnet,
unsigned char byte) { unsigned char byte) {
char *new_buffer; char *new_buffer;
size_t i; size_t i;
@ -429,20 +429,20 @@ static libtelnet_error_t _buffer_byte(libtelnet_t *telnet,
/* overflow -- can't grow any more */ /* overflow -- can't grow any more */
if (i >= _buffer_sizes_count - 1) { if (i >= _buffer_sizes_count - 1) {
_error(telnet, __LINE__, __func__, LIBTELNET_EOVERFLOW, 0, _error(telnet, __LINE__, __func__, TELNET_EOVERFLOW, 0,
"subnegotiation buffer size limit reached"); "subnegotiation buffer size limit reached");
libtelnet_free(telnet); telnet_free(telnet);
return LIBTELNET_EOVERFLOW; return TELNET_EOVERFLOW;
} }
/* (re)allocate buffer */ /* (re)allocate buffer */
new_buffer = (char *)realloc(telnet->buffer, new_buffer = (char *)realloc(telnet->buffer,
_buffer_sizes[i + 1]); _buffer_sizes[i + 1]);
if (new_buffer == 0) { if (new_buffer == 0) {
_error(telnet, __LINE__, __func__, LIBTELNET_ENOMEM, 0, _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
"realloc() failed"); "realloc() failed");
libtelnet_free(telnet); telnet_free(telnet);
return LIBTELNET_ENOMEM; return TELNET_ENOMEM;
} }
telnet->buffer = new_buffer; telnet->buffer = new_buffer;
@ -451,10 +451,10 @@ static libtelnet_error_t _buffer_byte(libtelnet_t *telnet,
/* push the byte, all set */ /* push the byte, all set */
telnet->buffer[telnet->buffer_pos++] = byte; telnet->buffer[telnet->buffer_pos++] = byte;
return LIBTELNET_EOK; return TELNET_EOK;
} }
static void _process(libtelnet_t *telnet, const char *buffer, static void _process(telnet_t *telnet, const char *buffer,
size_t size) { size_t size) {
unsigned char byte; unsigned char byte;
size_t i, start; size_t i, start;
@ -462,146 +462,146 @@ static void _process(libtelnet_t *telnet, const char *buffer,
byte = buffer[i]; byte = buffer[i];
switch (telnet->state) { switch (telnet->state) {
/* regular data */ /* regular data */
case LIBTELNET_STATE_DATA: case TELNET_STATE_DATA:
/* on an IAC byte, pass through all pending bytes and /* on an IAC byte, pass through all pending bytes and
* switch states */ * switch states */
if (byte == LIBTELNET_IAC) { if (byte == TELNET_IAC) {
if (i != start) if (i != start)
_event(telnet, LIBTELNET_EV_DATA, 0, 0, &buffer[start], _event(telnet, TELNET_EV_DATA, 0, 0, &buffer[start],
i - start); i - start);
telnet->state = LIBTELNET_STATE_IAC; telnet->state = TELNET_STATE_IAC;
} }
break; break;
/* IAC command */ /* IAC command */
case LIBTELNET_STATE_IAC: case TELNET_STATE_IAC:
switch (byte) { switch (byte) {
/* subnegotiation */ /* subnegotiation */
case LIBTELNET_SB: case TELNET_SB:
telnet->state = LIBTELNET_STATE_SB; telnet->state = TELNET_STATE_SB;
break; break;
/* negotiation commands */ /* negotiation commands */
case LIBTELNET_WILL: case TELNET_WILL:
telnet->state = LIBTELNET_STATE_WILL; telnet->state = TELNET_STATE_WILL;
break; break;
case LIBTELNET_WONT: case TELNET_WONT:
telnet->state = LIBTELNET_STATE_WONT; telnet->state = TELNET_STATE_WONT;
break; break;
case LIBTELNET_DO: case TELNET_DO:
telnet->state = LIBTELNET_STATE_DO; telnet->state = TELNET_STATE_DO;
break; break;
case LIBTELNET_DONT: case TELNET_DONT:
telnet->state = LIBTELNET_STATE_DONT; telnet->state = TELNET_STATE_DONT;
break; break;
/* IAC escaping */ /* IAC escaping */
case LIBTELNET_IAC: case TELNET_IAC:
_event(telnet, LIBTELNET_EV_DATA, 0, 0, (char*)&byte, 1); _event(telnet, TELNET_EV_DATA, 0, 0, (char*)&byte, 1);
start = i + 1; start = i + 1;
telnet->state = LIBTELNET_STATE_DATA; telnet->state = TELNET_STATE_DATA;
break; break;
/* some other command */ /* some other command */
default: default:
_event(telnet, LIBTELNET_EV_IAC, byte, 0, 0, 0); _event(telnet, TELNET_EV_IAC, byte, 0, 0, 0);
start = i + 1; start = i + 1;
telnet->state = LIBTELNET_STATE_DATA; telnet->state = TELNET_STATE_DATA;
} }
break; break;
/* negotiation commands */ /* negotiation commands */
case LIBTELNET_STATE_DO: case TELNET_STATE_DO:
_negotiate(telnet, LIBTELNET_DO, byte); _negotiate(telnet, TELNET_DO, byte);
start = i + 1; start = i + 1;
telnet->state = LIBTELNET_STATE_DATA; telnet->state = TELNET_STATE_DATA;
break; break;
case LIBTELNET_STATE_DONT: case TELNET_STATE_DONT:
_negotiate(telnet, LIBTELNET_DONT, byte); _negotiate(telnet, TELNET_DONT, byte);
start = i + 1; start = i + 1;
telnet->state = LIBTELNET_STATE_DATA; telnet->state = TELNET_STATE_DATA;
break; break;
case LIBTELNET_STATE_WILL: case TELNET_STATE_WILL:
_negotiate(telnet, LIBTELNET_WILL, byte); _negotiate(telnet, TELNET_WILL, byte);
start = i + 1; start = i + 1;
telnet->state = LIBTELNET_STATE_DATA; telnet->state = TELNET_STATE_DATA;
break; break;
case LIBTELNET_STATE_WONT: case TELNET_STATE_WONT:
_negotiate(telnet, LIBTELNET_WONT, byte); _negotiate(telnet, TELNET_WONT, byte);
start = i + 1; start = i + 1;
telnet->state = LIBTELNET_STATE_DATA; telnet->state = TELNET_STATE_DATA;
break; break;
/* subnegotiation -- determine subnegotiation telopt */ /* subnegotiation -- determine subnegotiation telopt */
case LIBTELNET_STATE_SB: case TELNET_STATE_SB:
telnet->sb_telopt = byte; telnet->sb_telopt = byte;
telnet->buffer_pos = 0; telnet->buffer_pos = 0;
telnet->state = LIBTELNET_STATE_SB_DATA; telnet->state = TELNET_STATE_SB_DATA;
break; break;
/* subnegotiation -- buffer bytes until end request */ /* subnegotiation -- buffer bytes until end request */
case LIBTELNET_STATE_SB_DATA: case TELNET_STATE_SB_DATA:
/* IAC command in subnegotiation -- either IAC SE or IAC IAC */ /* IAC command in subnegotiation -- either IAC SE or IAC IAC */
if (byte == LIBTELNET_IAC) { if (byte == TELNET_IAC) {
telnet->state = LIBTELNET_STATE_SB_DATA_IAC; telnet->state = TELNET_STATE_SB_DATA_IAC;
/* buffer the byte, or bail if we can't */ /* buffer the byte, or bail if we can't */
} else if (_buffer_byte(telnet, byte) != LIBTELNET_EOK) { } else if (_buffer_byte(telnet, byte) != TELNET_EOK) {
start = i + 1; start = i + 1;
telnet->state = LIBTELNET_STATE_DATA; telnet->state = TELNET_STATE_DATA;
} }
break; break;
/* IAC escaping inside a subnegotiation */ /* IAC escaping inside a subnegotiation */
case LIBTELNET_STATE_SB_DATA_IAC: case TELNET_STATE_SB_DATA_IAC:
switch (byte) { switch (byte) {
/* end subnegotiation */ /* end subnegotiation */
case LIBTELNET_SE: case TELNET_SE:
/* return to default state */ /* return to default state */
start = i + 1; start = i + 1;
telnet->state = LIBTELNET_STATE_DATA; telnet->state = TELNET_STATE_DATA;
/* invoke callback */ /* invoke callback */
_event(telnet, LIBTELNET_EV_SUBNEGOTIATION, 0, _event(telnet, TELNET_EV_SUBNEGOTIATION, 0,
telnet->sb_telopt, telnet->buffer, telnet->buffer_pos); telnet->sb_telopt, telnet->buffer, telnet->buffer_pos);
#ifdef HAVE_ZLIB #ifdef HAVE_ZLIB
/* received COMPRESS2 begin marker, setup our zlib box and /* received COMPRESS2 begin marker, setup our zlib box and
* start handling the compressed stream if it's not already. * start handling the compressed stream if it's not already.
*/ */
if (telnet->sb_telopt == LIBTELNET_TELOPT_COMPRESS2) { if (telnet->sb_telopt == TELNET_TELOPT_COMPRESS2) {
if (_init_zlib(telnet, 0, 1) != LIBTELNET_EOK) if (_init_zlib(telnet, 0, 1) != TELNET_EOK)
break; break;
/* notify app that compression was enabled */ /* notify app that compression was enabled */
_event(telnet, LIBTELNET_EV_COMPRESS, 1, 0, 0, 0); _event(telnet, TELNET_EV_COMPRESS, 1, 0, 0, 0);
/* any remaining bytes in the buffer are compressed. /* any remaining bytes in the buffer are compressed.
* we have to re-invoke libtelnet_push to get those * we have to re-invoke telnet_push to get those
* bytes inflated and abort trying to process the * bytes inflated and abort trying to process the
* remaining compressed bytes in the current _process * remaining compressed bytes in the current _process
* buffer argument * buffer argument
*/ */
libtelnet_push(telnet, &buffer[start], size - start); telnet_push(telnet, &buffer[start], size - start);
return; return;
} }
#endif /* HAVE_ZLIB */ #endif /* HAVE_ZLIB */
break; break;
/* escaped IAC byte */ /* escaped IAC byte */
case LIBTELNET_IAC: case TELNET_IAC:
/* push IAC into buffer */ /* push IAC into buffer */
if (_buffer_byte(telnet, LIBTELNET_IAC) != if (_buffer_byte(telnet, TELNET_IAC) !=
LIBTELNET_EOK) { TELNET_EOK) {
start = i + 1; start = i + 1;
telnet->state = LIBTELNET_STATE_DATA; telnet->state = TELNET_STATE_DATA;
} else { } else {
telnet->state = LIBTELNET_STATE_SB_DATA; telnet->state = TELNET_STATE_SB_DATA;
} }
break; break;
/* something else -- protocol error */ /* something else -- protocol error */
default: default:
_error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0, _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
"unexpected byte after IAC inside SB: %d", "unexpected byte after IAC inside SB: %d",
byte); byte);
start = i + 1; start = i + 1;
telnet->state = LIBTELNET_STATE_DATA; telnet->state = TELNET_STATE_DATA;
break; break;
} }
break; break;
@ -609,16 +609,16 @@ static void _process(libtelnet_t *telnet, const char *buffer,
} }
/* pass through any remaining bytes */ /* pass through any remaining bytes */
if (telnet->state == LIBTELNET_STATE_DATA && i != start) if (telnet->state == TELNET_STATE_DATA && i != start)
_event(telnet, LIBTELNET_EV_DATA, 0, 0, buffer + start, i - start); _event(telnet, TELNET_EV_DATA, 0, 0, buffer + start, i - start);
} }
/* push a bytes into the state tracker */ /* push a bytes into the state tracker */
void libtelnet_push(libtelnet_t *telnet, const char *buffer, void telnet_push(telnet_t *telnet, const char *buffer,
size_t size) { size_t size) {
#ifdef HAVE_ZLIB #ifdef HAVE_ZLIB
/* if we have an inflate (decompression) zlib stream, use it */ /* if we have an inflate (decompression) zlib stream, use it */
if (telnet->z != 0 && !(telnet->flags & LIBTELNET_PFLAG_DEFLATE)) { if (telnet->z != 0 && !(telnet->flags & TELNET_PFLAG_DEFLATE)) {
char inflate_buffer[4096]; char inflate_buffer[4096];
int rs; int rs;
@ -640,7 +640,7 @@ void libtelnet_push(libtelnet_t *telnet, const char *buffer,
_process(telnet, inflate_buffer, sizeof(inflate_buffer) - _process(telnet, inflate_buffer, sizeof(inflate_buffer) -
telnet->z->avail_out); telnet->z->avail_out);
else else
_error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS, 1, _error(telnet, __LINE__, __func__, TELNET_ECOMPRESS, 1,
"inflate() failed: %s", zError(rs)); "inflate() failed: %s", zError(rs));
/* prepare output buffer for next run */ /* prepare output buffer for next run */
@ -649,7 +649,7 @@ void libtelnet_push(libtelnet_t *telnet, const char *buffer,
/* on error (or on end of stream) disable further inflation */ /* on error (or on end of stream) disable further inflation */
if (rs != Z_OK) { if (rs != Z_OK) {
_event(telnet, LIBTELNET_EV_COMPRESS, 0, 0, 0, 0); _event(telnet, TELNET_EV_COMPRESS, 0, 0, 0, 0);
inflateEnd(telnet->z); inflateEnd(telnet->z);
free(telnet->z); free(telnet->z);
@ -665,26 +665,26 @@ void libtelnet_push(libtelnet_t *telnet, const char *buffer,
} }
/* send an iac command */ /* send an iac command */
void libtelnet_send_command(libtelnet_t *telnet, unsigned char cmd) { void telnet_send_command(telnet_t *telnet, unsigned char cmd) {
char bytes[2] = { LIBTELNET_IAC, cmd }; char bytes[2] = { TELNET_IAC, cmd };
_send(telnet, bytes, 2); _send(telnet, bytes, 2);
} }
/* send an iac command with telopt */ /* send an iac command with telopt */
void libtelnet_send_telopt(libtelnet_t *telnet, unsigned char cmd, void telnet_send_telopt(telnet_t *telnet, unsigned char cmd,
unsigned char telopt) { unsigned char telopt) {
char bytes[3] = { LIBTELNET_IAC, cmd, telopt }; char bytes[3] = { TELNET_IAC, cmd, telopt };
_send(telnet, bytes, 3); _send(telnet, bytes, 3);
} }
/* send negotiation */ /* send negotiation */
void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd, void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
unsigned char telopt) { unsigned char telopt) {
libtelnet_rfc1143_t q; telnet_rfc1143_t q;
/* if we're in proxy mode, just send it now */ /* if we're in proxy mode, just send it now */
if (telnet->flags & LIBTELNET_FLAG_PROXY) { if (telnet->flags & TELNET_FLAG_PROXY) {
char bytes[3] = { LIBTELNET_IAC, cmd, telopt }; char bytes[3] = { TELNET_IAC, cmd, telopt };
_send(telnet, bytes, 3); _send(telnet, bytes, 3);
return; return;
} }
@ -694,12 +694,12 @@ void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd,
switch (cmd) { switch (cmd) {
/* advertise willingess to support an option */ /* advertise willingess to support an option */
case LIBTELNET_WILL: case TELNET_WILL:
switch (q.us) { switch (q.us) {
case RFC1143_NO: case RFC1143_NO:
q.us = RFC1143_WANTYES; q.us = RFC1143_WANTYES;
_set_rfc1143(telnet, q); _set_rfc1143(telnet, q);
_negotiate(telnet, LIBTELNET_WILL, telopt); _negotiate(telnet, TELNET_WILL, telopt);
break; break;
case RFC1143_YES: case RFC1143_YES:
break; break;
@ -719,14 +719,14 @@ void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd,
break; break;
/* force turn-off of locally enabled option */ /* force turn-off of locally enabled option */
case LIBTELNET_WONT: case TELNET_WONT:
switch (q.us) { switch (q.us) {
case RFC1143_NO: case RFC1143_NO:
break; break;
case RFC1143_YES: case RFC1143_YES:
q.us = RFC1143_WANTNO; q.us = RFC1143_WANTNO;
_set_rfc1143(telnet, q); _set_rfc1143(telnet, q);
_negotiate(telnet, LIBTELNET_WONT, telopt); _negotiate(telnet, TELNET_WONT, telopt);
break; break;
case RFC1143_WANTNO: case RFC1143_WANTNO:
break; break;
@ -744,12 +744,12 @@ void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd,
break; break;
/* ask remote end to enable an option */ /* ask remote end to enable an option */
case LIBTELNET_DO: case TELNET_DO:
switch (q.him) { switch (q.him) {
case RFC1143_NO: case RFC1143_NO:
q.him = RFC1143_WANTYES; q.him = RFC1143_WANTYES;
_set_rfc1143(telnet, q); _set_rfc1143(telnet, q);
_negotiate(telnet, LIBTELNET_DO, telopt); _negotiate(telnet, TELNET_DO, telopt);
break; break;
case RFC1143_YES: case RFC1143_YES:
break; break;
@ -769,14 +769,14 @@ void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd,
break; break;
/* demand remote end disable an option */ /* demand remote end disable an option */
case LIBTELNET_DONT: case TELNET_DONT:
switch (q.him) { switch (q.him) {
case RFC1143_NO: case RFC1143_NO:
break; break;
case RFC1143_YES: case RFC1143_YES:
q.him = RFC1143_WANTNO; q.him = RFC1143_WANTNO;
_set_rfc1143(telnet, q); _set_rfc1143(telnet, q);
_negotiate(telnet, LIBTELNET_DONT, telopt); _negotiate(telnet, TELNET_DONT, telopt);
break; break;
case RFC1143_WANTNO: case RFC1143_WANTNO:
break; break;
@ -796,20 +796,20 @@ void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd,
} }
/* send non-command data (escapes IAC bytes) */ /* send non-command data (escapes IAC bytes) */
void libtelnet_send_data(libtelnet_t *telnet, const char *buffer, void telnet_send_data(telnet_t *telnet, const char *buffer,
size_t size) { size_t size) {
size_t i, l; size_t i, l;
for (l = i = 0; i != size; ++i) { for (l = i = 0; i != size; ++i) {
/* dump prior portion of text, send escaped bytes */ /* dump prior portion of text, send escaped bytes */
if (buffer[i] == LIBTELNET_IAC) { if (buffer[i] == TELNET_IAC) {
/* dump prior text if any */ /* dump prior text if any */
if (i != l) if (i != l)
_send(telnet, buffer + l, i - l); _send(telnet, buffer + l, i - l);
l = i + 1; l = i + 1;
/* send escape */ /* send escape */
libtelnet_send_command(telnet, LIBTELNET_IAC); telnet_send_command(telnet, TELNET_IAC);
} }
} }
@ -819,67 +819,50 @@ void libtelnet_send_data(libtelnet_t *telnet, const char *buffer,
} }
/* send sub-request */ /* send sub-request */
void libtelnet_send_subnegotiation(libtelnet_t *telnet, unsigned char telopt, void telnet_send_subnegotiation(telnet_t *telnet, unsigned char telopt,
const char *buffer, size_t size) { const char *buffer, size_t size) {
libtelnet_send_telopt(telnet, LIBTELNET_SB, telopt); telnet_send_telopt(telnet, TELNET_SB, telopt);
libtelnet_send_data(telnet, buffer, size); telnet_send_data(telnet, buffer, size);
libtelnet_send_command(telnet, LIBTELNET_SE); telnet_send_command(telnet, TELNET_SE);
#ifdef HAVE_ZLIB #ifdef HAVE_ZLIB
/* if we're a proxy and we just sent the COMPRESS2 marker, we must /* if we're a proxy and we just sent the COMPRESS2 marker, we must
* make sure all further data is compressed if not already. * make sure all further data is compressed if not already.
*/ */
if (telnet->flags & LIBTELNET_FLAG_PROXY && if (telnet->flags & TELNET_FLAG_PROXY &&
telopt == LIBTELNET_TELOPT_COMPRESS2) { telopt == TELNET_TELOPT_COMPRESS2) {
if (_init_zlib(telnet, 1, 1) != LIBTELNET_EOK) if (_init_zlib(telnet, 1, 1) != TELNET_EOK)
return; return;
/* notify app that compression was enabled */ /* notify app that compression was enabled */
_event(telnet, LIBTELNET_EV_COMPRESS, 1, 0, 0, 0); _event(telnet, TELNET_EV_COMPRESS, 1, 0, 0, 0);
} }
#endif /* HAVE_ZLIB */ #endif /* HAVE_ZLIB */
} }
void libtelnet_begin_compress2(libtelnet_t *telnet) { void telnet_begin_compress2(telnet_t *telnet) {
#ifdef HAVE_ZLIB #ifdef HAVE_ZLIB
static const char compress2[] = { LIBTELNET_IAC, LIBTELNET_SB, static const char compress2[] = { TELNET_IAC, TELNET_SB,
LIBTELNET_TELOPT_COMPRESS2, LIBTELNET_IAC, LIBTELNET_SE }; TELNET_TELOPT_COMPRESS2, TELNET_IAC, TELNET_SE };
/* attempt to create output stream first, bail if we can't */ /* attempt to create output stream first, bail if we can't */
if (_init_zlib(telnet, 1, 0) != LIBTELNET_EOK) if (_init_zlib(telnet, 1, 0) != TELNET_EOK)
return; return;
/* send compression marker. we send directly to the event handler /* send compression marker. we send directly to the event handler
* instead of passing through _send because _send would result in * instead of passing through _send because _send would result in
* the compress marker itself being compressed. * the compress marker itself being compressed.
*/ */
_event(telnet, LIBTELNET_EV_SEND, 0, 0, compress2, sizeof(compress2)); _event(telnet, TELNET_EV_SEND, 0, 0, compress2, sizeof(compress2));
/* notify app that compression was successfully enabled */ /* notify app that compression was successfully enabled */
_event(telnet, LIBTELNET_EV_COMPRESS, 1, 0, 0, 0); _event(telnet, TELNET_EV_COMPRESS, 1, 0, 0, 0);
#endif /* HAVE_ZLIB */ #endif /* HAVE_ZLIB */
} }
/* send formatted data through libtelnet_send_data */
int libtelnet_printf(libtelnet_t *telnet, const char *fmt, ...) {
char buffer[4096];
va_list va;
int rs;
/* format */
va_start(va, fmt);
rs = vsnprintf(buffer, sizeof(buffer), fmt, va);
va_end(va);
/* send */
libtelnet_send_data(telnet, (char *)buffer, rs);
return rs;
}
/* send formatted data with \r and \n translation in addition to IAC IAC */ /* send formatted data with \r and \n translation in addition to IAC IAC */
int libtelnet_printf2(libtelnet_t *telnet, const char *fmt, ...) { int telnet_printf(telnet_t *telnet, const char *fmt, ...) {
static const char CRLF[] = { '\r', '\n' }; static const char CRLF[] = { '\r', '\n' };
static const char CRNUL[] = { '\r', '\0' }; static const char CRNUL[] = { '\r', '\0' };
char buffer[4096]; char buffer[4096];
@ -894,7 +877,7 @@ int libtelnet_printf2(libtelnet_t *telnet, const char *fmt, ...) {
/* send */ /* send */
for (l = i = 0; i != rs; ++i) { for (l = i = 0; i != rs; ++i) {
/* special characters */ /* special characters */
if (buffer[i] == LIBTELNET_IAC || buffer[i] == '\r' || if (buffer[i] == TELNET_IAC || buffer[i] == '\r' ||
buffer[i] == '\n') { buffer[i] == '\n') {
/* dump prior portion of text */ /* dump prior portion of text */
if (i != l) if (i != l)
@ -902,8 +885,8 @@ int libtelnet_printf2(libtelnet_t *telnet, const char *fmt, ...) {
l = i + 1; l = i + 1;
/* IAC -> IAC IAC */ /* IAC -> IAC IAC */
if (buffer[i] == LIBTELNET_IAC) if (buffer[i] == TELNET_IAC)
libtelnet_send_command(telnet, LIBTELNET_IAC); telnet_send_command(telnet, TELNET_IAC);
/* automatic translation of \r -> CRNUL */ /* automatic translation of \r -> CRNUL */
else if (buffer[i] == '\r') else if (buffer[i] == '\r')
_send(telnet, CRNUL, 2); _send(telnet, CRNUL, 2);
@ -919,3 +902,20 @@ int libtelnet_printf2(libtelnet_t *telnet, const char *fmt, ...) {
return rs; return rs;
} }
/* send formatted data through telnet_send_data */
int telnet_printf2(telnet_t *telnet, const char *fmt, ...) {
char buffer[4096];
va_list va;
int rs;
/* format */
va_start(va, fmt);
rs = vsnprintf(buffer, sizeof(buffer), fmt, va);
va_end(va);
/* send */
telnet_send_data(telnet, (char *)buffer, rs);
return rs;
}

View File

@ -13,132 +13,132 @@
#define LIBTELNET_INCLUDE 1 #define LIBTELNET_INCLUDE 1
/* forward declarations */ /* forward declarations */
typedef struct libtelnet_t libtelnet_t; typedef struct telnet_t telnet_t;
typedef struct libtelnet_event_t libtelnet_event_t; typedef struct telnet_event_t telnet_event_t;
typedef struct libtelnet_rfc1143_t libtelnet_rfc1143_t; typedef struct telnet_rfc1143_t telnet_rfc1143_t;
/* telnet special values */ /* telnet special values */
#define LIBTELNET_IAC 255 #define TELNET_IAC 255
#define LIBTELNET_DONT 254 #define TELNET_DONT 254
#define LIBTELNET_DO 253 #define TELNET_DO 253
#define LIBTELNET_WONT 252 #define TELNET_WONT 252
#define LIBTELNET_WILL 251 #define TELNET_WILL 251
#define LIBTELNET_SB 250 #define TELNET_SB 250
#define LIBTELNET_SB 250 #define TELNET_SB 250
#define LIBTELNET_GA 249 #define TELNET_GA 249
#define LIBTELNET_EL 248 #define TELNET_EL 248
#define LIBTELNET_EC 247 #define TELNET_EC 247
#define LIBTELNET_AYT 246 #define TELNET_AYT 246
#define LIBTELNET_AO 245 #define TELNET_AO 245
#define LIBTELNET_IP 244 #define TELNET_IP 244
#define LIBTELNET_BREAK 243 #define TELNET_BREAK 243
#define LIBTELNET_DM 242 #define TELNET_DM 242
#define LIBTELNET_NOP 241 #define TELNET_NOP 241
#define LIBTELNET_SE 240 #define TELNET_SE 240
#define LIBTELNET_EOR 239 #define TELNET_EOR 239
#define LIBTELNET_ABORT 238 #define TELNET_ABORT 238
#define LIBTELNET_SUSP 237 #define TELNET_SUSP 237
#define LIBTELNET_EOF 236 #define TELNET_EOF 236
/* telnet options */ /* telnet options */
#define LIBTELNET_TELOPT_BINARY 0 #define TELNET_TELOPT_BINARY 0
#define LIBTELNET_TELOPT_ECHO 1 #define TELNET_TELOPT_ECHO 1
#define LIBTELNET_TELOPT_RCP 2 #define TELNET_TELOPT_RCP 2
#define LIBTELNET_TELOPT_SGA 3 #define TELNET_TELOPT_SGA 3
#define LIBTELNET_TELOPT_NAMS 4 #define TELNET_TELOPT_NAMS 4
#define LIBTELNET_TELOPT_STATUS 5 #define TELNET_TELOPT_STATUS 5
#define LIBTELNET_TELOPT_TM 6 #define TELNET_TELOPT_TM 6
#define LIBTELNET_TELOPT_RCTE 7 #define TELNET_TELOPT_RCTE 7
#define LIBTELNET_TELOPT_NAOL 8 #define TELNET_TELOPT_NAOL 8
#define LIBTELNET_TELOPT_NAOP 9 #define TELNET_TELOPT_NAOP 9
#define LIBTELNET_TELOPT_NAOCRD 10 #define TELNET_TELOPT_NAOCRD 10
#define LIBTELNET_TELOPT_NAOHTS 11 #define TELNET_TELOPT_NAOHTS 11
#define LIBTELNET_TELOPT_NAOHTD 12 #define TELNET_TELOPT_NAOHTD 12
#define LIBTELNET_TELOPT_NAOFFD 13 #define TELNET_TELOPT_NAOFFD 13
#define LIBTELNET_TELOPT_NAOVTS 14 #define TELNET_TELOPT_NAOVTS 14
#define LIBTELNET_TELOPT_NAOVTD 15 #define TELNET_TELOPT_NAOVTD 15
#define LIBTELNET_TELOPT_NAOLFD 16 #define TELNET_TELOPT_NAOLFD 16
#define LIBTELNET_TELOPT_XASCII 17 #define TELNET_TELOPT_XASCII 17
#define LIBTELNET_TELOPT_LOGOUT 18 #define TELNET_TELOPT_LOGOUT 18
#define LIBTELNET_TELOPT_BM 19 #define TELNET_TELOPT_BM 19
#define LIBTELNET_TELOPT_DET 20 #define TELNET_TELOPT_DET 20
#define LIBTELNET_TELOPT_SUPDUP 21 #define TELNET_TELOPT_SUPDUP 21
#define LIBTELNET_TELOPT_SUPDUPOUTPUT 22 #define TELNET_TELOPT_SUPDUPOUTPUT 22
#define LIBTELNET_TELOPT_SNDLOC 23 #define TELNET_TELOPT_SNDLOC 23
#define LIBTELNET_TELOPT_TTYPE 24 #define TELNET_TELOPT_TTYPE 24
#define LIBTELNET_TELOPT_EOR 25 #define TELNET_TELOPT_EOR 25
#define LIBTELNET_TELOPT_TUID 26 #define TELNET_TELOPT_TUID 26
#define LIBTELNET_TELOPT_OUTMRK 27 #define TELNET_TELOPT_OUTMRK 27
#define LIBTELNET_TELOPT_TTYLOC 28 #define TELNET_TELOPT_TTYLOC 28
#define LIBTELNET_TELOPT_3270REGIME 29 #define TELNET_TELOPT_3270REGIME 29
#define LIBTELNET_TELOPT_X3PAD 30 #define TELNET_TELOPT_X3PAD 30
#define LIBTELNET_TELOPT_NAWS 31 #define TELNET_TELOPT_NAWS 31
#define LIBTELNET_TELOPT_TSPEED 32 #define TELNET_TELOPT_TSPEED 32
#define LIBTELNET_TELOPT_LFLOW 33 #define TELNET_TELOPT_LFLOW 33
#define LIBTELNET_TELOPT_LINEMODE 34 #define TELNET_TELOPT_LINEMODE 34
#define LIBTELNET_TELOPT_XDISPLOC 35 #define TELNET_TELOPT_XDISPLOC 35
#define LIBTELNET_TELOPT_ENVIRON 36 #define TELNET_TELOPT_ENVIRON 36
#define LIBTELNET_TELOPT_AUTHENTICATION 37 #define TELNET_TELOPT_AUTHENTICATION 37
#define LIBTELNET_TELOPT_ENCRYPT 38 #define TELNET_TELOPT_ENCRYPT 38
#define LIBTELNET_TELOPT_NEW_ENVIRON 39 #define TELNET_TELOPT_NEW_ENVIRON 39
#define LIBTELNET_TELOPT_COMPRESS 85 #define TELNET_TELOPT_COMPRESS 85
#define LIBTELNET_TELOPT_COMPRESS2 86 #define TELNET_TELOPT_COMPRESS2 86
#define LIBTELNET_TELOPT_ZMP 93 #define TELNET_TELOPT_ZMP 93
#define LIBTELNET_TELOPT_EXOPL 255 #define TELNET_TELOPT_EXOPL 255
/* libtelnet feature flags */ /* libtelnet feature flags */
#define LIBTELNET_FLAG_PROXY (1<<0) #define TELNET_FLAG_PROXY (1<<0)
#define LIBTELNET_PFLAG_DEFLATE (1<<7) #define TELNET_PFLAG_DEFLATE (1<<7)
/* telnet states */ /* telnet states */
enum libtelnet_state_t { enum telnet_state_t {
LIBTELNET_STATE_DATA = 0, TELNET_STATE_DATA = 0,
LIBTELNET_STATE_IAC, TELNET_STATE_IAC,
LIBTELNET_STATE_DO, TELNET_STATE_DO,
LIBTELNET_STATE_DONT, TELNET_STATE_DONT,
LIBTELNET_STATE_WILL, TELNET_STATE_WILL,
LIBTELNET_STATE_WONT, TELNET_STATE_WONT,
LIBTELNET_STATE_SB, TELNET_STATE_SB,
LIBTELNET_STATE_SB_DATA, TELNET_STATE_SB_DATA,
LIBTELNET_STATE_SB_DATA_IAC TELNET_STATE_SB_DATA_IAC
}; };
typedef enum libtelnet_state_t libtelnet_state_t; typedef enum telnet_state_t telnet_state_t;
/* error codes */ /* error codes */
enum libtelnet_error_t { enum telnet_error_t {
LIBTELNET_EOK = 0, TELNET_EOK = 0,
LIBTELNET_EBADVAL, /* invalid parameter, or API misuse */ TELNET_EBADVAL, /* invalid parameter, or API misuse */
LIBTELNET_ENOMEM, /* memory allocation failure */ TELNET_ENOMEM, /* memory allocation failure */
LIBTELNET_EOVERFLOW, /* data exceeds buffer size */ TELNET_EOVERFLOW, /* data exceeds buffer size */
LIBTELNET_EPROTOCOL, /* invalid sequence of special bytes */ TELNET_EPROTOCOL, /* invalid sequence of special bytes */
LIBTELNET_ECOMPRESS /* error handling compressed streams */ TELNET_ECOMPRESS /* error handling compressed streams */
}; };
typedef enum libtelnet_error_t libtelnet_error_t; typedef enum telnet_error_t telnet_error_t;
/* event codes */ /* event codes */
enum libtelnet_event_type_t { enum telnet_event_type_t {
LIBTELNET_EV_DATA = 0, TELNET_EV_DATA = 0,
LIBTELNET_EV_SEND, TELNET_EV_SEND,
LIBTELNET_EV_IAC, TELNET_EV_IAC,
LIBTELNET_EV_WILL, TELNET_EV_WILL,
LIBTELNET_EV_WONT, TELNET_EV_WONT,
LIBTELNET_EV_DO, TELNET_EV_DO,
LIBTELNET_EV_DONT, TELNET_EV_DONT,
LIBTELNET_EV_SUBNEGOTIATION, TELNET_EV_SUBNEGOTIATION,
LIBTELNET_EV_COMPRESS, TELNET_EV_COMPRESS,
LIBTELNET_EV_WARNING, TELNET_EV_WARNING,
LIBTELNET_EV_ERROR TELNET_EV_ERROR
}; };
typedef enum libtelnet_event_type_t libtelnet_event_type_t; typedef enum telnet_event_type_t telnet_event_type_t;
/* event information */ /* event information */
struct libtelnet_event_t { struct telnet_event_t {
/* data buffer: for DATA, SEND, SUBNEGOTIATION, and ERROR events */ /* data buffer: for DATA, SEND, SUBNEGOTIATION, and ERROR events */
const char *buffer; const char *buffer;
size_t size; size_t size;
/* type of event */ /* type of event */
enum libtelnet_event_type_t type; enum telnet_event_type_t type;
/* IAC command */ /* IAC command */
unsigned char command; unsigned char command;
/* telopt info: for negotiation events SUBNEGOTIATION */ /* telopt info: for negotiation events SUBNEGOTIATION */
@ -148,27 +148,27 @@ struct libtelnet_event_t {
}; };
/* option negotiation state (RFC 1143) */ /* option negotiation state (RFC 1143) */
struct libtelnet_rfc1143_t { struct telnet_rfc1143_t {
unsigned char telopt; unsigned char telopt;
char us:4, him:4; char us:4, him:4;
}; };
/* event handler declaration */ /* event handler declaration */
typedef void (*libtelnet_event_handler_t)(libtelnet_t *telnet, typedef void (*telnet_event_handler_t)(telnet_t *telnet,
libtelnet_event_t *event, void *user_data); telnet_event_t *event, void *user_data);
/* state tracker */ /* state tracker */
struct libtelnet_t { struct telnet_t {
/* user data */ /* user data */
void *ud; void *ud;
/* event handler */ /* event handler */
libtelnet_event_handler_t eh; telnet_event_handler_t eh;
#ifdef HAVE_ZLIB #ifdef HAVE_ZLIB
/* zlib (mccp2) compression */ /* zlib (mccp2) compression */
z_stream *z; z_stream *z;
#endif #endif
/* RFC1143 option negotiation states */ /* RFC1143 option negotiation states */
struct libtelnet_rfc1143_t *q; struct telnet_rfc1143_t *q;
/* sub-request buffer */ /* sub-request buffer */
char *buffer; char *buffer;
/* current size of the buffer */ /* current size of the buffer */
@ -176,7 +176,7 @@ struct libtelnet_t {
/* current buffer write position (also length of buffer data) */ /* current buffer write position (also length of buffer data) */
size_t buffer_pos; size_t buffer_pos;
/* current state */ /* current state */
enum libtelnet_state_t state; enum telnet_state_t state;
/* option flags */ /* option flags */
unsigned char flags; unsigned char flags;
/* current subnegotiation telopt */ /* current subnegotiation telopt */
@ -186,57 +186,58 @@ struct libtelnet_t {
}; };
/* initialize a telnet state tracker */ /* initialize a telnet state tracker */
extern void libtelnet_init(libtelnet_t *telnet, libtelnet_event_handler_t eh, extern void telnet_init(telnet_t *telnet, telnet_event_handler_t eh,
unsigned char flags, void *user_data); unsigned char flags, void *user_data);
/* free up any memory allocated by a state tracker */ /* free up any memory allocated by a state tracker */
extern void libtelnet_free(libtelnet_t *telnet); extern void telnet_free(telnet_t *telnet);
/* push a byte buffer into the state tracker */ /* push a byte buffer into the state tracker */
extern void libtelnet_push(libtelnet_t *telnet, const char *buffer, extern void telnet_push(telnet_t *telnet, const char *buffer,
size_t size); size_t size);
/* send an iac command */ /* send an iac command */
extern void libtelnet_send_command(libtelnet_t *telnet, unsigned char cmd); extern void telnet_send_command(telnet_t *telnet, unsigned char cmd);
/* send an iac command with a telopt */ /* send an iac command with a telopt */
extern void libtelnet_send_telopt(libtelnet_t *telnet, unsigned char cmd, extern void telnet_send_telopt(telnet_t *telnet, unsigned char cmd,
unsigned char telopt); unsigned char telopt);
/* send negotiation, with RFC1143 checking. /* send negotiation, with RFC1143 checking.
* will not actually send unless necessary, but will update internal * will not actually send unless necessary, but will update internal
* negotiation queue. * negotiation queue.
*/ */
extern void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd, extern void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
unsigned char opt); unsigned char opt);
/* send non-command data (escapes IAC bytes) */ /* send non-command data (escapes IAC bytes) */
extern void libtelnet_send_data(libtelnet_t *telnet, extern void telnet_send_data(telnet_t *telnet,
const char *buffer, size_t size); const char *buffer, size_t size);
/* send sub-request, equivalent to: /* send sub-request, equivalent to:
* libtelnet_send_telopt(telnet, LIBTELNET_SB, telopt) * telnet_send_telopt(telnet, TELNET_SB, telopt)
* libtelnet_send_data(telnet, buffer, size); * telnet_send_data(telnet, buffer, size);
* libtelnet_send_command(telnet, LIBTELNET_SE); * telnet_send_command(telnet, TELNET_SE);
* manually generating sequence may be easier for complex subnegotiations * manually generating sequence may be easier for complex subnegotiations
* thare are most easily implemented with a series of send_data calls. * thare are most easily implemented with a series of send_data calls.
*/ */
extern void libtelnet_send_subnegotiation(libtelnet_t *telnet, extern void telnet_send_subnegotiation(telnet_t *telnet,
unsigned char telopt, const char *buffer, size_t size); unsigned char telopt, const char *buffer, size_t size);
/* begin sending compressed data (server only) */ /* begin sending compressed data (server only) */
extern void libtelnet_begin_compress2(libtelnet_t *telnet); extern void telnet_begin_compress2(telnet_t *telnet);
/* send formatted data (through libtelnet_send_data) */ /* printf type checking feature in GCC and some other compilers */
#ifdef __GNUC__ #ifdef __GNUC__
# define LIBTELNET_GNU_PRINTF(f,a) __attribute__((printf(f, a))) # define TELNET_GNU_PRINTF(f,a) __attribute__((printf(f, a)))
#else #else
# define LIBTELNET_GNU_PRINTF(f,a) # define TELNET_GNU_PRINTF(f,a)
#endif #endif
extern int libtelnet_printf(libtelnet_t *telnet, const char *fmt, ...); /* send formatted data with \r and \n translated, and IAC escaped */
extern int telnet_printf(telnet_t *telnet, const char *fmt, ...);
/* send formatted data with \r and \n translated */ /* send formatted data with just IAC escaped */
extern int libtelnet_printf2(libtelnet_t *telnet, const char *fmt, ...); extern int telnet_printf2(telnet_t *telnet, const char *fmt, ...);
#endif /* !defined(LIBTELNET_INCLUDE) */ #endif /* !defined(LIBTELNET_INCLUDE) */

View File

@ -29,7 +29,7 @@
#include "libtelnet.h" #include "libtelnet.h"
static struct termios orig_tios; static struct termios orig_tios;
static libtelnet_t telnet; static telnet_t telnet;
static int do_echo; static int do_echo;
static void _cleanup(void) { static void _cleanup(void) {
@ -48,11 +48,11 @@ static void _input(char *buffer, int size) {
if (buffer[i] == '\r' || buffer[i] == '\n') { if (buffer[i] == '\r' || buffer[i] == '\n') {
if (do_echo) if (do_echo)
write(STDOUT_FILENO, crlf, 2); write(STDOUT_FILENO, crlf, 2);
libtelnet_send_data(&telnet, crlf, 2); telnet_send_data(&telnet, crlf, 2);
} else { } else {
if (do_echo) if (do_echo)
write(STDOUT_FILENO, buffer + i, 1); write(STDOUT_FILENO, buffer + i, 1);
libtelnet_send_data(&telnet, buffer + i, 1); telnet_send_data(&telnet, buffer + i, 1);
} }
} }
} }
@ -76,49 +76,49 @@ static void _send(int sock, const char *buffer, size_t size) {
} }
} }
static void _event_handler(libtelnet_t *telnet, libtelnet_event_t *ev, static void _event_handler(telnet_t *telnet, telnet_event_t *ev,
void *user_data) { void *user_data) {
int sock = *(int*)user_data; int sock = *(int*)user_data;
switch (ev->type) { switch (ev->type) {
/* data received */ /* data received */
case LIBTELNET_EV_DATA: case TELNET_EV_DATA:
write(STDOUT_FILENO, ev->buffer, ev->size); write(STDOUT_FILENO, ev->buffer, ev->size);
break; break;
/* data must be sent */ /* data must be sent */
case LIBTELNET_EV_SEND: case TELNET_EV_SEND:
_send(sock, ev->buffer, ev->size); _send(sock, ev->buffer, ev->size);
break; break;
/* request to enable remote feature (or receipt) */ /* request to enable remote feature (or receipt) */
case LIBTELNET_EV_WILL: case TELNET_EV_WILL:
/* we accept COMPRESS2 (MCCP) */ /* we accept COMPRESS2 (MCCP) */
if (ev->telopt == LIBTELNET_TELOPT_COMPRESS2) if (ev->telopt == TELNET_TELOPT_COMPRESS2)
ev->accept = 1; ev->accept = 1;
/* we'll agree to turn off our echo if server wants us to stop */ /* we'll agree to turn off our echo if server wants us to stop */
else if (ev->telopt == LIBTELNET_TELOPT_ECHO) { else if (ev->telopt == TELNET_TELOPT_ECHO) {
do_echo = 0; do_echo = 0;
ev->accept = 1; ev->accept = 1;
} }
break; break;
/* notification of disabling remote feature (or receipt) */ /* notification of disabling remote feature (or receipt) */
case LIBTELNET_EV_WONT: case TELNET_EV_WONT:
if (ev->telopt == LIBTELNET_TELOPT_ECHO) if (ev->telopt == TELNET_TELOPT_ECHO)
do_echo = 1; do_echo = 1;
break; break;
/* request to enable local feature (or receipt) */ /* request to enable local feature (or receipt) */
case LIBTELNET_EV_DO: case TELNET_EV_DO:
/* we support the TTYPE option */ /* we support the TTYPE option */
if (ev->telopt == LIBTELNET_TELOPT_TTYPE) if (ev->telopt == TELNET_TELOPT_TTYPE)
ev->accept = 1; ev->accept = 1;
break; break;
/* demand to disable local feature (or receipt) */ /* demand to disable local feature (or receipt) */
case LIBTELNET_EV_DONT: case TELNET_EV_DONT:
break; break;
/* respond to particular subnegotiations */ /* respond to particular subnegotiations */
case LIBTELNET_EV_SUBNEGOTIATION: case TELNET_EV_SUBNEGOTIATION:
/* respond with our terminal type */ /* respond with our terminal type */
if (ev->telopt == LIBTELNET_TELOPT_TTYPE) { if (ev->telopt == TELNET_TELOPT_TTYPE) {
/* NOTE: we just assume the server sent a legitimate /* NOTE: we just assume the server sent a legitimate
* sub-negotiation, as there really isn't anything else * sub-negotiation, as there really isn't anything else
* it's allowed to send * it's allowed to send
@ -126,12 +126,12 @@ static void _event_handler(libtelnet_t *telnet, libtelnet_event_t *ev,
char buffer[64]; char buffer[64];
buffer[0] = 0; /* IS code for RFC 1091 */ buffer[0] = 0; /* IS code for RFC 1091 */
snprintf(buffer + 1, sizeof(buffer) - 1, "%s", getenv("TERM")); snprintf(buffer + 1, sizeof(buffer) - 1, "%s", getenv("TERM"));
libtelnet_send_subnegotiation(telnet, LIBTELNET_TELOPT_TTYPE, telnet_send_subnegotiation(telnet, TELNET_TELOPT_TTYPE,
(char *)buffer, 1 + strlen(buffer + 1)); (char *)buffer, 1 + strlen(buffer + 1));
} }
break; break;
/* error */ /* error */
case LIBTELNET_EV_ERROR: case TELNET_EV_ERROR:
fprintf(stderr, "ERROR: %s\n", ev->buffer); fprintf(stderr, "ERROR: %s\n", ev->buffer);
exit(1); exit(1);
default: default:
@ -202,7 +202,7 @@ int main(int argc, char **argv) {
do_echo = 1; do_echo = 1;
/* initialize telnet box */ /* initialize telnet box */
libtelnet_init(&telnet, _event_handler, 0, &sock); telnet_init(&telnet, _event_handler, 0, &sock);
/* initialize poll descriptors */ /* initialize poll descriptors */
memset(pfd, 0, sizeof(pfd)); memset(pfd, 0, sizeof(pfd));
@ -229,7 +229,7 @@ int main(int argc, char **argv) {
/* read from client */ /* read from client */
if (pfd[1].revents & POLLIN) { if (pfd[1].revents & POLLIN) {
if ((rs = recv(sock, buffer, sizeof(buffer), 0)) > 0) { if ((rs = recv(sock, buffer, sizeof(buffer), 0)) > 0) {
libtelnet_push(&telnet, buffer, rs); telnet_push(&telnet, buffer, rs);
} else if (rs == 0) { } else if (rs == 0) {
break; break;
} else { } else {
@ -241,7 +241,7 @@ int main(int argc, char **argv) {
} }
/* clean up */ /* clean up */
libtelnet_free(&telnet); telnet_free(&telnet);
close(sock); close(sock);
return 0; return 0;

View File

@ -44,7 +44,7 @@
struct conn_t { struct conn_t {
const char *name; const char *name;
int sock; int sock;
libtelnet_t telnet; telnet_t telnet;
struct conn_t *remote; struct conn_t *remote;
}; };
@ -165,21 +165,21 @@ static void _send(int sock, const char *buffer, size_t size) {
} }
} }
static void _event_handler(libtelnet_t *telnet, libtelnet_event_t *ev, static void _event_handler(telnet_t *telnet, telnet_event_t *ev,
void *user_data) { void *user_data) {
struct conn_t *conn = (struct conn_t*)user_data; struct conn_t *conn = (struct conn_t*)user_data;
switch (ev->type) { switch (ev->type) {
/* data received */ /* data received */
case LIBTELNET_EV_DATA: case TELNET_EV_DATA:
printf("%s DATA: ", conn->name); printf("%s DATA: ", conn->name);
print_buffer(ev->buffer, ev->size); print_buffer(ev->buffer, ev->size);
printf(COLOR_NORMAL "\n"); printf(COLOR_NORMAL "\n");
libtelnet_send_data(&conn->remote->telnet, ev->buffer, ev->size); telnet_send_data(&conn->remote->telnet, ev->buffer, ev->size);
break; break;
/* data must be sent */ /* data must be sent */
case LIBTELNET_EV_SEND: case TELNET_EV_SEND:
/* DONT SPAM /* DONT SPAM
printf("%s SEND: ", conn->name); printf("%s SEND: ", conn->name);
print_buffer(ev->buffer, ev->size); print_buffer(ev->buffer, ev->size);
@ -189,41 +189,41 @@ static void _event_handler(libtelnet_t *telnet, libtelnet_event_t *ev,
_send(conn->sock, ev->buffer, ev->size); _send(conn->sock, ev->buffer, ev->size);
break; break;
/* IAC command */ /* IAC command */
case LIBTELNET_EV_IAC: case TELNET_EV_IAC:
printf("%s IAC %s" COLOR_NORMAL "\n", conn->name, printf("%s IAC %s" COLOR_NORMAL "\n", conn->name,
get_cmd(ev->command)); get_cmd(ev->command));
libtelnet_send_command(&conn->remote->telnet, ev->command); telnet_send_command(&conn->remote->telnet, ev->command);
break; break;
/* negotiation, WILL */ /* negotiation, WILL */
case LIBTELNET_EV_WILL: case TELNET_EV_WILL:
printf("%s IAC WILL %d (%s)" COLOR_NORMAL "\n", conn->name, printf("%s IAC WILL %d (%s)" COLOR_NORMAL "\n", conn->name,
(int)ev->telopt, get_opt(ev->telopt)); (int)ev->telopt, get_opt(ev->telopt));
libtelnet_send_negotiate(&conn->remote->telnet, LIBTELNET_WILL, telnet_send_negotiate(&conn->remote->telnet, TELNET_WILL,
ev->telopt); ev->telopt);
break; break;
/* negotiation, WONT */ /* negotiation, WONT */
case LIBTELNET_EV_WONT: case TELNET_EV_WONT:
printf("%s IAC WONT %d (%s)" COLOR_NORMAL "\n", conn->name, printf("%s IAC WONT %d (%s)" COLOR_NORMAL "\n", conn->name,
(int)ev->telopt, get_opt(ev->telopt)); (int)ev->telopt, get_opt(ev->telopt));
libtelnet_send_negotiate(&conn->remote->telnet, LIBTELNET_WONT, telnet_send_negotiate(&conn->remote->telnet, TELNET_WONT,
ev->telopt); ev->telopt);
break; break;
/* negotiation, DO */ /* negotiation, DO */
case LIBTELNET_EV_DO: case TELNET_EV_DO:
printf("%s IAC DO %d (%s)" COLOR_NORMAL "\n", conn->name, printf("%s IAC DO %d (%s)" COLOR_NORMAL "\n", conn->name,
(int)ev->telopt, get_opt(ev->telopt)); (int)ev->telopt, get_opt(ev->telopt));
libtelnet_send_negotiate(&conn->remote->telnet, LIBTELNET_DO, telnet_send_negotiate(&conn->remote->telnet, TELNET_DO,
ev->telopt); ev->telopt);
break; break;
case LIBTELNET_EV_DONT: case TELNET_EV_DONT:
printf("%s IAC DONT %d (%s)" COLOR_NORMAL "\n", conn->name, printf("%s IAC DONT %d (%s)" COLOR_NORMAL "\n", conn->name,
(int)ev->telopt, get_opt(ev->telopt)); (int)ev->telopt, get_opt(ev->telopt));
libtelnet_send_negotiate(&conn->remote->telnet, LIBTELNET_DONT, telnet_send_negotiate(&conn->remote->telnet, TELNET_DONT,
ev->telopt); ev->telopt);
break; break;
/* subnegotiation */ /* subnegotiation */
case LIBTELNET_EV_SUBNEGOTIATION: case TELNET_EV_SUBNEGOTIATION:
printf("%s SUB %d (%s)", conn->name, (int)ev->telopt, printf("%s SUB %d (%s)", conn->name, (int)ev->telopt,
get_opt(ev->telopt)); get_opt(ev->telopt));
if (ev->size > 0) { if (ev->size > 0) {
@ -232,20 +232,20 @@ static void _event_handler(libtelnet_t *telnet, libtelnet_event_t *ev,
} }
printf(COLOR_NORMAL "\n"); printf(COLOR_NORMAL "\n");
libtelnet_send_subnegotiation(&conn->remote->telnet, ev->telopt, telnet_send_subnegotiation(&conn->remote->telnet, ev->telopt,
ev->buffer, ev->size); ev->buffer, ev->size);
break; break;
/* compression notification */ /* compression notification */
case LIBTELNET_EV_COMPRESS: case TELNET_EV_COMPRESS:
printf("%s COMPRESSION %s" COLOR_NORMAL "\n", conn->name, printf("%s COMPRESSION %s" COLOR_NORMAL "\n", conn->name,
ev->command ? "ON" : "OFF"); ev->command ? "ON" : "OFF");
break; break;
/* warning */ /* warning */
case LIBTELNET_EV_WARNING: case TELNET_EV_WARNING:
printf("%s WARNING: %s" COLOR_NORMAL "\n", conn->name, ev->buffer); printf("%s WARNING: %s" COLOR_NORMAL "\n", conn->name, ev->buffer);
break; break;
/* error */ /* error */
case LIBTELNET_EV_ERROR: case TELNET_EV_ERROR:
printf("%s ERROR: %s" COLOR_NORMAL "\n", conn->name, ev->buffer); printf("%s ERROR: %s" COLOR_NORMAL "\n", conn->name, ev->buffer);
exit(1); exit(1);
} }
@ -357,9 +357,9 @@ int main(int argc, char **argv) {
client.remote = &server; client.remote = &server;
/* initialize telnet boxes */ /* initialize telnet boxes */
libtelnet_init(&server.telnet, _event_handler, LIBTELNET_FLAG_PROXY, telnet_init(&server.telnet, _event_handler, TELNET_FLAG_PROXY,
&server); &server);
libtelnet_init(&client.telnet, _event_handler, LIBTELNET_FLAG_PROXY, telnet_init(&client.telnet, _event_handler, TELNET_FLAG_PROXY,
&client); &client);
/* initialize poll descriptors */ /* initialize poll descriptors */
@ -374,7 +374,7 @@ int main(int argc, char **argv) {
/* read from server */ /* read from server */
if (pfd[0].revents & POLLIN) { if (pfd[0].revents & POLLIN) {
if ((rs = recv(server.sock, buffer, sizeof(buffer), 0)) > 0) { if ((rs = recv(server.sock, buffer, sizeof(buffer), 0)) > 0) {
libtelnet_push(&server.telnet, buffer, rs); telnet_push(&server.telnet, buffer, rs);
} else if (rs == 0) { } else if (rs == 0) {
printf("%s DISCONNECTED" COLOR_NORMAL "\n", server.name); printf("%s DISCONNECTED" COLOR_NORMAL "\n", server.name);
break; break;
@ -388,7 +388,7 @@ int main(int argc, char **argv) {
/* read from client */ /* read from client */
if (pfd[1].revents & POLLIN) { if (pfd[1].revents & POLLIN) {
if ((rs = recv(client.sock, buffer, sizeof(buffer), 0)) > 0) { if ((rs = recv(client.sock, buffer, sizeof(buffer), 0)) > 0) {
libtelnet_push(&client.telnet, buffer, rs); telnet_push(&client.telnet, buffer, rs);
} else if (rs == 0) { } else if (rs == 0) {
printf("%s DISCONNECTED" COLOR_NORMAL "\n", client.name); printf("%s DISCONNECTED" COLOR_NORMAL "\n", client.name);
break; break;
@ -401,8 +401,8 @@ int main(int argc, char **argv) {
} }
/* clean up */ /* clean up */
libtelnet_free(&server.telnet); telnet_free(&server.telnet);
libtelnet_free(&client.telnet); telnet_free(&client.telnet);
close(server.sock); close(server.sock);
close(client.sock); close(client.sock);