#include "log/messages.h"
-static SdTreeNode* AddChild(SdTreeNode *node, SdOptionData *data, char *pattern);
-
-
-SdOptionData::SdOptionData(std::string pattern, uint8_t threshold)
+SdOptionData::SdOptionData(std::string pattern_)
{
- validate_func = nullptr;
- match_success = 0;
-
- if (pattern == "credit_card")
+ if (pattern_ == "credit_card")
{
- pattern = SD_CREDIT_PATTERN_ALL;
- validate_func = SdLuhnAlgorithm;
+ pattern_ = SD_CREDIT_PATTERN_ALL;
+ validate = SdLuhnAlgorithm;
}
- else if (pattern == "us_social")
- pattern = SD_SOCIAL_PATTERN;
- else if (pattern == "us_social_nodashes")
- pattern = SD_SOCIAL_NODASHES_PATTERN;
- pii = strdup(pattern.c_str());
- if (!pii)
- FatalError("Failed to copy sd_pattern");
+ else if (pattern_ == "us_social")
+ pattern_ = SD_SOCIAL_PATTERN;
- count = threshold;
-}
+ else if (pattern_ == "us_social_nodashes")
+ pattern_ = SD_SOCIAL_NODASHES_PATTERN;
-SdContext::SdContext(SdOptionData *sd_data)
-{
- head_node = (SdTreeNode*)calloc(1, sizeof(*head_node));
- if (!head_node)
- FatalError("Failed to allocate SdContext node\n");
-
- sd_data->counter_index = num_patterns++;
- AddPii(head_node, sd_data);
-}
-
-// Main pattern-adding function.
-// Arguments:
-// head => pointer to top node in PII tree
-// data => pointer to SdOptionData struct w/ new pattern
-// Return values:
-// -1: error
-// 1: pattern added successfully
-//
-static int AddPiiPattern(SdTreeNode *head, SdOptionData *data)
-{
- AddChild(head, data, data->pii);
- return 1;
+ pattern = strdup(pattern_.c_str());
+ if (!pattern)
+ {
+ FatalError("Failed to copy sd_pattern");
+ }
+ ExpandBrackets();
}
-// Check that the brackets in a pattern match up, and only contain numbers.
-//
-// Arguments:
-// pii - string containing pattern.
-//
-// Returns: void function. Raises fatal error if there's a problem.
-//
-static void ExpandBrackets(char **pii)
+void SdOptionData::ExpandBrackets(void)
{
- char *bracket_index, *new_pii, *endptr, *pii_position;
+ char* bracket_index, * new_pii, * endptr, * pii_position;
unsigned long int new_pii_size, repetitions, total_reps = 0;
unsigned int num_brackets = 0;
- if (pii == NULL || *pii == NULL)
+ if ( !pattern )
return;
- // Locate first '{'
- bracket_index = strchr(*pii, '{');
+ bracket_index = strchr(pattern, '{');
- // Brackets at the beginning have nothing to modify.
- if (bracket_index == *pii)
- {
- ParseError("sd_pattern \"%s\" starts with curly brackets which have nothing to modify.", *pii);
- }
+ if ( bracket_index == pattern )
+ ParseError("sd_pattern \"%s\" starts with curly brackets which have nothing to modify.", pattern);
- // Check for various error cases. Total up the # of bytes needed in new pattern
- while (bracket_index)
+ while ( bracket_index )
{
- // Ignore escaped brackets
- if ((bracket_index > *pii) && (*(bracket_index-1) == '\\'))
+ if ( (bracket_index > pattern) && (*(bracket_index-1) == '\\') )
{
+ // Ignore escaped brackets
bracket_index = strchr(bracket_index+1, '{');
continue;
}
// Check for the case of one bracket set modifying another, i.e. "{3}{4}"
// Note: "\}{4}" is OK
- if ((bracket_index > (*pii)+1) &&
- (*(bracket_index-1) == '}') &&
- (*(bracket_index-2) != '\\') )
- {
- ParseError("sd_pattern \"%s\" contains curly brackets which have nothing to modify.", *pii);
- }
+ if ( (bracket_index > pattern + 1) && (*(bracket_index - 1) == '}') && (*(bracket_index - 2) != '\\') )
+ ParseError("sd_pattern \"%s\" contains curly brackets which have nothing to modify.", pattern);
- // Get the number from inside the brackets
repetitions = strtoul(bracket_index+1, &endptr, 10);
- if (*endptr != '}' && *endptr != '\0')
- {
- ParseError("sd_pattern \"%s\" contains curly brackets with non-digits inside.", *pii);
- }
+ if ( *endptr != '}' && *endptr != '\0' )
+ ParseError("sd_pattern \"%s\" contains curly brackets with non-digits inside.", pattern);
+
else if (*endptr == '\0')
- {
- ParseError("sd_pattern \"%s\" contains an unterminated curly bracket.", *pii);
- }
+ ParseError("sd_pattern \"%s\" contains an unterminated curly bracket.", pattern);
- // The brackets look OK. Increase the rep count.
- if ((bracket_index > (*pii)+1) && (*(bracket_index-2) == '\\'))
+ if ( (bracket_index > pattern+1) && (*(bracket_index-2) == '\\') )
total_reps += (repetitions * 2);
else
total_reps += repetitions;
num_brackets++;
- // Next bracket
bracket_index = strchr(bracket_index+1, '{');
}
- // By this point, the brackets all match up.
- if (num_brackets == 0)
+ if ( num_brackets == 0 )
return;
- // Allocate the new pii string.
- new_pii_size = (strlen(*pii) + total_reps - 2*num_brackets + 1);
- new_pii = (char*)calloc(new_pii_size, sizeof(char));
- if (new_pii == NULL)
- {
+ new_pii_size = (strlen(pattern) + total_reps - 2 * num_brackets + 1);
+ new_pii = (char*) calloc(new_pii_size, sizeof(*new_pii));
+ if ( !new_pii )
FatalError("Failed to allocate memory for sd_pattern rule option\n");
- }
- // Copy the PII string, expanding repeated sections.
- pii_position = *pii;
+ pii_position = pattern;
while (*pii_position != '\0')
{
char repeated_section[3] = {'\0'};
pii_position = endptr+1;
}
- // Channeling "Shlemiel the Painter" here.
for (i = 0; i < reps; i++)
- {
strncat(new_pii, repeated_section, 2);
- }
- }
-
- // Switch out the pii strings.
- free(*pii);
- *pii = new_pii;
-}
-
-// Perform any modifications needed to a pattern string, then add it to the
-// tree.
-int AddPii(SdTreeNode *head, SdOptionData *data)
-{
- ExpandBrackets(&(data->pii));
-
- return AddPiiPattern(head, data);
-}
-
-// Create a new tree node, and add it as a child to the current node.
-static SdTreeNode * AddChild(SdTreeNode *node, SdOptionData *data, char *pattern)
-{
- SdTreeNode * new_node = NULL;
-
- // Take care not to step on the other children
- node->children = (SdTreeNode**)calloc(1,sizeof(SdTreeNode*));
- if (node->children == NULL)
- {
- FatalError("Could not allocate node children\n");
- }
-
- node->children[0] = (SdTreeNode*)calloc(1,sizeof(SdTreeNode));
- if (node->children[0] == NULL)
- {
- FatalError("Could not allocate node children[0]\n");
- }
-
- node->num_children = 1;
- new_node = node->children[0];
-
- new_node->pattern = strdup(pattern);
- if (new_node->pattern == NULL)
- {
- FatalError("Could not allocate node pattern\n");
}
- new_node->num_option_data = 1;
- new_node->option_data_list = (SdOptionData**)calloc(1, sizeof(SdOptionData*));
- if (new_node->option_data_list == NULL)
- {
- FatalError("Could not allocate node list\n");
- }
-
- new_node->option_data_list[0] = data;
-
- return new_node;
+ free(pattern);
+ pattern = new_pii;
}
-// Frees an entire PII tree.
-int FreePiiTree(SdTreeNode *node)
+bool SdOptionData::match(const uint8_t * const buf, uint16_t * const buf_index, uint16_t buflen)
{
- uint16_t i;
+ uint16_t pattern_index = 0;
+ bool node_match = true;
- for (i = 0; i < node->num_children; i++)
+ while ( *buf_index < buflen && pattern[pattern_index] != '\0' && node_match )
{
- FreePiiTree(node->children[i]);
- }
-
- free(node->pattern);
- free(node->children);
+ char const * const pc = &pattern[pattern_index];
- for (i = 0; i < node->num_option_data; i++)
- delete node->option_data_list[i];
-
- free(node->option_data_list);
- free(node);
-
- return 0;
-}
-
-// Returns an SdTreeNode that matches the pattern
-SdTreeNode * FindPiiRecursively(SdTreeNode *node, const uint8_t *buf, uint16_t *buf_index,
- uint16_t buflen, uint16_t *partial_index, SdTreeNode **partial_node)
-{
- uint16_t old_buf_index;
- uint16_t pattern_index = *partial_index;
- int node_match = 1;
-
- *partial_index = 0;
- *partial_node = NULL;
-
- old_buf_index = *buf_index;
-
- // NOTE: node->pattern is a NULL-terminated string, but buf is network data
- // and may legitimately contain NULL bytes.
- while (*buf_index < buflen &&
- *(node->pattern + pattern_index) != '\0' &&
- node_match )
- {
- // Match a byte at a time.
- if ( *(node->pattern + pattern_index) == '\\' &&
- *(node->pattern + pattern_index + 1) != '\0' )
+ if ( pc[0] == '\\' && pc[1] != '\0' )
{
- // Escape sequence found
+match__rescan:
pattern_index++;
- switch ( *(node->pattern + pattern_index) )
+ switch ( pattern[pattern_index] )
{
// Escaped special character
case '\\':
case '{':
case '}':
case '?':
- node_match = (*(buf + *buf_index) == *(node->pattern + pattern_index));
+ node_match = (buf[*buf_index] == pattern[pattern_index]);
break;
// \d : match digit
case 'd':
- node_match = isdigit( (int)(*(buf + *buf_index)) );
+ node_match = isdigit((int)buf[*buf_index]);
break;
+
// \D : match non-digit
case 'D':
- node_match = !isdigit( (int)(*(buf + *buf_index)) );
+ node_match = !isdigit((int)buf[*buf_index]);
break;
// \w : match alphanumeric
case 'w':
- node_match = isalnum( (int)(*(buf + *buf_index)) );
+ node_match = isalnum((int)buf[*buf_index]);
break;
+
// \W : match non-alphanumeric */
case 'W':
- node_match = !isalnum( (int)(*(buf + *buf_index)) );
+ node_match = !isalnum((int)buf[*buf_index]);
break;
// \l : match a letter
case 'l':
- node_match = isalpha( (int)(*(buf + *buf_index)) );
+ node_match = isalpha((int)buf[*buf_index]);
break;
+
// \L : match a non-letter
case 'L':
- node_match = !isalpha( (int)(*(buf + *buf_index)) );
+ node_match = !isalpha((int)buf[*buf_index]);
break;
+
+ // \b : match a numeric boundary
+ case 'b':
+ node_match = !isdigit((int)buf[*buf_index]);
+ if ( !node_match && *buf_index == 0
+ && pattern[pattern_index+1] != '\0'
+ && pattern[pattern_index+2] != '\0' )
+ {
+ pattern_index++;
+ goto match__rescan;
+ }
}
}
else
{
- // Normal byte
- node_match = (*(buf + *buf_index) == *(node->pattern + pattern_index));
+ // Normal byte match
+ node_match = (buf[*buf_index] == pattern[pattern_index]);
}
// Handle optional characters
- if (*(node->pattern + pattern_index + 1) == '?')
+ if (pattern[pattern_index + 1] == '?')
{
- // Advance past the '?' in the pattern string.
- // Only advance in the buffer if we matched the optional char.
pattern_index += 2;
if (node_match)
(*buf_index)++;
else
- node_match = 1;
+ node_match = true;
}
else
{
- // Advance to next byte
(*buf_index)++;
pattern_index++;
}
}
- if (node_match)
- {
- uint16_t j;
- bool node_contains_matches = false;
- SdTreeNode *matched_node = NULL;
+ if ( !node_match )
+ return false;
- if(*buf_index == buflen)
- {
- if( (*(node->pattern + pattern_index) != '\0')
- || ((strlen(node->pattern) == pattern_index) && node->num_children))
- {
- *partial_index = pattern_index;
- *partial_node = node;
- return NULL;
- }
- }
-
- if ( matched_node || *partial_index )
- return matched_node;
+ if( *buf_index == buflen )
+ {
+ char const * const pc = &pattern[pattern_index];
- // An SdTreeNode holds multiple SdOptionData. It's possible to get
- // some with validation funs and some without. Evaluate them independently.
- for (j = 0; j < node->num_option_data; j++)
+ // '\b' can match EOM
+ if ( !(pc[0] == '\\' && pc[1] == 'b') )
{
- SdOptionData *option_data = node->option_data_list[j];
-
- // Run eval func, return NULL if it exists but fails
- if ( option_data->validate_func
- && option_data->validate_func(buf, *buf_index) != 1 )
- {
- *buf_index = old_buf_index;
- option_data->match_success = 0;
- }
+ if( (pc[0] == '\0') )
+ return true;
+
else
- {
- // No eval func necessary, or an eval func existed and returned 1
- option_data->match_success = 1;
- node_contains_matches = true;
- }
+ return false;
}
-
- if (node_contains_matches)
- return node;
}
- // No match here.
- *buf_index = old_buf_index;
- return NULL;
-}
-
-SdTreeNode * FindPii(const SdTreeNode *head,
- const uint8_t *buf, uint16_t *buf_index, uint16_t buflen,
- SdSessionData *session)
-{
- uint16_t i;
- uint16_t *partial_index = &(session->part_match_index);
- SdTreeNode **partial_node = &(session->part_match_node);
- *partial_index = 0;
-
- for (i = 0; i < head->num_children; i++)
- {
- SdTreeNode * matched_node = FindPiiRecursively(head->children[i],
- buf, buf_index, buflen, partial_index, partial_node);
-
- if (matched_node || *partial_index)
- return matched_node;
- }
+ if ( validate && validate(buf, *buf_index) != 1 )
+ return false;
- return NULL;
+ // Success!
+ return true;
}