Skip to content
This repository has been archived by the owner on Nov 27, 2024. It is now read-only.

Commit

Permalink
Implement incoming NVT EOL translation in process()
Browse files Browse the repository at this point in the history
The translation is enabled by a new bit in telnet_init() flags
parameter.

Remove telnet_translate_eol() since that function is subsumed.
  • Loading branch information
slcasner committed Aug 12, 2017
1 parent d99eb2a commit 5382149
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 69 deletions.
14 changes: 5 additions & 9 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ IIa. Initialization
Operate in proxy mode. This disables the RFC1143 support and
enables automatic detection of COMPRESS2 streams.

TELNET_FLAG_NVT_EOL
Receive data with translation of the TELNET NVT CR NUL and CR LF
sequences specified in RFC854 to C carriage return (\r) and C
newline (\n), respectively.

If telnet_init() fails to allocate the required memory, the
returned pointer will be zero.

Expand All @@ -145,15 +150,6 @@ IIb. Receiving Data
triggered for any regular data such as user input or server
process output.

size_t telnet_translate_eol(telnet_t *telnet,
char *buffer, size_t size, int *eol_was_split);
Scans a buffer received in a TELNET_EV_DATA event to translate the
TELNET NVT CR NUL and CR LF sequences specified in RFC854 to C
carriage return (\r) and C newline (\n), respectively. Sequences
split across a buffer boundary are handled using the eol_was_split
flag that should be initialized to 0 before the first call. The
possibly shorter length of the text after translation is returned.

IIc. Sending Data

All of the output functions will invoke the TELNET_EV_SEND event.
Expand Down
77 changes: 30 additions & 47 deletions libtelnet.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
/* telnet state codes */
enum telnet_state_t {
TELNET_STATE_DATA = 0,
TELNET_STATE_EOL,
TELNET_STATE_IAC,
TELNET_STATE_WILL,
TELNET_STATE_WONT,
Expand Down Expand Up @@ -105,10 +106,6 @@ struct telnet_t {
unsigned char q_size;
};

/* Internal-only bits in option flags */
#define TELNET_FLAG_TRANSMIT_BINARY (1<<1)
#define TELNET_FLAG_RECEIVE_BINARY (1<<2)

/* RFC1143 option negotiation state */
typedef struct telnet_rfc1143_t {
unsigned char telopt;
Expand Down Expand Up @@ -978,9 +975,38 @@ static void _process(telnet_t *telnet, const char *buffer, size_t size) {
telnet->eh(telnet, &ev, telnet->ud);
}
telnet->state = TELNET_STATE_IAC;
} else if (byte == '\r' &&
(telnet->flags & TELNET_FLAG_NVT_EOL) &&
!(telnet->flags & TELNET_FLAG_RECEIVE_BINARY)) {
if (i != start) {
ev.type = TELNET_EV_DATA;
ev.data.buffer = buffer + start;
ev.data.size = i - start;
telnet->eh(telnet, &ev, telnet->ud);
}
telnet->state = TELNET_STATE_EOL;
}
break;

/* NVT EOL to be translated */
case TELNET_STATE_EOL:
if (byte != '\n') {
byte = '\r';
ev.type = TELNET_EV_DATA;
ev.data.buffer = (char*)&byte;
ev.data.size = 1;
telnet->eh(telnet, &ev, telnet->ud);
byte = buffer[i];
}
// any byte following '\r' other than '\n' or '\0' is invalid,
// so pass both \r and the byte
start = i;
if (byte == '\0')
++start;
/* state update */
telnet->state = TELNET_STATE_DATA;
break;

/* IAC command */
case TELNET_STATE_IAC:
switch (byte) {
Expand Down Expand Up @@ -1137,49 +1163,6 @@ static void _process(telnet_t *telnet, const char *buffer, size_t size) {
}
}

/* perform NVT end-of-line translation for received text */
size_t telnet_translate_eol(telnet_t *telnet, char *buffer, size_t size,
int *eol_was_split) {
size_t i = 0, l = 0;
if (size == 0)
return size;

/* no translation if in BINARY mode */
if (telnet->flags & TELNET_FLAG_RECEIVE_BINARY)
return size;

/* fix up translation if split across buffer boundary */
if (*eol_was_split) {
/* CR-NUL translates to \r which was skipped at end of previous */
/* buffer, while CR-LF translates to \n, so just leave it */
if (buffer[i] == '\0') {
buffer[i] = '\r';
}
++i;
}

for ( ; i < size-1; ++i, ++l) {
buffer[l] = buffer[i];
if (buffer[i] == '\r') {
if (buffer[i+1] == '\n') {
/* CR-LF translates to \n */
buffer[l] = '\n';
++i;
} else if (buffer[i+1] == '\0') {
/* CR-NUL translates to \r */
++i;
}
}
}
if (buffer[i] == '\r') {
--l;
*eol_was_split = 1;
} else {
*eol_was_split = 0;
}
return l + 1;
}

/* push a bytes into the state tracker */
void telnet_recv(telnet_t *telnet, const char *buffer,
size_t size) {
Expand Down
17 changes: 4 additions & 13 deletions libtelnet.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,11 @@ typedef struct telnet_telopt_t telnet_telopt_t;
/*@{*/
/*! Control behavior of telnet state tracker. */
#define TELNET_FLAG_PROXY (1<<0)
#define TELNET_FLAG_NVT_EOL (1<<1)

/* Internal-only bits in option flags */
#define TELNET_FLAG_TRANSMIT_BINARY (1<<5)
#define TELNET_FLAG_RECEIVE_BINARY (1<<6)
#define TELNET_PFLAG_DEFLATE (1<<7)
/*@}*/

Expand Down Expand Up @@ -445,19 +449,6 @@ extern void telnet_send(telnet_t *telnet,
extern void telnet_send_text(telnet_t *telnet,
const char *buffer, size_t size);

/*!
* Translate NVT EOL byte sequences into local characters
* (CR-NUL -> \\r and CR-LF -> \\n) unless in BINARY mode.
*
* \param telnet Telnet state tracker object.
* \param buffer Buffer of bytes to translate.
* \param size Number of bytes to translate.
* \param split 1 if in the middle of EOL byte pair at start/end.
* \return Number of bytes after translation.
*/
extern size_t telnet_translate_eol(telnet_t *telnet,
char *buffer, size_t size, int *split);

/*!
* \brief Begin a sub-negotiation command.
*
Expand Down

0 comments on commit 5382149

Please sign in to comment.