⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 telnet.c

📁 putty
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * Telnet backend.
 */

#include <stdio.h>
#include <stdlib.h>

#include "putty.h"

#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif

#define	IAC	255		       /* interpret as command: */
#define	DONT	254		       /* you are not to use option */
#define	DO	253		       /* please, you use option */
#define	WONT	252		       /* I won't use option */
#define	WILL	251		       /* I will use option */
#define	SB	250		       /* interpret as subnegotiation */
#define	SE	240		       /* end sub negotiation */

#define GA      249		       /* you may reverse the line */
#define EL      248		       /* erase the current line */
#define EC      247		       /* erase the current character */
#define	AYT	246		       /* are you there */
#define	AO	245		       /* abort output--but let prog finish */
#define	IP	244		       /* interrupt process--permanently */
#define	BREAK	243		       /* break */
#define DM      242		       /* data mark--for connect. cleaning */
#define NOP     241		       /* nop */
#define EOR     239		       /* end of record (transparent mode) */
#define ABORT   238		       /* Abort process */
#define SUSP    237		       /* Suspend process */
#define xEOF    236		       /* End of file: EOF is already used... */

#define TELOPT_BINARY	0	       /* 8-bit data path */
#define TELOPT_ECHO	1	       /* echo */
#define	TELOPT_RCP	2	       /* prepare to reconnect */
#define	TELOPT_SGA	3	       /* suppress go ahead */
#define	TELOPT_NAMS	4	       /* approximate message size */
#define	TELOPT_STATUS	5	       /* give status */
#define	TELOPT_TM	6	       /* timing mark */
#define	TELOPT_RCTE	7	       /* remote controlled transmission and echo */
#define TELOPT_NAOL 	8	       /* negotiate about output line width */
#define TELOPT_NAOP 	9	       /* negotiate about output page size */
#define TELOPT_NAOCRD	10	       /* negotiate about CR disposition */
#define TELOPT_NAOHTS	11	       /* negotiate about horizontal tabstops */
#define TELOPT_NAOHTD	12	       /* negotiate about horizontal tab disposition */
#define TELOPT_NAOFFD	13	       /* negotiate about formfeed disposition */
#define TELOPT_NAOVTS	14	       /* negotiate about vertical tab stops */
#define TELOPT_NAOVTD	15	       /* negotiate about vertical tab disposition */
#define TELOPT_NAOLFD	16	       /* negotiate about output LF disposition */
#define TELOPT_XASCII	17	       /* extended ascic character set */
#define	TELOPT_LOGOUT	18	       /* force logout */
#define	TELOPT_BM	19	       /* byte macro */
#define	TELOPT_DET	20	       /* data entry terminal */
#define	TELOPT_SUPDUP	21	       /* supdup protocol */
#define	TELOPT_SUPDUPOUTPUT 22	       /* supdup output */
#define	TELOPT_SNDLOC	23	       /* send location */
#define	TELOPT_TTYPE	24	       /* terminal type */
#define	TELOPT_EOR	25	       /* end or record */
#define	TELOPT_TUID	26	       /* TACACS user identification */
#define	TELOPT_OUTMRK	27	       /* output marking */
#define	TELOPT_TTYLOC	28	       /* terminal location number */
#define	TELOPT_3270REGIME 29	       /* 3270 regime */
#define	TELOPT_X3PAD	30	       /* X.3 PAD */
#define	TELOPT_NAWS	31	       /* window size */
#define	TELOPT_TSPEED	32	       /* terminal speed */
#define	TELOPT_LFLOW	33	       /* remote flow control */
#define TELOPT_LINEMODE	34	       /* Linemode option */
#define TELOPT_XDISPLOC	35	       /* X Display Location */
#define TELOPT_OLD_ENVIRON 36	       /* Old - Environment variables */
#define	TELOPT_AUTHENTICATION 37       /* Authenticate */
#define	TELOPT_ENCRYPT	38	       /* Encryption option */
#define TELOPT_NEW_ENVIRON 39	       /* New - Environment variables */
#define TELOPT_TN3270E	40	       /* TN3270 enhancements */
#define TELOPT_XAUTH	41
#define TELOPT_CHARSET	42	       /* Character set */
#define TELOPT_RSP	43	       /* Remote serial port */
#define TELOPT_COM_PORT_OPTION 44      /* Com port control */
#define TELOPT_SLE	45	       /* Suppress local echo */
#define TELOPT_STARTTLS	46	       /* Start TLS */
#define TELOPT_KERMIT	47	       /* Automatic Kermit file transfer */
#define TELOPT_SEND_URL	48
#define TELOPT_FORWARD_X 49
#define TELOPT_PRAGMA_LOGON	138
#define TELOPT_SSPI_LOGON	139
#define TELOPT_PRAGMA_HEARTBEAT	140
#define	TELOPT_EXOPL	255	       /* extended-options-list */

#define	TELQUAL_IS	0	       /* option is... */
#define	TELQUAL_SEND	1	       /* send option */
#define	TELQUAL_INFO	2	       /* ENVIRON: informational version of IS */
#define BSD_VAR 1
#define BSD_VALUE 0
#define RFC_VAR 0
#define RFC_VALUE 1

#define CR 13
#define LF 10
#define NUL 0

#define iswritable(x) \
	( (x) != IAC && \
	      (telnet->opt_states[o_we_bin.index] == ACTIVE || (x) != CR))

static char *telopt(int opt)
{
#define i(x) if (opt == TELOPT_ ## x) return #x;
    i(BINARY);
    i(ECHO);
    i(RCP);
    i(SGA);
    i(NAMS);
    i(STATUS);
    i(TM);
    i(RCTE);
    i(NAOL);
    i(NAOP);
    i(NAOCRD);
    i(NAOHTS);
    i(NAOHTD);
    i(NAOFFD);
    i(NAOVTS);
    i(NAOVTD);
    i(NAOLFD);
    i(XASCII);
    i(LOGOUT);
    i(BM);
    i(DET);
    i(SUPDUP);
    i(SUPDUPOUTPUT);
    i(SNDLOC);
    i(TTYPE);
    i(EOR);
    i(TUID);
    i(OUTMRK);
    i(TTYLOC);
    i(X3PAD);
    i(NAWS);
    i(TSPEED);
    i(LFLOW);
    i(LINEMODE);
    i(XDISPLOC);
    i(OLD_ENVIRON);
    i(AUTHENTICATION);
    i(ENCRYPT);
    i(NEW_ENVIRON);
    i(TN3270E);
    i(XAUTH);
    i(CHARSET);
    i(RSP);
    i(COM_PORT_OPTION);
    i(SLE);
    i(STARTTLS);
    i(KERMIT);
    i(SEND_URL);
    i(FORWARD_X);
    i(PRAGMA_LOGON);
    i(SSPI_LOGON);
    i(PRAGMA_HEARTBEAT);
    i(EXOPL);
#undef i
    return "<unknown>";
}

static void telnet_size(void *handle, int width, int height);

struct Opt {
    int send;			       /* what we initially send */
    int nsend;			       /* -ve send if requested to stop it */
    int ack, nak;		       /* +ve and -ve acknowledgements */
    int option;			       /* the option code */
    int index;			       /* index into telnet->opt_states[] */
    enum {
	REQUESTED, ACTIVE, INACTIVE, REALLY_INACTIVE
    } initial_state;
};

enum {
    OPTINDEX_NAWS,
    OPTINDEX_TSPEED,
    OPTINDEX_TTYPE,
    OPTINDEX_OENV,
    OPTINDEX_NENV,
    OPTINDEX_ECHO,
    OPTINDEX_WE_SGA,
    OPTINDEX_THEY_SGA,
    OPTINDEX_WE_BIN,
    OPTINDEX_THEY_BIN,
    NUM_OPTS
};

static const struct Opt o_naws =
    { WILL, WONT, DO, DONT, TELOPT_NAWS, OPTINDEX_NAWS, REQUESTED };
static const struct Opt o_tspeed =
    { WILL, WONT, DO, DONT, TELOPT_TSPEED, OPTINDEX_TSPEED, REQUESTED };
static const struct Opt o_ttype =
    { WILL, WONT, DO, DONT, TELOPT_TTYPE, OPTINDEX_TTYPE, REQUESTED };
static const struct Opt o_oenv =
    { WILL, WONT, DO, DONT, TELOPT_OLD_ENVIRON, OPTINDEX_OENV, INACTIVE };
static const struct Opt o_nenv =
    { WILL, WONT, DO, DONT, TELOPT_NEW_ENVIRON, OPTINDEX_NENV, REQUESTED };
static const struct Opt o_echo =
    { DO, DONT, WILL, WONT, TELOPT_ECHO, OPTINDEX_ECHO, REQUESTED };
static const struct Opt o_we_sga =
    { WILL, WONT, DO, DONT, TELOPT_SGA, OPTINDEX_WE_SGA, REQUESTED };
static const struct Opt o_they_sga =
    { DO, DONT, WILL, WONT, TELOPT_SGA, OPTINDEX_THEY_SGA, REQUESTED };
static const struct Opt o_we_bin =
    { WILL, WONT, DO, DONT, TELOPT_BINARY, OPTINDEX_WE_BIN, INACTIVE };
static const struct Opt o_they_bin =
    { DO, DONT, WILL, WONT, TELOPT_BINARY, OPTINDEX_THEY_BIN, INACTIVE };

static const struct Opt *const opts[] = {
    &o_naws, &o_tspeed, &o_ttype, &o_oenv, &o_nenv, &o_echo,
    &o_we_sga, &o_they_sga, &o_we_bin, &o_they_bin, NULL
};

typedef struct telnet_tag {
    const struct plug_function_table *fn;
    /* the above field _must_ be first in the structure */

    Socket s;

    void *frontend;
    void *ldisc;
    int term_width, term_height;

    int opt_states[NUM_OPTS];

    int echoing, editing;
    int activated;
    int bufsize;
    int in_synch;
    int sb_opt, sb_len;
    unsigned char *sb_buf;
    int sb_size;

    enum {
	TOP_LEVEL, SEENIAC, SEENWILL, SEENWONT, SEENDO, SEENDONT,
	    SEENSB, SUBNEGOT, SUBNEG_IAC, SEENCR
    } state;

    Config cfg;

    Pinger pinger;
} *Telnet;

#define TELNET_MAX_BACKLOG 4096

#define SB_DELTA 1024

static void c_write(Telnet telnet, char *buf, int len)
{
    int backlog;
    backlog = from_backend(telnet->frontend, 0, buf, len);
    sk_set_frozen(telnet->s, backlog > TELNET_MAX_BACKLOG);
}

static void log_option(Telnet telnet, char *sender, int cmd, int option)
{
    char *buf;
    /*
     * The strange-looking "<?""?>" below is there to avoid a
     * trigraph - a double question mark followed by > maps to a
     * closing brace character!
     */
    buf = dupprintf("%s:\t%s %s", sender,
		    (cmd == WILL ? "WILL" : cmd == WONT ? "WONT" :
		     cmd == DO ? "DO" : cmd == DONT ? "DONT" : "<?""?>"),
		    telopt(option));
    logevent(telnet->frontend, buf);
    sfree(buf);
}

static void send_opt(Telnet telnet, int cmd, int option)
{
    unsigned char b[3];

    b[0] = IAC;
    b[1] = cmd;
    b[2] = option;
    telnet->bufsize = sk_write(telnet->s, (char *)b, 3);
    log_option(telnet, "client", cmd, option);
}

static void deactivate_option(Telnet telnet, const struct Opt *o)
{
    if (telnet->opt_states[o->index] == REQUESTED ||
	telnet->opt_states[o->index] == ACTIVE)
	send_opt(telnet, o->nsend, o->option);
    telnet->opt_states[o->index] = REALLY_INACTIVE;
}

/*
 * Generate side effects of enabling or disabling an option.
 */
static void option_side_effects(Telnet telnet, const struct Opt *o, int enabled)
{
    if (o->option == TELOPT_ECHO && o->send == DO)
	telnet->echoing = !enabled;
    else if (o->option == TELOPT_SGA && o->send == DO)
	telnet->editing = !enabled;
    if (telnet->ldisc)		       /* cause ldisc to notice the change */
	ldisc_send(telnet->ldisc, NULL, 0, 0);

    /* Ensure we get the minimum options */
    if (!telnet->activated) {
	if (telnet->opt_states[o_echo.index] == INACTIVE) {
	    telnet->opt_states[o_echo.index] = REQUESTED;
	    send_opt(telnet, o_echo.send, o_echo.option);
	}
	if (telnet->opt_states[o_we_sga.index] == INACTIVE) {
	    telnet->opt_states[o_we_sga.index] = REQUESTED;
	    send_opt(telnet, o_we_sga.send, o_we_sga.option);
	}
	if (telnet->opt_states[o_they_sga.index] == INACTIVE) {
	    telnet->opt_states[o_they_sga.index] = REQUESTED;
	    send_opt(telnet, o_they_sga.send, o_they_sga.option);
	}
	telnet->activated = TRUE;
    }
}

static void activate_option(Telnet telnet, const struct Opt *o)
{
    if (o->send == WILL && o->option == TELOPT_NAWS)
	telnet_size(telnet, telnet->term_width, telnet->term_height);
    if (o->send == WILL &&
	(o->option == TELOPT_NEW_ENVIRON ||
	 o->option == TELOPT_OLD_ENVIRON)) {
	/*
	 * We may only have one kind of ENVIRON going at a time.
	 * This is a hack, but who cares.
	 */
	deactivate_option(telnet, o->option ==
			  TELOPT_NEW_ENVIRON ? &o_oenv : &o_nenv);
    }
    option_side_effects(telnet, o, 1);
}

static void refused_option(Telnet telnet, const struct Opt *o)
{
    if (o->send == WILL && o->option == TELOPT_NEW_ENVIRON &&
	telnet->opt_states[o_oenv.index] == INACTIVE) {
	send_opt(telnet, WILL, TELOPT_OLD_ENVIRON);
	telnet->opt_states[o_oenv.index] = REQUESTED;
    }
    option_side_effects(telnet, o, 0);
}

static void proc_rec_opt(Telnet telnet, int cmd, int option)
{
    const struct Opt *const *o;

    log_option(telnet, "server", cmd, option);
    for (o = opts; *o; o++) {
	if ((*o)->option == option && (*o)->ack == cmd) {
	    switch (telnet->opt_states[(*o)->index]) {
	      case REQUESTED:
		telnet->opt_states[(*o)->index] = ACTIVE;
		activate_option(telnet, *o);
		break;
	      case ACTIVE:
		break;
	      case INACTIVE:
		telnet->opt_states[(*o)->index] = ACTIVE;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -