1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
#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 */