Move ttynvt source to src/

This commit is contained in:
Kim Woelders
2019-09-03 18:29:31 +02:00
committed by Kim Woelders
parent cf6b334bcc
commit e3675b9e89
9 changed files with 17 additions and 16 deletions
+13
View File
@@ -0,0 +1,13 @@
CFLAGS_OPT = -O3
CFLAGS_WARN = -Wall -Wextra -Werror -Wno-unused-parameter
bin_PROGRAMS = ttynvt
ttynvt_SOURCES = \
ttynvt.c \
telnet_basic.c telnet_rfc2217.c telnet.h telnet_param.h
ttynvt_CPPFLAGS = -I$(top_builddir) $(FUSE_CFLAGS) $(CFLAGS_OPT) $(CFLAGS_WARN)
ttynvt_LDADD = $(FUSE_LIBS)
+70
View File
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2018 Lars Thrane A/S
* SPDX-License-Identifier: GPL-2.0
*
* Telnet interface
*/
#ifndef TELNET_H
#define TELNET_H
typedef int (srv_tx_f) (void *cctx, const void *buf, int len);
typedef int (srv_rx_f) (void *cctx, int timeout);
typedef void (srv_ms_f) (void *cctx, int status);
/* Telnet context */
typedef struct {
void *cctx; /* Client context */
srv_tx_f *srv_tx; /* Write to server */
srv_rx_f *srv_rx; /* Read from server */
srv_ms_f *srv_ms; /* Modem status from server */
unsigned int bytes_rx; /* Rx byte count */
unsigned int off_rx; /* Rx buffer offset */
unsigned char mode_telnet; /* Telnet mode */
unsigned char mode_rfc2217; /* RFC-2217 mode */
unsigned char telnet_ack[256]; /* telnet option ack counter */
} tn_ctx_t;
extern tn_ctx_t *telnet_ctx_init(void *cctx, srv_tx_f * ftx, srv_rx_f * frx,
srv_ms_f * fss);
extern int telnet_open(tn_ctx_t * tcc);
extern int telnet_rx(tn_ctx_t * tcc, char *buf, int *plen);
extern int telnet_tx(tn_ctx_t * tcc, const char *buf, int len);
extern void telnet_set_opt(tn_ctx_t * tcc, int opt, int prm,
const void *val, int len);
extern void telnet_rfc2217_handle_opt(tn_ctx_t * tcc, int opt,
unsigned char *pu, int nd);
extern void telnet_rfc2217_cfg(tn_ctx_t * tcc, int cmd,
const void *val, int nd);
extern void telnet_rfc2217_ctl(tn_ctx_t * tcc, unsigned int val);
/*RFC2217 modem state*/
#define TNS_STATE_DCD 0x80
#define TNS_STATE_RI 0x40
#define TNS_STATE_DSR 0x20
#define TNS_STATE_CTS 0x10
/*RFC2217 configuration commands*/
#define TNS_SET_BAUDRATE 1
#define TNS_SET_DATASIZE 2
#define TNS_SET_PARITY 3
#define TNS_SET_STOPSIZE 4
#define TNS_SET_CONTROL 5
#define TNS_SET_PURGE 12
/*RFC2217 control commands*/
#define TNS_CTL_NOFLOW 1
#define TNS_CTL_XONOFF 2
#define TNS_CTL_CTSRTS 3
#define TNS_CTL_DTR_ON 8
#define TNS_CTL_DTR_OFF 9
#define TNS_CTL_RTS_ON 11
#define TNS_CTL_RTS_OFF 12
#endif /*TELNET_H */
+299
View File
@@ -0,0 +1,299 @@
/*
* Copyright (c) 2018 Lars Thrane A/S
* SPDX-License-Identifier: GPL-2.0
*
* Telnet server - Telnet protocol handling
*/
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "telnet.h"
#include "telnet_param.h"
/* Telnet commands */
#if 0
static const char *const tn_cmd[] = {
"SE", "NOP", "MARK", "BRK", "IP", "AO", "AYT", "EC",
"EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC"
};
#endif
#define OPT_NACK 0 /* Reject (DONT/WONT) */
#define OPT_IGNORE 1 /* Ignore the command (?) */
#define OPT_ACK 2 /* Acknowledge (DO /WILL) */
/* Telnet option support */
static const unsigned char tn_opt[256] = {
/* *INDENT-OFF* */
[TNO_BINARY] = OPT_ACK,
[TNO_SUPP_GA] = OPT_ACK,
// [TNO_TTYP] = OPT_NACK,
// [TNO_NAWS] = OPT_NACK,
// [TNO_NEO] = OPT_NACK,
[TNO_CPCO] = OPT_ACK,
// [TNO_KERMIT] = OPT_NACK,
/* *INDENT-ON* */
};
static void _telnet_handle_req(tn_ctx_t * tcc, int cmd, int opt)
{
char buf[3];
if (tcc->telnet_ack[opt] > 0)
return;
switch (tn_opt[opt])
{
default:
case OPT_IGNORE:
return;
case OPT_ACK:
cmd = TNC_FD_DO;
break;
case OPT_NACK:
cmd = TNC_FE_DONT;
break;
}
buf[0] = TNC_FF_IAC;
buf[1] = cmd;
buf[2] = opt;
tcc->telnet_ack[opt]++;
tcc->srv_tx(tcc->cctx, buf, 3);
}
static void _telnet_handle_resp(tn_ctx_t * tcc, int cmd, int opt)
{
if (opt == TNO_CPCO)
{
if (cmd == TNC_FD_DO)
tcc->mode_rfc2217 = 1;
}
}
void telnet_set_opt(tn_ctx_t * tcc, int opt, int prm, const void *val, int len)
{
unsigned char buf[128], *pu = buf;
const unsigned char *pv;
int i;
*pu++ = TNC_FF_IAC;
*pu++ = TNC_FA_SB;
*pu++ = opt;
*pu++ = prm;
if (len > 0 && len <= 32)
{
pv = val;
for (i = 0; i < len; i++)
{
*pu++ = *pv;
if (*pv++ == TNC_FF_IAC)
*pu++ = TNC_FF_IAC;
}
}
*pu++ = TNC_FF_IAC;
*pu++ = TNC_F0_SE;
len = pu - buf;
tcc->srv_tx(tcc->cctx, buf, len);
}
static void _telnet_handle_opt(tn_ctx_t * tcc, int opt,
unsigned char *pu, int nd)
{
switch (opt)
{
default:
break;
case TNO_CPCO: /* RFC 2217 */
tcc->mode_rfc2217 = 1;
telnet_rfc2217_handle_opt(tcc, opt, pu, nd);
break;
}
}
int telnet_rx(tn_ctx_t * tcc, char *buf, int *plen)
{
char *s, *p;
unsigned char *pu;
int len, rem;
int np, nd;
int b1, b2;
len = *plen;
tcc->bytes_rx += len;
if (len < (int)tcc->off_rx)
tcc->off_rx = 0;
for (s = buf + tcc->off_rx, rem = len - tcc->off_rx; rem > 0; s = p)
{
p = memchr(s, TNC_FF_IAC, rem);
if (!p)
break;
/* We have IAC (= 0xff) */
np = rem - (p - s); /* N. chars available incl. IAC */
if (np < 2)
return 1;
pu = (unsigned char *)p;
b1 = pu[1];
switch (b1)
{
default:
case TNC_F0_SE:
case TNC_F1_NOP:
case TNC_F2_MARK:
case TNC_F3_BRK:
case TNC_F4_IP:
case TNC_F5_AO:
case TNC_F6_AYT:
case TNC_F7_EC:
case TNC_F8_EL:
case TNC_F9_GA:
nd = 2; /* Drop 2 bytes */
goto tn_drop;
case TNC_FB_WILL:
case TNC_FC_WONT:
case TNC_FD_DO:
case TNC_FE_DONT:
if (np < 3)
goto tn_more; /* Need more */
tcc->mode_telnet = 1; /* Any such sequence activates TN */
b2 = pu[2];
if (b1 == TNC_FB_WILL)
_telnet_handle_req(tcc, b1, b2);
else if (b1 == TNC_FD_DO)
_telnet_handle_resp(tcc, b1, b2);
nd = 3; /* Drop 3 bytes */
goto tn_drop;
case TNC_FA_SB:
for (nd = 2; nd < np - 1; nd++)
{
if (pu[nd] == TNC_FF_IAC && pu[nd + 1] == TNC_F0_SE)
{
nd -= 2;
if (nd <= 0)
break;
b2 = pu[2];
tcc->mode_telnet = 1; /* Any such sequence activates TN */
_telnet_handle_opt(tcc, b2, pu + 3, nd - 1);
nd += 4;
goto tn_drop;
}
}
if (np < 16)
goto tn_more; /* Not done */
/* This does not look right */
rem = 0; /* Quit loop */
break;
case TNC_FF_IAC:
p++;
nd = 1; /* Drop 1 bytes */
goto tn_drop;
tn_drop:
if (!tcc->mode_telnet)
goto tn_break;
rem -= nd + (p - s);
len -= nd;
memmove(p, p + nd, rem);
break;
tn_break:
rem = 0; /* Quit loop */
break;
tn_more: /* Request more data */
tcc->off_rx = len - np;
*plen = len;
return 1;
}
}
tcc->off_rx = 0;
*plen = len;
return 0;
}
int telnet_tx(tn_ctx_t * tcc, const char *buf, int len)
{
const char *s, *p;
int rem, nd;
for (s = buf, rem = len; rem > 0; s = p)
{
if (tcc->mode_telnet)
p = memchr(s, TNC_FF_IAC, rem);
else
p = NULL;
if (!p)
{
/* Send the rest */
nd = rem;
tcc->srv_tx(tcc->cctx, s, nd);
}
else
{
nd = p - s + 1;
tcc->srv_tx(tcc->cctx, s, nd);
tcc->srv_tx(tcc->cctx, p, 1); /* One TNC_FF_IAC */
p++;
}
rem -= nd;
}
return 0;
}
int telnet_open(tn_ctx_t * tcc)
{
time_t t = time(NULL);;
char buf[3];
int res;
buf[0] = TNC_FF_IAC;
buf[1] = TNC_FB_WILL;
buf[2] = TNO_CPCO;
tcc->srv_tx(tcc->cctx, buf, 3);
while (1)
{
res = tcc->srv_rx(tcc->cctx, 1000);
if (res <= 0)
return -1;
else if (tcc->mode_rfc2217)
return 0;
else if (t - time(NULL) > 2)
return -1;
}
}
tn_ctx_t *telnet_ctx_init(void *cctx, srv_tx_f * ftx,
srv_rx_f * frx, srv_ms_f * fms)
{
tn_ctx_t *tcc;
tcc = calloc(1, sizeof(tn_ctx_t));
tcc->cctx = cctx;
tcc->srv_tx = ftx; /* Write to server */
tcc->srv_rx = frx; /* Read from server */
tcc->srv_ms = fms; /* Set modem state */
return tcc;
}
+123
View File
@@ -0,0 +1,123 @@
/*
* Copyright (c) 2018 Lars Thrane A/S
* SPDX-License-Identifier: GPL-2.0
*
* Telnet parameters
*/
#ifndef TELNET_PARAM_H
#define TELNET_PARAM_H
/*
* Telnet commands
*/
#define TNC_F0_SE (0xf0) /* End of subnegotiation parameters */
#define TNC_F1_NOP (0xf1) /* No operation */
#define TNC_F2_MARK (0xf2) /* The data stream portion of a Synch.
This should always be accompanied
by a TCP Urgent notification. */
#define TNC_F3_BRK (0xf3) /* NVT character BRK. */
#define TNC_F4_IP (0xf4) /* The function IP (interrupt process) */
#define TNC_F5_AO (0xf5) /* The function AO (abort output) */
#define TNC_F6_AYT (0xf6) /* The function AYT (are you there) */
#define TNC_F7_EC (0xf7) /* The function EC (erase charceter) */
#define TNC_F8_EL (0xf8) /* The function EL (erase line) */
#define TNC_F9_GA (0xf9) /* The GA signal (go ahead) */
#define TNC_FA_SB (0xfa) /* Subnegotiation begin */
#define TNC_FB_WILL (0xfb) /* Indicates the desire to begin
performing, or confirmation that
you are now performing, the
indicated option. */
#define TNC_FC_WONT (0xfc) /* Indicates the refusal to perform,
or continue performing, the
indicated option. */
#define TNC_FD_DO (0xfd) /* Indicates the request that the
other party perform, or
confirmation that you are expecting
the other party to perform, the
indicated option. */
#define TNC_FE_DONT (0xfe) /* Indicates the demand that the
other party stop performing,
or confirmation that you are no
longer expecting the other party
to perform, the indicated option. */
#define TNC_FF_IAC (0xff) /* Interpret as Command / data byte */
/*
* Telnet options
*/
/*
* https://www.iana.org/assignments/telnet-options/telnet-options.xhtml
*
* 0 Binary Transmission [RFC856]
* 1 Echo [RFC857]
* 2 Reconnection [DDN Protocol Handbook, ... ]
* 3 Suppress Go Ahead [RFC858]
* 4 Approx Message Size Negotiation ["The Ethernet, ... ]
* 5 Status [RFC859]
* 6 Timing Mark [RFC860]
* 7 Remote Controlled Trans and Echo [RFC726]
* 8 Output Line Width [DDN Protocol Handbook, ... ]
* 9 Output Page Size [DDN Protocol Handbook, ... ]
* 10 Output Carriage-Return Disposition [RFC652]
* 11 Output Horizontal Tab Stops [RFC653]
* 12 Output Horizontal Tab Disposition [RFC654]
* 13 Output Formfeed Disposition [RFC655]
* 14 Output Vertical Tabstops [RFC656]
* 15 Output Vertical Tab Disposition [RFC657]
* 16 Output Linefeed Disposition [RFC658]
* 17 Extended ASCII [RFC698]
* 18 Logout [RFC727]
* 19 Byte Macro [RFC735]
* 20 Data Entry Terminal [RFC1043][RFC732]
* 21 SUPDUP [RFC736][RFC734]
* 22 SUPDUP Output [RFC749]
* 23 Send Location [RFC779]
* 24 Terminal Type [RFC1091]
* 25 End of Record [RFC885]
* 26 TACACS User Identification [RFC927]
* 27 Output Marking [RFC933]
* 28 Terminal Location Number [RFC946]
* 29 Telnet 3270 Regime [RFC1041]
* 30 X.3 PAD [RFC1053]
* 31 Negotiate About Window Size [RFC1073]
* 32 Terminal Speed [RFC1079]
* 33 Remote Flow Control [RFC1372]
* 34 Linemode [RFC1184]
* 35 X Display Location [RFC1096]
* 36 Environment Option [RFC1408]
* 37 Authentication Option [RFC2941]
* 38 Encryption Option [RFC2946]
* 39 New Environment Option [RFC1572]
* 40 TN3270E [RFC2355]
* 41 XAUTH [Rob_Earhart]
* 42 CHARSET [RFC2066]
* 43 Telnet Remote Serial Port (RSP) [Robert_Barnes]
* 44 Com Port Control Option [RFC2217]
* 45 Telnet Suppress Local Echo [Wirt_Atmar]
* 46 Telnet Start TLS [Michael_Boe]
* 47 KERMIT [RFC2840]
* 48 SEND-URL [David_Croft]
* 49 FORWARD_X [Jeffrey_Altman]
* 50-137 Unassigned [IANA]
* 138 TELOPT PRAGMA LOGON [Steve_McGregory]
* 139 TELOPT SSPI LOGON [Steve_McGregory]
* 140 TELOPT PRAGMA HEARTBEAT [Steve_McGregory]
* 141-254 Unassigned
* 255 Extended-Options-List [RFC861]
*/
#define TNO_BINARY 0 /* Binary Transmission */
#define TNO_ECHO 1 /* Echo */
#define TNO_SUPP_GA 3 /* Suppress Go Ahead */
#define TNO_LOGOUT 18 /* Logout */
#define TNO_TTYP 24 /* Terminal Type */
#define TNO_NAWS 31 /* Negotiate About Window Size */
#define TNO_NEO 39 /* New Environment Option */
#define TNO_CPCO 44 /* RFC 2217 */
#define TNO_KERMIT 47 /* Kermit */
#endif /* TELNET_PARAM_H */
+54
View File
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2018 Lars Thrane A/S
* SPDX-License-Identifier: GPL-2.0
*
* Telnet server - RFC-2217 handling
*/
#include <stddef.h>
#include "telnet.h"
#include "telnet_param.h"
void telnet_rfc2217_handle_opt(tn_ctx_t * tcc, int opt,
unsigned char *pu, int nd)
{
unsigned int sub;
sub = pu[0];
switch (sub)
{
default:
break;
case 100: /* SIGNATURE */
telnet_set_opt(tcc, opt, 0, "LT-NVT", 6);
break;
case 106: /* NOTIFY-LINESTATE */
break;
case 107: /* NOTIFY-MODEMSTATE */
if (tcc->srv_ms)
tcc->srv_ms(tcc->cctx, pu[1]);
break;
case 108: /* FLOWCONTROL-SUSPEND */
case 109: /* FLOWCONTROL-RESUME */
break;
}
}
void telnet_rfc2217_cfg(tn_ctx_t * tcc, int cmd, const void *val, int nd)
{
if (!tcc->mode_rfc2217)
return;
telnet_set_opt(tcc, TNO_CPCO, cmd, val, nd);
}
void telnet_rfc2217_ctl(tn_ctx_t * tcc, unsigned int val)
{
unsigned char byte = val;
if (!tcc->mode_rfc2217)
return;
telnet_set_opt(tcc, TNO_CPCO, TNS_SET_CONTROL, &byte, 1);
}
+1252
View File
File diff suppressed because it is too large Load Diff