From 287d03ac26ae79baa51a55732ac82e221171f422 Mon Sep 17 00:00:00 2001 From: Rob Swindell <rob@synchro.net> Date: Tue, 10 May 2022 17:04:36 -0700 Subject: [PATCH] Set Telnet-server options (e.g. will echo) in answer() --- src/vdmodem/vdmodem.c | 326 ++++++++++++++++++++++-------------------- 1 file changed, 167 insertions(+), 159 deletions(-) diff --git a/src/vdmodem/vdmodem.c b/src/vdmodem/vdmodem.c index 4fbbc966f4..93d1f29f0e 100644 --- a/src/vdmodem/vdmodem.c +++ b/src/vdmodem/vdmodem.c @@ -220,7 +220,6 @@ char* connect_result(struct modem* modem) char* connected(struct modem* modem) { - ZERO_VAR(telnet); modem->online = true; modem->ringing = false; ResetEvent(hungup_event); @@ -269,6 +268,164 @@ int address_family() return PF_UNSPEC; } +int putcom(char* buf, size_t len) +{ + return send(sock, buf, len, /* flags: */0); +} + +static void send_telnet_cmd(uchar cmd, uchar opt) +{ + char buf[16]; + + if(cmd<TELNET_WILL) { + dprintf("TELNET TX: %s" + ,telnet_cmd_desc(cmd)); + sprintf(buf,"%c%c",TELNET_IAC,cmd); + putcom(buf,2); + } else { + dprintf("TELNET TX: %s %s" + ,telnet_cmd_desc(cmd), telnet_opt_desc(opt)); + sprintf(buf,"%c%c%c",TELNET_IAC,cmd,opt); + putcom(buf,3); + } +} + +void request_telnet_opt(uchar cmd, uchar opt) +{ + if(cmd==TELNET_DO || cmd==TELNET_DONT) { /* remote option */ + if(telnet.remote_option[opt]==telnet_opt_ack(cmd)) + return; /* already set in this mode, do nothing */ + telnet.remote_option[opt]=telnet_opt_ack(cmd); + } else { /* local option */ + if(telnet.local_option[opt]==telnet_opt_ack(cmd)) + return; /* already set in this mode, do nothing */ + telnet.local_option[opt]=telnet_opt_ack(cmd); + } + send_telnet_cmd(cmd,opt); +} + +BYTE* telnet_interpret(BYTE* inbuf, size_t inlen, BYTE* outbuf, size_t *outlen) +{ + BYTE command; + BYTE option; + BYTE* first_cr=NULL; + BYTE* first_int=NULL; + size_t i; + + if(inlen<1) { + *outlen=0; + return(inbuf); /* no length? No interpretation */ + } + + first_int=(BYTE*)memchr(inbuf, TELNET_IAC, inlen); + if(telnet.remote_option[TELNET_BINARY_TX]!=TELNET_WILL) { + first_cr=(BYTE*)memchr(inbuf, '\r', inlen); + if(first_cr) { + if(first_int==NULL || first_cr < first_int) + first_int=first_cr; + } + } + + if(telnet.cmdlen==0 && first_int==NULL) { + *outlen=inlen; + return(inbuf); /* no interpretation needed */ + } + + if(telnet.cmdlen==0 /* If we haven't returned and telnet.cmdlen==0 then first_int is not NULL */ ) { + *outlen=first_int-inbuf; + memcpy(outbuf, inbuf, *outlen); + } else + *outlen=0; + + for(i=*outlen;i<inlen;i++) { + if(telnet.remote_option[TELNET_BINARY_TX]!=TELNET_WILL) { + if(telnet.cmdlen==1 && telnet.cmd[0]=='\r') { + outbuf[(*outlen)++]='\r'; + if(inbuf[i]!=0 && inbuf[i]!=TELNET_IAC) + outbuf[(*outlen)++]=inbuf[i]; + telnet.cmdlen=0; + if(inbuf[i]!=TELNET_IAC) + continue; + } + if(inbuf[i]=='\r' && telnet.cmdlen==0) { + telnet.cmd[telnet.cmdlen++]='\r'; + continue; + } + } + + if(inbuf[i]==TELNET_IAC && telnet.cmdlen==1) { /* escaped 255 */ + telnet.cmdlen=0; + outbuf[(*outlen)++]=TELNET_IAC; + continue; + } + if(inbuf[i]==TELNET_IAC || telnet.cmdlen) { + + if(telnet.cmdlen<sizeof(telnet.cmd)) + telnet.cmd[telnet.cmdlen++]=inbuf[i]; + + command = telnet.cmd[1]; + option = telnet.cmd[2]; + + if(telnet.cmdlen>=2 && command==TELNET_SB) { + if(inbuf[i]==TELNET_SE + && telnet.cmd[telnet.cmdlen-2]==TELNET_IAC) { + telnet.cmdlen=0; + } + } + else if(telnet.cmdlen==2 && inbuf[i]<TELNET_WILL) { + telnet.cmdlen=0; + } + else if(telnet.cmdlen>=3) { /* telnet option negotiation */ + + dprintf("TELNET RX: %s %s" + ,telnet_cmd_desc(command),telnet_opt_desc(option)); + + if(command==TELNET_DO || command==TELNET_DONT) { /* local options */ + if(telnet.local_option[option]!=command) { + switch(option) { + case TELNET_BINARY_TX: + case TELNET_ECHO: + case TELNET_TERM_TYPE: + case TELNET_SUP_GA: + case TELNET_NEGOTIATE_WINDOW_SIZE: + telnet.local_option[option]=command; + send_telnet_cmd(telnet_opt_ack(command),option); + break; + default: /* unsupported local options */ + if(command==TELNET_DO) /* NAK */ + send_telnet_cmd(telnet_opt_nak(command),option); + break; + } + } + } else { /* WILL/WONT (remote options) */ + if(telnet.remote_option[option]!=command) { + + switch(option) { + case TELNET_BINARY_TX: + case TELNET_ECHO: + case TELNET_TERM_TYPE: + case TELNET_SUP_GA: + case TELNET_NEGOTIATE_WINDOW_SIZE: + telnet.remote_option[option]=command; + send_telnet_cmd(telnet_opt_ack(command),option); + break; + default: /* unsupported remote options */ + if(command==TELNET_WILL) /* NAK */ + send_telnet_cmd(telnet_opt_nak(command),option); + break; + } + } + } + + telnet.cmdlen=0; + + } + } else + outbuf[(*outlen)++]=inbuf[i]; + } + return(outbuf); +} + // Significant portions copies from syncterm/conn.c char* dial(struct modem* modem, const char* number) { @@ -386,6 +543,7 @@ connected: dprintf("%s %d connected!", __FILE__, __LINE__); int keepalives = TRUE; setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepalives, sizeof(keepalives)); + ZERO_VAR(telnet); return connected(modem); } @@ -409,6 +567,14 @@ char* answer(struct modem* modem) } char tmp[256]; dprintf("Connection accepted from TCP port %hu at %s", inet_addrport(&addr), inet_addrtop(&addr, tmp, sizeof(tmp))); + + if(mode == TELNET) { + ZERO_VAR(telnet); + /* Disable Telnet Terminal Echo */ + request_telnet_opt(TELNET_WILL,TELNET_ECHO); + /* Will suppress Go Ahead */ + request_telnet_opt(TELNET_WILL,TELNET_SUP_GA); + } return connected(modem); } @@ -650,164 +816,6 @@ void listen_thread(void* arg) } } -int putcom(char* buf, size_t len) -{ - return send(sock, buf, len, /* flags: */0); -} - -static void send_telnet_cmd(uchar cmd, uchar opt) -{ - char buf[16]; - - if(cmd<TELNET_WILL) { - dprintf("TELNET TX: %s" - ,telnet_cmd_desc(cmd)); - sprintf(buf,"%c%c",TELNET_IAC,cmd); - putcom(buf,2); - } else { - dprintf("TELNET TX: %s %s" - ,telnet_cmd_desc(cmd), telnet_opt_desc(opt)); - sprintf(buf,"%c%c%c",TELNET_IAC,cmd,opt); - putcom(buf,3); - } -} - -void request_telnet_opt(uchar cmd, uchar opt) -{ - if(cmd==TELNET_DO || cmd==TELNET_DONT) { /* remote option */ - if(telnet.remote_option[opt]==telnet_opt_ack(cmd)) - return; /* already set in this mode, do nothing */ - telnet.remote_option[opt]=telnet_opt_ack(cmd); - } else { /* local option */ - if(telnet.local_option[opt]==telnet_opt_ack(cmd)) - return; /* already set in this mode, do nothing */ - telnet.local_option[opt]=telnet_opt_ack(cmd); - } - send_telnet_cmd(cmd,opt); -} - -BYTE* telnet_interpret(BYTE* inbuf, size_t inlen, BYTE* outbuf, size_t *outlen) -{ - BYTE command; - BYTE option; - BYTE* first_cr=NULL; - BYTE* first_int=NULL; - size_t i; - - if(inlen<1) { - *outlen=0; - return(inbuf); /* no length? No interpretation */ - } - - first_int=(BYTE*)memchr(inbuf, TELNET_IAC, inlen); - if(telnet.remote_option[TELNET_BINARY_TX]!=TELNET_WILL) { - first_cr=(BYTE*)memchr(inbuf, '\r', inlen); - if(first_cr) { - if(first_int==NULL || first_cr < first_int) - first_int=first_cr; - } - } - - if(telnet.cmdlen==0 && first_int==NULL) { - *outlen=inlen; - return(inbuf); /* no interpretation needed */ - } - - if(telnet.cmdlen==0 /* If we haven't returned and telnet.cmdlen==0 then first_int is not NULL */ ) { - *outlen=first_int-inbuf; - memcpy(outbuf, inbuf, *outlen); - } else - *outlen=0; - - for(i=*outlen;i<inlen;i++) { - if(telnet.remote_option[TELNET_BINARY_TX]!=TELNET_WILL) { - if(telnet.cmdlen==1 && telnet.cmd[0]=='\r') { - outbuf[(*outlen)++]='\r'; - if(inbuf[i]!=0 && inbuf[i]!=TELNET_IAC) - outbuf[(*outlen)++]=inbuf[i]; - telnet.cmdlen=0; - if(inbuf[i]!=TELNET_IAC) - continue; - } - if(inbuf[i]=='\r' && telnet.cmdlen==0) { - telnet.cmd[telnet.cmdlen++]='\r'; - continue; - } - } - - if(inbuf[i]==TELNET_IAC && telnet.cmdlen==1) { /* escaped 255 */ - telnet.cmdlen=0; - outbuf[(*outlen)++]=TELNET_IAC; - continue; - } - if(inbuf[i]==TELNET_IAC || telnet.cmdlen) { - - if(telnet.cmdlen<sizeof(telnet.cmd)) - telnet.cmd[telnet.cmdlen++]=inbuf[i]; - - command = telnet.cmd[1]; - option = telnet.cmd[2]; - - if(telnet.cmdlen>=2 && command==TELNET_SB) { - if(inbuf[i]==TELNET_SE - && telnet.cmd[telnet.cmdlen-2]==TELNET_IAC) { - telnet.cmdlen=0; - } - } - else if(telnet.cmdlen==2 && inbuf[i]<TELNET_WILL) { - telnet.cmdlen=0; - } - else if(telnet.cmdlen>=3) { /* telnet option negotiation */ - - dprintf("TELNET RX: %s %s" - ,telnet_cmd_desc(command),telnet_opt_desc(option)); - - if(command==TELNET_DO || command==TELNET_DONT) { /* local options */ - if(telnet.local_option[option]!=command) { - switch(option) { - case TELNET_BINARY_TX: - case TELNET_ECHO: - case TELNET_TERM_TYPE: - case TELNET_SUP_GA: - case TELNET_NEGOTIATE_WINDOW_SIZE: - telnet.local_option[option]=command; - send_telnet_cmd(telnet_opt_ack(command),option); - break; - default: /* unsupported local options */ - if(command==TELNET_DO) /* NAK */ - send_telnet_cmd(telnet_opt_nak(command),option); - break; - } - } - } else { /* WILL/WONT (remote options) */ - if(telnet.remote_option[option]!=command) { - - switch(option) { - case TELNET_BINARY_TX: - case TELNET_ECHO: - case TELNET_TERM_TYPE: - case TELNET_SUP_GA: - case TELNET_NEGOTIATE_WINDOW_SIZE: - telnet.remote_option[option]=command; - send_telnet_cmd(telnet_opt_ack(command),option); - break; - default: /* unsupported remote options */ - if(command==TELNET_WILL) /* NAK */ - send_telnet_cmd(telnet_opt_nak(command),option); - break; - } - } - } - - telnet.cmdlen=0; - - } - } else - outbuf[(*outlen)++]=inbuf[i]; - } - return(outbuf); -} - int main(int argc, char** argv) { int argn = 1; -- GitLab