ttynvt version 0.10

This commit is contained in:
Frank Rolsted Jensen
2018-09-11 10:21:35 +02:00
committed by Kim Woelders
parent 02a2149c1f
commit e68e140ef0
11 changed files with 1753 additions and 4 deletions
+26
View File
@@ -0,0 +1,26 @@
# autoreconf
/aclocal.m4
/autom4te.cache/
/compile
/config.h.in
/config.h.in~
/configure
/depcomp
/install-sh
/missing
Makefile.in
# configure
/config.h
/config.log
/config.status
/stamp-h1
.deps
Makefile
# build
*.o
/ttynvt
/ttynvt-*.tar.gz
/ttynvt-*.tar.xz
+2
View File
@@ -0,0 +1,2 @@
Frank Rolsted Jensen <frj@thrane.eu>
Kim Woelders <kw@thrane.eu>
+4 -4
View File
@@ -1,7 +1,7 @@
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
Version 2, June 1991 Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/> Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed. of this license document, but changing it is not allowed.
@@ -290,8 +290,8 @@ to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found. the "copyright" line and a pointer to where the full notice is found.
ttynvt <one line to give the program's name and a brief idea of what it does.>
Copyright (C) 2018 lars-thrane-as Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -329,7 +329,7 @@ necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker. `Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989 <signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice Ty Coon, President of Vice
This General Public License does not permit incorporating your program into This General Public License does not permit incorporating your program into
+20
View File
@@ -0,0 +1,20 @@
# Build ttynvt
#
MAINTAINERCLEANFILES = \
aclocal.m4 autom4te.cache compile config.h.in config.h.in~ configure \
depcomp install-sh missing \
Makefile.in
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)
+75
View File
@@ -0,0 +1,75 @@
ttynvt makes a virtual serial device (tty) and connects
the device to a Network Virtual Terminal (NVT).
+-ttynvt-+------------------------+
| |\ |
| | +---------------+ |
| | | |
| | | |
/dev/ttyNVT | pty /dev/ppp pty |
| | slave | master |
| | | | | |
--------------------------------------------------
| | | | | |
| | | | | |
+--FUSE--+ +-tty--ldisc------+ TCP--->host
1 Build environment
gcc is required.
glibc must support pthreads.
libfuse - Filesystem in Userspace - development support is needed.
2 Target
The linux kernel at the target system must support FUSE (FUSE_FS=y) and
libpthread and libfuse must be installed in the root filesystem.
3 Build
$ autoreconf -vif
Example configuration for native build:
$ ./configure
Example configuration for cross build:
$ ./configure --host=ARCH-unknown-linux \
CC=PATH-TO-CROSS-GCC \
PKG_CONFIG_LIBDIR=PATH-TO-CROSS-PKG_CONFIG_LIBDIR"
or
$ ./configure --host=ARCH-unknown-linux \
CC=PATH-TO-CROSS-GCC \
LDFLAGS="-L PATH-TO-LOCATION-OF-libfuse.so"
$ make
The default target in the Makefile builds the Network Virtual Terminal.
Output name is: ttynvt.
4 Run
The application (ttynvt) installs a virtual serial device in the /dev
directory (by default: /dev/ttyNVT0).
The major/minor number of the device, the address (name/IP) and the port
number of the serial server must be specified when the application
is started (command-line options).
E.g.
./ttynvt -M 199 -m 6 -n ttyNVT0 -S 169.254.1.1:5020
To get a list of all command-line options:
./ttynvt --help
5. Test
The serial server: ser2net (http://ser2net.sourceforge.net/) might be used
to test the virtual serial server on the target.
Install the server (ser2net) and add following line to the configuration
file (/etc/ser2net.conf):
5020:telnet:0:/dev/ttyS0:115200 remctl NONE 1STOPBIT 8DATABITS RTSCTS HANGUP_WHEN_DONE
At the server, plug-in a loopback connector in the serial port (ttyS0).
At the target, open the virtual serial port, with a termial program,
e.g minicom:
minicom -D /dev/ttyNVT0
6 Diagnostic
Add the command-line option '-D <level>' to enable logging of diagnostic information.
The log is forwarded to syslog with the debug level.
Wireshark is also very useful when debugging the interface between the client
and the server.
Ref: RFC-854 - Telnet Protocol Specification
RFC-2217 - Telnet Com Port Control Option
+42
View File
@@ -0,0 +1,42 @@
m4_define([pkg_version], [0.10])
#m4_define([pkg_revision], [005])
m4_define([pkg_version], m4_ifdef([pkg_revision], [pkg_version.pkg_revision], [pkg_version]))
AC_INIT([ttynvt],[pkg_version],[frj@thrane.eu])
AM_INIT_AUTOMAKE([foreign dist-xz])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_USE_SYSTEM_EXTENSIONS
AC_PROG_CC
AC_PROG_INSTALL
AC_HEADER_STDC
define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl
define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl
define([AC_LIBTOOL_LANG_GCJ_CONFIG], [:])dnl
AC_C_BIGENDIAN
AC_C_CONST
AC_C_INLINE
AC_CHECK_SIZEOF(int, 4)
AC_CHECK_SIZEOF(long, 4)
PKG_PROG_PKG_CONFIG
PKG_CHECK_MODULES(FUSE, fuse)
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([
Makefile
])
AC_OUTPUT
echo
echo "------------------------------------------------------------------------"
echo "$PACKAGE Version $VERSION configured"
echo "------------------------------------------------------------------------"
echo
+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, size_t * 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, int cmd);
/*RFC2217 modem state*/
#define TNS_STATE_CD 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, size_t * plen)
{
char *s, *p;
unsigned char *pu;
size_t len, rem;
int np, nd;
int b1, b2;
len = *plen;
tcc->bytes_rx += len;
if (len < (size_t) 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 */
+52
View File
@@ -0,0 +1,52 @@
/*
* 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, int cmd)
{
if (!tcc->mode_rfc2217)
return;
telnet_set_opt(tcc, TNO_CPCO, TNS_SET_CONTROL, &cmd, 1);
}
+1040
View File
File diff suppressed because it is too large Load Diff