From 2382c3de50d09de26bd9542e70dec5ca80693bbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ege=20=C3=87etin?= <64282645+egecetin@users.noreply.github.com> Date: Sat, 23 Sep 2023 10:14:52 +0300 Subject: [PATCH 1/4] Improve coverage (#1207) --- Packet++/src/FtpLayer.cpp | 88 ++++++------ Tests/Packet++Test/Tests/FtpTests.cpp | 194 +++++++++++++++++++++++--- 2 files changed, 218 insertions(+), 64 deletions(-) diff --git a/Packet++/src/FtpLayer.cpp b/Packet++/src/FtpLayer.cpp index 0e69eb4a83..2f2c24bd00 100644 --- a/Packet++/src/FtpLayer.cpp +++ b/Packet++/src/FtpLayer.cpp @@ -53,13 +53,13 @@ namespace pcpp switch (code) { case FtpCommand::ABOR: - return "Abort an active file transfer."; + return "Abort an active file transfer"; case FtpCommand::ACCT: - return "Account information."; + return "Account information"; case FtpCommand::ADAT: return "Authentication/Security Data"; case FtpCommand::ALLO: - return "Allocate sufficient disk space to receive a file."; + return "Allocate sufficient disk space to receive a file"; case FtpCommand::APPE: return "Append (with create)"; case FtpCommand::AUTH: @@ -69,98 +69,98 @@ namespace pcpp case FtpCommand::CCC: return "Clear Command Channel"; case FtpCommand::CDUP: - return "Change to Parent Directory."; + return "Change to Parent Directory"; case FtpCommand::CONF: return "Confidentiality Protection Command"; case FtpCommand::CSID: return "Client / Server Identification"; case FtpCommand::CWD: - return "Change working directory."; + return "Change working directory"; case FtpCommand::DELE: - return "Delete file."; + return "Delete file"; case FtpCommand::DSIZ: return "Get the directory size"; case FtpCommand::ENC: return "Privacy Protected Channel"; case FtpCommand::EPRT: - return "Specifies an extended address and port to which the server should connect."; + return "Specifies an extended address and port to which the server should connect"; case FtpCommand::EPSV: - return "Enter extended passive mode."; + return "Enter extended passive mode"; case FtpCommand::FEAT: - return "Get the feature list implemented by the server."; + return "Get the feature list implemented by the server"; case FtpCommand::HELP: - return "Returns usage documentation on a command if specified, else a general help document is returned."; + return "Returns usage documentation on a command if specified, else a general help document is returned"; case FtpCommand::HOST: - return "Identify desired virtual host on server, by name."; + return "Identify desired virtual host on server, by name"; case FtpCommand::LANG: return "Language Negotiation"; case FtpCommand::LIST: return "Returns information of a file or directory if specified, else information of the current working " - "directory is returned."; + "directory is returned"; case FtpCommand::LPRT: - return "Specifies a long address and port to which the server should connect."; + return "Specifies a long address and port to which the server should connect"; case FtpCommand::LPSV: - return "Enter long passive mode."; + return "Enter long passive mode"; case FtpCommand::MDTM: - return "Return the last-modified time of a specified file."; + return "Return the last-modified time of a specified file"; case FtpCommand::MFCT: - return "Modify the creation time of a file."; + return "Modify the creation time of a file"; case FtpCommand::MFF: - return "Modify fact (the last modification time, creation time, UNIX group/owner/mode of a file)."; + return "Modify fact (the last modification time, creation time, UNIX group/owner/mode of a file)"; case FtpCommand::MFMT: - return "Modify the last modification time of a file."; + return "Modify the last modification time of a file"; case FtpCommand::MIC: return "Integrity Protected Command"; case FtpCommand::MKD: - return "Make directory."; + return "Make directory"; case FtpCommand::MLSD: - return "Lists the contents of a directory in a standardized machine-readable format."; + return "Lists the contents of a directory in a standardized machine-readable format"; case FtpCommand::MLST: return "Provides data about exactly the object named on its command line in a standardized " - "machine-readable format."; + "machine-readable format"; case FtpCommand::MODE: - return "Sets the transfer mode (Stream, Block, or Compressed)."; + return "Sets the transfer mode (Stream, Block, or Compressed)"; case FtpCommand::NLST: - return "Returns a list of file names in a specified directory."; + return "Returns a list of file names in a specified directory"; case FtpCommand::NOOP: - return "No operation (dummy packet; used mostly on keepalives)."; + return "No operation (dummy packet; used mostly on keepalives)"; case FtpCommand::OPTS: - return "Select options for a feature (for example OPTS UTF8 ON)."; + return "Select options for a feature (for example OPTS UTF8 ON)"; case FtpCommand::PASS: - return "Authentication password."; + return "Authentication password"; case FtpCommand::PASV: - return "Enter passive mode."; + return "Enter passive mode"; case FtpCommand::PBSZ: return "Protection Buffer Size"; case FtpCommand::PORT: - return "Specifies an address and port to which the server should connect."; + return "Specifies an address and port to which the server should connect"; case FtpCommand::PROT: - return "Data Channel Protection Level."; + return "Data Channel Protection Level"; case FtpCommand::PWD: - return "Print working directory. Returns the current directory of the host."; + return "Print working directory. Returns the current directory of the host"; case FtpCommand::QUIT: - return "Disconnect."; + return "Disconnect"; case FtpCommand::REIN: - return "Re initializes the connection."; + return "Re initializes the connection"; case FtpCommand::REST: - return "Restart transfer from the specified point."; + return "Restart transfer from the specified point"; case FtpCommand::RETR: return "Retrieve a copy of the file"; case FtpCommand::RMD: - return "Remove a directory."; + return "Remove a directory"; case FtpCommand::RMDA: return "Remove a directory tree"; case FtpCommand::RNFR: - return "Rename from."; + return "Rename from"; case FtpCommand::RNTO: - return "Rename to."; + return "Rename to"; case FtpCommand::SITE: return "Sends site specific commands to remote server (like SITE IDLE 60 or SITE UMASK 002). Inspect SITE " - "HELP output for complete list of supported commands."; + "HELP output for complete list of supported commands"; case FtpCommand::SIZE: - return "Return the size of a file."; + return "Return the size of a file"; case FtpCommand::SMNT: - return "Mount file structure."; + return "Mount file structure"; case FtpCommand::SPSV: return "Use single port passive mode (only one TCP port number for both control connections and " "passive-mode data connections)"; @@ -169,17 +169,17 @@ namespace pcpp case FtpCommand::STOR: return "Accept the data and to store the data as a file at the server site"; case FtpCommand::STOU: - return "Store file uniquely."; + return "Store file uniquely"; case FtpCommand::STRU: - return "Set file transfer structure."; + return "Set file transfer structure"; case FtpCommand::SYST: - return "Return system type."; + return "Return system type"; case FtpCommand::THMB: return "Get a thumbnail of a remote image file"; case FtpCommand::TYPE: - return "Sets the transfer mode (ASCII/Binary)."; + return "Sets the transfer mode (ASCII/Binary)"; case FtpCommand::USER: - return "Authentication username."; + return "Authentication username"; case FtpCommand::XCUP: return "Change to the parent of the current working directory"; case FtpCommand::XMKD: diff --git a/Tests/Packet++Test/Tests/FtpTests.cpp b/Tests/Packet++Test/Tests/FtpTests.cpp index ebae434370..e61825c167 100644 --- a/Tests/Packet++Test/Tests/FtpTests.cpp +++ b/Tests/Packet++Test/Tests/FtpTests.cpp @@ -27,10 +27,6 @@ PTF_TEST_CASE(FtpParsingTests) PTF_ASSERT_EQUAL(ftpLayer1->toString(), "FTP Request: USER"); PTF_ASSERT_FALSE(ftpLayer1->isMultiLine()); - PTF_ASSERT_EQUAL(pcpp::FtpRequestLayer::getCommandInfo(pcpp::FtpRequestLayer::FtpCommand::USER), - "Authentication username."); - PTF_ASSERT_EQUAL(pcpp::FtpRequestLayer::getCommandAsString(pcpp::FtpRequestLayer::FtpCommand::USER), "USER"); - READ_FILE_AND_CREATE_PACKET(2, "PacketExamples/ftpIpv4Resp.dat"); pcpp::Packet ftpPacket2(&rawPacket2); @@ -43,10 +39,6 @@ PTF_TEST_CASE(FtpParsingTests) PTF_ASSERT_EQUAL(ftpLayer2->toString(), "FTP Response: 250"); PTF_ASSERT_FALSE(ftpLayer2->isMultiLine()); - PTF_ASSERT_EQUAL( - pcpp::FtpResponseLayer::getStatusCodeAsString(pcpp::FtpResponseLayer::FtpStatusCode::REQ_FILE_OK_COMPLETE), - "Requested file action okay, completed"); - READ_FILE_AND_CREATE_PACKET(3, "PacketExamples/ftpIpv4RespHyphen.dat"); pcpp::Packet ftpPacket3(&rawPacket3); @@ -59,10 +51,6 @@ PTF_TEST_CASE(FtpParsingTests) PTF_ASSERT_EQUAL(ftpLayer3->toString(), "FTP Response: 211"); PTF_ASSERT_TRUE(ftpLayer3->isMultiLine()); - PTF_ASSERT_EQUAL( - pcpp::FtpResponseLayer::getStatusCodeAsString(pcpp::FtpResponseLayer::FtpStatusCode::SYSTEM_STATUS), - "System status, or system help reply"); - // Test IPv6 packets READ_FILE_AND_CREATE_PACKET(4, "PacketExamples/ftpIpv6Req.dat"); @@ -76,10 +64,6 @@ PTF_TEST_CASE(FtpParsingTests) PTF_ASSERT_EQUAL(ftpLayer4->toString(), "FTP Request: PASS"); PTF_ASSERT_FALSE(ftpLayer4->isMultiLine()); - PTF_ASSERT_EQUAL(pcpp::FtpRequestLayer::getCommandInfo(pcpp::FtpRequestLayer::FtpCommand::PASS), - "Authentication password."); - PTF_ASSERT_EQUAL(pcpp::FtpRequestLayer::getCommandAsString(pcpp::FtpRequestLayer::FtpCommand::PASS), "PASS"); - READ_FILE_AND_CREATE_PACKET(5, "PacketExamples/ftpIpv6Resp.dat"); pcpp::Packet ftpPacket5(&rawPacket5); @@ -93,10 +77,6 @@ PTF_TEST_CASE(FtpParsingTests) PTF_ASSERT_EQUAL(ftpLayer5->toString(), "FTP Response: 502"); PTF_ASSERT_FALSE(ftpLayer5->isMultiLine()); - PTF_ASSERT_EQUAL( - pcpp::FtpResponseLayer::getStatusCodeAsString(pcpp::FtpResponseLayer::FtpStatusCode::COMMAND_NOT_IMPLEMENTED), - "Command not implemented"); - // Test FTP Data READ_FILE_AND_CREATE_PACKET(6, "PacketExamples/ftp-data.dat"); @@ -107,6 +87,180 @@ PTF_TEST_CASE(FtpParsingTests) PTF_ASSERT_EQUAL(ftpDataLayer->getDataLen(), 1452); PTF_ASSERT_EQUAL(ftpDataLayer->toString(), "FTP Data"); + + // Command codes + std::vector> possibleCommandCodes = { + {static_cast(0), "Unknown command"}, + {pcpp::FtpRequestLayer::FtpCommand::ABOR, "Abort an active file transfer"}, + {pcpp::FtpRequestLayer::FtpCommand::ACCT, "Account information"}, + {pcpp::FtpRequestLayer::FtpCommand::ADAT, "Authentication/Security Data"}, + {pcpp::FtpRequestLayer::FtpCommand::ALLO, "Allocate sufficient disk space to receive a file"}, + {pcpp::FtpRequestLayer::FtpCommand::APPE, "Append (with create)"}, + {pcpp::FtpRequestLayer::FtpCommand::AUTH, "Authentication/Security Mechanism"}, + {pcpp::FtpRequestLayer::FtpCommand::AVBL, "Get the available space"}, + {pcpp::FtpRequestLayer::FtpCommand::CCC, "Clear Command Channel"}, + {pcpp::FtpRequestLayer::FtpCommand::CDUP, "Change to Parent Directory"}, + {pcpp::FtpRequestLayer::FtpCommand::CONF, "Confidentiality Protection Command"}, + {pcpp::FtpRequestLayer::FtpCommand::CSID, "Client / Server Identification"}, + {pcpp::FtpRequestLayer::FtpCommand::CWD, "Change working directory"}, + {pcpp::FtpRequestLayer::FtpCommand::DELE, "Delete file"}, + {pcpp::FtpRequestLayer::FtpCommand::DSIZ, "Get the directory size"}, + {pcpp::FtpRequestLayer::FtpCommand::ENC, "Privacy Protected Channel"}, + {pcpp::FtpRequestLayer::FtpCommand::EPRT, + "Specifies an extended address and port to which the server should connect"}, + {pcpp::FtpRequestLayer::FtpCommand::EPSV, "Enter extended passive mode"}, + {pcpp::FtpRequestLayer::FtpCommand::FEAT, "Get the feature list implemented by the server"}, + {pcpp::FtpRequestLayer::FtpCommand::HELP, + "Returns usage documentation on a command if specified, else a general help document is returned"}, + {pcpp::FtpRequestLayer::FtpCommand::HOST, "Identify desired virtual host on server, by name"}, + {pcpp::FtpRequestLayer::FtpCommand::LANG, "Language Negotiation"}, + {pcpp::FtpRequestLayer::FtpCommand::LIST, "Returns information of a file or directory if specified, else " + "information of the current working directory is returned"}, + {pcpp::FtpRequestLayer::FtpCommand::LPRT, + "Specifies a long address and port to which the server should connect"}, + {pcpp::FtpRequestLayer::FtpCommand::LPSV, "Enter long passive mode"}, + {pcpp::FtpRequestLayer::FtpCommand::MDTM, "Return the last-modified time of a specified file"}, + {pcpp::FtpRequestLayer::FtpCommand::MFCT, "Modify the creation time of a file"}, + {pcpp::FtpRequestLayer::FtpCommand::MFF, + "Modify fact (the last modification time, creation time, UNIX group/owner/mode of a file)"}, + {pcpp::FtpRequestLayer::FtpCommand::MFMT, "Modify the last modification time of a file"}, + {pcpp::FtpRequestLayer::FtpCommand::MIC, "Integrity Protected Command"}, + {pcpp::FtpRequestLayer::FtpCommand::MKD, "Make directory"}, + {pcpp::FtpRequestLayer::FtpCommand::MLSD, + "Lists the contents of a directory in a standardized machine-readable format"}, + {pcpp::FtpRequestLayer::FtpCommand::MLST, + "Provides data about exactly the object named on its command line in a standardized machine-readable format"}, + {pcpp::FtpRequestLayer::FtpCommand::MODE, "Sets the transfer mode (Stream, Block, or Compressed)"}, + {pcpp::FtpRequestLayer::FtpCommand::NLST, "Returns a list of file names in a specified directory"}, + {pcpp::FtpRequestLayer::FtpCommand::NOOP, "No operation (dummy packet; used mostly on keepalives)"}, + {pcpp::FtpRequestLayer::FtpCommand::OPTS, "Select options for a feature (for example OPTS UTF8 ON)"}, + {pcpp::FtpRequestLayer::FtpCommand::PASS, "Authentication password"}, + {pcpp::FtpRequestLayer::FtpCommand::PASV, "Enter passive mode"}, + {pcpp::FtpRequestLayer::FtpCommand::PBSZ, "Protection Buffer Size"}, + {pcpp::FtpRequestLayer::FtpCommand::PORT, "Specifies an address and port to which the server should connect"}, + {pcpp::FtpRequestLayer::FtpCommand::PROT, "Data Channel Protection Level"}, + {pcpp::FtpRequestLayer::FtpCommand::PWD, "Print working directory. Returns the current directory of the host"}, + {pcpp::FtpRequestLayer::FtpCommand::QUIT, "Disconnect"}, + {pcpp::FtpRequestLayer::FtpCommand::REIN, "Re initializes the connection"}, + {pcpp::FtpRequestLayer::FtpCommand::REST, "Restart transfer from the specified point"}, + {pcpp::FtpRequestLayer::FtpCommand::RETR, "Retrieve a copy of the file"}, + {pcpp::FtpRequestLayer::FtpCommand::RMD, "Remove a directory"}, + {pcpp::FtpRequestLayer::FtpCommand::RMDA, "Remove a directory tree"}, + {pcpp::FtpRequestLayer::FtpCommand::RNFR, "Rename from"}, + {pcpp::FtpRequestLayer::FtpCommand::RNTO, "Rename to"}, + {pcpp::FtpRequestLayer::FtpCommand::SITE, + "Sends site specific commands to remote server (like SITE IDLE 60 or SITE UMASK 002). Inspect SITE HELP " + "output for complete list of supported commands"}, + {pcpp::FtpRequestLayer::FtpCommand::SIZE, "Return the size of a file"}, + {pcpp::FtpRequestLayer::FtpCommand::SMNT, "Mount file structure"}, + {pcpp::FtpRequestLayer::FtpCommand::SPSV, "Use single port passive mode (only one TCP port number for both " + "control connections and passive-mode data connections)"}, + {pcpp::FtpRequestLayer::FtpCommand::STAT, + "Returns information on the server status, including the status of the current connection"}, + {pcpp::FtpRequestLayer::FtpCommand::STOR, "Accept the data and to store the data as a file at the server site"}, + {pcpp::FtpRequestLayer::FtpCommand::STOU, "Store file uniquely"}, + {pcpp::FtpRequestLayer::FtpCommand::STRU, "Set file transfer structure"}, + {pcpp::FtpRequestLayer::FtpCommand::SYST, "Return system type"}, + {pcpp::FtpRequestLayer::FtpCommand::THMB, "Get a thumbnail of a remote image file"}, + {pcpp::FtpRequestLayer::FtpCommand::TYPE, "Sets the transfer mode (ASCII/Binary)"}, + {pcpp::FtpRequestLayer::FtpCommand::USER, "Authentication username"}, + {pcpp::FtpRequestLayer::FtpCommand::XCUP, "Change to the parent of the current working directory"}, + {pcpp::FtpRequestLayer::FtpCommand::XMKD, "Make a directory"}, + {pcpp::FtpRequestLayer::FtpCommand::XPWD, "Print the current working directory"}, + {pcpp::FtpRequestLayer::FtpCommand::XRCP, ""}, + {pcpp::FtpRequestLayer::FtpCommand::XRMD, "Remove the directory"}, + {pcpp::FtpRequestLayer::FtpCommand::XRSQ, ""}, + {pcpp::FtpRequestLayer::FtpCommand::XSEM, "Send, mail if cannot"}, + {pcpp::FtpRequestLayer::FtpCommand::XSEN, "Send to terminal"}}; + + for (const auto &entry : possibleCommandCodes) + { + PTF_ASSERT_EQUAL(pcpp::FtpRequestLayer::getCommandInfo(entry.first), entry.second); + } + + // Status codes + std::vector> possibleStatusCodes = { + {static_cast(0), "Unknown Status Code"}, + {pcpp::FtpResponseLayer::FtpStatusCode::RESTART_MARKER, "Restart marker reply"}, + {pcpp::FtpResponseLayer::FtpStatusCode::SERVICE_READY_IN_MIN, "Service ready in nnn minutes"}, + {pcpp::FtpResponseLayer::FtpStatusCode::DATA_ALREADY_OPEN_START_TRANSFER, + "Data connection already open; transfer starting"}, + {pcpp::FtpResponseLayer::FtpStatusCode::FILE_OK, "File status okay; about to open data connection"}, + {pcpp::FtpResponseLayer::FtpStatusCode::COMMAND_OK, "Command okay"}, + {pcpp::FtpResponseLayer::FtpStatusCode::COMMAND_NOT_IMPLEMENTED_SUPERFLUOUS, + "Command not implemented, superfluous at this site"}, + {pcpp::FtpResponseLayer::FtpStatusCode::SYSTEM_STATUS, "System status, or system help reply"}, + {pcpp::FtpResponseLayer::FtpStatusCode::DIR_STATUS, "Directory status"}, + {pcpp::FtpResponseLayer::FtpStatusCode::FILE_STATUS, "File status"}, + {pcpp::FtpResponseLayer::FtpStatusCode::HELP_MESSAGE, "Help message"}, + {pcpp::FtpResponseLayer::FtpStatusCode::NAME_SYSTEM_TYPE, "NAME system type"}, + {pcpp::FtpResponseLayer::FtpStatusCode::SERVICE_READY_FOR_USER, "Service ready for new user"}, + {pcpp::FtpResponseLayer::FtpStatusCode::SERVICE_CLOSING_CONTROL, "Service closing control connection"}, + {pcpp::FtpResponseLayer::FtpStatusCode::DATA_OPEN_NO_TRANSFER, "Data connection open; no transfer in progress"}, + {pcpp::FtpResponseLayer::FtpStatusCode::CLOSING_DATA, "Closing data connection"}, + {pcpp::FtpResponseLayer::FtpStatusCode::ENTERING_PASSIVE, "Entering Passive Mode"}, + {pcpp::FtpResponseLayer::FtpStatusCode::ENTERING_EXTENDED_PASSIVE, "Entering Extended Passive Mode"}, + {pcpp::FtpResponseLayer::FtpStatusCode::USER_LOG_IN_PROCEED, "User logged in, proceed"}, + {pcpp::FtpResponseLayer::FtpStatusCode::USER_LOG_IN_AUTHORIZED, + "User logged in, authorized by security data exchange"}, + {pcpp::FtpResponseLayer::FtpStatusCode::SEC_DATA_EXCHANGE_COMPLETE, "Security data exchange complete"}, + {pcpp::FtpResponseLayer::FtpStatusCode::SEC_DATA_EXCHANGE_COMPLETE_SUCCESS, + "Security data exchange completed successfully"}, + {pcpp::FtpResponseLayer::FtpStatusCode::REQ_FILE_OK_COMPLETE, "Requested file action okay, completed"}, + {pcpp::FtpResponseLayer::FtpStatusCode::PATHNAME_CREATED, "PATHNAME created"}, + {pcpp::FtpResponseLayer::FtpStatusCode::USER_OK_NEED_PASSWORD, "User name okay, need password"}, + {pcpp::FtpResponseLayer::FtpStatusCode::NEED_ACCOUNT, "Need account for login"}, + {pcpp::FtpResponseLayer::FtpStatusCode::REQ_SEC_MECHANISM_OK, "Requested security mechanism is ok"}, + {pcpp::FtpResponseLayer::FtpStatusCode::SEC_IS_ACCEPTABLE, "Security data is acceptable, more is required"}, + {pcpp::FtpResponseLayer::FtpStatusCode::USER_OK_NEED_PASS_CHALLENGE, + "Username okay, need password. Challenge is ..."}, + {pcpp::FtpResponseLayer::FtpStatusCode::FILE_PENDING_ACTION, + "Requested file action pending further information"}, + {pcpp::FtpResponseLayer::FtpStatusCode::SERVICE_NOT_AVAILABLE, + "Service not available, closing control connection"}, + {pcpp::FtpResponseLayer::FtpStatusCode::CANT_OPEN_DATA_CONNECTION, "Can't open data connection"}, + {pcpp::FtpResponseLayer::FtpStatusCode::CONNECTION_CLOSED, "Connection closed; transfer aborted"}, + {pcpp::FtpResponseLayer::FtpStatusCode::NEED_UNAVAILABLE_RESOURCE_TO_SEC, + "Need some unavailable resource to process security"}, + {pcpp::FtpResponseLayer::FtpStatusCode::REQ_FILE_ACTION_NOT_TAKEN, "Requested file action not taken"}, + {pcpp::FtpResponseLayer::FtpStatusCode::REQ_ACTION_ABORTED, + "Requested action aborted: local error in processing"}, + {pcpp::FtpResponseLayer::FtpStatusCode::REQ_ACTION_NOT_TAKEN, + "Requested action not taken. Insufficient storage space in system"}, + {pcpp::FtpResponseLayer::FtpStatusCode::SYNTAX_ERROR_COMMAND_UNRECOGNIZED, + "Syntax error, command unrecognized"}, + {pcpp::FtpResponseLayer::FtpStatusCode::SYNTAX_ERROR_PARAMETER_OR_ARGUMENT, + "Syntax error in parameters or arguments"}, + {pcpp::FtpResponseLayer::FtpStatusCode::COMMAND_NOT_IMPLEMENTED, "Command not implemented"}, + {pcpp::FtpResponseLayer::FtpStatusCode::BAD_SEQUENCE_COMMANDS, "Bad sequence of commands"}, + {pcpp::FtpResponseLayer::FtpStatusCode::COMMAND_NOT_IMPLEMENTED_FOR_PARAMETER, + "Command not implemented for that parameter"}, + {pcpp::FtpResponseLayer::FtpStatusCode::NETWORK_PROTOCOL_NOT_SUPPORTED, "Network protocol not supported"}, + {pcpp::FtpResponseLayer::FtpStatusCode::NOT_LOGGED_IN, "Not logged in"}, + {pcpp::FtpResponseLayer::FtpStatusCode::NEED_ACCOUNT_FOR_STORE_FILE, "Need account for storing files"}, + {pcpp::FtpResponseLayer::FtpStatusCode::COMMAND_PROTECTION_DENIED, + "Command protection level denied for policy reasons"}, + {pcpp::FtpResponseLayer::FtpStatusCode::REQUEST_DENIED, "Request denied for policy reasons"}, + {pcpp::FtpResponseLayer::FtpStatusCode::FAILED_SEC_CHECK, "Failed security check (hash, sequence, etc)"}, + {pcpp::FtpResponseLayer::FtpStatusCode::REQ_PROT_LEVEL_NOT_SUPPORTED, + "Requested PROT level not supported by mechanism"}, + {pcpp::FtpResponseLayer::FtpStatusCode::COMMAND_PROTECTION_LEVEL_NOT_SUPPORTED, + "Command protection level not supported by security mechanism"}, + {pcpp::FtpResponseLayer::FtpStatusCode::FILE_UNAVAILABLE, "Requested action not taken: File unavailable"}, + {pcpp::FtpResponseLayer::FtpStatusCode::PAGE_TYPE_UNKNOWN, "Requested action aborted: page type unknown"}, + {pcpp::FtpResponseLayer::FtpStatusCode::EXCEED_STORAGE_ALLOCATION, + "Requested file action aborted: Exceeded storage allocation"}, + {pcpp::FtpResponseLayer::FtpStatusCode::FILENAME_NOT_ALLOWED, + "Requested action not taken: File name not allowed"}, + {pcpp::FtpResponseLayer::FtpStatusCode::INTEGRITY_PROTECTED, "Integrity protected reply"}, + {pcpp::FtpResponseLayer::FtpStatusCode::CONFIDENTIALITY_AND_INTEGRITY_PROTECTED, + "Confidentiality and integrity protected reply"}, + {pcpp::FtpResponseLayer::FtpStatusCode::CONFIDENTIALITY_PROTECTED, "Confidentiality protected reply"}}; + + for (const auto &entry : possibleStatusCodes) + { + PTF_ASSERT_EQUAL(pcpp::FtpResponseLayer::getStatusCodeAsString(entry.first), entry.second); + } } PTF_TEST_CASE(FtpCreationTests) From 55f9825669ceebb770cb0046bc3c8299aeb9bd5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ege=20=C3=87etin?= <64282645+egecetin@users.noreply.github.com> Date: Sat, 23 Sep 2023 18:51:01 +0300 Subject: [PATCH 2/4] Improve Telnet coverage (#1208) * Scoped enum + improve coverage * fix * update equal enumclass * fix alignment * remove tabs * remove trailing whitespace --- Packet++/header/TelnetLayer.h | 4 +- Packet++/src/TelnetLayer.cpp | 198 +++++++++++------------ Tests/Packet++Test/Tests/TelnetTests.cpp | 191 +++++++++++++++++----- 3 files changed, 253 insertions(+), 140 deletions(-) diff --git a/Packet++/header/TelnetLayer.h b/Packet++/header/TelnetLayer.h index c2795b613e..571cbd6697 100644 --- a/Packet++/header/TelnetLayer.h +++ b/Packet++/header/TelnetLayer.h @@ -42,7 +42,7 @@ class TelnetLayer : public Layer /** * Telnet Command Indicator */ - enum TelnetCommand + enum class TelnetCommand : int { /// Indicator to parser reached end of packet TelnetCommandEndOfPacket = -1, @@ -103,7 +103,7 @@ class TelnetLayer : public Layer /** * Telnet Options */ - enum TelnetOption + enum class TelnetOption : int { /// Internal return for no option detected TelnetOptionNoOption = -1, diff --git a/Packet++/src/TelnetLayer.cpp b/Packet++/src/TelnetLayer.cpp index 6804bc1c1c..3f0e58b272 100644 --- a/Packet++/src/TelnetLayer.cpp +++ b/Packet++/src/TelnetLayer.cpp @@ -14,7 +14,7 @@ namespace pcpp bool TelnetLayer::isDataField(uint8_t *pos) const { // "FF FF" means data - return pos[0] != InterpretAsCommand || pos[1] == InterpretAsCommand; + return pos[0] != static_cast(TelnetCommand::InterpretAsCommand) || pos[1] == static_cast(TelnetCommand::InterpretAsCommand); } bool TelnetLayer::isCommandField(uint8_t *pos) const @@ -33,14 +33,14 @@ size_t TelnetLayer::distanceToNextIAC(uint8_t *startPos, size_t maxLength) if (addition) addition += 2; - pos = (uint8_t *)memchr(startPos + currentOffset + 1, InterpretAsCommand, maxLength - currentOffset); + pos = (uint8_t *)memchr(startPos + currentOffset + 1, static_cast(TelnetCommand::InterpretAsCommand), maxLength - currentOffset); if (pos) addition += pos - (startPos + currentOffset); else addition += maxLength - currentOffset; currentOffset = currentOffset + addition; // "FF FF" means data continue - } while (pos && (pos[1] == InterpretAsCommand) && (currentOffset < maxLength)); + } while (pos && (pos[1] == static_cast(TelnetCommand::InterpretAsCommand)) && (currentOffset < maxLength)); return addition; } @@ -48,13 +48,13 @@ size_t TelnetLayer::distanceToNextIAC(uint8_t *startPos, size_t maxLength) size_t TelnetLayer::getFieldLen(uint8_t *startPos, size_t maxLength) { // Check first byte is IAC - if (startPos && (startPos[0] == InterpretAsCommand) && (maxLength >= 2)) + if (startPos && (startPos[0] == static_cast(TelnetCommand::InterpretAsCommand)) && (maxLength >= 2)) { // If subnegotiation parse until next IAC - if (startPos[1] == Subnegotiation) + if (startPos[1] == static_cast(TelnetCommand::Subnegotiation)) return distanceToNextIAC(startPos, maxLength); // Only WILL, WONT, DO, DONT have option. Ref http://pcmicro.com/netfoss/telnet.html - else if (startPos[1] >= WillPerform && startPos[1] <= DontPerform) + else if (startPos[1] >= static_cast(TelnetCommand::WillPerform) && startPos[1] <= static_cast(TelnetCommand::DontPerform)) return 3; return 2; } @@ -97,14 +97,14 @@ uint8_t *TelnetLayer::getNextCommandField(uint8_t *pos, size_t len) int16_t TelnetLayer::getSubCommand(uint8_t *pos, size_t len) { - if (len < 3 || pos[1] < Subnegotiation) - return TelnetOptionNoOption; + if (len < 3 || pos[1] < static_cast(TelnetCommand::Subnegotiation)) + return static_cast(TelnetOption::TelnetOptionNoOption); return pos[2]; } uint8_t *TelnetLayer::getCommandData(uint8_t *pos, size_t &len) { - if (pos[1] == Subnegotiation && len > 3) + if (pos[1] == static_cast(TelnetCommand::Subnegotiation) && len > 3) { len -= 3; return &pos[3]; @@ -161,11 +161,11 @@ size_t TelnetLayer::getTotalNumberOfCommands() size_t TelnetLayer::getNumberOfCommands(TelnetCommand command) { - if (command < 0) + if (static_cast(command) < 0) return 0; size_t ctr = 0; - if (isCommandField(m_Data) && m_Data[1] == command) + if (isCommandField(m_Data) && m_Data[1] == static_cast(command)) ++ctr; uint8_t *pos = m_Data; @@ -173,7 +173,7 @@ size_t TelnetLayer::getNumberOfCommands(TelnetCommand command) { size_t offset = pos - m_Data; pos = getNextCommandField(pos, m_DataLen - offset); - if (pos && pos[1] == command) + if (pos && pos[1] == static_cast(command)) ++ctr; } @@ -190,7 +190,7 @@ TelnetLayer::TelnetCommand TelnetLayer::getFirstCommand() uint8_t *pos = getNextCommandField(m_Data, m_DataLen); if (pos) return static_cast(pos[1]); - return TelnetCommandEndOfPacket; + return TelnetCommand::TelnetCommandEndOfPacket; } TelnetLayer::TelnetCommand TelnetLayer::getNextCommand() @@ -209,7 +209,7 @@ TelnetLayer::TelnetCommand TelnetLayer::getNextCommand() return static_cast(pos[1]); } lastPositionOffset = SIZE_MAX; - return TelnetCommandEndOfPacket; + return TelnetCommand::TelnetCommandEndOfPacket; } TelnetLayer::TelnetOption TelnetLayer::getOption() @@ -217,19 +217,19 @@ TelnetLayer::TelnetOption TelnetLayer::getOption() if (lastPositionOffset < m_DataLen) return static_cast(getSubCommand( &m_Data[lastPositionOffset], getFieldLen(&m_Data[lastPositionOffset], m_DataLen - lastPositionOffset))); - return TelnetOptionNoOption; + return TelnetOption::TelnetOptionNoOption; } TelnetLayer::TelnetOption TelnetLayer::getOption(TelnetCommand command) { // Check input - if (command < 0) + if (static_cast(command) < 0) { PCPP_LOG_ERROR("Command type can't be negative"); - return TelnetOptionNoOption; + return TelnetOption::TelnetOptionNoOption; } - if (isCommandField(m_Data) && m_Data[1] == command) + if (isCommandField(m_Data) && m_Data[1] == static_cast(command)) return static_cast(getSubCommand(m_Data, getFieldLen(m_Data, m_DataLen))); uint8_t *pos = m_Data; @@ -238,12 +238,12 @@ TelnetLayer::TelnetOption TelnetLayer::getOption(TelnetCommand command) size_t offset = pos - m_Data; pos = getNextCommandField(pos, m_DataLen - offset); - if (pos && pos[1] == command) + if (pos && pos[1] == static_cast(command)) return static_cast(getSubCommand(pos, getFieldLen(pos, m_DataLen - offset))); } PCPP_LOG_DEBUG("Can't find requested command"); - return TelnetOptionNoOption; + return TelnetOption::TelnetOptionNoOption; } uint8_t *TelnetLayer::getOptionData(size_t &length) @@ -262,14 +262,14 @@ uint8_t *TelnetLayer::getOptionData(size_t &length) uint8_t *TelnetLayer::getOptionData(TelnetCommand command, size_t &length) { // Check input - if (command < 0) + if (static_cast(command) < 0) { PCPP_LOG_ERROR("Command type can't be negative"); length = 0; return nullptr; } - if (isCommandField(m_Data) && m_Data[1] == command) + if (isCommandField(m_Data) && m_Data[1] == static_cast(command)) { size_t lenBuffer = getFieldLen(m_Data, m_DataLen); uint8_t *posBuffer = getCommandData(m_Data, lenBuffer); @@ -284,7 +284,7 @@ uint8_t *TelnetLayer::getOptionData(TelnetCommand command, size_t &length) size_t offset = pos - m_Data; pos = getNextCommandField(pos, m_DataLen - offset); - if (pos && pos[1] == command) + if (pos && pos[1] == static_cast(command)) { size_t lenBuffer = getFieldLen(m_Data, m_DataLen); uint8_t *posBuffer = getCommandData(m_Data, lenBuffer); @@ -303,47 +303,47 @@ std::string TelnetLayer::getTelnetCommandAsString(TelnetCommand val) { switch (val) { - case TelnetCommandEndOfPacket: + case TelnetCommand::TelnetCommandEndOfPacket: return "Reached end of packet while parsing"; - case EndOfFile: + case TelnetCommand::EndOfFile: return "End of File"; - case Suspend: + case TelnetCommand::Suspend: return "Suspend current process"; - case Abort: + case TelnetCommand::Abort: return "Abort Process"; - case EndOfRecordCommand: + case TelnetCommand::EndOfRecordCommand: return "End of Record"; - case SubnegotiationEnd: + case TelnetCommand::SubnegotiationEnd: return "Subnegotiation End"; - case NoOperation: + case TelnetCommand::NoOperation: return "No Operation"; - case DataMark: + case TelnetCommand::DataMark: return "Data Mark"; - case Break: + case TelnetCommand::Break: return "Break"; - case InterruptProcess: + case TelnetCommand::InterruptProcess: return "Interrupt Process"; - case AbortOutput: + case TelnetCommand::AbortOutput: return "Abort Output"; - case AreYouThere: + case TelnetCommand::AreYouThere: return "Are You There"; - case EraseCharacter: + case TelnetCommand::EraseCharacter: return "Erase Character"; - case EraseLine: + case TelnetCommand::EraseLine: return "Erase Line"; - case GoAhead: + case TelnetCommand::GoAhead: return "Go Ahead"; - case Subnegotiation: + case TelnetCommand::Subnegotiation: return "Subnegotiation"; - case WillPerform: + case TelnetCommand::WillPerform: return "Will Perform"; - case WontPerform: + case TelnetCommand::WontPerform: return "Wont Perform"; - case DoPerform: + case TelnetCommand::DoPerform: return "Do Perform"; - case DontPerform: + case TelnetCommand::DontPerform: return "Dont Perform"; - case InterpretAsCommand: + case TelnetCommand::InterpretAsCommand: return "Interpret As Command"; default: return "Unknown Command"; @@ -354,115 +354,115 @@ std::string TelnetLayer::getTelnetOptionAsString(TelnetOption val) { switch (val) { - case TelnetOptionNoOption: + case TelnetOption::TelnetOptionNoOption: return "No option for this command"; - case TransmitBinary: + case TelnetOption::TransmitBinary: return "Binary Transmission"; - case Echo: + case TelnetOption::Echo: return "Echo"; - case Reconnection: + case TelnetOption::Reconnection: return "Reconnection"; - case SuppressGoAhead: + case TelnetOption::SuppressGoAhead: return "Suppress Go Ahead"; - case ApproxMsgSizeNegotiation: + case TelnetOption::ApproxMsgSizeNegotiation: return "Negotiate approximate message size"; - case Status: + case TelnetOption::Status: return "Status"; - case TimingMark: + case TelnetOption::TimingMark: return "Timing Mark"; - case RemoteControlledTransAndEcho: + case TelnetOption::RemoteControlledTransAndEcho: return "Remote Controlled Transmission and Echo"; - case OutputLineWidth: + case TelnetOption::OutputLineWidth: return "Output Line Width"; - case OutputPageSize: + case TelnetOption::OutputPageSize: return "Output Page Size"; - case OutputCarriageReturnDisposition: + case TelnetOption::OutputCarriageReturnDisposition: return "Negotiate About Output Carriage-Return Disposition"; - case OutputHorizontalTabStops: + case TelnetOption::OutputHorizontalTabStops: return "Negotiate About Output Horizontal Tabstops"; - case OutputHorizontalTabDisposition: + case TelnetOption::OutputHorizontalTabDisposition: return "Negotiate About Output Horizontal Tab Disposition"; - case OutputFormfeedDisposition: + case TelnetOption::OutputFormfeedDisposition: return "Negotiate About Output Formfeed Disposition"; - case OutputVerticalTabStops: + case TelnetOption::OutputVerticalTabStops: return "Negotiate About Vertical Tabstops"; - case OutputVerticalTabDisposition: + case TelnetOption::OutputVerticalTabDisposition: return "Negotiate About Output Vertcial Tab Disposition"; - case OutputLinefeedDisposition: + case TelnetOption::OutputLinefeedDisposition: return "Negotiate About Output Linefeed Disposition"; - case ExtendedASCII: + case TelnetOption::ExtendedASCII: return "Extended ASCII"; - case Logout: + case TelnetOption::Logout: return "Logout"; - case ByteMacro: + case TelnetOption::ByteMacro: return "Byte Macro"; - case DataEntryTerminal: + case TelnetOption::DataEntryTerminal: return "Data Entry Terminal"; - case SUPDUP: + case TelnetOption::SUPDUP: return "SUPDUP"; - case SUPDUPOutput: + case TelnetOption::SUPDUPOutput: return "SUPDUP Output"; - case SendLocation: + case TelnetOption::SendLocation: return "Send Location"; - case TerminalType: + case TelnetOption::TerminalType: return "Terminal Type"; - case EndOfRecordOption: + case TelnetOption::EndOfRecordOption: return "End Of Record"; - case TACACSUserIdentification: + case TelnetOption::TACACSUserIdentification: return "TACACS User Identification"; - case OutputMarking: + case TelnetOption::OutputMarking: return "Output Marking"; - case TerminalLocationNumber: + case TelnetOption::TerminalLocationNumber: return "Terminal Location Number"; - case Telnet3270Regime: + case TelnetOption::Telnet3270Regime: return "Telnet 3270 Regime"; - case X3Pad: + case TelnetOption::X3Pad: return "X3 Pad"; - case NegotiateAboutWindowSize: + case TelnetOption::NegotiateAboutWindowSize: return "Negotiate About Window Size"; - case TerminalSpeed: + case TelnetOption::TerminalSpeed: return "Terminal Speed"; - case RemoteFlowControl: + case TelnetOption::RemoteFlowControl: return "Remote Flow Control"; - case Linemode: + case TelnetOption::Linemode: return "Line mode"; - case XDisplayLocation: + case TelnetOption::XDisplayLocation: return "X Display Location"; - case EnvironmentOption: + case TelnetOption::EnvironmentOption: return "Environment Option"; - case AuthenticationOption: + case TelnetOption::AuthenticationOption: return "Authentication Option"; - case EncryptionOption: + case TelnetOption::EncryptionOption: return "Encryption Option"; - case NewEnvironmentOption: + case TelnetOption::NewEnvironmentOption: return "New Environment Option"; - case TN3270E: + case TelnetOption::TN3270E: return "TN3270E"; - case XAuth: + case TelnetOption::XAuth: return "X Server Authentication"; - case Charset: + case TelnetOption::Charset: return "Charset"; - case TelnetRemoteSerialPort: + case TelnetOption::TelnetRemoteSerialPort: return "Telnet Remote Serial Port"; - case ComPortControlOption: + case TelnetOption::ComPortControlOption: return "Com Port Control Option"; - case TelnetSuppressLocalEcho: + case TelnetOption::TelnetSuppressLocalEcho: return "Telnet Suppress Local Echo"; - case TelnetStartTLS: + case TelnetOption::TelnetStartTLS: return "Telnet Start TLS"; - case Kermit: + case TelnetOption::Kermit: return "Kermit"; - case SendURL: + case TelnetOption::SendURL: return "Send URL"; - case ForwardX: + case TelnetOption::ForwardX: return "Forward X Server"; - case TelOptPragmaLogon: + case TelnetOption::TelOptPragmaLogon: return "Telnet Option Pragma Logon"; - case TelOptSSPILogon: + case TelnetOption::TelOptSSPILogon: return "Telnet Option SSPI Logon"; - case TelOptPragmaHeartbeat: + case TelnetOption::TelOptPragmaHeartbeat: return "Telnet Option Pragma Heartbeat"; - case ExtendedOptions: + case TelnetOption::ExtendedOptions: return "Extended option list"; default: return "Unknown Option"; diff --git a/Tests/Packet++Test/Tests/TelnetTests.cpp b/Tests/Packet++Test/Tests/TelnetTests.cpp index 0735f7834c..58b95fe24e 100644 --- a/Tests/Packet++Test/Tests/TelnetTests.cpp +++ b/Tests/Packet++Test/Tests/TelnetTests.cpp @@ -24,47 +24,58 @@ PTF_TEST_CASE(TelnetCommandParsingTests) PTF_ASSERT_EQUAL(telnetLayer->getDataAsString(), ""); PTF_ASSERT_EQUAL(telnetLayer->getTotalNumberOfCommands(), 8); - PTF_ASSERT_EQUAL(telnetLayer->getNumberOfCommands(pcpp::TelnetLayer::WillPerform), 1); - PTF_ASSERT_EQUAL(telnetLayer->getNumberOfCommands(pcpp::TelnetLayer::DoPerform), 5); - PTF_ASSERT_EQUAL(telnetLayer->getNumberOfCommands(pcpp::TelnetLayer::SubnegotiationEnd), 1); + PTF_ASSERT_EQUAL(telnetLayer->getNumberOfCommands(pcpp::TelnetLayer::TelnetCommand::WillPerform), 1); + PTF_ASSERT_EQUAL(telnetLayer->getNumberOfCommands(pcpp::TelnetLayer::TelnetCommand::DoPerform), 5); + PTF_ASSERT_EQUAL(telnetLayer->getNumberOfCommands(pcpp::TelnetLayer::TelnetCommand::SubnegotiationEnd), 1); - PTF_ASSERT_EQUAL(telnetLayer->getFirstCommand(), pcpp::TelnetLayer::WillPerform); + PTF_ASSERT_EQUAL(telnetLayer->getFirstCommand(), pcpp::TelnetLayer::TelnetCommand::WillPerform, enumclass); - PTF_ASSERT_EQUAL(telnetLayer->getOption(pcpp::TelnetLayer::WillPerform), pcpp::TelnetLayer::SuppressGoAhead); - PTF_ASSERT_EQUAL(telnetLayer->getOption(pcpp::TelnetLayer::DoPerform), pcpp::TelnetLayer::TerminalType); - PTF_ASSERT_EQUAL(telnetLayer->getOption(pcpp::TelnetLayer::AreYouThere), pcpp::TelnetLayer::TelnetOptionNoOption); + PTF_ASSERT_EQUAL(telnetLayer->getOption(pcpp::TelnetLayer::TelnetCommand::WillPerform), + pcpp::TelnetLayer::TelnetOption::SuppressGoAhead, enumclass); + PTF_ASSERT_EQUAL(telnetLayer->getOption(pcpp::TelnetLayer::TelnetCommand::DoPerform), + pcpp::TelnetLayer::TelnetOption::TerminalType, enumclass); + PTF_ASSERT_EQUAL(telnetLayer->getOption(pcpp::TelnetLayer::TelnetCommand::AreYouThere), + pcpp::TelnetLayer::TelnetOption::TelnetOptionNoOption, enumclass); // Check iteration - pcpp::TelnetLayer::TelnetCommand vCommand[] = { - pcpp::TelnetLayer::WillPerform, pcpp::TelnetLayer::DoPerform, pcpp::TelnetLayer::DoPerform, - pcpp::TelnetLayer::DoPerform, pcpp::TelnetLayer::DoPerform, pcpp::TelnetLayer::DoPerform, - pcpp::TelnetLayer::Subnegotiation, pcpp::TelnetLayer::SubnegotiationEnd}; - pcpp::TelnetLayer::TelnetOption vOptions[] = {pcpp::TelnetLayer::SuppressGoAhead, - pcpp::TelnetLayer::TerminalType, - pcpp::TelnetLayer::NegotiateAboutWindowSize, - pcpp::TelnetLayer::TerminalSpeed, - pcpp::TelnetLayer::RemoteFlowControl, - pcpp::TelnetLayer::Linemode, - pcpp::TelnetLayer::Linemode, - pcpp::TelnetLayer::TelnetOptionNoOption}; - std::string vCommandString[] = {"Will Perform", "Do Perform", "Do Perform", "Do Perform", - "Do Perform", "Do Perform", "Subnegotiation", "Subnegotiation End"}; - std::string vOptionString[] = { + std::vector vCommand = { + pcpp::TelnetLayer::TelnetCommand::WillPerform, + pcpp::TelnetLayer::TelnetCommand::DoPerform, + pcpp::TelnetLayer::TelnetCommand::DoPerform, + pcpp::TelnetLayer::TelnetCommand::DoPerform, + pcpp::TelnetLayer::TelnetCommand::DoPerform, + pcpp::TelnetLayer::TelnetCommand::DoPerform, + pcpp::TelnetLayer::TelnetCommand::Subnegotiation, + pcpp::TelnetLayer::TelnetCommand::SubnegotiationEnd}; + + std::vector vOptions = { + pcpp::TelnetLayer::TelnetOption::SuppressGoAhead, + pcpp::TelnetLayer::TelnetOption::TerminalType, + pcpp::TelnetLayer::TelnetOption::NegotiateAboutWindowSize, + pcpp::TelnetLayer::TelnetOption::TerminalSpeed, + pcpp::TelnetLayer::TelnetOption::RemoteFlowControl, + pcpp::TelnetLayer::TelnetOption::Linemode, + pcpp::TelnetLayer::TelnetOption::Linemode, + pcpp::TelnetLayer::TelnetOption::TelnetOptionNoOption}; + + std::vector vCommandString = {"Will Perform", "Do Perform", "Do Perform", "Do Perform", + "Do Perform", "Do Perform", "Subnegotiation", "Subnegotiation End"}; + std::vector vOptionString = { "Suppress Go Ahead", "Terminal Type", "Negotiate About Window Size", "Terminal Speed", "Remote Flow Control", - "Line mode", "Line mode", "No option for this command"}; + "Line mode", "Line mode", "No option for this command"}; size_t ctr = 0; size_t length = 0; pcpp::TelnetLayer::TelnetCommand commandVal = telnetLayer->getNextCommand(); - while (commandVal != pcpp::TelnetLayer::TelnetCommandEndOfPacket) + while (commandVal != pcpp::TelnetLayer::TelnetCommand::TelnetCommandEndOfPacket) { // Check command - PTF_ASSERT_EQUAL(commandVal, vCommand[ctr]); + PTF_ASSERT_EQUAL(commandVal, vCommand[ctr], enumclass); PTF_ASSERT_EQUAL(telnetLayer->getTelnetCommandAsString(commandVal), vCommandString[ctr]); // Check option pcpp::TelnetLayer::TelnetOption option = telnetLayer->getOption(); - PTF_ASSERT_EQUAL(option, vOptions[ctr]); + PTF_ASSERT_EQUAL(option, vOptions[ctr], enumclass); PTF_ASSERT_EQUAL(telnetLayer->getTelnetOptionAsString(option), vOptionString[ctr]); // Check option data @@ -97,18 +108,23 @@ PTF_TEST_CASE(TelnetCommandParsingTests) PTF_ASSERT_EQUAL(telnetLayer2->getDataAsString(), "@"); PTF_ASSERT_EQUAL(telnetLayer2->getTotalNumberOfCommands(), 3); - pcpp::TelnetLayer::TelnetCommand vCommand2[] = {pcpp::TelnetLayer::DoPerform, pcpp::TelnetLayer::WillPerform, - pcpp::TelnetLayer::EndOfRecordCommand}; - pcpp::TelnetLayer::TelnetOption vOptions2[] = { - pcpp::TelnetLayer::TransmitBinary, pcpp::TelnetLayer::TransmitBinary, pcpp::TelnetLayer::TelnetOptionNoOption}; + std::vector vCommand2 = { + pcpp::TelnetLayer::TelnetCommand::DoPerform, + pcpp::TelnetLayer::TelnetCommand::WillPerform, + pcpp::TelnetLayer::TelnetCommand::EndOfRecordCommand}; + + std::vector vOptions2 = { + pcpp::TelnetLayer::TelnetOption::TransmitBinary, + pcpp::TelnetLayer::TelnetOption::TransmitBinary, + pcpp::TelnetLayer::TelnetOption::TelnetOptionNoOption}; size_t ctr2 = 0; size_t length2 = 0; pcpp::TelnetLayer::TelnetCommand commandVal2 = telnetLayer2->getNextCommand(); - while (commandVal2 != pcpp::TelnetLayer::TelnetCommandEndOfPacket) + while (commandVal2 != pcpp::TelnetLayer::TelnetCommand::TelnetCommandEndOfPacket) { - PTF_ASSERT_EQUAL(commandVal2, vCommand2[ctr2]); - PTF_ASSERT_EQUAL(telnetLayer2->getOption(), vOptions2[ctr2]); + PTF_ASSERT_EQUAL(commandVal2, vCommand2[ctr2], enumclass); + PTF_ASSERT_EQUAL(telnetLayer2->getOption(), vOptions2[ctr2], enumclass); // Check option data PTF_ASSERT_NULL(telnetLayer2->getOptionData(length2)); @@ -133,14 +149,111 @@ PTF_TEST_CASE(TelnetCommandParsingTests) "expired.Login using username and passwordWelcome to Microsoft Telnet Service login: "); PTF_ASSERT_EQUAL(telnetLayer3->getTotalNumberOfCommands(), 2); - PTF_ASSERT_EQUAL(telnetLayer3->getNumberOfCommands(pcpp::TelnetLayer::Subnegotiation), 1); - PTF_ASSERT_EQUAL(telnetLayer3->getNumberOfCommands(pcpp::TelnetLayer::SubnegotiationEnd), 1); + PTF_ASSERT_EQUAL(telnetLayer3->getNumberOfCommands(pcpp::TelnetLayer::TelnetCommand::Subnegotiation), 1); + PTF_ASSERT_EQUAL(telnetLayer3->getNumberOfCommands(pcpp::TelnetLayer::TelnetCommand::SubnegotiationEnd), 1); - PTF_ASSERT_EQUAL(telnetLayer3->getOption(pcpp::TelnetLayer::Subnegotiation), - pcpp::TelnetLayer::AuthenticationOption); - PTF_ASSERT_EQUAL(telnetLayer3->getOption(pcpp::TelnetLayer::SubnegotiationEnd), - pcpp::TelnetLayer::TelnetOptionNoOption); + PTF_ASSERT_EQUAL(telnetLayer3->getOption(pcpp::TelnetLayer::TelnetCommand::Subnegotiation), + pcpp::TelnetLayer::TelnetOption::AuthenticationOption, enumclass); + PTF_ASSERT_EQUAL(telnetLayer3->getOption(pcpp::TelnetLayer::TelnetCommand::SubnegotiationEnd), + pcpp::TelnetLayer::TelnetOption::TelnetOptionNoOption, enumclass); PTF_ASSERT_EQUAL(telnetLayer3->toString(), "Telnet Control"); + + // Commands + std::vector> possibleCommands = { + {static_cast(0), "Unknown Command"}, + {pcpp::TelnetLayer::TelnetCommand::TelnetCommandEndOfPacket, "Reached end of packet while parsing"}, + {pcpp::TelnetLayer::TelnetCommand::EndOfFile, "End of File"}, + {pcpp::TelnetLayer::TelnetCommand::Suspend, "Suspend current process"}, + {pcpp::TelnetLayer::TelnetCommand::Abort, "Abort Process"}, + {pcpp::TelnetLayer::TelnetCommand::EndOfRecordCommand, "End of Record"}, + {pcpp::TelnetLayer::TelnetCommand::SubnegotiationEnd, "Subnegotiation End"}, + {pcpp::TelnetLayer::TelnetCommand::NoOperation, "No Operation"}, + {pcpp::TelnetLayer::TelnetCommand::DataMark, "Data Mark"}, + {pcpp::TelnetLayer::TelnetCommand::Break, "Break"}, + {pcpp::TelnetLayer::TelnetCommand::InterruptProcess, "Interrupt Process"}, + {pcpp::TelnetLayer::TelnetCommand::AbortOutput, "Abort Output"}, + {pcpp::TelnetLayer::TelnetCommand::AreYouThere, "Are You There"}, + {pcpp::TelnetLayer::TelnetCommand::EraseCharacter, "Erase Character"}, + {pcpp::TelnetLayer::TelnetCommand::EraseLine, "Erase Line"}, + {pcpp::TelnetLayer::TelnetCommand::GoAhead, "Go Ahead"}, + {pcpp::TelnetLayer::TelnetCommand::Subnegotiation, "Subnegotiation"}, + {pcpp::TelnetLayer::TelnetCommand::WillPerform, "Will Perform"}, + {pcpp::TelnetLayer::TelnetCommand::WontPerform, "Wont Perform"}, + {pcpp::TelnetLayer::TelnetCommand::DoPerform, "Do Perform"}, + {pcpp::TelnetLayer::TelnetCommand::DontPerform, "Dont Perform"}, + {pcpp::TelnetLayer::TelnetCommand::InterpretAsCommand, "Interpret As Command"}}; + + for (const auto &entry : possibleCommands) + { + PTF_ASSERT_EQUAL(pcpp::TelnetLayer::getTelnetCommandAsString(entry.first), entry.second); + } + + // Options + std::vector> possibleOptions = { + {static_cast(-10), "Unknown Option"}, + {pcpp::TelnetLayer::TelnetOption::TelnetOptionNoOption, "No option for this command"}, + {pcpp::TelnetLayer::TelnetOption::TransmitBinary, "Binary Transmission"}, + {pcpp::TelnetLayer::TelnetOption::Echo, "Echo"}, + {pcpp::TelnetLayer::TelnetOption::Reconnection, "Reconnection"}, + {pcpp::TelnetLayer::TelnetOption::SuppressGoAhead, "Suppress Go Ahead"}, + {pcpp::TelnetLayer::TelnetOption::ApproxMsgSizeNegotiation, "Negotiate approximate message size"}, + {pcpp::TelnetLayer::TelnetOption::Status, "Status"}, + {pcpp::TelnetLayer::TelnetOption::TimingMark, "Timing Mark"}, + {pcpp::TelnetLayer::TelnetOption::RemoteControlledTransAndEcho, "Remote Controlled Transmission and Echo"}, + {pcpp::TelnetLayer::TelnetOption::OutputLineWidth, "Output Line Width"}, + {pcpp::TelnetLayer::TelnetOption::OutputPageSize, "Output Page Size"}, + {pcpp::TelnetLayer::TelnetOption::OutputCarriageReturnDisposition, + "Negotiate About Output Carriage-Return Disposition"}, + {pcpp::TelnetLayer::TelnetOption::OutputHorizontalTabStops, "Negotiate About Output Horizontal Tabstops"}, + {pcpp::TelnetLayer::TelnetOption::OutputHorizontalTabDisposition, + "Negotiate About Output Horizontal Tab Disposition"}, + {pcpp::TelnetLayer::TelnetOption::OutputFormfeedDisposition, "Negotiate About Output Formfeed Disposition"}, + {pcpp::TelnetLayer::TelnetOption::OutputVerticalTabStops, "Negotiate About Vertical Tabstops"}, + {pcpp::TelnetLayer::TelnetOption::OutputVerticalTabDisposition, + "Negotiate About Output Vertcial Tab Disposition"}, + {pcpp::TelnetLayer::TelnetOption::OutputLinefeedDisposition, "Negotiate About Output Linefeed Disposition"}, + {pcpp::TelnetLayer::TelnetOption::ExtendedASCII, "Extended ASCII"}, + {pcpp::TelnetLayer::TelnetOption::Logout, "Logout"}, + {pcpp::TelnetLayer::TelnetOption::ByteMacro, "Byte Macro"}, + {pcpp::TelnetLayer::TelnetOption::DataEntryTerminal, "Data Entry Terminal"}, + {pcpp::TelnetLayer::TelnetOption::SUPDUP, "SUPDUP"}, + {pcpp::TelnetLayer::TelnetOption::SUPDUPOutput, "SUPDUP Output"}, + {pcpp::TelnetLayer::TelnetOption::SendLocation, "Send Location"}, + {pcpp::TelnetLayer::TelnetOption::TerminalType, "Terminal Type"}, + {pcpp::TelnetLayer::TelnetOption::EndOfRecordOption, "End Of Record"}, + {pcpp::TelnetLayer::TelnetOption::TACACSUserIdentification, "TACACS User Identification"}, + {pcpp::TelnetLayer::TelnetOption::OutputMarking, "Output Marking"}, + {pcpp::TelnetLayer::TelnetOption::TerminalLocationNumber, "Terminal Location Number"}, + {pcpp::TelnetLayer::TelnetOption::Telnet3270Regime, "Telnet 3270 Regime"}, + {pcpp::TelnetLayer::TelnetOption::X3Pad, "X3 Pad"}, + {pcpp::TelnetLayer::TelnetOption::NegotiateAboutWindowSize, "Negotiate About Window Size"}, + {pcpp::TelnetLayer::TelnetOption::TerminalSpeed, "Terminal Speed"}, + {pcpp::TelnetLayer::TelnetOption::RemoteFlowControl, "Remote Flow Control"}, + {pcpp::TelnetLayer::TelnetOption::Linemode, "Line mode"}, + {pcpp::TelnetLayer::TelnetOption::XDisplayLocation, "X Display Location"}, + {pcpp::TelnetLayer::TelnetOption::EnvironmentOption, "Environment Option"}, + {pcpp::TelnetLayer::TelnetOption::AuthenticationOption, "Authentication Option"}, + {pcpp::TelnetLayer::TelnetOption::EncryptionOption, "Encryption Option"}, + {pcpp::TelnetLayer::TelnetOption::NewEnvironmentOption, "New Environment Option"}, + {pcpp::TelnetLayer::TelnetOption::TN3270E, "TN3270E"}, + {pcpp::TelnetLayer::TelnetOption::XAuth, "X Server Authentication"}, + {pcpp::TelnetLayer::TelnetOption::Charset, "Charset"}, + {pcpp::TelnetLayer::TelnetOption::TelnetRemoteSerialPort, "Telnet Remote Serial Port"}, + {pcpp::TelnetLayer::TelnetOption::ComPortControlOption, "Com Port Control Option"}, + {pcpp::TelnetLayer::TelnetOption::TelnetSuppressLocalEcho, "Telnet Suppress Local Echo"}, + {pcpp::TelnetLayer::TelnetOption::TelnetStartTLS, "Telnet Start TLS"}, + {pcpp::TelnetLayer::TelnetOption::Kermit, "Kermit"}, + {pcpp::TelnetLayer::TelnetOption::SendURL, "Send URL"}, + {pcpp::TelnetLayer::TelnetOption::ForwardX, "Forward X Server"}, + {pcpp::TelnetLayer::TelnetOption::TelOptPragmaLogon, "Telnet Option Pragma Logon"}, + {pcpp::TelnetLayer::TelnetOption::TelOptSSPILogon, "Telnet Option SSPI Logon"}, + {pcpp::TelnetLayer::TelnetOption::TelOptPragmaHeartbeat, "Telnet Option Pragma Heartbeat"}, + {pcpp::TelnetLayer::TelnetOption::ExtendedOptions, "Extended option list"}}; + + for (const auto &entry : possibleOptions) + { + PTF_ASSERT_EQUAL(pcpp::TelnetLayer::getTelnetOptionAsString(entry.first), entry.second); + } } PTF_TEST_CASE(TelnetDataParsingTests) From 4cf8ed44f9dd145f874dc1dd747dfefcfcab75be Mon Sep 17 00:00:00 2001 From: seladb Date: Tue, 26 Sep 2023 00:46:33 -0700 Subject: [PATCH 3/4] Bump up the version to 23.09 (#1209) --- CMakeLists.txt | 2 +- Common++/header/PcapPlusPlusVersion.h | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e07e40ab1..0f24d43f39 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # We need 3.12 or later, so that we can set policy CMP0074; see below. cmake_minimum_required(VERSION 3.12) -set(PCAPPP_VERSION "22.11+") +set(PCAPPP_VERSION "23.09") # MAIN_PROJECT CHECK set(PCAPPP_MAIN_PROJECT OFF) diff --git a/Common++/header/PcapPlusPlusVersion.h b/Common++/header/PcapPlusPlusVersion.h index 3d94dc0d2b..604edc30be 100644 --- a/Common++/header/PcapPlusPlusVersion.h +++ b/Common++/header/PcapPlusPlusVersion.h @@ -11,20 +11,20 @@ */ namespace pcpp { - #define PCAPPLUSPLUS_VERSION "22.11+" - #define PCAPPLUSPLUS_VERSION_OFFICIAL "non-official release" + #define PCAPPLUSPLUS_VERSION "23.09" + #define PCAPPLUSPLUS_VERSION_OFFICIAL "official release" #define PCAPPLUSPLUS_VERSION_FULL "v" PCAPPLUSPLUS_VERSION " (" PCAPPLUSPLUS_VERSION_OFFICIAL ")" /** - * @return PcapPlusPlus current version, e.g: 22.11. Notice that for non-official releases (which were pulled from GitHub) the version will end with a '+'. - * For example: '22.11+' means non-official release but '22.11' means official release + * @return PcapPlusPlus current version, e.g: 23.09. Notice that for non-official releases (which were pulled from GitHub) the version will end with a '+'. + * For example: '23.09+' means non-official release but '23.09' means official release */ inline std::string getPcapPlusPlusVersion() { return PCAPPLUSPLUS_VERSION; } /** - * @return PcapPlusPlus long version string which includes the version and info whether it's an official or non-official release. For example: "v22.11+ (non-official release)" - * or "v22.11 (official release)" + * @return PcapPlusPlus long version string which includes the version and info whether it's an official or non-official release. For example: "v23.09+ (non-official release)" + * or "v23.09 (official release)" */ inline std::string getPcapPlusPlusVersionFull() { return PCAPPLUSPLUS_VERSION_FULL; } From 09141bb6529eb11085f6ccc5b5828db65bd27191 Mon Sep 17 00:00:00 2001 From: seladb Date: Sat, 30 Sep 2023 10:38:33 -0700 Subject: [PATCH 4/4] Update the version to 23.09+ (non-official) (#1211) --- CMakeLists.txt | 2 +- Common++/header/PcapPlusPlusVersion.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f24d43f39..afaa6c683a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # We need 3.12 or later, so that we can set policy CMP0074; see below. cmake_minimum_required(VERSION 3.12) -set(PCAPPP_VERSION "23.09") +set(PCAPPP_VERSION "23.09+") # MAIN_PROJECT CHECK set(PCAPPP_MAIN_PROJECT OFF) diff --git a/Common++/header/PcapPlusPlusVersion.h b/Common++/header/PcapPlusPlusVersion.h index 604edc30be..11142bbb3e 100644 --- a/Common++/header/PcapPlusPlusVersion.h +++ b/Common++/header/PcapPlusPlusVersion.h @@ -11,8 +11,8 @@ */ namespace pcpp { - #define PCAPPLUSPLUS_VERSION "23.09" - #define PCAPPLUSPLUS_VERSION_OFFICIAL "official release" + #define PCAPPLUSPLUS_VERSION "23.09+" + #define PCAPPLUSPLUS_VERSION_OFFICIAL "non-official release" #define PCAPPLUSPLUS_VERSION_FULL "v" PCAPPLUSPLUS_VERSION " (" PCAPPLUSPLUS_VERSION_OFFICIAL ")"