Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix SingleCommandTextProtocol parsing #1259

Merged
merged 3 commits into from
Dec 8, 2023
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 33 additions & 24 deletions Packet++/src/SingleCommandTextProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,41 @@

#define ASCII_HYPHEN 0x2d
#define ASCII_SPACE 0x20
#define MAX_COMMAND_LENGTH 9 // From SMTP command "STARTTLS" + 1 byte hyphen or space
#define MIN_PACKET_LENGTH 2 // CRLF
egecetin marked this conversation as resolved.
Show resolved Hide resolved

namespace pcpp
{

size_t SingleCommandTextProtocol::getArgumentFieldOffset() const
{
size_t maxLen;
if (m_DataLen < 5)
if (m_DataLen < MAX_COMMAND_LENGTH)
maxLen = m_DataLen;
else
maxLen = 5;
maxLen = MAX_COMMAND_LENGTH;

// Find <SP> if exists
uint8_t *pos = (uint8_t *)memchr(m_Data, ASCII_SPACE, maxLen);
if (pos)
return pos - m_Data;
// To correctly detect multi-line packets with the option containing a space in
// the first MAX_CONTENT_LENGTH bytes, search the both of hyphen and space to take
// correct command delimiter

// Find Hyphen "-" if exists
pos = (uint8_t *)memchr(m_Data, ASCII_HYPHEN, maxLen);
if (pos)
return pos - m_Data;
std::string field(reinterpret_cast<char *>(m_Data), maxLen);

return m_DataLen - 1;
size_t posHyphen = field.find_first_of(ASCII_HYPHEN);
size_t posSpace = field.find_first_of(ASCII_SPACE);
size_t posCRLF = field.rfind("\r\n");

// No delimiter or packet end
if (posHyphen == std::string::npos && posSpace == std::string::npos && posCRLF == std::string::npos)
return 0;
// Both hyphen and space found
else if (posHyphen != std::string::npos || posSpace != std::string::npos)
return std::min(posSpace, posHyphen);
// If nothing found but there is a CRLF it is a only command packet
else if (posCRLF != std::string::npos)
return posCRLF;

return 0;
}

void SingleCommandTextProtocol::setDelimiter(bool hyphen)
Expand All @@ -38,17 +50,17 @@ namespace pcpp
memset(&m_Data[getArgumentFieldOffset()], ASCII_SPACE, 1);
}

bool SingleCommandTextProtocol::hyphenRequired(const std::string& value)
bool SingleCommandTextProtocol::hyphenRequired(const std::string &value)
{
size_t firstPos = value.find_first_of("\r\n");
size_t lastPos = value.find_last_of("\r\n");
return (firstPos != std::string::npos) && (lastPos != std::string::npos) && (firstPos != lastPos - 1);
size_t firstPos = value.find("\r\n");
size_t lastPos = value.rfind("\r\n");
return (firstPos != std::string::npos) && (lastPos != std::string::npos) && (firstPos != lastPos);
}

SingleCommandTextProtocol::SingleCommandTextProtocol(const std::string &command, const std::string &option)
{
m_Data = new uint8_t[6];
m_DataLen = 6;
m_Data = new uint8_t[MIN_PACKET_LENGTH];
m_DataLen = MIN_PACKET_LENGTH;
if (!command.empty())
setCommandInternal(command);
if (!option.empty())
Expand Down Expand Up @@ -80,7 +92,7 @@ namespace pcpp

bool SingleCommandTextProtocol::setCommandOptionInternal(std::string value)
{
size_t lastPos = value.find_last_of("\r\n");
size_t lastPos = value.rfind("\r\n");
if (lastPos == std::string::npos || lastPos != value.size() - 2)
value += "\r\n";

Expand Down Expand Up @@ -123,18 +135,15 @@ namespace pcpp
return "";
}

bool SingleCommandTextProtocol::isMultiLine() const
{
return m_Data[getArgumentFieldOffset()] == ASCII_HYPHEN;
}
bool SingleCommandTextProtocol::isMultiLine() const { return m_Data[getArgumentFieldOffset()] == ASCII_HYPHEN; }

bool SingleCommandTextProtocol::isDataValid(const uint8_t *data, size_t dataSize)
{
if (data == nullptr || dataSize < 6)
if (data == nullptr || dataSize < MIN_PACKET_LENGTH)
return false;

std::string payload = std::string((char *)data, dataSize);
return payload.find_last_of("\r\n") == dataSize - 1;
return payload.rfind("\r\n") == dataSize - 2;
}

} // namespace pcpp