/src/PcapPlusPlus/Packet++/src/TelnetLayer.cpp
Line | Count | Source |
1 | 63.4k | #define LOG_MODULE PacketLogModuleTelnetLayer |
2 | | |
3 | | #include "TelnetLayer.h" |
4 | | #include "Logger.h" |
5 | | #include "GeneralUtils.h" |
6 | | #include "AssertionUtils.h" |
7 | | #include <cstring> |
8 | | #include <iterator> |
9 | | #include <algorithm> |
10 | | |
11 | | namespace pcpp |
12 | | { |
13 | | namespace |
14 | | { |
15 | | /// @brief An enum representing the type of a Telnet sequence |
16 | | enum class TelnetSequenceType |
17 | | { |
18 | | /// @brief An unknown sequence type. Usually means parsing error. |
19 | | /// Commonly happens when an IAC symbol is found at the end of the buffer without a following byte. |
20 | | Unknown, |
21 | | /// @brief A telnet command sequence. Starts with IAC followed by a command code. |
22 | | Command, |
23 | | /// @brief A telnet data sequence. Either does not start with IAC or starts with IAC IAC. |
24 | | UserData, |
25 | | }; |
26 | | |
27 | | /// @brief Checks if a given sequence matches Telnet command or data pattern. |
28 | | /// @param first Start of the sequence to check |
29 | | /// @param maxCount Maximum number of bytes to check |
30 | | /// @return The type of the Telnet sequence. Unknown if the sequence does not match either command or data |
31 | | /// pattern or if parsing error occurs. |
32 | | TelnetSequenceType getTelnetSequenceType(uint8_t const* first, size_t maxCount) |
33 | 17.2M | { |
34 | 17.2M | if (first == nullptr || maxCount == 0) |
35 | 0 | { |
36 | 0 | PCPP_LOG_DEBUG("Checking empty or null buffer for telnet sequence type"); |
37 | 0 | return TelnetSequenceType::Unknown; |
38 | 0 | } |
39 | | |
40 | | // If first byte is not "FF" it's data |
41 | 17.2M | if (*first != static_cast<int>(TelnetLayer::TelnetCommand::InterpretAsCommand)) |
42 | 6.16M | { |
43 | 6.16M | return TelnetSequenceType::UserData; |
44 | 6.16M | } |
45 | | |
46 | | // IAC must be followed by another octet |
47 | 11.0M | if (maxCount <= 1) |
48 | 7.82k | { |
49 | 7.82k | PCPP_LOG_DEBUG("Telnet Parse Error: IAC (FF) must always be followed by another octet"); |
50 | 7.82k | return TelnetSequenceType::Unknown; |
51 | 7.82k | } |
52 | | |
53 | 11.0M | if (first[1] == static_cast<int>(TelnetLayer::TelnetCommand::InterpretAsCommand)) |
54 | 2.02M | { |
55 | | // "FF FF" means data continue |
56 | 2.02M | return TelnetSequenceType::UserData; |
57 | 2.02M | } |
58 | | |
59 | | // "FF X" where X != "FF" means command |
60 | 9.05M | return TelnetSequenceType::Command; |
61 | 11.0M | } |
62 | | |
63 | | /// @brief Checks if a given sequence matches Telnet command pattern. |
64 | | /// @param first Start of the sequence to check |
65 | | /// @param maxCount Maximum number of bytes to check |
66 | | /// @return True if the buffer matches Telnet command pattern, false otherwise |
67 | | bool isTelnetCommand(uint8_t const* first, size_t maxCount) |
68 | 176k | { |
69 | 176k | return getTelnetSequenceType(first, maxCount) == TelnetSequenceType::Command; |
70 | 176k | } |
71 | | |
72 | | /// @brief Finds the next IAC symbol in a data stream ignoring the first byte. |
73 | | /// @param[in] first Iterator to the start of the data stream to check. |
74 | | /// @param[in] last Iterator one past the end of the data stream to check. |
75 | | /// @return The next encountered IAC symbol after the first. |
76 | | uint8_t* findNextIAC(uint8_t* first, uint8_t* last) |
77 | 6.94M | { |
78 | | // FF FF pattern is FF literal |
79 | | // FF non-FF pattern is IAC op code |
80 | | // Sample seq: FF AB CD 0F FF FF A4 B5 [FF] 2D DA |
81 | | |
82 | | // Requires at least 2 elements. |
83 | 6.94M | if (first + 1 >= last) |
84 | 6.21k | return last; |
85 | | |
86 | 6.93M | constexpr int IAC = static_cast<int>(TelnetLayer::TelnetCommand::InterpretAsCommand); |
87 | | |
88 | | // Start the search from the second byte. |
89 | 6.93M | auto it = first + 1; |
90 | 12.8M | while (it != last) |
91 | 12.8M | { |
92 | | // Find the next IAC symbol. |
93 | 12.8M | it = std::find(it, last, IAC); |
94 | | |
95 | | // Reached the end of the sequence. |
96 | 12.8M | if (it == last) |
97 | 35.0k | return last; |
98 | | |
99 | 12.8M | auto itNext = std::next(it); |
100 | | // Reached the end of the sequence. |
101 | | // IAC at the end of the sequence is invalid. |
102 | 12.8M | if (itNext == last) |
103 | 10.7k | return last; |
104 | | |
105 | | // If the next symbol is not IAC, this isn't an escaped sequence. |
106 | 12.7M | if (*itNext != IAC) |
107 | 6.88M | return it; |
108 | | |
109 | | // Escaped sequence "FF FF", move it to 1 past the second FF, to skip the view "FF [[FF XX]]". |
110 | 5.90M | it = std::next(itNext); |
111 | 5.90M | } |
112 | | |
113 | 7.80k | return last; |
114 | 6.93M | } |
115 | | } // namespace |
116 | | |
117 | | size_t TelnetLayer::distanceToNextIAC(uint8_t* startPos, size_t maxLength) |
118 | 6.94M | { |
119 | 6.94M | auto beginIt = startPos; |
120 | 6.94M | auto endIt = startPos + maxLength; |
121 | 6.94M | auto nextIacIt = findNextIAC(beginIt, endIt); |
122 | 6.94M | return std::distance(beginIt, nextIacIt); |
123 | 6.94M | } |
124 | | |
125 | | size_t TelnetLayer::getFieldLen(uint8_t* startPos, size_t maxLength) |
126 | 17.2M | { |
127 | | // Check first byte is IAC |
128 | 17.2M | if (startPos && (startPos[0] == static_cast<int>(TelnetCommand::InterpretAsCommand)) && (maxLength >= 2)) |
129 | 11.1M | { |
130 | | // If subnegotiation parse until next IAC |
131 | 11.1M | if (startPos[1] == static_cast<int>(TelnetCommand::Subnegotiation)) |
132 | 836k | return distanceToNextIAC(startPos, maxLength); |
133 | | // Only WILL, WONT, DO, DONT have option. Ref http://pcmicro.com/netfoss/telnet.html |
134 | 10.3M | else if (startPos[1] >= static_cast<int>(TelnetCommand::WillPerform) && |
135 | 3.95M | startPos[1] <= static_cast<int>(TelnetCommand::DontPerform)) |
136 | 1.94M | return std::min<size_t>(3, maxLength); |
137 | 8.36M | return 2; |
138 | 11.1M | } |
139 | 6.10M | return distanceToNextIAC(startPos, maxLength); |
140 | 17.2M | } |
141 | | |
142 | | uint8_t* TelnetLayer::getNextDataField(uint8_t* pos, size_t len) |
143 | 31.9k | { |
144 | | // This assumes `pos` points to the start of a valid field. |
145 | 31.9k | auto const endIt = pos + len; |
146 | | |
147 | | // Advance to the next field, as we are skipping the current one from the search. |
148 | 31.9k | pos += getFieldLen(pos, len); |
149 | | |
150 | 61.4k | while (pos < endIt) |
151 | 54.5k | { |
152 | | // Check if the current field is data |
153 | 54.5k | switch (getTelnetSequenceType(pos, std::distance(pos, endIt))) |
154 | 54.5k | { |
155 | 988 | case TelnetSequenceType::Unknown: |
156 | 988 | { |
157 | 988 | PCPP_LOG_DEBUG("Telnet Parse Error: Unknown sequence found during data field search."); |
158 | 988 | return nullptr; |
159 | 0 | } |
160 | 24.0k | case TelnetSequenceType::UserData: |
161 | 24.0k | return pos; |
162 | 29.5k | default: |
163 | 29.5k | break; // continue searching |
164 | 54.5k | } |
165 | | |
166 | | // If not data, move to next field |
167 | 29.5k | pos += getFieldLen(pos, std::distance(pos, endIt)); |
168 | 29.5k | } |
169 | | |
170 | | // If we got here, no data field has been found before the end of the buffer |
171 | 6.86k | return nullptr; |
172 | 31.9k | } |
173 | | |
174 | | uint8_t* TelnetLayer::getNextCommandField(uint8_t* pos, size_t len) |
175 | 8.95M | { |
176 | | // This assumes `pos` points to the start of a valid field. |
177 | 8.95M | auto const endIt = pos + len; |
178 | | |
179 | | // Advance to the next field, as we are skipping the current one from the search. |
180 | 8.95M | pos += getFieldLen(pos, len); |
181 | | |
182 | 16.9M | while (pos < endIt) |
183 | 16.9M | { |
184 | | // Check if the current field is command |
185 | 16.9M | switch (getTelnetSequenceType(pos, std::distance(pos, endIt))) |
186 | 16.9M | { |
187 | 5.85k | case TelnetSequenceType::Unknown: |
188 | 5.85k | { |
189 | 5.85k | PCPP_LOG_DEBUG("Telnet Parse Error: Unknown sequence found during command field search."); |
190 | 5.85k | return nullptr; |
191 | 0 | } |
192 | 8.88M | case TelnetSequenceType::Command: |
193 | 8.88M | return pos; |
194 | 8.04M | default: |
195 | 8.04M | break; // continue searching |
196 | 16.9M | } |
197 | | |
198 | | // If not command, move to next field |
199 | 8.04M | pos += getFieldLen(pos, std::distance(pos, endIt)); |
200 | 8.04M | } |
201 | | |
202 | | // If we got here, no command field has been found before the end of the buffer |
203 | 64.2k | return nullptr; |
204 | 8.95M | } |
205 | | |
206 | | int16_t TelnetLayer::getSubCommand(uint8_t* pos, size_t len) |
207 | 97.0k | { |
208 | 97.0k | if (len < 3 || pos[1] < static_cast<int>(TelnetCommand::Subnegotiation)) |
209 | 62.2k | return static_cast<int>(TelnetOption::TelnetOptionNoOption); |
210 | 34.7k | return pos[2]; |
211 | 97.0k | } |
212 | | |
213 | | uint8_t* TelnetLayer::getCommandData(uint8_t* pos, size_t& len) |
214 | 97.0k | { |
215 | 97.0k | if (pos[1] == static_cast<int>(TelnetCommand::Subnegotiation) && len > 3) |
216 | 16.8k | { |
217 | 16.8k | len -= 3; |
218 | 16.8k | return &pos[3]; |
219 | 16.8k | } |
220 | 80.2k | len = 0; |
221 | 80.2k | return nullptr; |
222 | 97.0k | } |
223 | | |
224 | | std::string TelnetLayer::getDataAsString(bool removeEscapeCharacters) |
225 | 58.7k | { |
226 | 58.7k | if (m_Data == nullptr) |
227 | 0 | { |
228 | 0 | PCPP_LOG_DEBUG("Layer does not have data"); |
229 | 0 | return {}; |
230 | 0 | } |
231 | | |
232 | | // Convert to string |
233 | 58.7k | if (removeEscapeCharacters) |
234 | 58.7k | { |
235 | 58.7k | uint8_t* dataPos = nullptr; |
236 | 58.7k | switch (getTelnetSequenceType(m_Data, m_DataLen)) |
237 | 58.7k | { |
238 | 164 | case TelnetSequenceType::Unknown: |
239 | 164 | { |
240 | 164 | PCPP_LOG_DEBUG("Telnet Parse Error: Unknown sequence found during data string extraction."); |
241 | 164 | return {}; |
242 | 0 | } |
243 | 26.6k | case TelnetSequenceType::UserData: |
244 | 26.6k | dataPos = m_Data; |
245 | 26.6k | break; |
246 | 31.9k | case TelnetSequenceType::Command: |
247 | 31.9k | dataPos = getNextDataField(m_Data, m_DataLen); |
248 | 31.9k | break; |
249 | 0 | default: |
250 | 0 | throw std::logic_error("Unsupported sequence type"); |
251 | 58.7k | } |
252 | | |
253 | 58.5k | if (!dataPos) |
254 | 7.85k | { |
255 | 7.85k | PCPP_LOG_DEBUG("Packet does not have a data field"); |
256 | 7.85k | return std::string(); |
257 | 7.85k | } |
258 | | |
259 | 50.7k | PCPP_ASSERT(dataPos >= m_Data && dataPos < (m_Data + m_DataLen), |
260 | 50.7k | "Data position is out of bounds, this should never happen!"); |
261 | | |
262 | | // End of range is corrected by the advance offset. |
263 | 50.7k | auto const* beginIt = dataPos; |
264 | 50.7k | auto const* endIt = dataPos + m_DataLen - std::distance(m_Data, dataPos); |
265 | | |
266 | 50.7k | std::string result; |
267 | 132M | std::copy_if(beginIt, endIt, std::back_inserter(result), [](char ch) -> bool { |
268 | 132M | return ch > 31 && ch < 127; // From SPACE to ~ |
269 | 132M | }); |
270 | 50.7k | return result; |
271 | 58.5k | } |
272 | 0 | return std::string(reinterpret_cast<char*>(m_Data), m_DataLen); |
273 | 58.7k | } |
274 | | |
275 | | size_t TelnetLayer::getTotalNumberOfCommands() |
276 | 10.1k | { |
277 | 10.1k | size_t ctr = 0; |
278 | 10.1k | if (isTelnetCommand(m_Data, m_DataLen)) |
279 | 5.24k | ++ctr; |
280 | | |
281 | 10.1k | uint8_t* pos = m_Data; |
282 | 63.6k | while (pos != nullptr) |
283 | 53.4k | { |
284 | 53.4k | size_t offset = pos - m_Data; |
285 | 53.4k | pos = getNextCommandField(pos, m_DataLen - offset); |
286 | 53.4k | if (pos) |
287 | 43.2k | ++ctr; |
288 | 53.4k | } |
289 | | |
290 | 10.1k | return ctr; |
291 | 10.1k | } |
292 | | |
293 | | size_t TelnetLayer::getNumberOfCommands(TelnetCommand command) |
294 | 58.7k | { |
295 | 58.7k | if (static_cast<int>(command) < 0) |
296 | 10.1k | return 0; |
297 | | |
298 | 48.5k | size_t ctr = 0; |
299 | 48.5k | if (isTelnetCommand(m_Data, m_DataLen) && m_Data[1] == static_cast<int>(command)) |
300 | 8.89k | ++ctr; |
301 | | |
302 | 48.5k | uint8_t* pos = m_Data; |
303 | 7.89M | while (pos != nullptr) |
304 | 7.84M | { |
305 | 7.84M | size_t offset = pos - m_Data; |
306 | 7.84M | pos = getNextCommandField(pos, m_DataLen - offset); |
307 | 7.84M | if (pos && pos[1] == static_cast<int>(command)) |
308 | 1.12M | ++ctr; |
309 | 7.84M | } |
310 | | |
311 | 48.5k | return ctr; |
312 | 58.7k | } |
313 | | |
314 | | TelnetLayer::TelnetCommand TelnetLayer::getFirstCommand() |
315 | 10.1k | { |
316 | | // If starts with command |
317 | 10.1k | if (isTelnetCommand(m_Data, m_DataLen)) |
318 | 5.24k | return static_cast<TelnetCommand>(m_Data[1]); |
319 | | |
320 | | // Check is there any command |
321 | 4.93k | uint8_t* pos = getNextCommandField(m_Data, m_DataLen); |
322 | 4.93k | if (pos) |
323 | 3.70k | return static_cast<TelnetCommand>(pos[1]); |
324 | 1.23k | return TelnetCommand::TelnetCommandEndOfPacket; |
325 | 4.93k | } |
326 | | |
327 | | TelnetLayer::TelnetCommand TelnetLayer::getNextCommand() |
328 | 58.7k | { |
329 | 58.7k | if (lastPositionOffset == SIZE_MAX) |
330 | 10.1k | { |
331 | 10.1k | lastPositionOffset = 0; |
332 | 10.1k | if (isTelnetCommand(m_Data, m_DataLen)) |
333 | 5.24k | return static_cast<TelnetLayer::TelnetCommand>(m_Data[1]); |
334 | 10.1k | } |
335 | | |
336 | 53.4k | uint8_t* pos = getNextCommandField(&m_Data[lastPositionOffset], m_DataLen - lastPositionOffset); |
337 | 53.4k | if (pos) |
338 | 43.2k | { |
339 | 43.2k | lastPositionOffset = pos - m_Data; |
340 | 43.2k | return static_cast<TelnetLayer::TelnetCommand>(pos[1]); |
341 | 43.2k | } |
342 | 10.1k | lastPositionOffset = SIZE_MAX; |
343 | 10.1k | return TelnetCommand::TelnetCommandEndOfPacket; |
344 | 53.4k | } |
345 | | |
346 | | TelnetLayer::TelnetOption TelnetLayer::getOption() |
347 | 58.7k | { |
348 | 58.7k | if (lastPositionOffset < m_DataLen) |
349 | 48.5k | return static_cast<TelnetOption>(getSubCommand( |
350 | 48.5k | &m_Data[lastPositionOffset], getFieldLen(&m_Data[lastPositionOffset], m_DataLen - lastPositionOffset))); |
351 | 10.1k | return TelnetOption::TelnetOptionNoOption; |
352 | 58.7k | } |
353 | | |
354 | | TelnetLayer::TelnetOption TelnetLayer::getOption(TelnetCommand command) |
355 | 58.7k | { |
356 | | // Check input |
357 | 58.7k | if (static_cast<int>(command) < 0) |
358 | 10.1k | { |
359 | 10.1k | PCPP_LOG_ERROR("Command type can't be negative"); |
360 | 10.1k | return TelnetOption::TelnetOptionNoOption; |
361 | 10.1k | } |
362 | | |
363 | 48.5k | if (isTelnetCommand(m_Data, m_DataLen) && m_Data[1] == static_cast<int>(command)) |
364 | 8.89k | return static_cast<TelnetOption>(getSubCommand(m_Data, getFieldLen(m_Data, m_DataLen))); |
365 | | |
366 | 39.6k | uint8_t* pos = m_Data; |
367 | 500k | while (pos != nullptr) |
368 | 500k | { |
369 | 500k | size_t offset = pos - m_Data; |
370 | 500k | pos = getNextCommandField(pos, m_DataLen - offset); |
371 | | |
372 | 500k | if (pos && pos[1] == static_cast<int>(command)) |
373 | 39.6k | { |
374 | 39.6k | offset = pos - m_Data; |
375 | 39.6k | return static_cast<TelnetOption>(getSubCommand(pos, getFieldLen(pos, m_DataLen - offset))); |
376 | 39.6k | } |
377 | 500k | } |
378 | | |
379 | 0 | PCPP_LOG_DEBUG("Can't find requested command"); |
380 | 0 | return TelnetOption::TelnetOptionNoOption; |
381 | 39.6k | } |
382 | | |
383 | | uint8_t* TelnetLayer::getOptionData(size_t& length) |
384 | 58.7k | { |
385 | 58.7k | if (lastPositionOffset < m_DataLen) |
386 | 48.5k | { |
387 | 48.5k | size_t lenBuffer = getFieldLen(&m_Data[lastPositionOffset], m_DataLen - lastPositionOffset); |
388 | 48.5k | uint8_t* posBuffer = getCommandData(&m_Data[lastPositionOffset], lenBuffer); |
389 | | |
390 | 48.5k | length = lenBuffer; |
391 | 48.5k | return posBuffer; |
392 | 48.5k | } |
393 | 10.1k | return nullptr; |
394 | 58.7k | } |
395 | | |
396 | | uint8_t* TelnetLayer::getOptionData(TelnetCommand command, size_t& length) |
397 | 58.7k | { |
398 | | // Check input |
399 | 58.7k | if (static_cast<int>(command) < 0) |
400 | 10.1k | { |
401 | 10.1k | PCPP_LOG_ERROR("Command type can't be negative"); |
402 | 10.1k | length = 0; |
403 | 10.1k | return nullptr; |
404 | 10.1k | } |
405 | | |
406 | 48.5k | if (isTelnetCommand(m_Data, m_DataLen) && m_Data[1] == static_cast<int>(command)) |
407 | 8.89k | { |
408 | 8.89k | size_t lenBuffer = getFieldLen(m_Data, m_DataLen); |
409 | 8.89k | uint8_t* posBuffer = getCommandData(m_Data, lenBuffer); |
410 | | |
411 | 8.89k | length = lenBuffer; |
412 | 8.89k | return posBuffer; |
413 | 8.89k | } |
414 | | |
415 | 39.6k | uint8_t* pos = m_Data; |
416 | 500k | while (pos != nullptr) |
417 | 500k | { |
418 | 500k | size_t offset = pos - m_Data; |
419 | 500k | pos = getNextCommandField(pos, m_DataLen - offset); |
420 | | |
421 | 500k | if (pos && pos[1] == static_cast<int>(command)) |
422 | 39.6k | { |
423 | 39.6k | offset = pos - m_Data; |
424 | 39.6k | size_t lenBuffer = getFieldLen(pos, m_DataLen - offset); |
425 | 39.6k | uint8_t* posBuffer = getCommandData(pos, lenBuffer); |
426 | | |
427 | 39.6k | length = lenBuffer; |
428 | 39.6k | return posBuffer; |
429 | 39.6k | } |
430 | 500k | } |
431 | | |
432 | 0 | PCPP_LOG_DEBUG("Can't find requested command"); |
433 | 0 | length = 0; |
434 | 0 | return nullptr; |
435 | 39.6k | } |
436 | | |
437 | | std::string TelnetLayer::getTelnetCommandAsString(TelnetCommand val) |
438 | 58.7k | { |
439 | 58.7k | switch (val) |
440 | 58.7k | { |
441 | 10.1k | case TelnetCommand::TelnetCommandEndOfPacket: |
442 | 10.1k | return "Reached end of packet while parsing"; |
443 | 145 | case TelnetCommand::EndOfFile: |
444 | 145 | return "End of File"; |
445 | 310 | case TelnetCommand::Suspend: |
446 | 310 | return "Suspend current process"; |
447 | 346 | case TelnetCommand::Abort: |
448 | 346 | return "Abort Process"; |
449 | 2.44k | case TelnetCommand::EndOfRecordCommand: |
450 | 2.44k | return "End of Record"; |
451 | 2.08k | case TelnetCommand::SubnegotiationEnd: |
452 | 2.08k | return "Subnegotiation End"; |
453 | 115 | case TelnetCommand::NoOperation: |
454 | 115 | return "No Operation"; |
455 | 139 | case TelnetCommand::DataMark: |
456 | 139 | return "Data Mark"; |
457 | 66 | case TelnetCommand::Break: |
458 | 66 | return "Break"; |
459 | 646 | case TelnetCommand::InterruptProcess: |
460 | 646 | return "Interrupt Process"; |
461 | 307 | case TelnetCommand::AbortOutput: |
462 | 307 | return "Abort Output"; |
463 | 174 | case TelnetCommand::AreYouThere: |
464 | 174 | return "Are You There"; |
465 | 792 | case TelnetCommand::EraseCharacter: |
466 | 792 | return "Erase Character"; |
467 | 254 | case TelnetCommand::EraseLine: |
468 | 254 | return "Erase Line"; |
469 | 404 | case TelnetCommand::GoAhead: |
470 | 404 | return "Go Ahead"; |
471 | 9.98k | case TelnetCommand::Subnegotiation: |
472 | 9.98k | return "Subnegotiation"; |
473 | 1.10k | case TelnetCommand::WillPerform: |
474 | 1.10k | return "Will Perform"; |
475 | 1.89k | case TelnetCommand::WontPerform: |
476 | 1.89k | return "Wont Perform"; |
477 | 1.85k | case TelnetCommand::DoPerform: |
478 | 1.85k | return "Do Perform"; |
479 | 3.82k | case TelnetCommand::DontPerform: |
480 | 3.82k | return "Dont Perform"; |
481 | 0 | case TelnetCommand::InterpretAsCommand: |
482 | 0 | return "Interpret As Command"; |
483 | 21.6k | default: |
484 | 21.6k | return "Unknown Command"; |
485 | 58.7k | } |
486 | 58.7k | } |
487 | | |
488 | | std::string TelnetLayer::getTelnetOptionAsString(TelnetOption val) |
489 | 58.7k | { |
490 | 58.7k | switch (val) |
491 | 58.7k | { |
492 | 41.4k | case TelnetOption::TelnetOptionNoOption: |
493 | 41.4k | return "No option for this command"; |
494 | 206 | case TelnetOption::TransmitBinary: |
495 | 206 | return "Binary Transmission"; |
496 | 596 | case TelnetOption::Echo: |
497 | 596 | return "Echo"; |
498 | 35 | case TelnetOption::Reconnection: |
499 | 35 | return "Reconnection"; |
500 | 54 | case TelnetOption::SuppressGoAhead: |
501 | 54 | return "Suppress Go Ahead"; |
502 | 32 | case TelnetOption::ApproxMsgSizeNegotiation: |
503 | 32 | return "Negotiate approximate message size"; |
504 | 45 | case TelnetOption::Status: |
505 | 45 | return "Status"; |
506 | 154 | case TelnetOption::TimingMark: |
507 | 154 | return "Timing Mark"; |
508 | 117 | case TelnetOption::RemoteControlledTransAndEcho: |
509 | 117 | return "Remote Controlled Transmission and Echo"; |
510 | 462 | case TelnetOption::OutputLineWidth: |
511 | 462 | return "Output Line Width"; |
512 | 50 | case TelnetOption::OutputPageSize: |
513 | 50 | return "Output Page Size"; |
514 | 21 | case TelnetOption::OutputCarriageReturnDisposition: |
515 | 21 | return "Negotiate About Output Carriage-Return Disposition"; |
516 | 86 | case TelnetOption::OutputHorizontalTabStops: |
517 | 86 | return "Negotiate About Output Horizontal Tabstops"; |
518 | 64 | case TelnetOption::OutputHorizontalTabDisposition: |
519 | 64 | return "Negotiate About Output Horizontal Tab Disposition"; |
520 | 49 | case TelnetOption::OutputFormfeedDisposition: |
521 | 49 | return "Negotiate About Output Formfeed Disposition"; |
522 | 16 | case TelnetOption::OutputVerticalTabStops: |
523 | 16 | return "Negotiate About Vertical Tabstops"; |
524 | 3.84k | case TelnetOption::OutputVerticalTabDisposition: |
525 | 3.84k | return "Negotiate About Output Vertcial Tab Disposition"; |
526 | 67 | case TelnetOption::OutputLinefeedDisposition: |
527 | 67 | return "Negotiate About Output Linefeed Disposition"; |
528 | 321 | case TelnetOption::ExtendedASCII: |
529 | 321 | return "Extended ASCII"; |
530 | 284 | case TelnetOption::Logout: |
531 | 284 | return "Logout"; |
532 | 272 | case TelnetOption::ByteMacro: |
533 | 272 | return "Byte Macro"; |
534 | 48 | case TelnetOption::DataEntryTerminal: |
535 | 48 | return "Data Entry Terminal"; |
536 | 27 | case TelnetOption::SUPDUP: |
537 | 27 | return "SUPDUP"; |
538 | 75 | case TelnetOption::SUPDUPOutput: |
539 | 75 | return "SUPDUP Output"; |
540 | 2 | case TelnetOption::SendLocation: |
541 | 2 | return "Send Location"; |
542 | 254 | case TelnetOption::TerminalType: |
543 | 254 | return "Terminal Type"; |
544 | 532 | case TelnetOption::EndOfRecordOption: |
545 | 532 | return "End Of Record"; |
546 | 70 | case TelnetOption::TACACSUserIdentification: |
547 | 70 | return "TACACS User Identification"; |
548 | 42 | case TelnetOption::OutputMarking: |
549 | 42 | return "Output Marking"; |
550 | 94 | case TelnetOption::TerminalLocationNumber: |
551 | 94 | return "Terminal Location Number"; |
552 | 57 | case TelnetOption::Telnet3270Regime: |
553 | 57 | return "Telnet 3270 Regime"; |
554 | 205 | case TelnetOption::X3Pad: |
555 | 205 | return "X3 Pad"; |
556 | 53 | case TelnetOption::NegotiateAboutWindowSize: |
557 | 53 | return "Negotiate About Window Size"; |
558 | 204 | case TelnetOption::TerminalSpeed: |
559 | 204 | return "Terminal Speed"; |
560 | 235 | case TelnetOption::RemoteFlowControl: |
561 | 235 | return "Remote Flow Control"; |
562 | 382 | case TelnetOption::Linemode: |
563 | 382 | return "Line mode"; |
564 | 695 | case TelnetOption::XDisplayLocation: |
565 | 695 | return "X Display Location"; |
566 | 50 | case TelnetOption::EnvironmentOption: |
567 | 50 | return "Environment Option"; |
568 | 133 | case TelnetOption::AuthenticationOption: |
569 | 133 | return "Authentication Option"; |
570 | 378 | case TelnetOption::EncryptionOption: |
571 | 378 | return "Encryption Option"; |
572 | 460 | case TelnetOption::NewEnvironmentOption: |
573 | 460 | return "New Environment Option"; |
574 | 1 | case TelnetOption::TN3270E: |
575 | 1 | return "TN3270E"; |
576 | 0 | case TelnetOption::XAuth: |
577 | 0 | return "X Server Authentication"; |
578 | 21 | case TelnetOption::Charset: |
579 | 21 | return "Charset"; |
580 | 137 | case TelnetOption::TelnetRemoteSerialPort: |
581 | 137 | return "Telnet Remote Serial Port"; |
582 | 260 | case TelnetOption::ComPortControlOption: |
583 | 260 | return "Com Port Control Option"; |
584 | 19 | case TelnetOption::TelnetSuppressLocalEcho: |
585 | 19 | return "Telnet Suppress Local Echo"; |
586 | 2 | case TelnetOption::TelnetStartTLS: |
587 | 2 | return "Telnet Start TLS"; |
588 | 168 | case TelnetOption::Kermit: |
589 | 168 | return "Kermit"; |
590 | 39 | case TelnetOption::SendURL: |
591 | 39 | return "Send URL"; |
592 | 203 | case TelnetOption::ForwardX: |
593 | 203 | return "Forward X Server"; |
594 | 48 | case TelnetOption::TelOptPragmaLogon: |
595 | 48 | return "Telnet Option Pragma Logon"; |
596 | 341 | case TelnetOption::TelOptSSPILogon: |
597 | 341 | return "Telnet Option SSPI Logon"; |
598 | 48 | case TelnetOption::TelOptPragmaHeartbeat: |
599 | 48 | return "Telnet Option Pragma Heartbeat"; |
600 | 3.31k | case TelnetOption::ExtendedOptions: |
601 | 3.31k | return "Extended option list"; |
602 | 1.87k | default: |
603 | 1.87k | return "Unknown Option"; |
604 | 58.7k | } |
605 | 58.7k | } |
606 | | |
607 | | std::string TelnetLayer::toString() const |
608 | 20.3k | { |
609 | | // TODO: Perhaps print the entire sequence of commands and data? |
610 | 20.3k | switch (getTelnetSequenceType(m_Data, m_DataLen)) |
611 | 20.3k | { |
612 | 328 | case TelnetSequenceType::Unknown: |
613 | 328 | return "Telnet Unknown"; |
614 | 10.4k | case TelnetSequenceType::Command: |
615 | 10.4k | return "Telnet Control"; |
616 | 9.55k | case TelnetSequenceType::UserData: |
617 | 9.55k | return "Telnet Data"; |
618 | 0 | default: |
619 | 0 | throw std::logic_error("Unsupported sequence type"); |
620 | 20.3k | } |
621 | 20.3k | } |
622 | | |
623 | | } // namespace pcpp |