void printoption(const char *direction, int cmd, int option) { if (!showoptions) return; if (cmd == IAC) { if (TELCMD_OK(option)) fprintf(NetTrace, "%s IAC %s", direction, TELCMD(option)); else fprintf(NetTrace, "%s IAC %d", direction, option); } else { const char *fmt; fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" : (cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0; if (fmt) { fprintf(NetTrace, "%s %s ", direction, fmt); if (TELOPT_OK(option)) fprintf(NetTrace, "%s", TELOPT(option)); else if (option == TELOPT_EXOPL) fprintf(NetTrace, "EXOPL"); else fprintf(NetTrace, "%d", option); } else fprintf(NetTrace, "%s %d %d", direction, cmd, option); } if (NetTrace == stdout) { fprintf(NetTrace, "\r\n"); fflush(NetTrace); } else { fprintf(NetTrace, "\n"); } return; }
void handle_telnet(const unsigned char *bytes, uint16_t frame_len) { print1("TELNET "); print_ips_from_last_header_v1(); printf1("%u bytes\n", frame_len); const unsigned char *end = bytes + frame_len; while(bytes < end) { if(*bytes & 0xFF) { bytes++; uint8_t command = *bytes++; printf3(" cmd %s (%u): ", TELCMD_OK(command) ? TELCMD(command) : "CMD?", command); switch(command) { case DO: case DONT: case WONT: case WILL: { uint8_t option = *bytes++; printf3("%s (%u)", TELOPT(option), option); break; } case SB: { uint8_t suboption = *bytes++; printf3("%s (%u)", TELOPT(suboption), suboption); switch(suboption) { case TELOPT_TSPEED: printf3(" = %u", *bytes++); break; case TELOPT_NAWS: printf3(" = %u x %u", ntohs(*(uint16_t*)&bytes[0]), ntohs(*(uint16_t*)&bytes[2])); bytes += 4; break; default: break; } break; } case SE: print3("end of suboptions"); break; default: print3("unknown command"); break; } putchar3('\n'); if(command == SE) break; // end of options } else { bytes++; } } }
/* int length; length of suboption data */ void printsub (char direction, unsigned char *pointer, int length) { register int i; extern int want_status_response; #if defined AUTHENTICATION || defined ENCRYPTION char buf[512]; #endif if (showoptions || direction == 0 || (want_status_response && (pointer[0] == TELOPT_STATUS))) { if (direction) { fprintf (NetTrace, "%s IAC SB ", (direction == '<') ? "RCVD" : "SENT"); if (length >= 3) { register int j; i = pointer[length - 2]; j = pointer[length - 1]; if (i != IAC || j != SE) { fprintf (NetTrace, "(terminated by "); if (TELOPT_OK (i)) fprintf (NetTrace, "%s ", TELOPT (i)); else if (TELCMD_OK (i)) fprintf (NetTrace, "%s ", TELCMD (i)); else fprintf (NetTrace, "%d ", i); if (TELOPT_OK (j)) fprintf (NetTrace, "%s", TELOPT (j)); else if (TELCMD_OK (j)) fprintf (NetTrace, "%s", TELCMD (j)); else fprintf (NetTrace, "%d", j); fprintf (NetTrace, ", not IAC SE!) "); } } length -= 2; } if (length < 1) { fprintf (NetTrace, "(Empty suboption??\?)"); if (NetTrace == stdout) fflush (NetTrace); return; } switch (pointer[0]) { case TELOPT_TTYPE: fprintf (NetTrace, "TERMINAL-TYPE "); switch (pointer[1]) { case TELQUAL_IS: fprintf (NetTrace, "IS \"%.*s\"", length - 2, (char *) pointer + 2); break; case TELQUAL_SEND: fprintf (NetTrace, "SEND"); break; default: fprintf (NetTrace, "- unknown qualifier %d (0x%x).", pointer[1], pointer[1]); } break; case TELOPT_TSPEED: fprintf (NetTrace, "TERMINAL-SPEED"); if (length < 2) { fprintf (NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case TELQUAL_IS: fprintf (NetTrace, " IS "); fprintf (NetTrace, "%.*s", length - 2, (char *) pointer + 2); break; default: if (pointer[1] == 1) fprintf (NetTrace, " SEND"); else fprintf (NetTrace, " %d (unknown)", pointer[1]); for (i = 2; i < length; i++) fprintf (NetTrace, " ?%d?", pointer[i]); break; } break; case TELOPT_LFLOW: fprintf (NetTrace, "TOGGLE-FLOW-CONTROL"); if (length < 2) { fprintf (NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case LFLOW_OFF: fprintf (NetTrace, " OFF"); break; case LFLOW_ON: fprintf (NetTrace, " ON"); break; case LFLOW_RESTART_ANY: fprintf (NetTrace, " RESTART-ANY"); break; case LFLOW_RESTART_XON: fprintf (NetTrace, " RESTART-XON"); break; default: fprintf (NetTrace, " %d (unknown)", pointer[1]); } for (i = 2; i < length; i++) fprintf (NetTrace, " ?%d?", pointer[i]); break; case TELOPT_NAWS: fprintf (NetTrace, "NAWS"); if (length < 2) { fprintf (NetTrace, " (empty suboption??\?)"); break; } if (length == 2) { fprintf (NetTrace, " ?%d?", pointer[1]); break; } fprintf (NetTrace, " %d %d (%d)", pointer[1], pointer[2], (int) ((((unsigned int) pointer[1]) << 8) | ((unsigned int) pointer[2]))); if (length == 4) { fprintf (NetTrace, " ?%d?", pointer[3]); break; } fprintf (NetTrace, " %d %d (%d)", pointer[3], pointer[4], (int) ((((unsigned int) pointer[3]) << 8) | ((unsigned int) pointer[4]))); for (i = 5; i < length; i++) fprintf (NetTrace, " ?%d?", pointer[i]); break; #if defined AUTHENTICATION case TELOPT_AUTHENTICATION: fprintf (NetTrace, "AUTHENTICATION"); if (length < 2) { fprintf (NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case TELQUAL_REPLY: case TELQUAL_IS: fprintf (NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ? "IS" : "REPLY"); if (AUTHTYPE_NAME_OK (pointer[2]) && AUTHTYPE_NAME (pointer[2])) fprintf (NetTrace, "%s ", AUTHTYPE_NAME (pointer[2])); else fprintf (NetTrace, "%d ", pointer[2]); if (length < 3) { fprintf (NetTrace, "(partial suboption??\?)"); break; } fprintf (NetTrace, "%s|%s", ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? "CLIENT" : "SERVER", ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? "MUTUAL" : "ONE-WAY"); auth_printsub (&pointer[1], length - 1, buf, sizeof (buf)); fprintf (NetTrace, "%s", buf); break; case TELQUAL_SEND: i = 2; fprintf (NetTrace, " SEND "); while (i < length) { if (AUTHTYPE_NAME_OK (pointer[i]) && AUTHTYPE_NAME (pointer[i])) fprintf (NetTrace, "%s ", AUTHTYPE_NAME (pointer[i])); else fprintf (NetTrace, "%d ", pointer[i]); if (++i >= length) { fprintf (NetTrace, "(partial suboption??\?)"); break; } fprintf (NetTrace, "%s|%s ", ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? "CLIENT" : "SERVER", ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? "MUTUAL" : "ONE-WAY"); ++i; } break; case TELQUAL_NAME: i = 2; fprintf (NetTrace, " NAME \""); while (i < length) putc (pointer[i++], NetTrace); putc ('"', NetTrace); break; default: for (i = 2; i < length; i++) fprintf (NetTrace, " ?%d?", pointer[i]); break; } break; #endif #ifdef ENCRYPTION case TELOPT_ENCRYPT: fprintf (NetTrace, "ENCRYPT"); if (length < 2) { fprintf (NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case ENCRYPT_START: fprintf (NetTrace, " START"); break; case ENCRYPT_END: fprintf (NetTrace, " END"); break; case ENCRYPT_REQSTART: fprintf (NetTrace, " REQUEST-START"); break; case ENCRYPT_REQEND: fprintf (NetTrace, " REQUEST-END"); break; case ENCRYPT_IS: case ENCRYPT_REPLY: fprintf (NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ? "IS" : "REPLY"); if (length < 3) { fprintf (NetTrace, " (partial suboption??\?)"); break; } if (ENCTYPE_NAME_OK (pointer[2]) && ENCTYPE_NAME (pointer[2])) fprintf (NetTrace, "%s ", ENCTYPE_NAME (pointer[2])); else fprintf (NetTrace, " %d (unknown)", pointer[2]); encrypt_printsub (&pointer[1], length - 1, buf, sizeof (buf)); fprintf (NetTrace, "%s", buf); break; case ENCRYPT_SUPPORT: i = 2; fprintf (NetTrace, " SUPPORT "); while (i < length) { if (ENCTYPE_NAME_OK (pointer[i]) && ENCTYPE_NAME (pointer[i])) fprintf (NetTrace, "%s ", ENCTYPE_NAME (pointer[i])); else fprintf (NetTrace, "%d ", pointer[i]); i++; } break; case ENCRYPT_ENC_KEYID: fprintf (NetTrace, " ENC_KEYID "); goto encommon; case ENCRYPT_DEC_KEYID: fprintf (NetTrace, " DEC_KEYID "); goto encommon; default: fprintf (NetTrace, " %d (unknown)", pointer[1]); encommon: for (i = 2; i < length; i++) fprintf (NetTrace, " %d", pointer[i]); break; } break; #endif /* ENCRYPTION */ case TELOPT_LINEMODE: fprintf (NetTrace, "LINEMODE "); if (length < 2) { fprintf (NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case WILL: fprintf (NetTrace, "WILL "); goto common; case WONT: fprintf (NetTrace, "WONT "); goto common; case DO: fprintf (NetTrace, "DO "); goto common; case DONT: fprintf (NetTrace, "DONT "); common: if (length < 3) { fprintf (NetTrace, "(no option??\?)"); break; } switch (pointer[2]) { case LM_FORWARDMASK: fprintf (NetTrace, "Forward Mask"); for (i = 3; i < length; i++) fprintf (NetTrace, " %x", pointer[i]); break; default: fprintf (NetTrace, "%d (unknown)", pointer[2]); for (i = 3; i < length; i++) fprintf (NetTrace, " %d", pointer[i]); break; } break; case LM_SLC: fprintf (NetTrace, "SLC"); for (i = 2; i < length - 2; i += 3) { if (SLC_NAME_OK (pointer[i + SLC_FUNC])) fprintf (NetTrace, " %s", SLC_NAME (pointer[i + SLC_FUNC])); else fprintf (NetTrace, " %d", pointer[i + SLC_FUNC]); switch (pointer[i + SLC_FLAGS] & SLC_LEVELBITS) { case SLC_NOSUPPORT: fprintf (NetTrace, " NOSUPPORT"); break; case SLC_CANTCHANGE: fprintf (NetTrace, " CANTCHANGE"); break; case SLC_VARIABLE: fprintf (NetTrace, " VARIABLE"); break; case SLC_DEFAULT: fprintf (NetTrace, " DEFAULT"); break; } fprintf (NetTrace, "%s%s%s", (pointer[i + SLC_FLAGS] & SLC_ACK) ? "|ACK" : "", (pointer[i + SLC_FLAGS] & SLC_FLUSHIN) ? "|FLUSHIN" : "", (pointer[i + SLC_FLAGS] & SLC_FLUSHOUT) ? "|FLUSHOUT" : ""); if (pointer[i + SLC_FLAGS] & ~(SLC_ACK | SLC_FLUSHIN | SLC_FLUSHOUT | SLC_LEVELBITS)) fprintf (NetTrace, "(0x%x)", pointer[i + SLC_FLAGS]); fprintf (NetTrace, " %d;", pointer[i + SLC_VALUE]); if ((pointer[i + SLC_VALUE] == IAC) && (pointer[i + SLC_VALUE + 1] == IAC)) i++; } for (; i < length; i++) fprintf (NetTrace, " ?%d?", pointer[i]); break; case LM_MODE: fprintf (NetTrace, "MODE "); if (length < 3) { fprintf (NetTrace, "(no mode??\?)"); break; } { char tbuf[64]; sprintf (tbuf, "%s%s%s%s%s", pointer[2] & MODE_EDIT ? "|EDIT" : "", pointer[2] & MODE_TRAPSIG ? "|TRAPSIG" : "", pointer[2] & MODE_SOFT_TAB ? "|SOFT_TAB" : "", pointer[2] & MODE_LIT_ECHO ? "|LIT_ECHO" : "", pointer[2] & MODE_ACK ? "|ACK" : ""); fprintf (NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0"); } if (pointer[2] & ~(MODE_MASK)) fprintf (NetTrace, " (0x%x)", pointer[2]); for (i = 3; i < length; i++) fprintf (NetTrace, " ?0x%x?", pointer[i]); break; default: fprintf (NetTrace, "%d (unknown)", pointer[1]); for (i = 2; i < length; i++) fprintf (NetTrace, " %d", pointer[i]); } break; case TELOPT_STATUS: { register char *cp; register int j, k; fprintf (NetTrace, "STATUS"); switch (pointer[1]) { default: if (pointer[1] == TELQUAL_SEND) fprintf (NetTrace, " SEND"); else fprintf (NetTrace, " %d (unknown)", pointer[1]); for (i = 2; i < length; i++) fprintf (NetTrace, " ?%d?", pointer[i]); break; case TELQUAL_IS: if (--want_status_response < 0) want_status_response = 0; if (NetTrace == stdout) fprintf (NetTrace, " IS\r\n"); else fprintf (NetTrace, " IS\n"); for (i = 2; i < length; i++) { switch (pointer[i]) { case DO: cp = "DO"; goto common2; case DONT: cp = "DONT"; goto common2; case WILL: cp = "WILL"; goto common2; case WONT: cp = "WONT"; goto common2; common2: i++; if (TELOPT_OK ((int) pointer[i])) fprintf (NetTrace, " %s %s", cp, TELOPT (pointer[i])); else fprintf (NetTrace, " %s %d", cp, pointer[i]); if (NetTrace == stdout) fprintf (NetTrace, "\r\n"); else fprintf (NetTrace, "\n"); break; case SB: fprintf (NetTrace, " SB "); i++; j = k = i; while (j < length) { if (pointer[j] == SE) { if (j + 1 == length) break; if (pointer[j + 1] == SE) j++; else break; } pointer[k++] = pointer[j++]; } printsub (0, &pointer[i], k - i); if (i < length) { fprintf (NetTrace, " SE"); i = j; } else i = j - 1; if (NetTrace == stdout) fprintf (NetTrace, "\r\n"); else fprintf (NetTrace, "\n"); break; default: fprintf (NetTrace, " %d", pointer[i]); break; } } break; } break; } case TELOPT_XDISPLOC: fprintf (NetTrace, "X-DISPLAY-LOCATION "); switch (pointer[1]) { case TELQUAL_IS: fprintf (NetTrace, "IS \"%.*s\"", length - 2, (char *) pointer + 2); break; case TELQUAL_SEND: fprintf (NetTrace, "SEND"); break; default: fprintf (NetTrace, "- unknown qualifier %d (0x%x).", pointer[1], pointer[1]); } break; case TELOPT_NEW_ENVIRON: fprintf (NetTrace, "NEW-ENVIRON "); #ifdef OLD_ENVIRON goto env_common1; case TELOPT_OLD_ENVIRON: fprintf (NetTrace, "OLD-ENVIRON"); env_common1: #endif switch (pointer[1]) { case TELQUAL_IS: fprintf (NetTrace, "IS "); goto env_common; case TELQUAL_SEND: fprintf (NetTrace, "SEND "); goto env_common; case TELQUAL_INFO: fprintf (NetTrace, "INFO "); env_common: { const char *quote = ""; #if defined ENV_HACK && defined OLD_ENVIRON extern int old_env_var, old_env_value; #endif for (i = 2; i < length; i++) { switch (pointer[i]) { case NEW_ENV_VALUE: #ifdef OLD_ENVIRON /* case NEW_ENV_OVAR: */ if (pointer[0] == TELOPT_OLD_ENVIRON) { # ifdef ENV_HACK if (old_env_var == OLD_ENV_VALUE) fprintf (NetTrace, "%s(VALUE) ", quote); else # endif fprintf (NetTrace, "%sVAR ", quote); } else #endif /* OLD_ENVIRON */ fprintf (NetTrace, "%sVALUE ", quote); quote = ""; break; case NEW_ENV_VAR: #ifdef OLD_ENVIRON /* case OLD_ENV_VALUE: */ if (pointer[0] == TELOPT_OLD_ENVIRON) { # ifdef ENV_HACK if (old_env_value == OLD_ENV_VAR) fprintf (NetTrace, "%s(VAR) ", quote); else # endif fprintf (NetTrace, "%sVALUE ", quote); } else #endif /* OLD_ENVIRON */ fprintf (NetTrace, "%sVAR ", quote); quote = ""; break; case ENV_ESC: fprintf (NetTrace, "%sESC ", quote); quote = ""; break; case ENV_USERVAR: fprintf (NetTrace, "%sUSERVAR ", quote); quote = ""; break; default: if (isprint (pointer[i]) && pointer[i] != '"') { if (quote[0] == '\0') { putc ('"', NetTrace); quote = "\" "; } putc (pointer[i], NetTrace); } else { fprintf (NetTrace, "%s%03o ", quote, pointer[i]); quote = ""; } break; } } if (quote[0] != '\0') putc ('"', NetTrace); break; } } break; default: if (TELOPT_OK (pointer[0])) fprintf (NetTrace, "%s (unknown)", TELOPT (pointer[0])); else fprintf (NetTrace, "%d (unknown)", pointer[0]); for (i = 1; i < length; i++) fprintf (NetTrace, " %d", pointer[i]); break; } if (direction) { if (NetTrace == stdout) fprintf (NetTrace, "\r\n"); else fprintf (NetTrace, "\n"); } if (NetTrace == stdout) fflush (NetTrace); } }
void optionstatus (void) { register int i; extern char will_wont_resp[], do_dont_resp[]; for (i = 0; i < 256; i++) { if (do_dont_resp[i]) { if (TELOPT_OK (i)) printf ("resp DO_DONT %s: %d\n", TELOPT (i), do_dont_resp[i]); else if (TELCMD_OK (i)) printf ("resp DO_DONT %s: %d\n", TELCMD (i), do_dont_resp[i]); else printf ("resp DO_DONT %d: %d\n", i, do_dont_resp[i]); if (my_want_state_is_do (i)) { if (TELOPT_OK (i)) printf ("want DO %s\n", TELOPT (i)); else if (TELCMD_OK (i)) printf ("want DO %s\n", TELCMD (i)); else printf ("want DO %d\n", i); } else { if (TELOPT_OK (i)) printf ("want DONT %s\n", TELOPT (i)); else if (TELCMD_OK (i)) printf ("want DONT %s\n", TELCMD (i)); else printf ("want DONT %d\n", i); } } else { if (my_state_is_do (i)) { if (TELOPT_OK (i)) printf (" DO %s\n", TELOPT (i)); else if (TELCMD_OK (i)) printf (" DO %s\n", TELCMD (i)); else printf (" DO %d\n", i); } } if (will_wont_resp[i]) { if (TELOPT_OK (i)) printf ("resp WILL_WONT %s: %d\n", TELOPT (i), will_wont_resp[i]); else if (TELCMD_OK (i)) printf ("resp WILL_WONT %s: %d\n", TELCMD (i), will_wont_resp[i]); else printf ("resp WILL_WONT %d: %d\n", i, will_wont_resp[i]); if (my_want_state_is_will (i)) { if (TELOPT_OK (i)) printf ("want WILL %s\n", TELOPT (i)); else if (TELCMD_OK (i)) printf ("want WILL %s\n", TELCMD (i)); else printf ("want WILL %d\n", i); } else { if (TELOPT_OK (i)) printf ("want WONT %s\n", TELOPT (i)); else if (TELCMD_OK (i)) printf ("want WONT %s\n", TELCMD (i)); else printf ("want WONT %d\n", i); } } else { if (my_state_is_will (i)) { if (TELOPT_OK (i)) printf (" WILL %s\n", TELOPT (i)); else if (TELCMD_OK (i)) printf (" WILL %s\n", TELCMD (i)); else printf (" WILL %d\n", i); } } } }
int telopt_handler( DESCRIPTOR_DATA *d, unsigned char *src, int srclen, unsigned char *out ) { int cnt = 0, skip = 0; unsigned char *pti, *pto; pti = src; pto = out; while ( srclen > 0 ) { switch ( *pti ) { case IAC: for ( cnt = 0; telopt_table[cnt].code; cnt++ ) { if ( srclen >= telopt_table[cnt].size && !memcmp(pti, telopt_table[cnt].code, telopt_table[cnt].size) ) { skip = telopt_table[cnt].func(d, pti, srclen); break; } } if ( telopt_table[cnt].code == NULL ) { switch ( pti[1] ) { case WILL: case DO: case WONT: case DONT: skip = 3; break; case SB: //fixme break; case IAC: *pto++ = *pti++; srclen--; skip = 1; break; default: if ( TELCMD_OK(pti[1]) ) skip = 2; else skip = 1; break; } } skip = URANGE(0, skip, srclen); pti += skip; srclen -= skip; break; case '\0': pti++; srclen--; break; case '\r': pti++; srclen--; break; case '\n': *pto++ = *pti++; srclen--; break; default: *pto++ = *pti++; srclen--; break; } } *pto = 0; return strlen((const char *)out); }
/* input: raw character * output: telnet command if c was handled, otherwise zero. */ unsigned int telnet_handler(unsigned char c) { static unsigned char iac_quote = 0; /* as byte to reduce memory */ static unsigned char iac_opt_req = 0; static unsigned char iac_buf[TELNET_IAC_MAXLEN]; static unsigned int iac_buflen = 0; /* we have to quote all IACs. */ if(c == IAC && !iac_quote) { iac_quote = 1; return NOP; } #ifdef DETECT_CLIENT /* hash client telnet sequences */ if(cuser.userid[0]==0) { if(iac_state == IAC_WAIT_SE) { // skip suboption } else { if(iac_quote) UpdateClientCode(IAC); UpdateClientCode(c); } } #endif /* a special case is the top level iac. otherwise, iac is just a quote. */ if (iac_quote) { if(iac_state == IAC_NONE) iac_state = IAC_COMMAND; if(iac_state == IAC_WAIT_SE && c == SE) iac_state = IAC_PROCESS_OPT; iac_quote = 0; } /* now, let's process commands by state */ switch(iac_state) { case IAC_NONE: return 0; case IAC_COMMAND: #if 0 // def DEBUG { int cx = c; /* to make compiler happy */ write(0, "-", 1); if(TELCMD_OK(cx)) write(0, TELCMD(c), strlen(TELCMD(c))); write(0, " ", 1); } #endif iac_state = IAC_NONE; /* by default we restore state. */ switch(c) { case IAC: // return 0; // we don't want to allow IACs as input. return 1; /* we don't want to process these. or maybe in future. */ case BREAK: /* break */ #ifdef DBG_OUTRPT fakeEscape = !fakeEscape; return NOP; #endif case ABORT: /* Abort process */ case SUSP: /* Suspend process */ case AO: /* abort output--but let prog finish */ case IP: /* interrupt process--permanently */ case EOR: /* end of record (transparent mode) */ case DM: /* data mark--for connect. cleaning */ case xEOF: /* End of file: EOF is already used... */ return NOP; case NOP: /* nop */ return NOP; /* we should process these, but maybe in future. */ case GA: /* you may reverse the line */ case EL: /* erase the current line */ case EC: /* erase the current character */ return NOP; /* good */ case AYT: /* are you there */ { const char *alive = "I'm still alive, loading: "; char buf[STRLEN]; /* respond as fast as we can */ write(0, alive, strlen(alive)); // cpuload(buf); buf[0] = '0'; // TODO: cpuload write(0, buf, strlen(buf)); write(0, "\r\n", 2); } return NOP; case DONT: /* you are not to use option */ case DO: /* please, you use option */ case WONT: /* I won't use option */ case WILL: /* I will use option */ iac_opt_req = c; iac_state = IAC_WAIT_OPT; return NOP; case SB: /* interpret as subnegotiation */ iac_state = IAC_WAIT_SE; iac_buflen = 0; return NOP; case SE: /* end sub negotiation */ default: return NOP; } return 1; case IAC_WAIT_OPT: #if 0 // def DEBUG write(0, "-", 1); if(TELOPT_OK(c)) write(0, TELOPT(c), strlen(TELOPT(c))); write(0, " ", 1); #endif iac_state = IAC_NONE; /* * According to RFC, there're some tricky steps to prevent loop. * However because we have a poor term which does not allow * most abilities, let's be a strong boss here. * * Although my old imeplementation worked, it's even better to follow this: * http://www.tcpipguide.com/free/t_TelnetOptionsandOptionNegotiation-3.htm */ switch(c) { /* i-dont-care: i don't care about what client is. * these should be clamed in init and * client must follow me. */ case TELOPT_TTYPE: /* termtype or line. */ case TELOPT_NAWS: /* resize terminal */ case TELOPT_SGA: /* supress GA */ case TELOPT_ECHO: /* echo */ case TELOPT_BINARY: /* we are CJK. */ break; /* i-dont-agree: i don't understand/agree these. * according to RFC, saying NO stopped further * requests so there'll not be endless loop. */ case TELOPT_RCP: /* prepare to reconnect */ default: if (iac_opt_req == WILL || iac_opt_req == DO) { /* unknown option, reply with won't */ unsigned char cmd[3] = { IAC, DONT, 0 }; if(iac_opt_req == DO) cmd[1] = WONT; cmd[2] = c; write(0, cmd, sizeof(cmd)); } break; } return 1; case IAC_WAIT_SE: iac_buf[iac_buflen++] = c; /* no need to convert state because previous quoting will do. */ if(iac_buflen == TELNET_IAC_MAXLEN) { /* may be broken protocol? * whether finished or not, break for safety * or user may be frozen. */ iac_state = IAC_NONE; return 0; } return 1; case IAC_PROCESS_OPT: iac_state = IAC_NONE; #if 0 // def DEBUG write(0, "-", 1); if(TELOPT_OK(iac_buf[0])) write(0, TELOPT(iac_buf[0]), strlen(TELOPT(iac_buf[0]))); write(0, " ", 1); #endif switch(iac_buf[0]) { /* resize terminal */ case TELOPT_NAWS: { int w = (iac_buf[1] << 8) + (iac_buf[2]); int h = (iac_buf[3] << 8) + (iac_buf[4]); term_resize(w, h); #ifdef DETECT_CLIENT if(cuser.userid[0]==0) { UpdateClientCode(iac_buf[0]); if(w==80 && h==24) UpdateClientCode(1); else if(w==80) UpdateClientCode(2); else if(h==24) UpdateClientCode(3); else UpdateClientCode(4); UpdateClientCode(IAC); UpdateClientCode(SE); } #endif } break; default: #ifdef DETECT_CLIENT if(cuser.userid[0]==0) { int i; for(i=0;i<iac_buflen;i++) UpdateClientCode(iac_buf[i]); UpdateClientCode(IAC); UpdateClientCode(SE); } #endif break; } return 1; } return 1; /* never reached */ }
/** * @brief Parses Telnet Options negotiations * @param c * @return */ unsigned char TelnetManager::telnetOptionParse(unsigned char c) { // TEL-OPT Parser switch(m_teloptStage) { // Find IAC case 0: // Check first Char in Fresh Sequence if(c != IAC) { // Add character to output buffer. return c; } else { m_teloptStage++; } break; // Find Command case 1: if(c == IAC) { // If binary, then we expect double IAC for actual characer if (m_is_active_bin) { std::cout << "\r\n Got double IAC w/ Binary!!\r\n" << std::endl; m_teloptStage = 0; return IAC; } else { // Restart on next character // Double IAC = IAC character, not valid so skip it for now. // Telnet states binary mode, double IAC mean pass through // Char 255. But this doesn't equal any text in ExtASCII // So we going to stuff it. std::cout << "\r\n Got double IAC!!\r\n" << std::endl; break; } } if(c != IAC) { switch(c) { // Catch Pass-through commands. case GA: // 249 /* you may reverse the line */ case EL: // 248 /* erase the current line */ case EC: // 247 /* erase the current character */ case AYT: // 246 /* are you there */ case AO: // 245 /* abort output--but let prog finish */ case IP: // 244 /* interrupt process--permanently */ case BREAK: // 243 /* break */ case DM: // 242 /* data mark--for connect. cleaning */ case NOP: // 241 /* nop */ case SE: // 240 /* end sub negotiation */ case EOR: // 239 /* end of record (transparent mode) */ case ABORT: // 238 /* Abort process */ case SUSP: // 237 /* Suspend process */ case xEOF: // 236 /* End of file: EOF is already used... */ // Pass Through commands that don't need Response. std::cout << "[IAC] [" << (int)c << "] PASS-THROUGH" << std::endl; m_teloptStage = 0; break; default: // Move to Command Parsing. m_teloptCommand = c; m_teloptStage++; break; } } break; // Find Option case 2: m_teloptStage = 0; // Catch if were getting Invalid Commands. if(TELCMD_OK(m_teloptCommand)) std::cout << "[IAC] [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; else { // Hopefully won't get here! std::cout << "[IAC] [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; m_teloptStage = 0; break; } switch(m_teloptCommand) { // No responses needed, just stuff these. case DONT: std::cout << "[IAC] RECEIVED DONT [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; switch(c) { case IAC : m_teloptStage = 1; break; default: // Only Response Once, if we've already received this, then ignore it a second time! if (!checkActive(m_teloptCommand)) { std::cout << "[IAC] DONT -> WONT [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; telnetSendIAC(telnetOptionAcknowledge(m_teloptCommand),c); m_teloptStage = 0; // Only Response once to Don't! addActive(m_teloptCommand); } break; } break; case DO: // Replies WILL / WON'T std::cout << "[IAC] RECEIVED DO [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; switch(c) { case TELOPT_ECHO: if (!m_isECHOCompleted) { std::cout << "[IAC] DO TELOPT_ECHO [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; telnetSendIAC(telnetOptionDeny(m_teloptCommand),c); m_is_active_echo = false; m_isECHOCompleted = false; } break; case TELOPT_BINARY: if (!m_isBINCompleted) { std::cout << "[IAC] DO TELOPT_BINARY [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; telnetSendIAC(telnetOptionAcknowledge(m_teloptCommand),c); m_isBINCompleted = true; m_is_active_bin = true; } break; case TELOPT_SGA: if (!m_isSGACompleted) { std::cout << "[IAC] DO TELOPT_SGA [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; telnetSendIAC(telnetOptionAcknowledge(m_teloptCommand),c); m_isSGACompleted = true; m_is_active_sga = true; } break; case TELOPT_TTYPE: std::cout << "[IAC] DO TELOPT_TTYPE [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; telnetSendIAC(telnetOptionAcknowledge(m_teloptCommand),c); m_is_active_ttype = true; break; case TELOPT_NAWS: std::cout << "[IAC] DO TELOPT_NAWS [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; telnetSendIAC(telnetOptionAcknowledge(m_teloptCommand),c); telnetOptionNawsReply(); m_is_active_naws = true; break; /* case IAC : printf("\r\n [DO - INCORRECT IAC Received, resetting.] \r\n"); stage = 1; return 255; */ default: // Only Response Once, if we've already received this, then ignore it a second time! if (!checkActive(m_teloptCommand)) { std::cout << "[IAC] DO -> WONT [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; telnetSendIAC(telnetOptionDeny(m_teloptCommand),c); addActive(m_teloptCommand); } break; } m_teloptStage = 0; break; // WILL means the Server Will DO IT! // We reply Fine, do it! case WILL: // Replies DO And DONT std::cout << "[IAC] RECEIVED WILL [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; // Don't response to WILL Requests. switch(c) { case TELOPT_ECHO: if(!m_isECHOCompleted) { std::cout << "[IAC] WILL TELOPT_ECHO [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; telnetSendIAC(telnetOptionDeny(m_teloptCommand),c); m_is_active_echo = false; m_isECHOCompleted = true; } break; case TELOPT_BINARY : if(!m_isBINCompleted) { std::cout << "[IAC] WILL TELOPT_BINARY [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; telnetSendIAC(telnetOptionAcknowledge(m_teloptCommand),c); m_is_active_bin = true; m_isBINCompleted = true; } break; case TELOPT_SGA : if(!m_isSGACompleted) { std::cout << "[IAC] WILL TELOPT_SGA [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; telnetSendIAC(telnetOptionAcknowledge(m_teloptCommand),c); m_is_active_sga = true; m_isSGACompleted = true; } break; /* case IAC : stage = 1; return 255; */ default : // Only Response Once, if we've already received this, then ignore it a second time! if (!checkActive(m_teloptCommand)) { std::cout << "[IAC] WILL -> DONT [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; telnetSendIAC(telnetOptionDeny(m_teloptCommand),c); addActive(m_teloptCommand); } break; } m_teloptStage = 0; break; case WONT: // Don't respond to WONT std::cout << "[IAC] RECEIVED WONT [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; //telnetSendIAC(telnetOptionAcknowledge(m_teloptCommand),c); //printf("\r\n [WONT - responded DONT %i] \r\n",c); m_teloptStage = 0; break; // Start of Sub Negotiations and Stages 3 - 4 case SB: // 250 std::cout << "[IAC] TELNET_STATE_SB [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; if(c == TELOPT_TTYPE) { m_currentOption = c; m_teloptStage = 3; } else { std::cout << "[IAC] TELNET_STATE_SB INVALID [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; // Invalid, reset back. m_teloptStage = 0; } break; default: // Options or Commands Not Parsed, RESET. std::cout << "[IAC] INVALID [" << (int)m_teloptCommand << "] [" << (int)c << "]" << std::endl; m_teloptStage = 0; break; } break; case 3: std::cout << "--> STAGE 3 [" << (int)c << "]" << std::endl; //Options will be 1 After SB //IAC SB TTYPE SEND IAC SE switch(m_currentOption) { case TELOPT_TTYPE: if(c == TELQUAL_SEND) // SEND { std::cout << "[IAC] TELQUAL_SEND [" << (int)m_currentOption << "] [" << (int)c << "]" << std::endl; m_teloptStage = 4; } else m_teloptStage = 0; break; default: //printf("\r\n [Stage 3 - unregistered stuff it] - %i, %i \r\n",opt, c); if(c == SE) { std::cout << "[IAC] SB END [" << (int)m_currentOption << "] [" << (int)c << "]" << std::endl; m_teloptStage = 0; } else { // reset m_teloptStage = 0; } break; } break; // Only Gets here on TTYPE Sub-Negotiation. case 4: std::cout << "--> STAGE 4 [" << (int)c << "]" << std::endl; switch(c) { case IAC: std::cout << "[IAC] TTYPE TELNET_STATE_SB IAC [" << (int)m_currentOption << "] [" << (int)c << "]" << std::endl; break; case SE: std::cout << "[IAC] TTYPE TELNET_STATE_SB SE [" << (int)m_currentOption << "] [" << (int)c << "]" << std::endl; // Send TTYPE After End of Complete Sequence is Registered. telnetOptionTerminalTypeReply(); m_teloptStage = 0; break; } break; } //std::cout << "[IAC] null return [" << (int)c << "] " << std::endl; return '\0'; }