#ifndef PACKETPP_TELNET_LAYER #define PACKETPP_TELNET_LAYER #include "Layer.h" /// @file /** * \namespace pcpp * \brief The main namespace for the PcapPlusPlus lib */ namespace pcpp { /** * Class for representing the Telnet Layer */ class TelnetLayer : public Layer { private: // Position iterator for next command size_t lastPositionOffset; // Checks if position is a data field bool isDataField(uint8_t *pos) const; // Checks if position is a command field bool isCommandField(uint8_t *pos) const; // Returns distance to next IAC size_t distanceToNextIAC(uint8_t *startPos, size_t maxLength); // Returns length of provided field size_t getFieldLen(uint8_t *startPos, size_t maxLength); // Get position of next data field uint8_t *getNextDataField(uint8_t *pos, size_t len); // Get position of next command field uint8_t *getNextCommandField(uint8_t *pos, size_t len); // Get options of provided field int16_t getSubCommand(uint8_t *pos, size_t len); // Get data of provided field uint8_t *getCommandData(uint8_t *pos, size_t &slen); public: /** * Telnet Command Indicator */ enum class TelnetCommand : int { /// Indicator to parser reached end of packet TelnetCommandEndOfPacket = -1, /// End of file EndOfFile = 236, /// Suspend current process Suspend, /// Abort Process Abort, /// End of Record EndOfRecordCommand, /// Marks the end of a Telnet option subnegotiation, used with the SB code to specify more specific option /// parameters. SubnegotiationEnd, /// Null command; does nothing. NoOperation, /// Used to mark the end of a sequence of data that the recipient should scan for urgent Telnet commands. DataMark, /// Represents the pressing of the “break” or “attention” key on the terminal. Break, /// Tells the recipient to interrupt, abort, suspend or terminate the process currently in use. InterruptProcess, /// Instructs the remote host to continue running the current process, but discard all remaining output from it. /// This may be needed if a program starts to send unexpectedly large amounts of data to the user. AbortOutput, /// May be used to check that the remote host is still “alive”. When this character is sent the remote host /// returns some type of output to indicate that it is still functioning. AreYouThere, /// Instructs the recipient to delete the last undeleted character from the data stream. Used to “undo” the /// sending of a character. EraseCharacter, /// Tells the recipient to delete all characters from the data stream back to (but not including) the last end /// of line (CR+LF) sequence. EraseLine, /// Used in Telnet half-duplex mode to signal the other device that it may transmit. GoAhead, /// Marks the beginning of a Telnet option subnegotiation, used when an option requires the client and server to /// exchange parameters. Subnegotiation, /// Indicates that the device sending this code is willing to perform or continue performing a particular /// option. WillPerform, /// Indicates that the device sending this code is either not willing to perform a particular option, or is now /// refusing to continue to perform it. WontPerform, /// Requests that the other device perform a particular option or confirms the expectation that the other device /// will perform that option. DoPerform, /// Specifies that the other party not perform an option, or confirms a device’s expectation that the other /// party not perform an option. DontPerform, /// Precedes command values 240 through 254 as described above. A pair of IAC bytes in a row represents the data /// value 255. InterpretAsCommand }; /** * Telnet Options */ enum class TelnetOption : int { /// Internal return for no option detected TelnetOptionNoOption = -1, /// Binary Transmission RFC856 https://www.iana.org/go/rfc856 TransmitBinary = 0, /// Echo RFC857 https://www.iana.org/go/rfc857 Echo, /// Reconnection Reconnection, /// Suppress Go Ahead RFC858 https://www.iana.org/go/rfc858 SuppressGoAhead, /// Negotiate approximate message size ApproxMsgSizeNegotiation, /// Status RFC859 https://www.iana.org/go/rfc859 Status, /// Timing Mark RFC860 https://www.iana.org/go/rfc860 TimingMark, /// RCTE, Remote Controlled Transmission and Echo RFC726 https://www.iana.org/go/rfc726 RemoteControlledTransAndEcho, /// Output Line Width OutputLineWidth, /// Output Page Size OutputPageSize, /// NAOCRD, Negotiate About Output Carriage-Return Disposition RFC652 https://www.iana.org/go/rfc652 OutputCarriageReturnDisposition, /// NAOHTS, Negotiate About Output Horizontal Tabstops RFC653 https://www.iana.org/go/rfc653 OutputHorizontalTabStops, /// NAOHTD, Negotiate About Output Horizontal Tab Disposition RFC654 https://www.iana.org/go/rfc654 OutputHorizontalTabDisposition, /// NAOFFD, Negotiate About Output Formfeed Disposition RFC655 https://www.iana.org/go/rfc655 OutputFormfeedDisposition, /// NAOVTS, Negotiate About Vertical Tabstops RFC656 https://www.iana.org/go/rfc656 OutputVerticalTabStops, /// NAOVTD, Negotiate About Output Vertcial Tab Disposition RFC657 https://www.iana.org/go/rfc657 OutputVerticalTabDisposition, /// NAOLFD, Negotiate About Output Linefeed Disposition RFC658 https://www.iana.org/go/rfc658 OutputLinefeedDisposition, /// Extended ASCII RFC698 https://www.iana.org/go/rfc698 ExtendedASCII, /// Logout RFC727 https://www.iana.org/go/rfc727 Logout, /// BM, Byte Macro RFC735 https://www.iana.org/go/rfc735 ByteMacro, /// Data Entry Terminal RFC1043 - RFC732 https://www.iana.org/go/rfc1043 https://www.iana.org/go/rfc732 DataEntryTerminal, /// SUPDUP RFC736 - RFC734 https://www.iana.org/go/rfc736 https://www.iana.org/go/rfc734 SUPDUP, /// SUPDUP Output RFC749 https://www.iana.org/go/rfc749 SUPDUPOutput, /// Send Location RFC779 https://www.iana.org/go/rfc779 SendLocation, /// Terminal Type RFC1091 https://www.iana.org/go/rfc1091 TerminalType, /// End of record RFC885 https://www.iana.org/go/rfc885 EndOfRecordOption, /// TUID, TACACS User Identification RFC927 https://www.iana.org/go/rfc927 TACACSUserIdentification, /// OUTMRK, Output Marking RFC933 https://www.iana.org/go/rfc933 OutputMarking, /// TTYLOC, Terminal Location Number RFC946 https://www.iana.org/go/rfc946 TerminalLocationNumber, /// Telnet 3270 Regime RFC1041 https://www.iana.org/go/rfc1041 Telnet3270Regime, /// X.3 PAD RFC1053 https://www.iana.org/go/rfc1053 X3Pad, /// NAWS, Negotiate About Window Size RFC1073 https://www.iana.org/go/rfc1073 NegotiateAboutWindowSize, /// Terminal Speed RFC1079 https://www.iana.org/go/rfc1079 TerminalSpeed, /// Remote Flow Control RFC1372 https://www.iana.org/go/rfc1372 RemoteFlowControl, /// Line Mode RFC1184 https://www.iana.org/go/rfc1184 Linemode, /// X Display Location RFC1096 https://www.iana.org/go/rfc1096 XDisplayLocation, /// Environment Option RFC1408 https://www.iana.org/go/rfc1408 EnvironmentOption, /// Authentication Option RFC2941 https://www.iana.org/go/rfc2941 AuthenticationOption, /// Encryption Option RFC2946 https://www.iana.org/go/rfc2946 EncryptionOption, /// New Environment Option RFC1572 https://www.iana.org/go/rfc1572 NewEnvironmentOption, /// TN3270E RFC2355 https://www.iana.org/go/rfc2355 TN3270E, /// X Server Authentication XAuth, /// Charset RFC2066 https://www.iana.org/go/rfc2066 Charset, /// RSP, Telnet Remote Serial Port TelnetRemoteSerialPort, /// Com Port Control Option RFC2217 https://www.iana.org/go/rfc2217 ComPortControlOption, /// Telnet Suppress Local Echo TelnetSuppressLocalEcho, /// Telnet Start TLS TelnetStartTLS, /// Kermit RFC2840 https://www.iana.org/go/rfc2840 Kermit, /// Send URL SendURL, /// Forward X Server ForwardX, /// Telnet Option Pragma Logon TelOptPragmaLogon = 138, /// Telnet Option SSPI Logon TelOptSSPILogon, /// Telnet Option Pragma Heartbeat TelOptPragmaHeartbeat, /// Extended option list ExtendedOptions = 255 }; /** * A constructor that creates the layer from an existing packet raw data * @param[in] data A pointer to the raw data * @param[in] dataLen Size of the data in bytes * @param[in] prevLayer A pointer to the previous layer * @param[in] packet A pointer to the Packet instance where layer will be stored in */ TelnetLayer(uint8_t *data, size_t dataLen, Layer *prevLayer, Packet *packet) : Layer(data, dataLen, prevLayer, packet) { m_Protocol = Telnet; lastPositionOffset = SIZE_MAX; }; /** * Get the Telnet data as readable string * @param[in] removeEscapeCharacters Whether non-alphanumerical characters should be removed or not * @return Full payload as readable string, empty if Telnet packet contains control commands/options. */ std::string getDataAsString(bool removeEscapeCharacters = true); /** * Get the total number of detected Telnet commands * @return size_t The number of Telnet commands */ size_t getTotalNumberOfCommands(); /** * Returns the number of occurrences of provided command * @param[in] command Telnet command to count * @return size_t Number of occurrences of command */ size_t getNumberOfCommands(TelnetCommand command); /** * Returns the first command of packet * @return TelnetCommand First detected command value, TelnetCommandEndOfPacket if there is no command field */ TelnetCommand getFirstCommand(); /** * Returns the next command of packet. Uses an internal iterator. The iterator resets when reached end of packet. * @return TelnetCommand Detected command value, TelnetCommandEndOfPacket if reached the end of packet. */ TelnetCommand getNextCommand(); /** * Returns the option of current command. Uses an internal iterator. Iterator can be moved with getNextCommand * @return TelnetOption Option of current command */ TelnetOption getOption(); /** * Returns the option of provided command. It will return option of first occurrence of the command * @param[in] command Telnet command to search * @return TelnetOption Option of the command. Returns TelnetOptionNoOption if the provided command not found. */ TelnetOption getOption(TelnetCommand command); /** * Returns the data of current command. Uses an internal iterator. Iterator can be moved with getNextCommand * @param[out] length Length of the data of current command * @return uint8_t* Pointer to the data of current command. NULL if there is no data for this command. */ uint8_t *getOptionData(size_t &length); /** * Returns the data of provided command. It will return data of first occurrence of the command * @param[in] command Telnet command to search * @param[out] length Length of the data of current command * @return uint8_t* Pointer to the data of current command. NULL if there is no data for this command or if can't * find the command. */ uint8_t *getOptionData(TelnetCommand command, size_t &length); /** * Convert the Telnet Command to readable string * @param[in] val Value of the command * @return The Telnet Command as readable string */ static std::string getTelnetCommandAsString(TelnetCommand val); /** * Convert the Telnet option to readable string * @param[in] val Value of the option * @return The Telnet Option as readable string */ static std::string getTelnetOptionAsString(TelnetOption val); /** * A static method that checks whether the port is considered as Telnet * @param[in] port The port number to be checked */ static bool isTelnetPort(uint16_t port) { return port == 23; } /** * A static method that takes a byte array and detects whether it is a Telnet message * @param[in] data A byte array * @param[in] dataSize The byte array size (in bytes) * @return True if the data is identified as Telnet message */ static bool isDataValid(const uint8_t *data, size_t dataSize) { return data && dataSize; } // overridden methods /// Parses the next layer. Telnet is the always last so does nothing for this layer void parseNextLayer() {} /** * @return Get the size of the layer */ size_t getHeaderLen() const { return m_DataLen; } /// Does nothing for this layer void computeCalculateFields() {} /** * @return The OSI layer level of Telnet (Application Layer). */ OsiModelLayer getOsiModelLayer() const { return OsiModelApplicationLayer; } /** * @return Returns the protocol info as readable string */ std::string toString() const; }; } // namespace pcpp #endif /* PACKETPP_TELNET_LAYER */