static InterpretCommand parseoption(TelnetState* ts, TAction action, TOption option) { switch (option) { case TIMING_MARK: // Send a reply when this is a request if (action == DO) SendOption(ts, WILL, TIMING_MARK); break; case SUPPRESS_GO_AHEAD: break; case ECHO: if (action == WILL) // we do the echo, not the client ! SendOption(ts, DONT, ECHO); break; case NAWS: // nothing special to do here... break; default: // Default unknown option, reply DONT/WONT if (action == DO || action == WILL) SendOption(ts, action<=WONT?DONT:WONT, option); break; } return IC_NOP; }
void TelnetOption::Start() { if (stateLocal == osYes) SendOption(TelnetProtocol::cdWILL); if (stateRemote == osYes) SendOption(TelnetProtocol::cdDO); }
void TelnetProtocol::SendSubNegotiation(int option, const BYTE_vector ¶ms) { SendOption(cdSB, (BYTE)option); printf(" "); for (BYTE_vector::const_iterator i = params.begin() ; i != params.end() ; i++) { BYTE b = *i; printf("%u ", (unsigned)b); SendRaw(&b, sizeof(b)); } printf("SE\n"); BYTE buf[2] = {cdIAC, cdSE}; SendRaw(buf, sizeof(buf)); }
void TelnetProtocol::SendSubNegotiation(BYTE option, const BYTE_vector ¶ms) { SendOption(cdSB, option); cout << " "; for (BYTE_vector::const_iterator i = params.begin() ; i != params.end() ; i++) { BYTE b = *i; cout << (unsigned)b << " "; streamEncoded += b; if (b == cdIAC) streamEncoded += b; } cout << "SE" << endl; streamEncoded += (BYTE)cdIAC; streamEncoded += (BYTE)cdSE; }
static int l_newinterpreter(lua_State *L) { TelnetState* ts; ts = lua_newuserdata(L, sizeof(*ts)); // Assign the metatable to the userdata luaL_getmetatable(L, OBJ_NAME); lua_setmetatable(L, -2); // Initialize default values memset(ts, 0, sizeof(*ts)); ts->L = L; // default settings ts->editmode = TELNET_LINE_MODE; ts->autocompletefuncref = LUA_NOREF; // Parse params int historysize = 0; if (lua_type(L, -2) == LUA_TTABLE) { // Edit mode setting lua_getfield(L, -2, "mode"); const char* m = lua_tostring(L, -1); if (m) { if (!strcmp("line", m)) ts->editmode = TELNET_LINE_MODE; else if (!strcmp("edit", m)) ts->editmode = TELNET_EDIT_MODE; else luaL_error(L, "mode should be either 'line' or 'edit' (got '%s' instead)", m); } lua_pop(L, 1); if (ts->editmode == TELNET_EDIT_MODE) { // History Size lua_getfield(L, -2, "history"); historysize = lua_tointeger(L, -1); lua_pop(L, 1); // Autocomplete function lua_getfield(L, -2, "autocomplete"); if (!lua_isnil(L, -1)) { if (lua_type(L, -1) == LUA_TFUNCTION) { ts->autocompletefuncref = luaL_ref(L, LUA_REGISTRYINDEX); lua_pushnil(L); // to make it even with the following pop } else luaL_error(L, "autocomplete must be a function"); } lua_pop(L, 1); } } if (ts->editmode == TELNET_EDIT_MODE) { // Do teel initialization and setup ts->teel = teel_initialize(teel_reader, teel_writer, ts); if (!ts->teel) return luaL_error(L, "Failed to initialize teel library"); teel_sethistorysize(ts->teel, historysize); teel_setautocompletefunc(ts->teel, teel_autocomplete); // Request that all char are sent when typed SendOption(ts, DO, SUPPRESS_GO_AHEAD); SendOption(ts, WILL, SUPPRESS_GO_AHEAD); // Request to echo SendOption(ts, WILL, ECHO); // Request negotiation of windows size SendOption(ts, DO, NAWS); } return 1; }
int TelnetProtocol::Write(const void *pBuf, int count) { for (int i = 0 ; i < count ; i++) { BYTE ch = ((const BYTE *)pBuf)[i]; switch (state) { case stData: if (ch == cdIAC) state = stCode; else WriteRaw(&ch, 1); break; case stCode: switch (ch) { case cdIAC: WriteRaw(&ch, 1); state = stData; break; case cdSB: case cdWILL: case cdWONT: case cdDO: case cdDONT: code = ch; state = stOption; break; default: printf("RECV: unknown code %u\n", (unsigned)ch); state = stData; } break; case stOption: printf("RECV: %s %u\n", code2name(code), (unsigned)ch); switch (code) { case cdSB: option = ch; params.clear(); state = stSubParams; break; case cdWILL: switch (options[ch].remoteOptionState) { case OptionState::osCant: SendOption(cdDONT, ch); break; case OptionState::osNo: options[ch].remoteOptionState = OptionState::osYes; SendOption(cdDO, ch); break; case OptionState::osYes: break; } break; case cdWONT: switch (options[ch].remoteOptionState) { case OptionState::osCant: case OptionState::osNo: break; case OptionState::osYes: options[ch].remoteOptionState = OptionState::osNo; SendOption(cdDONT, ch); break; } break; case cdDO: switch (options[ch].localOptionState) { case OptionState::osCant: SendOption(cdWONT, ch); break; case OptionState::osNo: options[ch].localOptionState = OptionState::osYes; SendOption(cdWILL, ch); break; case OptionState::osYes: break; } break; case cdDONT: switch (options[ch].localOptionState) { case OptionState::osCant: case OptionState::osNo: break; case OptionState::osYes: options[ch].localOptionState = OptionState::osNo; SendOption(cdWONT, ch); break; } break; default: printf(" ignored\n"); }; if (state == stOption) state = stData; break; case stSubParams: if (ch == cdIAC) state = stSubCode; else params.push_back(ch); break; case stSubCode: switch (ch) { case cdIAC: state = stSubParams; break; case cdSE: printf(" "); { for (BYTE_vector::const_iterator i = params.begin() ; i != params.end() ; i++) printf("%u ", (unsigned)*i); } printf("SE\n"); switch (option) { case opTerminalType: params.clear(); params.push_back(0); params.insert(params.end(), terminalType.begin(), terminalType.end()); SendSubNegotiation(option, params); break; default: printf(" ignored\n"); } state = stData; break; default: printf("RECV: unknown sub code %u\n", (unsigned)ch); state = stData; }; break; } } return count; }
HUB_MSG *TelnetProtocol::Decode(HUB_MSG *pMsg) { _ASSERTE(started == TRUE); _ASSERTE(pMsg->type == HUB_MSG_TYPE_LINE_DATA); DWORD len = pMsg->u.buf.size; BYTE_string org(pMsg->u.buf.pBuf, len); const BYTE *pBuf = org.data(); // discard original data from the stream if (!pMsgReplaceBuf(pMsg, HUB_MSG_TYPE_LINE_DATA, NULL, 0)) return NULL; for (; len ; len--) { BYTE ch = *pBuf++; switch (state) { case stData: if (ch == cdIAC) state = stCode; else streamDecoded += ch; break; case stCode: switch (ch) { case cdIAC: streamDecoded += ch; state = stData; break; case cdNOP: cout << name << " RECV: " << code2name(ch) << endl; state = stData; break; case cdSB: case cdWILL: case cdWONT: case cdDO: case cdDONT: code = ch; state = stOption; break; default: cout << name << " RECV: unknown code " << (unsigned)ch << endl; state = stData; } break; case stOption: cout << name << " RECV: " << code2name(code) << " " << (unsigned)ch << endl; switch (code) { case cdSB: option = ch; params.clear(); state = stSubParams; break; case cdWILL: if (options[ch] == NULL || options[ch]->stateRemote == TelnetOption::osCant) { SendOption(cdDONT, ch); } else if (options[ch]->stateRemote == TelnetOption::osNo) { options[ch]->stateRemote = TelnetOption::osYes; SendOption(cdDO, ch); } break; case cdWONT: if (options[ch] != NULL && options[ch]->stateRemote == TelnetOption::osYes) { options[ch]->stateRemote = TelnetOption::osNo; SendOption(cdDONT, ch); } break; case cdDO: if (options[ch] == NULL || options[ch]->stateLocal == TelnetOption::osCant) { SendOption(cdWONT, ch); } else if (options[ch]->stateLocal == TelnetOption::osNo) { options[ch]->stateLocal = TelnetOption::osYes; SendOption(cdWILL, ch); } break; case cdDONT: if (options[ch] != NULL && options[ch]->stateLocal == TelnetOption::osYes) { options[ch]->stateLocal = TelnetOption::osNo; SendOption(cdWONT, ch); } break; default: cout << " ignored" << endl; }; if (state == stOption) state = stData; break; case stSubParams: if (ch == cdIAC) state = stSubCode; else params.push_back(ch); break; case stSubCode: switch (ch) { case cdIAC: params.push_back(ch); state = stSubParams; break; case cdSE: cout << " "; { for (BYTE_vector::const_iterator i = params.begin() ; i != params.end() ; i++) cout << (unsigned)*i << " "; } cout << "SE" << endl; if (!options[option] || !options[option]->OnSubNegotiation(params, &pMsg)) cout << " ignored" << endl; if (!pMsg) return NULL; state = stData; break; default: cout << name << " RECV: unknown sub code " << (unsigned)ch << endl; state = stData; }; break; } } return FlushDecodedStream(pMsg); }