std::string& trim_quotes(std::string& s)
{
- if(s.length() < 2)
+ if (s.length() < 2)
return s;
- if((s.front() == '"' and s.back() == '"') or
+ if ((s.front() == '"' and s.back() == '"') or
(s.front() == '\'' and s.back() == '\''))
{
s.erase(0,1);
}
}
-std::string get_remain_data(std::istringstream& stream)
+std::string get_remain_data(std::istringstream& stream, bool trim)
{
// get string length
const std::streamoff pos = stream.tellg();
arg_c[length] = '\0';
std::string arg_s(arg_c);
delete[] arg_c;
- util::trim(arg_s);
+
+ if (trim)
+ util::trim(arg_s);
+
return arg_s;
}
+static bool is_semicolon_escaped(const std::string& args)
+{
+ unsigned bs_count = 0;
+
+ for (auto sym_it = args.rbegin();
+ sym_it != args.rend() and *sym_it == '\\';
+ ++sym_it, ++bs_count);
+
+ return bs_count % 2;
+}
+
std::string get_rule_option_args(std::istringstream& stream)
{
std::string args = std::string();
{
std::getline(stream, tmp, ';');
+ args += tmp + ";";
+
if (tmp.empty())
break;
-
- args += tmp + ";";
}
- while (tmp.back() == '\\');
+ while (is_semicolon_escaped(tmp));
// semicolon will be added when printing
if (!args.empty())
// Handle 2 cases: sid was read before/after gid.
#include <sstream>
+#include <unordered_map>
#include "conversion_state.h"
#include "helpers/converter.h"
static const std::string removed_gids[] = { "146" , "147" };
constexpr uint8_t MAX_GIDS = (sizeof(removed_gids) / sizeof(removed_gids[0]));
+// first -> gid, second -> error message
+static const std::unordered_map<std::string, std::string> rejected_gids =
+{
+ {"138", "gid 138(sensitive data) rules should be written with Snort3 functionality in mind"}
+};
+
class Gid : public ConversionState
{
public:
}
}
rule_api.add_option("gid", gid);
+
+ auto reject_it = rejected_gids.find(gid);
+
+ if ( reject_it != rejected_gids.end() )
+ rule_api.bad_rule(data_stream, reject_it->second);
+
return set_next_rule_state(data_stream);
}
public:
SDPattern(Converter& c) : ConversionState(c) { }
bool convert(std::istringstream& data) override;
+private:
+ std::string convert_pattern(const std::string& pattern);
};
} // namespace
-bool SDPattern::convert(std::istringstream& stream)
+std::string SDPattern::convert_pattern(const std::string& pattern)
{
- std::string count;
- std::string pattern;
+ const std::string unused_pcre_tokens("()[].+*^$|");
+
+ std::string s3_pattern;
+
+ for (unsigned i = 0; i < pattern.size(); ++i)
+ {
+ char sym = pattern[i];
+
+ switch (sym)
+ {
+ case '\\':
+ {
+ if (i + 1 < pattern.size())
+ sym = pattern[++i];
+ else
+ {
+ // if backslash placed at the end of the pattern
+ // Snort2 will process it as a usual symbol
+ s3_pattern.append("\\\\");
+ break;
+ }
+
+ switch (sym)
+ {
+ case 'l':
+ s3_pattern.append("\\p{L}");
+ break;
+
+ case 'L':
+ s3_pattern.append("[^\\p{L}]");
+ break;
+
+ case 'w':
+ case 'W':
+ case 'd':
+ case 'D':
+ case '\\':
+ case '{':
+ case '}':
+ case '?':
+ s3_pattern.push_back('\\');
+ s3_pattern.push_back(sym);
+ break;
+
+ default:
+ // Snort2 ignores unknown escape sequences
+ break;
+ }
+
+ break;
+ }
+
+ case '{':
+ case '}':
+ case '?':
+ s3_pattern.push_back(sym);
+ break;
+
+ default:
+ if (unused_pcre_tokens.find(sym) != std::string::npos)
+ s3_pattern.push_back('\\');
+ s3_pattern.push_back(sym);
+ break;
+ }
+ }
+
+ return s3_pattern;
+}
+bool SDPattern::convert(std::istringstream& stream)
+{
std::string args = util::get_rule_option_args(stream);
std::istringstream arg_stream(args);
- if ( !util::get_string(arg_stream, count, ",")
- || !util::get_string(arg_stream, pattern, ","))
+ std::string count;
+
+ if ( !util::get_string(arg_stream, count, ",") )
{
- rule_api.bad_rule(stream, "sd_pattern missing arguments");
+ rule_api.bad_rule(stream, "sd_pattern missing threshold argument");
return set_next_rule_state(stream);
}
- rule_api.add_option("sd_pattern", "\"" + pattern + "\"");
+ std::string pattern = util::get_remain_data(arg_stream, false);
+
+ if ( pattern.empty() )
+ {
+ rule_api.bad_rule(stream, "sd_pattern missing pattern argument");
+ return set_next_rule_state(stream);
+ }
+
+ std::string s3_pattern = convert_pattern(pattern);
+
+ rule_api.add_option("sd_pattern", "\"" + s3_pattern + "\"");
rule_api.add_suboption("threshold", count);
+ rule_api.bad_rule(stream, "sd_pattern: rules should be written with Snort3 "
+ "functionality in mind");
return set_next_rule_state(stream);
}