Sean Middleditch | b9e4864 | 2009-03-12 23:33:27 -0400 | [diff] [blame] | 1 | ===================================================================== |
| 2 | libtelnet - TELNET protocol handling library |
| 3 | ===================================================================== |
| 4 | |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 5 | http://github.com/elanthis/libtelnet |
| 6 | |
| 7 | Sean Middleditch |
| 8 | sean@sourcemud.org |
Sean Middleditch | b9e4864 | 2009-03-12 23:33:27 -0400 | [diff] [blame] | 9 | |
| 10 | --------------------------------------------------------------------- |
| 11 | The author or authors of this code dedicate any and all copyright |
| 12 | interest in this code to the public domain. We make this dedication |
| 13 | for the benefit of the public at large and to the detriment of our |
| 14 | heirs and successors. We intend this dedication to be an overt act of |
| 15 | relinquishment in perpetuity of all present and future rights to this |
| 16 | code under copyright law. |
| 17 | --------------------------------------------------------------------- |
| 18 | |
Sean Middleditch | 9d2f98a | 2009-03-14 05:24:56 -0400 | [diff] [blame] | 19 | *** TODO *** |
| 20 | |
| 21 | - RFC 1143 option negotiation algorithm |
| 22 | - automatic MCCP2 handling (controllable by host app) |
| 23 | - efficient one-byte sub-requests |
| 24 | ? MCCP1 |
| 25 | ? ZMP parsing |
| 26 | ? MSSP parsing |
| 27 | ? ENVIRON/NEW-ENVIRON parsing |
| 28 | ? telnet-status testing tool |
| 29 | ? few options to make telnet-proxy even more useful |
| 30 | |
Sean Middleditch | b9e4864 | 2009-03-12 23:33:27 -0400 | [diff] [blame] | 31 | I. INTRODUCTION |
| 32 | ===================================================================== |
| 33 | |
| 34 | libtelnet provides safe and correct handling of the core TELNET |
| 35 | protocol. It does not include any "smarts," and all use of the |
| 36 | protocol (such as deciding which options to support, enabling |
| 37 | and disabling options, or processing subrequests) must be implemented |
| 38 | by the application author. |
| 39 | |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 40 | For more information on the TELNET protocol, see: |
| 41 | |
| 42 | http://www.faqs.org/rfcs/rfc854.html |
| 43 | |
Sean Middleditch | b9e4864 | 2009-03-12 23:33:27 -0400 | [diff] [blame] | 44 | II. LIBTELNET API |
| 45 | ===================================================================== |
| 46 | |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 47 | The libtelnet API contains several distinct parts. The first part is |
| 48 | the basic initialization and deinitialization routines. The second |
| 49 | part is a single function for pushing received data into the |
| 50 | libtelnet processor. The third part is the libtelnet_send_*() |
| 51 | functions, which generate TELNET commands and ensure data is properly |
| 52 | formatted before sending over the wire. The final part is the |
Sean Middleditch | 3032302 | 2009-03-14 21:45:28 -0400 | [diff] [blame] | 53 | callback structure libtelnet_cb_t. |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 54 | |
| 55 | IIa. Initialization |
| 56 | |
| 57 | struct libtelnet_t; |
| 58 | This structure represents the state of the TELNET protocol for a |
| 59 | single connection. Each connection utilizing TELNET must have |
| 60 | its own libtelnet_t structure, which is passed to all libtelnet |
| 61 | API calls. |
| 62 | |
Sean Middleditch | 3032302 | 2009-03-14 21:45:28 -0400 | [diff] [blame] | 63 | struct libtelnet_cb_t; |
| 64 | An instance of this structure must be initialized and have all |
| 65 | mandatory and desired optional callbacks set. See section IId |
| 66 | for more information. |
| 67 | |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 68 | void libtelnet_init(struct libtelnet_t *telnet, |
Sean Middleditch | 3032302 | 2009-03-14 21:45:28 -0400 | [diff] [blame] | 69 | struct libtelnet_cb_t *cb, enum libtelnet_mode_t mode); |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 70 | The libtelnet_init() function is responsible for initializing |
| 71 | the data in a libtelnet_t structure. It must be called |
| 72 | immediately after establishing a connection and before any other |
| 73 | libtelnet API calls are made. |
| 74 | |
Sean Middleditch | 3032302 | 2009-03-14 21:45:28 -0400 | [diff] [blame] | 75 | The cb parameter must be a pointer to a fully initialized |
| 76 | instance of libtelnet_cb_t. A single instance of the structure |
| 77 | can be shared between any number of libtelnet_t instances. |
| 78 | |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 79 | The mode parameter must be one of LIBTELNET_MODE_SERVER or |
| 80 | LIBTELNET_MODE_CLIENT. These slightly alter the behavior of |
| 81 | libtelnet in certain instances. If you are implementing a |
| 82 | TELNET server, use the SERVER mode. If you are implementing a |
| 83 | client, use the CLIENT mode. |
| 84 | |
| 85 | boid libtelnet_free(struct libtelnet_t *telnet); |
| 86 | Releases any internal memory allocated by libtelnet. This must |
| 87 | be called whenever a connection is closed, or you will incur |
| 88 | memory leaks. |
| 89 | |
| 90 | IIb. Receiving Data |
| 91 | |
| 92 | void libtelnet_push(struct libtelnet_t *telnet, |
| 93 | unsigned char *buffer, unsigned int size, void *user_data); |
| 94 | When your application receives data over the socket from the |
| 95 | remote end, it must pass the received bytes into this function. |
| 96 | Callback functions will be invoked as the buffer is processed, |
| 97 | and the user_data parameter will be passed to each callback. |
| 98 | |
| 99 | IIc. Sending Data |
| 100 | |
| 101 | Note that all of the libtelnet_send_*() functions will invoke |
Sean Middleditch | 3032302 | 2009-03-14 21:45:28 -0400 | [diff] [blame] | 102 | the send callback function attached to the libtelnet_t instance. |
| 103 | The user_data parameter to each of these functions is passed |
| 104 | through to the callback. |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 105 | |
| 106 | void libtelnet_send_command(struct libtelnet_t *telnet, |
| 107 | unsigned char cmd, void *user_data); |
| 108 | Sends a single "simple" TELNET command, such as the GO-AHEAD |
| 109 | commands (255 249). |
| 110 | |
| 111 | void libtelnet_send_negotiate(struct libtelnet_t *telnet, |
| 112 | unsigned char cmd, unsigned char opt, void *user_data); |
| 113 | Sends a TELNET negotiation command. The cmd parameter must be |
| 114 | one of LIBTELNET_WILL, LIBTELNET_DONT, LIBTELNET_DO, or |
| 115 | LIBTELNET_DONT. The opt parameter is the option to |
| 116 | negotiate. |
| 117 | |
| 118 | void libtelnet_send_data(struct libtelnet_t *telnet, |
| 119 | unsigned char *buffer, unsigned int size, void *user_data); |
| 120 | Sends raw data, which would be either the process output from |
| 121 | a server or the user input from a client. |
| 122 | |
| 123 | void libtelnet_send_subnegotiation(struct libtelnet_t *telnet, |
| 124 | unsigned char opt, unsigned char *buffer, unsigned int size, |
| 125 | void *user_data); |
| 126 | Sends a TELNET sub-negotiation command. The opt parameter |
| 127 | is the sub-negotiation option. |
| 128 | |
| 129 | IId. Callbacks |
| 130 | |
Sean Middleditch | 3032302 | 2009-03-14 21:45:28 -0400 | [diff] [blame] | 131 | The libtelnet_cb_t structure containers a number of callback |
| 132 | entry points. Of these, only the send and data callbacks are |
| 133 | absolutely required. All others are optional. The declarations |
| 134 | below show the signature of the callback functions. |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 135 | |
Sean Middleditch | 3032302 | 2009-03-14 21:45:28 -0400 | [diff] [blame] | 136 | An example of initializing a libtelnet_cb_t structure: |
| 137 | |
| 138 | /* illustrative data callback */ |
| 139 | void my_data_cb(libtelnet_t *telnet, unsigned char *buffer, |
| 140 | unsigned int size, void *user_data) { |
| 141 | /* print number of bytes received and then show the |
| 142 | * whole buffer */ |
| 143 | printf("RECV(%d): %.*s\n", size, size, buffer); |
| 144 | } |
| 145 | |
| 146 | /* illustrative variable definitions */ |
| 147 | libtelnet_t conn; |
| 148 | libtelnet_cb_t callbacks; |
| 149 | |
| 150 | /* clear all callbacks and set just the ones we want */ |
| 151 | memset(&callbacks, 0, sizeof(callbacks)); |
| 152 | callbacks->send = my_send_cb; |
| 153 | callbacks->data = my_data_cb; |
| 154 | |
| 155 | /* initialize the connection with our callbacks */ |
| 156 | libtelnet_init(&conn, &callbacks, LIBTELNET_MODE_SERVER); |
| 157 | |
| 158 | Remember that a single libtelnet_cb_t structure can be shared |
| 159 | between any number of libtelnet_t instances. There is no reason |
| 160 | to make multiple copies of the data if all of your connections |
| 161 | use the same callback functions. |
| 162 | |
| 163 | void libtelnet_cb_t->data(struct libtelnet_t *telnet, |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 164 | unsigned char *buffer, unsigned int size, void *user_data); |
| 165 | Regular data has been received by the remote end. For a server, |
| 166 | this would be input typed by the client; for a client, this is |
| 167 | process output generated by the server. |
| 168 | |
| 169 | Note that data is not line-buffered by libtelnet. A single |
| 170 | line of input may be broken into pieces and given to |
| 171 | consecutive calls to libtelnet_data_cb(). If you are doing |
| 172 | line-based processing of data, it is your responsibility to |
| 173 | buffer data and find the line breaks. |
| 174 | |
Sean Middleditch | 3032302 | 2009-03-14 21:45:28 -0400 | [diff] [blame] | 175 | void libtelnet_cb_t->send(struct libtelnet_t *telnet, |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 176 | unsigned char *buffer, unsigned int size, void *user_data); |
| 177 | This is called whenever libtelnet has generated output to be |
| 178 | send to the remote end of the connection. In most cases this |
| 179 | will be a simple wrapper arround your applications network |
| 180 | output buffering/transmission code. |
| 181 | |
| 182 | You can pass socket information through the user_data |
| 183 | parameter to libtelnet calls so that it is available in this |
| 184 | callback. |
| 185 | |
Sean Middleditch | 3032302 | 2009-03-14 21:45:28 -0400 | [diff] [blame] | 186 | void libtelnet_cb_t->command(struct libtelnet_t *telnet, |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 187 | unsigned char cmd, void *user_data); |
| 188 | Called whenever a "simpler" TELNET command has arrived, such |
| 189 | as GO-AHEAD commands (255 249). The necessary processing |
| 190 | depends on the specific commands; see the TELNET RFC for |
| 191 | more information. |
| 192 | |
Sean Middleditch | 3032302 | 2009-03-14 21:45:28 -0400 | [diff] [blame] | 193 | void libtelnet_cb_t->negotiate(struct libtelnet_t *telnet, |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 194 | unsigned char cmd, unsigned char opt, void *user_data); |
| 195 | This function is called whenever a TELNET negotiation command |
| 196 | has been received. The cmd parameter will be one of |
| 197 | LIBTELNET_WILL, LIBTELNET_WONT, LIBTELNET_DO, or LIBTELNET_DONT. |
| 198 | The opt parameter is the option being negotiated. |
| 199 | |
| 200 | libtelnet does not currently manage negotiation for you. For |
| 201 | best practice in implementing TELNET negotiation, see: |
| 202 | |
| 203 | http://www.faqs.org/rfcs/rfc1143.html |
| 204 | |
Sean Middleditch | 3032302 | 2009-03-14 21:45:28 -0400 | [diff] [blame] | 205 | void libtelnet_cb_t->subnegotiation(struct libtelnet_t *telnet, |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 206 | unsigned char opt, unsigned char *data, unsigned int size, |
| 207 | void *user_data); |
| 208 | Called whenever a TELNET sub-negotiation has been received. |
| 209 | Sub-negotiations include the NAWS option for communicating |
| 210 | terminal size to a server, the NEW-ENVIRON and TTYPE options |
| 211 | for negotiating terminal features, and MUD-centric protocols |
| 212 | such as ZMP, MSSP, and MCCP2. |
| 213 | |
| 214 | The opt parameter is the option under sub-negotiation. The |
| 215 | remaining data (if any) is passed in the buffer. |
| 216 | |
Sean Middleditch | 3032302 | 2009-03-14 21:45:28 -0400 | [diff] [blame] | 217 | void libtelnet_cb_t->compress(struct libtelnet_t *telnet, |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 218 | char enabled, void *user_data); |
| 219 | The callback is invoked whenever the COMPRESS2 (MCCP2) |
| 220 | feature is enabled or disabled. For servers, this is called |
| 221 | immediately after beginning compression after a client accepts |
| 222 | the COMPRESS2 option. For clients, this is called immediately |
| 223 | after a compress stream begin or ends. |
| 224 | |
| 225 | The enabled parameter is 1 if compression has begun and 0 if |
| 226 | compression has ended. |
Sean Middleditch | b9e4864 | 2009-03-12 23:33:27 -0400 | [diff] [blame] | 227 | |
| 228 | III. INTEGRATING LIBTELNET |
| 229 | ===================================================================== |
| 230 | |
| 231 | FIXME: fill in notes about implementing the libtelnet_*_cb functions |
| 232 | |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 233 | IV. SAFETY AND CORRECTNESS CONSIDERATIONS |
Sean Middleditch | b9e4864 | 2009-03-12 23:33:27 -0400 | [diff] [blame] | 234 | ===================================================================== |
| 235 | |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 236 | Your existing application may make heavy use of its own output |
| 237 | buffering and transmission commands, including hand-made routines |
| 238 | for sending TELNET commands and sub-negotiation requests. There are |
| 239 | at times subtle issues that need to be handled when communication |
| 240 | over the TELNET protocol, not least of which is the need to escape |
| 241 | any byte value 0xFF with a special TELNET command. |
Sean Middleditch | b9e4864 | 2009-03-12 23:33:27 -0400 | [diff] [blame] | 242 | |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 243 | For these reasons, it is very important that applications making use |
| 244 | of libtelnet always make use of the libtelnet_send_*() family of |
| 245 | functions for all data being sent over the TELNET connection. |
| 246 | |
| 247 | V. MCCP2 COMPRESSION |
Sean Middleditch | b9e4864 | 2009-03-12 23:33:27 -0400 | [diff] [blame] | 248 | ===================================================================== |
| 249 | |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 250 | The MCCP2 (COMPRESS2) TELNET extension allows for the compression of |
| 251 | all traffic sent from server to client. For more information: |
| 252 | |
| 253 | http://www.mudbytes.net/index.php?a=articles&s=mccp |
| 254 | |
| 255 | libtelnet transparently supports MCCP2. For a server to support |
| 256 | MCCP2, the application must begin negotiation of the COMPRESS2 |
| 257 | option using libtelnet_send_negotiate(), for example: |
| 258 | |
| 259 | libtelnet_send_negotiate(&telnet, LIBTELNET_WILL, |
| 260 | LIBTELNET_OPTION_COMPRESS2, user_data); |
| 261 | |
| 262 | libtelnet will automatically detect if the client responds favoribly |
| 263 | and will begin compressing data. For clients, no action must be |
| 264 | taken, as libtelnet will automatically handle the requests. |
| 265 | |
| 266 | NOTE: libtelnet will still invoke the callback functions for |
| 267 | negotiation and sub-negotiation commands relating to MCCP2. Do not |
| 268 | respond to these. |
| 269 | |
| 270 | In order for libtelnet to support MCCP2, zlib must be installed and |
| 271 | enabled when compiling libtelnet. Use -DHAVE_ZLIB to enable zlib |
| 272 | when compiling libtelnet.c and pass -lz to the linker to link in the |
| 273 | zlib shared library. |
| 274 | |
| 275 | VI. TELNET PROXY UTILITY |
| 276 | ===================================================================== |
| 277 | |
| 278 | The telnet-proxy utility is a small application that serves both as |
| 279 | a testbed for libtelnet and as a powerful debugging tool for TELNET |
| 280 | servers and clients. |
| 281 | |
| 282 | To use telnet-proxy, you must first compile it using: |
| 283 | |
| 284 | $ make |
| 285 | |
| 286 | If you do not have zlib installed and wish to disable MCCP2 support |
| 287 | then you must first edit the Makefile and remove the -DHAVE_ZLIB and |
| 288 | the -lz from the compile flags. |
| 289 | |
Sean Middleditch | d88f183 | 2009-03-15 01:06:17 -0400 | [diff] [blame^] | 290 | To run telnet-proxy, you simply give it the server's host name or |
| 291 | IP address, the server's port number, and the port number that |
| 292 | telnet-proxy should listen on. For example, to connect to the server |
| 293 | on mud.example.com port 7800 and to listen on port 5000, run: |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 294 | |
Sean Middleditch | d88f183 | 2009-03-15 01:06:17 -0400 | [diff] [blame^] | 295 | $ ./telnet-proxy mud.example.com 7800 5000 |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 296 | |
| 297 | You can then connect to the host telnet-proxy is running on (e.g. |
Sean Middleditch | d88f183 | 2009-03-15 01:06:17 -0400 | [diff] [blame^] | 298 | 127.0.0.1) on port 500 and you will automatically be proxied into |
| 299 | mud.example.com. |
Sean Middleditch | 892c5f1 | 2009-03-14 13:39:07 -0400 | [diff] [blame] | 300 | |
| 301 | telnet-proxy will display status information about the data |
| 302 | passing through both ends of the tunnel. Once either end |
| 303 | disconnects, telnet-proxy will close. telnet-proxy can only |
| 304 | support a single tunnel at a time and must be restarted for each |
| 305 | connection. |