Attempt to make outgoing telnet work

This commit is contained in:
Michiel Broek 2003-11-23 22:47:26 +00:00
parent bb1105a61f
commit 4c919784a1
9 changed files with 399 additions and 291 deletions

View File

@ -3,6 +3,8 @@ $Id$
v0.39.2 21-Nov-2003
NOTE: Don't use this version yet, mbtelnetd might be removed again!
general:
With the use of a proxy based on the iftelnetd from the ifmail
package incoming telnet sessions are now supported. Outgoing
@ -11,9 +13,13 @@ v0.39.2 21-Nov-2003
upgrade:
See mbtelnetd.html how to install mbtelnetd.
common.a:
A small fix in printable function.
mbcico:
If called by inetd with the -t itn parameters, mbcico aborts
and writes a short instruction in the log to install mbtelnetd.
Outgoing telnet works almost.
mbtelnetd:
New program, a proxy to handle incoming telnet/vmodem sessions.

View File

@ -497,7 +497,7 @@ char *printable(char *s, int l)
case '\n': *p++='\\'; *p++='n'; break;
case '\t': *p++='\\'; *p++='t'; break;
case '\b': *p++='\\'; *p++='b'; break;
default: sprintf(p,"\\%02x",*s); p+=3; break;
default: sprintf(p,"\\%02x", (*s & 0xff)); p+=3; break;
}
s++;
}

View File

@ -138,6 +138,6 @@ mbcico.o: ../config.h ../lib/libs.h ../lib/structs.h ../lib/users.h ../lib/recor
outstat.o: ../config.h ../lib/libs.h ../lib/structs.h ../lib/users.h ../lib/records.h ../lib/common.h ../lib/nodelist.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/dbnode.h ../lib/dbftn.h ../lib/mberrors.h scanout.h callstat.h outstat.h
nlinfo.o: ../config.h ../lib/libs.h ../lib/structs.h ../lib/common.h ../lib/nodelist.h ../lib/clcomm.h nlinfo.h
mbout.o: ../config.h ../lib/libs.h ../lib/structs.h ../lib/users.h ../lib/records.h ../lib/common.h ../lib/nodelist.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/dbnode.h ../lib/dbftn.h ../lib/mberrors.h outstat.h nlinfo.h
mbtelnetd.o: ../config.h ../lib/libs.h ../lib/structs.h ../lib/users.h ../lib/records.h ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/mberrors.h telnio.h mbtelnetd.h
telnio.o: ../config.h ../lib/libs.h ../lib/clcomm.h telnio.h
mbtelnetd.o: ../config.h ../lib/libs.h ../lib/structs.h ../lib/users.h ../lib/records.h ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/mberrors.h hydra.h telnio.h mbtelnetd.h
telnio.o: ../config.h ../lib/libs.h ../lib/clcomm.h hydra.h telnio.h
# End of generated dependencies

View File

@ -55,34 +55,18 @@
#include "../lib/clcomm.h"
#include "../lib/dbcfg.h"
#include "../lib/mberrors.h"
#include "hydra.h"
#include "telnio.h"
#include "mbtelnetd.h"
#define MBT_BUFSIZ 8192
#define MBT_TIMEOUT 3600
void die(int);
int init_telnet(void);
void answer(int, int);
int read0(char *, int);
int write1(char *, int);
void com_gw(int);
#define WILL 251
#define WONT 252
#define DO 253
#define DONT 254
#define IAC 255
#define TN_TRANSMIT_BINARY 0
#define TN_ECHO 1
#define TN_SUPPRESS_GA 3
static int tellen;
char *envptr = NULL;
time_t t_start, t_end;
@ -200,11 +184,11 @@ int main(int ac, char **av)
die(MBERR_INIT_ERROR);
}
init_telnet();
telnet_init();
tmp = calloc(81, sizeof(char ));
sprintf(tmp, "mbtelnetd v%s\r\n", VERSION);
write1(tmp, strlen(tmp));
telnet_write(tmp, strlen(tmp));
free(tmp);
com_gw(s);
@ -218,139 +202,12 @@ int main(int ac, char **av)
/* --- This is an artwork of serge terekhov, 2:5000/13@fidonet :) --- */
void answer (int tag, int opt)
{
char buf[3];
char *r = (char *)"???";
switch (tag) {
case WILL:
r = (char *)"WILL";
break;
case WONT:
r = (char *)"WONT";
break;
case DO:
r = (char *)"DO";
break;
case DONT:
r = (char *)"DONT";
break;
}
Syslog('s', "TELNET send %s %d", r, opt);
buf[0] = IAC;
buf[1] = tag;
buf[2] = opt;
if (write (1, buf, 3) != 3)
WriteError("$answer cant send");
}
int init_telnet(void)
{
tellen = 0;
answer (DO, TN_SUPPRESS_GA);
answer (WILL, TN_SUPPRESS_GA);
answer (DO, TN_TRANSMIT_BINARY);
answer (WILL, TN_TRANSMIT_BINARY);
answer (DO, TN_ECHO);
answer (WILL, TN_ECHO);
return 1;
}
int read0 (char *buf, int len)
{
int n = 0, m;
char *q, *p;
static char telbuf[4];
while ((n == 0) && (n = read (0, buf + tellen, MBT_BUFSIZ - tellen)) > 0) {
if (tellen) {
memcpy(buf, telbuf, tellen);
n += tellen;
tellen = 0;
}
if (memchr (buf, IAC, n)) {
for (p = q = buf; n--; )
if ((m = (unsigned char)*q++) != IAC)
*p++ = m;
else {
if (n < 2) {
memcpy (telbuf, q - 1, tellen = n + 1);
break;
}
--n;
switch (m = (unsigned char)*q++) {
case WILL: m = (unsigned char)*q++; --n;
Syslog('s', "TELNET: recv WILL %d", m);
if (m != TN_TRANSMIT_BINARY && m != TN_SUPPRESS_GA && m != TN_ECHO)
answer (DONT, m);
break;
case WONT: m = *q++;
--n;
Syslog('s', "TELNET: recv WONT %d", m);
break;
case DO: m = (unsigned char)*q++;
--n;
Syslog('s', "TELNET: recv DO %d", m);
if (m != TN_TRANSMIT_BINARY && m != TN_SUPPRESS_GA && m != TN_ECHO)
answer (WONT, m);
break;
case DONT: m = (unsigned char)*q++;
--n;
Syslog('s', "TELNET: recv DONT %d", m);
break;
case IAC: *p++ = IAC;
break;
default: Syslog('s', "TELNET: recv IAC %d", m);
break;
}
}
n = p - buf;
}
}
return n;
}
int write1 (char *buf, int len)
{
char *q;
int k, l;
l = len;
while ((len > 0) && (q = memchr(buf, IAC, len))) {
k = (q - buf) + 1;
if ((write (1, buf, k) != k) || (write (1, q, 1) != 1)) {
return -1;
}
buf += k;
len -= k;
}
if ((len > 0) && write (1, buf, len) != len) {
return -1;
}
return l;
}
void com_gw(int in)
{
fd_set fds;
int n, fdsbits;
static struct timeval tout = { MBT_TIMEOUT, 0 };
unsigned char buf[MBT_BUFSIZ];
unsigned char buf[H_ZIPBUFLEN];
alarm(0);
fdsbits = in + 1;
@ -366,7 +223,7 @@ void com_gw(int in)
if ((n = select(fdsbits, &fds, NULL, NULL, &tout)) > 0) {
if (FD_ISSET(in, &fds)) {
if ((n = read(in, buf, sizeof buf)) > 0) {
if (write1(buf, n) < 0) {
if (telnet_write(buf, n) < 0) {
goto bad;
}
} else {
@ -374,7 +231,7 @@ void com_gw(int in)
}
}
if (FD_ISSET(0, &fds)) {
if ((n = read0(buf, sizeof buf)) > 0) {
if ((n = telnet_read(buf, sizeof buf)) > 0) {
if (write(in, buf, n) < 0) goto bad;
} else {
goto bad;

View File

@ -221,42 +221,3 @@ void closetcp(void)
}
#ifdef USE_TELNET
#define WILL 251
#define WONT 252
#define DO 253
#define DONT 254
#define IAC 255
#define TOPT_BIN 0
#define TOPT_ECHO 1
#define TOPT_SUPP 3
static void telnet_answer(int tag, int opt)
{
char buf[3];
Syslog('s', "telnet_answer(%d, %d)", tag, opt);
buf[0]=IAC;
buf[1]=tag;
buf[2]=opt;
tty_put(buf, 3);
}
void telnet_init(void)
{
Syslog('s', "telnet_init()");
telnet_answer(DO,TOPT_SUPP);
telnet_answer(WILL,TOPT_SUPP);
telnet_answer(DO,TOPT_BIN);
telnet_answer(WILL,TOPT_BIN);
telnet_answer(DO,TOPT_ECHO);
telnet_answer(WILL,TOPT_ECHO);
}
#endif

View File

@ -6,8 +6,4 @@
int opentcp(char *);
void closetcp(void);
#ifdef USE_TELNET
void telnet_init(void);
#endif
#endif

249
mbcico/telnio.c Normal file
View File

@ -0,0 +1,249 @@
/*****************************************************************************
*
* $id$
* Purpose ...............: Telnet IO filter
*
*****************************************************************************
* Copyright (C) 1997-2003
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* MBSE BBS is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*****************************************************************************/
#include "../config.h"
#include "../lib/libs.h"
#include "../lib/clcomm.h"
#include "hydra.h"
#include "telnio.h"
static int tellen;
/* --- This is an artwork of serge terekhov, 2:5000/13@fidonet :) --- */
void telnet_answer(int tag, int opt)
{
char buf[3];
char *r = (char *)"???";
switch (tag) {
case WILL:
r = (char *)"WILL";
break;
case WONT:
r = (char *)"WONT";
break;
case DO:
r = (char *)"DO";
break;
case DONT:
r = (char *)"DONT";
break;
}
Syslog('s', "TELNET send %s %d", r, opt);
buf[0] = IAC;
buf[1] = tag;
buf[2] = opt;
if (write (1, buf, 3) != 3)
WriteError("$answer cant send");
}
int telnet_init(void)
{
Syslog('s', "telnet_init()");
tellen = 0;
telnet_answer(DO, TOPT_SUPP);
telnet_answer(WILL, TOPT_SUPP);
telnet_answer(DO, TOPT_BIN);
telnet_answer(WILL, TOPT_BIN);
telnet_answer(DO, TOPT_ECHO);
telnet_answer(WILL, TOPT_ECHO);
return 1;
}
/*
* Read function for mbtelnetd
*/
int telnet_read(char *buf, int len)
{
int n = 0, m;
char *q, *p;
static char telbuf[4];
Syslog('s', "telnet_read(buf, %d tellen=%d)", len, tellen);
while ((n == 0) && (n = read (0, buf + tellen, H_ZIPBUFLEN - tellen)) > 0) {
Syslog('s', " n=%d tellen=%d", n, tellen);
if (n < 0) {
Syslog('s', "telnet_read n=%d", n);
return n;
}
if (tellen) {
Syslog('s', " memcpy");
memcpy(buf, telbuf, tellen);
n += tellen;
tellen = 0;
}
if (memchr (buf, IAC, n)) {
Syslog('s', " IAC detected");
for (p = q = buf; n--; )
if ((m = (unsigned char)*q++) != IAC)
*p++ = m;
else {
if (n < 2) {
memcpy (telbuf, q - 1, tellen = n + 1);
break;
}
--n;
switch (m = (unsigned char)*q++) {
case WILL: m = (unsigned char)*q++; --n;
Syslog('s', "TELNET: recv WILL %d", m);
if (m != TOPT_BIN && m != TOPT_SUPP && m != TOPT_ECHO)
telnet_answer(DONT, m);
break;
case WONT: m = *q++;
--n;
Syslog('s', "TELNET: recv WONT %d", m);
break;
case DO: m = (unsigned char)*q++;
--n;
Syslog('s', "TELNET: recv DO %d", m);
if (m != TOPT_BIN && m != TOPT_SUPP && m != TOPT_ECHO)
telnet_answer(WONT, m);
break;
case DONT: m = (unsigned char)*q++;
--n;
Syslog('s', "TELNET: recv DONT %d", m);
break;
case IAC: Syslog('s', "TELNET: recv 2nd IAC %d", m);
*p++ = IAC;
break;
default: Syslog('s', "TELNET: recv IAC %d", m);
break;
}
}
n = p - buf;
}
}
Syslog('s', " return n=%d", n);
return n;
}
/*
* Telnet output filter, IAC characters are escaped.
*/
int telnet_write(char *buf, int len)
{
char *q;
int k, l;
Syslog('s', "telnet_write(buf, %d)", len);
l = len;
while ((len > 0) && (q = memchr(buf, IAC, len))) {
k = (q - buf) + 1;
if ((write(1, buf, k) != k) || (write(1, q, 1) != 1)) {
return -1;
}
buf += k;
len -= k;
}
if ((len > 0) && write(1, buf, len) != len) {
return -1;
}
return l;
}
int telnet_buffer(char *buf, int len)
{
int i, j, m = 0, rc;
rc = len;
if (memchr (buf, IAC, rc)) {
Syslog('s', "telnet_buffer: IAC in input stream rc=%d", rc);
// Syslogp('s', printable(buf, rc));
j = 0;
for (i = 0; i < rc; i++) {
if ((buf[i] & 0xff) == IAC) {
i++;
switch (buf[i] & 0xff) {
case WILL: i++;
m = buf[i] & 0xff;
Syslog('s', "Telnet recv WILL %d", m);
if (m != TOPT_BIN && m != TOPT_SUPP && m != TOPT_ECHO)
telnet_answer(DONT, m);
break;
case WONT: i++;
m = buf[i] & 0xff;
Syslog('s', "Telnet recv WONT %d", m);
break;
case DO: i++;
m = buf[i] & 0xff;
Syslog('s', "Telnet recv DO %d", m);
if (m != TOPT_BIN && m != TOPT_SUPP && m != TOPT_ECHO)
telnet_answer(WONT, m);
break;
case DONT: i++;
m = buf[i] & 0xff;
Syslog('s', "Telnet recv DONT %d", m);
break;
case IAC: buf[j] = buf[i];
j++;
Syslog('s', "Telnet recv escaped IAC");
break;
default: m = buf[i] & 0xff;
Syslog('s', "TELNET: recv IAC %d, this is not good", m);
buf[j] = IAC;
j++;
buf[j] = m;
j++;
break;
}
} else {
buf[j] = buf[i];
j++;
}
}
rc = j;
// Syslog('s', "new rc=%d", rc);
// Syslogp('s', printable(buf, rc));
}
return rc;
}

23
mbcico/telnio.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef _TELNIO_H
#define _TELNIO_H
/* $Id$ */
#define MBT_WILL 251
#define MBT_WONT 252
#define MBT_DO 253
#define MBT_DONT 254
#define MBT_IAC 255
#define TOPT_BIN 0
#define TOPT_ECHO 1
#define TOPT_SUPP 3
void telnet_answer(int, int);
int telnet_init(void);
int telnet_read(char *, int);
int telnet_write(char *, int);
int telnet_buffer(char *, int);
#endif

View File

@ -38,14 +38,17 @@
#include "../lib/records.h"
#include "../lib/common.h"
#include "../lib/clcomm.h"
#include "telnio.h"
#include "ttyio.h"
#include "lutil.h"
extern int hanged_up;
extern int telnet;
extern int master;
extern char *inetaddr;
#define TT_BUFSIZ 1024
#define NUMTIMERS 3
#define TT_BUFSIZ 1024
#define NUMTIMERS 3
int tty_status = 0;
@ -241,6 +244,10 @@ static int tty_read(char *buf, int size, int tot)
Syslog('!', "tty_read: error flag");
}
rc=-tty_status;
} else {
if (master && telnet) {
rc = telnet_buffer(buf, rc);
}
}
return rc;
@ -253,7 +260,10 @@ int tty_write(char *buf, int size)
int result;
tty_status=0;
result = write(1,buf,size);
if (telnet && master)
result = telnet_write(buf, size);
else
result = write(1, buf, size);
if (result != size) {
if (hanged_up || (errno == EPIPE) || (errno == ECONNRESET)) {
@ -461,135 +471,141 @@ int tty_getc(int tot)
int tty_get(char *buf, int size, int tot)
{
int result=0;
int result=0;
if (left >= size) {
memcpy(buf,next,size);
next += size;
left -= size;
return 0;
}
if (left >= size) {
memcpy(buf,next,size);
next += size;
left -= size;
return 0;
}
if (left > 0) {
memcpy(buf,next,left);
buf += left;
next += left;
size -= left;
left=0;
}
if (left > 0) {
memcpy(buf,next,left);
buf += left;
next += left;
size -= left;
left=0;
}
while ((result=tty_read(buf,size,tot)) > 0) {
buf += result;
size -= result;
}
while ((result=tty_read(buf,size,tot)) > 0) {
buf += result;
size -= result;
}
return result;
return result;
}
int tty_putc(int c)
{
char buf = c;
char buf = c;
return tty_write(&buf,1);
return tty_write(&buf,1);
}
int tty_put(char *buf, int size)
{
return tty_write(buf,size);
return tty_write(buf,size);
}
int tty_putget(char **obuf, int *osize, char **ibuf, int *isize)
{
time_t timeout, now;
int i, rc;
fd_set readfds, writefds, exceptfds;
struct timeval seltimer;
time_t timeout, now;
int i, rc;
fd_set readfds, writefds, exceptfds;
struct timeval seltimer;
tty_status = 0;
now = time(NULL);
timeout = (time_t)300; /* maximum of 5 minutes */
tty_status = 0;
now = time(NULL);
timeout = (time_t)300; /* maximum of 5 minutes */
for (i = 0; i < NUMTIMERS; i++) {
if (timer[i]) {
if (now >= timer[i]) {
tty_status = STAT_TIMEOUT;
WriteError("tty_putget: timer %d already expired, return",i);
return -tty_status;
} else {
if (timeout > (timer[i]-now))
timeout=timer[i]-now;
}
}
for (i = 0; i < NUMTIMERS; i++) {
if (timer[i]) {
if (now >= timer[i]) {
tty_status = STAT_TIMEOUT;
WriteError("tty_putget: timer %d already expired, return",i);
return -tty_status;
} else {
if (timeout > (timer[i]-now))
timeout=timer[i]-now;
}
}
}
Syslog('t', "tty_putget: timeout=%d",timeout);
Syslog('t', "tty_putget: timeout=%d",timeout);
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&exceptfds);
FD_SET(0,&readfds);
FD_SET(1,&writefds);
FD_SET(0,&exceptfds);
FD_SET(1,&exceptfds);
seltimer.tv_sec=timeout;
seltimer.tv_usec=0;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&exceptfds);
FD_SET(0,&readfds);
FD_SET(1,&writefds);
FD_SET(0,&exceptfds);
FD_SET(1,&exceptfds);
seltimer.tv_sec=timeout;
seltimer.tv_usec=0;
rc=select(2,&readfds,&writefds,&exceptfds,&seltimer);
if (rc < 0) {
if (hanged_up) {
tty_status=STAT_HANGUP;
WriteError("tty_putget: hanged_up flag");
} else {
WriteError("$tty_putget: select failed");
tty_status=STAT_ERROR;
}
} else if (rc == 0) {
tty_status=STAT_TIMEOUT;
rc=select(2,&readfds,&writefds,&exceptfds,&seltimer);
if (rc < 0) {
if (hanged_up) {
tty_status=STAT_HANGUP;
WriteError("tty_putget: hanged_up flag");
} else {
/* rc > 0 */
if ((FD_ISSET(0,&exceptfds)) || (FD_ISSET(1,&exceptfds))) {
WriteError("$tty_putget: exeption error");
tty_status=STAT_ERROR;
}
WriteError("$tty_putget: select failed");
tty_status=STAT_ERROR;
}
if (tty_status) {
Syslog('t', "tty_putget: return after select status %s",ttystat[tty_status]);
return -tty_status;
} else if (rc == 0) {
tty_status=STAT_TIMEOUT;
} else {
/* rc > 0 */
if ((FD_ISSET(0,&exceptfds)) || (FD_ISSET(1,&exceptfds))) {
WriteError("$tty_putget: exeption error");
tty_status=STAT_ERROR;
}
}
if (FD_ISSET(0,&readfds) && *isize) {
rc=read(0,*ibuf,*isize);
if (rc < 0) {
WriteError("$tty_putget: read failed");
tty_status=STAT_ERROR;
} else {
(*ibuf)+=rc;
(*isize)-=rc;
}
if (tty_status) {
Syslog('t', "tty_putget: return after select status %s",ttystat[tty_status]);
return -tty_status;
}
if (FD_ISSET(0,&readfds) && *isize) {
rc = read(0, *ibuf, *isize);
if (rc < 0) {
WriteError("$tty_putget: read failed");
tty_status=STAT_ERROR;
} else {
if (master && telnet) {
rc = telnet_buffer(*ibuf, rc);
}
(*ibuf)+=rc;
(*isize)-=rc;
}
}
if (FD_ISSET(1,&writefds) && *osize) {
rc=write(1,*obuf,*osize);
if (rc < 0) {
WriteError("$tty_putget: write failed");
tty_status=STAT_ERROR;
} else {
(*obuf)+=rc;
(*osize)-=rc;
}
if (FD_ISSET(1,&writefds) && *osize) {
if (telnet && master)
rc = telnet_write(*obuf,*osize);
else
rc=write(1,*obuf,*osize);
if (rc < 0) {
WriteError("$tty_putget: write failed");
tty_status=STAT_ERROR;
} else {
(*obuf)+=rc;
(*osize)-=rc;
}
}
if (tty_status)
return -tty_status;
else
return ((*isize == 0) | ((*osize == 0) << 1));
if (tty_status)
return -tty_status;
else
return ((*isize == 0) | ((*osize == 0) << 1));
}