#include "protocoltelnet.h" #include ProtocolTelnet::ProtocolTelnet() { nTermType = termUnInited; bEchoOn = true; } ProtocolTelnet::~ProtocolTelnet() { } bool ProtocolTelnet::onNewConnection() { Connection *pCon = getConnection(); pCon->appendOutput( (char)IAC ); pCon->appendOutput( (char)WILL ); pCon->appendOutput( (char)SUPPRESSGA ); pCon->appendOutput( (char)IAC ); pCon->appendOutput( (char)DO ); pCon->appendOutput( (char)SUPPRESSGA ); pCon->appendOutput( (char)IAC ); pCon->appendOutput( (char)DONT ); pCon->appendOutput( (char)TERMTYPE ); // pCon->appendOutput( IAC ); // pCon->appendOutput( SB ); // pCon->appendOutput( TERMTYPE ); // pCon->appendOutput( 1 ); // pCon->appendOutput( IAC ); // pCon->appendOutput( SE ); pCon->appendOutput( (char)IAC ); pCon->appendOutput( (char)DONT ); pCon->appendOutput( (char)ECHO ); pCon->appendOutput( (char)IAC ); pCon->appendOutput( (char)WILL ); pCon->appendOutput( (char)ECHO ); // 255(IAC),251(WILL),3 } bool ProtocolTelnet::onNewData() { Connection *pCon = getConnection(); if( !pCon->hasInput() ) { return true; } int nInSize = pCon->getInputAmnt(); char *lpInStr = (char *)pCon->getInput(); // Here we interpret the basic commands and un-encapsulate them, so to // speak. We'll allow this, even if the terminal is in raw mode, we // just won't send anything in response... for( int j = 0; j < nInSize; j++ ) { switch( (unsigned char)lpInStr[j] ) { case '\r': fbEdited.appendData('\n'); if( bEchoOn ) pCon->appendOutput("\n\r"); break; case '\n': break; case '\177': // backspace if( fbEdited.getLength() > 0 ) { fbEdited.usedData( -1 ); // Delete one char from the end if( bEchoOn ) pCon->appendOutput(ESC "[D"); // Move the cursor back one if( bEchoOn ) pCon->appendOutput(ESC "[P"); // Delete one character } break; case '\x1B': // escape sequence if( (unsigned char)lpInStr[j+1] == '[' ) { switch( (unsigned char)lpInStr[j+2] ) { case 'A': // Up break; case 'B': // Down break; case 'C': // Right break; case 'D': // Left break; } j+=2; } break; case 0: // NOP: No operation break; case IAC: // IAC: Interpret as command switch( lpInStr[j+1] ) { case SE: // SE: End of subnegotiation parameters. break; case NOP: // NOP: No operation break; case DM: // DM: Data mark. Indicates the position of a Synch event within the data stream. This should always be accompanied by a TCP urgent notification. break; case BRK: // BRK: Break. Indicates that the "break" or "attention" key was hit. break; case IP: // IP: Suspend, interrupt or abort the process to which the NVT is connected. break; case AO: // AO: Abort output. Allows the current process to run to completion but do not send its output to the user. break; case AYT: // AYT: Are you there. Send back to the NVT some visible evidence that the AYT was received. break; case EC: // EC: Erase character. The receiver should delete the last preceding undeleted character from the data stream. break; case EL: // EL: Erase line. Delete characters from the data stream back to but not including the previous CRLF. break; case GA: // GA: Go ahead. Used, under certain circumstances, to tell the other end that it can transmit. break; case SB: // SB: Subnegotiation of the indicated option follows. switch( lpInStr[j+2] ) { case TERMTYPE: if( lpInStr[j+3] == 0 ) { for( int k = 0; j+4+k < nInSize; k++ ) { if( (unsigned char)lpInStr[j+4+k] == IAC && (unsigned char)lpInStr[j+5+k] == SE ) { lpInStr[j+4+k] = 0; //@TODO: Do something with the term type... printf("Term type: %s\n", &lpInStr[j+4] ); j += 5+k; } } } else { } break; default: //printf("unknown subnegotiation parameters! (%d)\n", lpInStr[j+2] ); break; } break; case WILL: // WILL: Indicates the desire to begin performing switch( lpInStr[j+2] ) { case SUPPRESSGA: j += 2; // pCon->usedInput( 3 ); break; case TERMTYPE: j += 2; // pCon->usedInput( 3 ); break; case ECHO: j += 2; // pCon->usedInput( 3 ); break; case NAWS: default: pCon->appendOutput( (char)ESC[0] ); pCon->appendOutput( (char)DONT ); pCon->appendOutput( lpInStr[j+2] ); //printf("unknown will command used! (%d)\n", lpInStr[j+2] ); j += 2; break; } break; case WONT: // WONT: Indicates the refusal to perform switch( lpInStr[j+2] ) { case ECHO: j += 2; // pCon->usedInput( 3 ); break; default: //printf("unknown wont command used! (%d)\n", lpInStr[j+2] ); j += 2; break; } break; case DO: // DO: Indicates the request that the other party perform switch( lpInStr[j+2] ) { case ECHO: j += 2; break; case SUPPRESSGA: j += 2; break; default: pCon->appendOutput( (char)ESC[0] ); pCon->appendOutput( (char)DONT ); pCon->appendOutput( lpInStr[j+2] ); //printf("unknown do command used! (%d)\n", lpInStr[j+2] ); j += 2; break; } // pCon->usedInput( 3 ); break; case DONT: // DONT: Indicates the demand that the other party stop performing switch( lpInStr[j+2] ) { case ECHO: j += 2; // pCon->usedInput( 3 ); break; default: printf("unknown dont command used! (%d)\n", lpInStr[j+2] ); j += 2; break; } break; } break; default: fbEdited.appendData( lpInStr[j] ); if( bEchoOn ) pCon->appendOutput( lpInStr[j] ); break; } } pCon->usedInput( pCon->getInputAmnt() ); return true; } char *ProtocolTelnet::getLine( bool bFullOnly ) { int i = fbEdited.findChar('\n'); if( i < 0 ) { if( bFullOnly == false ) { i = fbEdited.getLength(); } else { return NULL; } } char *lpStr = new char[i+1]; strncpy( lpStr, fbEdited.getData(), i ); lpStr[i] = '\0'; fbEdited.usedData( i+1 ); return lpStr; } char *ProtocolTelnet::peekLine( bool bFullOnly ) { int i = fbEdited.findChar('\n'); if( i < 0 ) { if( bFullOnly == false ) { i = fbEdited.getLength(); } else { return NULL; } } char *lpStr = new char[i+1]; strncpy( lpStr, fbEdited.getData(), i ); lpStr[i] = '\0'; return lpStr; } void ProtocolTelnet::setEcho( bool bEchoOn ) { this->bEchoOn = bEchoOn; }