Skip to content

Commit

Permalink
detect/port: find unique port points
Browse files Browse the repository at this point in the history
In order to create the smallest possible port ranges, it is convenient
to first have a list of unique ports. Then, the work becomes simple. See
below:

Given, a port range P1 = [1, 8]; SGH1
and another, P2 = [3, 94]; SGH2

right now, the code will follow a logic of recursively cutting port
ranges until we create the small ranges. But, with the help of unique
port points, we get, unique_port_points = [1, 3, 8, 94]

So, now, in a later stage, we can create the ranges as
[1, 2], [3, 7], [8, 8], [9, 94] and copy the designated SGHs where they
belong. Note that the intervals are closed which means that the range
is inclusive of both the points.

The final result becomes:
1. [1, 2]; SGH1
2. [3, 7]; SGH1 + SGH2
3. [8, 8]; SGH1 + SGH2
4. [9, 94]; SGH2

There would be 3 unique rule groups made for the case above.
Group 1: [1, 2]
Group 2: [3, 7], [8, 8]
Group 3: [9, 94]

Ticket 6792
Bug 6414
  • Loading branch information
inashivb authored and victorjulien committed Mar 4, 2024
1 parent 86f89e0 commit c9a911b
Showing 1 changed file with 50 additions and 0 deletions.
50 changes: 50 additions & 0 deletions src/detect-engine-build.c
Original file line number Diff line number Diff line change
Expand Up @@ -1129,15 +1129,59 @@ int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list, Detect
uint32_t unique_groups, int (*CompareFunc)(DetectPort *, DetectPort *));
int CreateGroupedPortListCmpCnt(DetectPort *a, DetectPort *b);

#define RANGE_PORT 1
#define SINGLE_PORT 2

/**
* \brief Function to set unique port points. Consider all the ports
* flattened out on one line, set the points that correspond
* to a valid port. Also store whether the port point stored
* was a single port or part of a range.
*
* \param p Port object to be set
* \param unique_list List of unique port points to be updated
* \param size_list Current size of the list
*
* \return Updated size of the list
*/
static inline uint32_t SetUniquePortPoints(
const DetectPort *p, uint8_t *unique_list, uint32_t size_list)
{
if (unique_list[p->port] == 0) {
if (p->port == p->port2) {
unique_list[p->port] = SINGLE_PORT;
} else {
unique_list[p->port] = RANGE_PORT;
}
size_list++;
}

/* Treat right boundary as single point to avoid creating unneeded
* ranges later on
* TODO merge the extra entry created in the rulegroup
* for such points in *CreateGroupedPortList* fn */
if (unique_list[p->port2] == 0) {
size_list++;
}
unique_list[p->port2] = SINGLE_PORT;
return size_list;
}

static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, uint8_t ipproto, uint32_t direction)
{
/* step 1: create a hash of 'DetectPort' objects based on all the
* rules. Each object will have a SGH with the sigs added
* that belong to the SGH. */
DetectPortHashInit(de_ctx);

uint32_t size_unique_port_arr = 0;
const Signature *s = de_ctx->sig_list;
DetectPort *list = NULL;

uint8_t *unique_port_points = (uint8_t *)SCCalloc(UINT16_MAX + 1, sizeof(uint8_t));
if (unique_port_points == NULL)
return NULL;

while (s) {
/* IP Only rules are handled separately */
if (s->type == SIG_TYPE_IPONLY)
Expand Down Expand Up @@ -1190,6 +1234,8 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, uint8_t ipproto, u
SigGroupHeadAppendSig(de_ctx, &tmp2->sh, s);
tmp2->sh->init->score = pwl;
DetectPortHashAdd(de_ctx, tmp2);
size_unique_port_arr =
SetUniquePortPoints(tmp2, unique_port_points, size_unique_port_arr);
}

p = p->next;
Expand Down Expand Up @@ -1268,6 +1314,10 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, uint8_t ipproto, u
direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient",
cnt, own, ref);
return list;

error:
if (unique_port_points != NULL)
SCFree(unique_port_points);
}

void SignatureSetType(DetectEngineCtx *de_ctx, Signature *s)
Expand Down

0 comments on commit c9a911b

Please sign in to comment.