You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
suricata/src/detect-engine-port.c

1485 lines
38 KiB
C

/* Ports part of the detection engine.
*
* Copyright (c) 2008 Victor Julien
*
* TODO VJ
* - move this out of the detection plugin structure
* - more unittesting
*
*
* */
#include "decode.h"
#include "detect.h"
#include "flow-var.h"
#include "util-cidr.h"
#include "util-unittest.h"
#include "detect-engine-siggroup.h"
#include "detect-engine-port.h"
int DetectPortSetupTmp (Signature *s, SigMatch *m, char *sidstr);
void DetectPortTests (void);
void DetectPortRegister (void) {
sigmatch_table[DETECT_PORT].name = "__port__";
sigmatch_table[DETECT_PORT].Match = NULL;
sigmatch_table[DETECT_PORT].Setup = DetectPortSetupTmp;
sigmatch_table[DETECT_PORT].Free = NULL;
sigmatch_table[DETECT_PORT].RegisterTests = DetectPortTests;
}
/* prototypes */
void DetectPortPrint(DetectPort *);
int DetectPortCut(DetectPort *, DetectPort *, DetectPort **);
int DetectPortCutNot(DetectPort *, DetectPort **);
int DetectPortCut(DetectPort *, DetectPort *, DetectPort **);
DetectPort *DetectPortCopy(DetectPort *src);
DetectPort *PortParse(char *str);
int DetectPortCmp(DetectPort *, DetectPort *);
/* memory usage counters */
static u_int32_t detect_port_memory = 0;
static u_int32_t detect_port_init_cnt = 0;
static u_int32_t detect_port_free_cnt = 0;
static u_int32_t detect_port_hash_add_cnt = 0;
static u_int32_t detect_port_hash_add_coll_cnt = 0;
static u_int32_t detect_port_hash_lookup_cnt = 0;
static u_int32_t detect_port_hash_lookup_miss_cnt = 0;
static u_int32_t detect_port_hash_lookup_hit_cnt = 0;
static u_int32_t detect_port_hash_lookup_loop_cnt = 0;
DetectPort *DetectPortInit(void) {
DetectPort *dp = malloc(sizeof(DetectPort));
if (dp == NULL) {
return NULL;
}
memset(dp,0,sizeof(DetectPort));
detect_port_memory += sizeof(DetectPort);
detect_port_init_cnt++;
return dp;
}
/* free a DetectPort object */
void DetectPortFree(DetectPort *dp) {
if (dp == NULL)
return;
/* only free the head if we have the original */
if (dp->sh != NULL && !(dp->flags & PORT_SIGGROUPHEAD_COPY)) {
SigGroupHeadFree(dp->sh);
}
dp->sh = NULL;
if (dp->dst_ph != NULL && !(dp->flags & PORT_GROUP_PORTS_COPY)) {
DetectPortCleanupList(dp->dst_ph);
}
dp->dst_ph = NULL;
detect_port_memory -= sizeof(DetectPort);
detect_port_free_cnt++;
free(dp);
}
void DetectPortPrintMemory(void) {
printf(" * Port memory stats (DetectPort %u):\n", sizeof(DetectPort));
printf(" - detect_port_memory %u\n", detect_port_memory);
printf(" - detect_port_init_cnt %u\n", detect_port_init_cnt);
printf(" - detect_port_free_cnt %u\n", detect_port_free_cnt);
printf(" - outstanding ports %u\n", detect_port_init_cnt - detect_port_free_cnt);
printf(" * Port memory stats done\n");
#if 0
printf(" x detect_port_hash_add_cnt %u\n", detect_port_hash_add_cnt);
printf(" x detect_port_hash_add_insert_cnt %u\n", detect_port_hash_add_insert_cnt);
printf(" x detect_port_hash_add_coll_cnt %u\n", detect_port_hash_add_coll_cnt);
printf(" x detect_port_hash_lookup_cnt %u\n", detect_port_hash_lookup_cnt);
printf(" x detect_port_hash_lookup_miss_cnt %u\n", detect_port_hash_lookup_miss_cnt);
printf(" x detect_port_hash_lookup_hit_cnt %u\n", detect_port_hash_lookup_hit_cnt);
printf(" x detect_port_hash_lookup_loop_cnt %u\n", detect_port_hash_lookup_loop_cnt);
#endif
}
/* used to see if the exact same portrange exists in the list
* returns a ptr to the match, or NULL if no match
*/
DetectPort *DetectPortLookup(DetectPort *head, DetectPort *dp) {
DetectPort *cur;
if (head != NULL) {
for (cur = head; cur != NULL; cur = cur->next) {
if (DetectPortCmp(cur, dp) == PORT_EQ)
return cur;
}
}
return NULL;
}
void DetectPortPrintList(DetectPort *head) {
DetectPort *cur;
u_int16_t cnt = 0;
printf("list:\n");
if (head != NULL) {
for (cur = head; cur != NULL; cur = cur->next) {
printf("SIGS %6u ", cur->sh ? cur->sh->sig_cnt : 0);
DetectPortPrint(cur);
cnt++;
printf("\n");
}
}
printf("endlist (cnt %u)\n", cnt);
}
void DetectPortCleanupList (DetectPort *head) {
if (head == NULL)
return;
DetectPort *cur, *next;
for (cur = head; cur != NULL; ) {
next = cur->next;
DetectPortFree(cur);
cur = next;
}
head = NULL;
}
/* do a sorted insert, where the top of the list should be the biggest
* port range.
*
* XXX current sorting only works for overlapping ranges */
int DetectPortAdd(DetectPort **head, DetectPort *dp) {
DetectPort *cur, *prev_cur = NULL;
//printf("DetectPortAdd: adding "); DetectPortPrint(ag); printf("\n");
if (*head != NULL) {
for (cur = *head; cur != NULL; cur = cur->next) {
prev_cur = cur;
int r = DetectPortCmp(dp,cur);
if (r == PORT_EB) {
/* insert here */
dp->prev = cur->prev;
dp->next = cur;
cur->prev = dp;
if (*head == cur) {
*head = dp;
} else {
dp->prev->next = dp;
}
return 0;
}
}
dp->prev = prev_cur;
prev_cur->next = dp;
} else {
*head = dp;
}
return 0;
}
int DetectPortInsertCopy(DetectPort **head, DetectPort *new) {
DetectPort *copy = DetectPortCopySingle(new);
//printf("new (%p): ", new); DetectPortPrint(new); printf(" "); DbgPrintSigs2(new->sh);
//printf("copy (%p): ",copy); DetectPortPrint(copy); printf(" "); DbgPrintSigs2(copy->sh);
if (copy != NULL) {
//printf("DetectPortInsertCopy: "); DetectPortPrint(copy); printf("\n");
}
return DetectPortInsert(head, copy);
}
//#define DBG
/* function for inserting a port group oject. This also makes sure
* SigGroupContainer lists are handled correctly.
*
* returncodes
* -1: error
* 0: not inserted, memory of new is freed
* 1: inserted
* */
int DetectPortInsert(DetectPort **head, DetectPort *new) {
if (new == NULL)
return 0;
#ifdef DBG
printf("DetectPortInsert: head %p, new %p, new->dp %p\n", head, new, new->dp);
printf("DetectPortInsert: inserting (sig %u) ", new->sh ? new->sh->sig_cnt : 0); DetectPortPrint(new); printf("\n");
//DetectPortPrintList(*head);
#endif
/* see if it already exists or overlaps with existing ag's */
if (*head != NULL) {
DetectPort *cur = NULL;
int r = 0;
for (cur = *head; cur != NULL; cur = cur->next) {
// printf("DetectPortInsert: cur %p ",cur); DetectPortPrint(cur); printf("\n");
// DetectPortPrintList(cur);
// printf("DetectPortInsert: cur end ========\n");
r = DetectPortCmp(new,cur);
if (r == PORT_ER) {
printf("PORT_ER DetectPortCmp compared:\n");
DetectPortPrint(new); printf(" vs. ");
DetectPortPrint(cur); printf("\n");
goto error;
}
/* if so, handle that */
if (r == PORT_EQ) {
#ifdef DBG
printf("DetectPortInsert: PORT_EQ %p %p\n", cur, new);
#endif
/* exact overlap/match */
if (cur != new) {
SigGroupHeadCopySigs(new->sh,&cur->sh);
cur->cnt += new->cnt;
DetectPortFree(new);
return 0;
}
return 1;
} else if (r == PORT_GT) {
#ifdef DBG
printf("DetectPortInsert: PORT_GT (cur->next %p)\n", cur->next);
#endif
/* only add it now if we are bigger than the last
* group. Otherwise we'll handle it later. */
if (cur->next == NULL) {
#ifdef DBG
printf("DetectPortInsert: adding GT\n");
#endif
/* put in the list */
new->prev = cur;
cur->next = new;
/*
printf("DetectPortInsert: cur %p ",cur); DetectPortPrint(cur); printf("\n");
DetectPortPrintList(cur);
printf("DetectPortInsert: cur end ========\n");
printf("DetectPortInsert: new %p ",new); DetectPortPrint(new); printf("\n");
DetectPortPrintList(new);
printf("DetectPortInsert: new end ========\n");
*/
return 1;
} else {
//printf("cur->next "); DetectPortPrint(cur->next); printf("\n");
}
} else if (r == PORT_LT) {
#ifdef DBG
printf("DetectPortInsert: PORT_LT\n");
#endif
/* see if we need to insert the ag anywhere */
/* put in the list */
if (cur->prev != NULL)
cur->prev->next = new;
new->prev = cur->prev;
new->next = cur;
cur->prev = new;
/* update head if required */
if (*head == cur) {
*head = new;
}
return 1;
/* alright, those were the simple cases,
* lets handle the more complex ones now */
} else if (r == PORT_ES) {
#ifdef DBG
printf("DetectPortInsert: PORT_ES\n");
#endif
DetectPort *c = NULL;
r = DetectPortCut(cur,new,&c);
DetectPortInsert(head, new);
if (c) {
#ifdef DBG
printf("DetectPortInsert: inserting C (%p) ",c); DetectPortPrint(c); printf("\n");
#endif
DetectPortInsert(head, c);
}
return 1;
} else if (r == PORT_EB) {
#ifdef DBG
printf("DetectPortInsert: PORT_EB\n");
#endif
DetectPort *c = NULL;
r = DetectPortCut(cur,new,&c);
//printf("DetectPortCut returned %d\n", r);
DetectPortInsert(head, new);
if (c) {
#ifdef DBG
printf("DetectPortInsert: inserting C "); DetectPortPrint(c); printf("\n");
#endif
DetectPortInsert(head, c);
}
return 1;
} else if (r == PORT_LE) {
#ifdef DBG
printf("DetectPortInsert: PORT_LE\n");
#endif
DetectPort *c = NULL;
r = DetectPortCut(cur,new,&c);
DetectPortInsert(head, new);
if (c) {
#ifdef DBG
printf("DetectPortInsert: inserting C "); DetectPortPrint(c); printf("\n");
#endif
DetectPortInsert(head, c);
}
return 1;
} else if (r == PORT_GE) {
#ifdef DBG
printf("DetectPortInsert: PORT_GE\n");
#endif
DetectPort *c = NULL;
r = DetectPortCut(cur,new,&c);
DetectPortInsert(head, new);
if (c) {
#ifdef DBG
printf("DetectPortInsert: inserting C "); DetectPortPrint(c); printf("\n");
#endif
DetectPortInsert(head, c);
}
return 1;
}
}
/* head is NULL, so get a group and set head to it */
} else {
#ifdef DBG
printf("DetectPortInsert: Setting new head\n");
#endif
*head = new;
}
return 1;
error:
/* XXX */
return -1;
}
int DetectPortSetup(DetectPort **head, char *s) {
DetectPort *ad = NULL;
int r = 0;
/* parse the address */
ad = PortParse(s);
if (ad == NULL) {
printf("PortParse error \"%s\"\n",s);
goto error;
}
/* handle the not case, we apply the negation
* then insert the part(s) */
if (ad->flags & PORT_FLAG_NOT) {
DetectPort *ad2 = NULL;
if (DetectPortCutNot(ad,&ad2) < 0) {
goto error;
}
/* normally a 'not' will result in two ad's
* unless the 'not' is on the start or end
* of the address space (e.g. 0.0.0.0 or
* 255.255.255.255). */
if (ad2 != NULL) {
if (DetectPortInsert(head, ad2) < 0)
goto error;
}
}
r = DetectPortInsert(head, ad);
if (r < 0)
goto error;
/* if any, insert 0.0.0.0/0 and ::/0 as well */
if (r == 1 && ad->flags & PORT_FLAG_ANY) {
ad = PortParse("0:65535");
if (ad == NULL)
goto error;
if (DetectPortInsert(head, ad) < 0)
goto error;
}
return 0;
error:
printf("DetectPortSetup error\n");
/* XXX cleanup */
return -1;
}
/* XXX error handling */
int DetectPortParse2(DetectPort **head, DetectPort **nhead, char *s,int negate) {
int i, x;
int o_set = 0, n_set = 0;
int depth = 0;
size_t size = strlen(s);
char address[1024] = "";
for (i = 0, x = 0; i < size && x < sizeof(address); i++) {
address[x] = s[i];
x++;
if (!o_set && s[i] == '!') {
n_set = 1;
x--;
} else if (s[i] == '[') {
if (!o_set) {
o_set = 1;
x = 0;
}
depth++;
} else if (s[i] == ']') {
if (depth == 1) {
address[x-1] = '\0';
x = 0;
DetectPortParse2(head,nhead,address,negate ? negate : n_set);
n_set = 0;
}
depth--;
} else if (depth == 0 && s[i] == ',') {
if (o_set == 1) {
o_set = 0;
} else {
address[x-1] = '\0';
if (negate == 0 && n_set == 0) {
DetectPortSetup(head,address);
} else {
DetectPortSetup(nhead,address);
}
n_set = 0;
}
x = 0;
} else if (depth == 0 && i == size-1) {
address[x] = '\0';
x = 0;
if (negate == 0 && n_set == 0) {
DetectPortSetup(head,address);
} else {
DetectPortSetup(nhead,address);
}
n_set = 0;
}
}
return 0;
//error:
// return -1;
}
int DetectPortMergeNot(DetectPort **head, DetectPort **nhead) {
DetectPort *ad;
DetectPort *ag, *ag2;
int r = 0;
/* step 0: if the head list is empty, but the nhead list isn't
* we have a pure not thingy. In that case we add a 0:65535
* first. */
if (*head == NULL && *nhead != NULL) {
r = DetectPortSetup(head,"0:65535");
if (r < 0) {
goto error;
}
}
/* step 1: insert our ghn members into the gh list */
for (ag = *nhead; ag != NULL; ag = ag->next) {
/* work with a copy of the ad so we can easily clean up
* the ghn group later. */
ad = DetectPortCopy(ag);
if (ad == NULL) {
goto error;
}
r = DetectPortInsert(head,ad);
if (r < 0) {
goto error;
}
}
/* step 2: pull the address blocks that match our 'not' blocks */
for (ag = *nhead; ag != NULL; ag = ag->next) {
for (ag2 = *head; ag2 != NULL; ) {
r = DetectPortCmp(ag,ag2);
if (r == PORT_EQ || r == PORT_EB) { /* XXX more ??? */
if (ag2->prev == NULL) {
*head = ag2->next;
} else {
ag2->prev->next = ag2->next;
}
if (ag2->next != NULL) {
ag2->next->prev = ag2->prev;
}
/* store the next ptr and remove the group */
DetectPort *next_ag2 = ag2->next;
DetectPortFree(ag2);
ag2 = next_ag2;
} else {
ag2 = ag2->next;
}
}
}
return 0;
error:
return -1;
}
int DetectPortParse(DetectPort **head, char *str) {
int r;
DetectPort *nhead = NULL;
r = DetectPortParse2(head,&nhead,str,/* start with negate no */0);
if (r < 0) {
goto error;
}
/* merge the 'not' address groups */
if (DetectPortMergeNot(head,&nhead) < 0) {
goto error;
}
/* free the temp negate head */
DetectPortFree(nhead);
return 0;
error:
DetectPortFree(nhead);
return -1;
}
int DetectPortCut(DetectPort *a, DetectPort *b, DetectPort **c) {
17 years ago
u_int32_t a_port1 = a->port;
u_int32_t a_port2 = a->port2;
u_int32_t b_port1 = b->port;
u_int32_t b_port2 = b->port2;
/* default to NULL */
*c = NULL;
//printf("a (%p): ",a); DetectPortPrint(a); printf(" "); DbgPrintSigs2(a->sh);
//printf("b (%p): ",b); DetectPortPrint(b); printf(" "); DbgPrintSigs2(b->sh);
int r = DetectPortCmp(a,b);
if (r != PORT_ES && r != PORT_EB && r != PORT_LE && r != PORT_GE) {
printf("DetectPortCut: we shouldn't be here\n");
goto error;
}
/* get a place to temporary put sigs lists */
DetectPort *tmp = NULL;
tmp = DetectPortInit();
if (tmp == NULL) {
goto error;
}
memset(tmp,0,sizeof(DetectPort));
/* we have 3 parts: [aaa[abab]bbb]
* part a: a_port1 <-> b_port1 - 1
* part b: b_port1 <-> a_port2
* part c: a_port2 + 1 <-> b_port2
*/
if (r == PORT_LE) {
#ifdef DBG
printf("DetectPortCut: cut r == PORT_LE\n");
#endif
a->port = a_port1;
a->port2 = b_port1 - 1;
b->port = b_port1;
b->port2 = a_port2;
DetectPort *tmp_c;
tmp_c = DetectPortInit();
if (tmp_c == NULL) {
goto error;
}
tmp_c->port = a_port2 + 1;
tmp_c->port2 = b_port2;
*c = tmp_c;
SigGroupHeadCopySigs(b->sh,&tmp_c->sh); /* copy old b to c */
SigGroupHeadCopySigs(a->sh,&b->sh); /* copy old b to a */
tmp_c->cnt += b->cnt;
b->cnt += a->cnt;
/* we have 3 parts: [bbb[baba]aaa]
* part a: b_port1 <-> a_port1 - 1
* part b: a_port1 <-> b_port2
* part c: b_port2 + 1 <-> a_port2
*/
} else if (r == PORT_GE) {
#ifdef DBG
printf("DetectPortCut: cut r == PORT_GE\n");
#endif
a->port = b_port1;
a->port2 = a_port1 - 1;
b->port = a_port1;
b->port2 = b_port2;
DetectPort *tmp_c;
tmp_c = DetectPortInit();
if (tmp_c == NULL) {
goto error;
}
tmp_c->port = b_port2 + 1;
tmp_c->port2 = a_port2;
*c = tmp_c;
/* 'a' gets clean and then 'b' sigs
* 'b' gets clean, then 'a' then 'b' sigs
* 'c' gets 'a' sigs */
SigGroupHeadCopySigs(a->sh,&tmp->sh); /* store old a list */
SigGroupHeadClearSigs(a->sh); /* clean a list */
SigGroupHeadCopySigs(tmp->sh,&tmp_c->sh); /* copy old b to c */
SigGroupHeadCopySigs(b->sh,&a->sh); /* copy old b to a */
SigGroupHeadCopySigs(tmp->sh,&b->sh); /* prepend old a before b */
SigGroupHeadClearSigs(tmp->sh); /* clean tmp list */
tmp->cnt += a->cnt;
a->cnt = 0;
tmp_c->cnt += tmp->cnt;
a->cnt += b->cnt;
b->cnt += tmp->cnt;
tmp->cnt = 0;
/* we have 2 or three parts:
*
* 2 part: [[abab]bbb] or [bbb[baba]]
* part a: a_port1 <-> a_port2
* part b: a_port2 + 1 <-> b_port2
*
* part a: b_port1 <-> a_port1 - 1
* part b: a_port1 <-> a_port2
*
* 3 part [bbb[aaa]bbb]
* becomes[aaa[bbb]ccc]
*
* part a: b_port1 <-> a_port1 - 1
* part b: a_port1 <-> a_port2
* part c: a_port2 + 1 <-> b_port2
*/
} else if (r == PORT_ES) {
#ifdef DBG
printf("DetectPortCut: cut r == PORT_ES\n");
#endif
if (a_port1 == b_port1) {
#ifdef DBG
printf("DetectPortCut: 1\n");
#endif
a->port = a_port1;
a->port2 = a_port2;
b->port = a_port2 + 1;
b->port2 = b_port2;
/* 'b' overlaps 'a' so 'a' needs the 'b' sigs */
SigGroupHeadCopySigs(b->sh,&a->sh);
a->cnt += b->cnt;
} else if (a_port2 == b_port2) {
#ifdef DBG
printf("DetectPortCut: 2\n");
#endif
a->port = b_port1;
a->port2 = a_port1 - 1;
b->port = a_port1;
b->port2 = a_port2;
/* 'a' overlaps 'b' so a needs the 'a' sigs */
SigGroupHeadCopySigs(a->sh,&b->sh);
b->cnt += a->cnt;
} else {
#ifdef DBG
printf("DetectPortCut: 3\n");
#endif
a->port = b_port1;
a->port2 = a_port1 - 1;
b->port = a_port1;
b->port2 = a_port2;
DetectPort *tmp_c;
tmp_c = DetectPortInit();
if (tmp_c == NULL) {
goto error;
}
tmp_c->port = a_port2 + 1;
tmp_c->port2 = b_port2;
*c = tmp_c;
/* 'a' gets clean and then 'b' sigs
* 'b' gets clean, then 'a' then 'b' sigs
* 'c' gets 'b' sigs */
SigGroupHeadCopySigs(a->sh,&tmp->sh); /* store old a list */
SigGroupHeadClearSigs(a->sh); /* clean a list */
SigGroupHeadCopySigs(b->sh,&tmp_c->sh); /* copy old b to c */
SigGroupHeadCopySigs(b->sh,&a->sh); /* copy old b to a */
SigGroupHeadCopySigs(tmp->sh,&b->sh); /* prepend old a before b */
SigGroupHeadClearSigs(tmp->sh); /* clean tmp list */
tmp->cnt += a->cnt;
a->cnt = 0;
tmp_c->cnt += b->cnt;
a->cnt += b->cnt;
b->cnt += tmp->cnt;
tmp->cnt = 0;
}
/* we have 2 or three parts:
*
* 2 part: [[baba]aaa] or [aaa[abab]]
* part a: b_port1 <-> b_port2
* part b: b_port2 + 1 <-> a_port2
*
* part a: a_port1 <-> b_port1 - 1
* part b: b_port1 <-> b_port2
*
* 3 part [aaa[bbb]aaa]
* becomes[aaa[bbb]ccc]
*
* part a: a_port1 <-> b_port2 - 1
* part b: b_port1 <-> b_port2
* part c: b_port2 + 1 <-> a_port2
*/
} else if (r == PORT_EB) {
#ifdef DBG
printf("DetectPortCut: cut r == PORT_EB\n");
#endif
if (a_port1 == b_port1) {
#ifdef DBG
printf("DetectPortCut: 1\n");
#endif
a->port = b_port1;
a->port2 = b_port2;
b->port = b_port2 + 1;
b->port2 = a_port2;
/* 'b' overlaps 'a' so a needs the 'b' sigs */
SigGroupHeadCopySigs(b->sh,&tmp->sh);
SigGroupHeadClearSigs(b->sh);
SigGroupHeadCopySigs(a->sh,&b->sh);
SigGroupHeadCopySigs(tmp->sh,&a->sh);
SigGroupHeadClearSigs(tmp->sh);
tmp->cnt += b->cnt;
b->cnt = 0;
b->cnt += a->cnt;
a->cnt += tmp->cnt;
tmp->cnt = 0;
//printf("2a (%p): ",a); DetectPortPrint(a); printf(" "); DbgPrintSigs2(a->sh);
//printf("2b (%p): ",b); DetectPortPrint(b); printf(" "); DbgPrintSigs2(b->sh);
} else if (a_port2 == b_port2) {
#ifdef DBG
printf("DetectPortCut: 2\n");
#endif
a->port = a_port1;
a->port2 = b_port1 - 1;
b->port = b_port1;
b->port2 = b_port2;
/* 'a' overlaps 'b' so a needs the 'a' sigs */
SigGroupHeadCopySigs(a->sh,&b->sh);
b->cnt += a->cnt;
} else {
#ifdef DBG
printf("DetectPortCut: 3\n");
#endif
a->port = a_port1;
a->port2 = b_port1 - 1;
b->port = b_port1;
b->port2 = b_port2;
DetectPort *tmp_c;
tmp_c = DetectPortInit();
if (tmp_c == NULL) {
goto error;
}
tmp_c->port = b_port2 + 1;
tmp_c->port2 = a_port2;
*c = tmp_c;
SigGroupHeadCopySigs(a->sh,&b->sh);
SigGroupHeadCopySigs(a->sh,&tmp_c->sh);
b->cnt += a->cnt;
tmp_c->cnt += a->cnt;
}
}
/* XXX free tmp */
DetectPortFree(tmp);
return 0;
error:
/* XXX free tmp */
DetectPortFree(tmp);
return -1;
return -1;
}
int DetectPortCutNot(DetectPort *a, DetectPort **b) {
u_int16_t a_port1 = a->port;
u_int16_t a_port2 = a->port2;
/* default to NULL */
*b = NULL;
if (a_port1 != 0x0000 && a_port2 != 0xFFFF) {
a->port = 0x0000;
a->port2 = a_port1 - 1;
DetectPort *tmp_b;
tmp_b = DetectPortInit();
if (tmp_b == NULL) {
goto error;
}
tmp_b->port = a_port2 + 1;
tmp_b->port2 = 0xFFFF;
*b = tmp_b;
} else if (a_port1 == 0x0000 && a_port2 != 0xFFFF) {
a->port = a_port2 + 1;
a->port2 = 0xFFFF;
} else if (a_port1 != 0x0000 && a_port2 == 0xFFFF) {
a->port = 0x0000;
a->port2 = a_port1 - 1;
} else {
goto error;
}
return 0;
error:
return -1;
return -1;
}
int DetectPortCmp(DetectPort *a, DetectPort *b) {
/* check any */
if (a->flags & PORT_FLAG_ANY && b->flags & PORT_FLAG_ANY)
return PORT_EQ;
if (a->flags & PORT_FLAG_ANY && !(b->flags & PORT_FLAG_ANY))
return PORT_LT;
if (!(a->flags & PORT_FLAG_ANY) && b->flags & PORT_FLAG_ANY)
return PORT_GT;
17 years ago
u_int16_t a_port1 = a->port;
u_int16_t a_port2 = a->port2;
u_int16_t b_port1 = b->port;
u_int16_t b_port2 = b->port2;
/* PORT_EQ */
if (a_port1 == b_port1 && a_port2 == b_port2) {
//printf("PORT_EQ\n");
return PORT_EQ;
/* PORT_ES */
} else if (a_port1 >= b_port1 && a_port1 <= b_port2 && a_port2 <= b_port2) {
//printf("PORT_ES\n");
return PORT_ES;
/* PORT_EB */
} else if (a_port1 <= b_port1 && a_port2 >= b_port2) {
//printf("PORT_EB\n");
return PORT_EB;
} else if (a_port1 < b_port1 && a_port2 < b_port2 && a_port2 >= b_port1) {
//printf("PORT_LE\n");
return PORT_LE;
} else if (a_port1 < b_port1 && a_port2 < b_port2) {
//printf("PORT_LT\n");
return PORT_LT;
} else if (a_port1 > b_port1 && a_port1 <= b_port2 && a_port2 > b_port2) {
//printf("PORT_GE\n");
return PORT_GE;
} else if (a_port1 > b_port2) {
//printf("PORT_GT\n");
return PORT_GT;
} else {
/* should be unreachable */
printf("Internal Error: should be unreachable\n");
}
return PORT_ER;
}
DetectPort *PortParse(char *str) {
char *portdup = strdup(str);
char *port2 = NULL;
DetectPort *dp = DetectPortInit();
if (dp == NULL)
goto error;
/* we dup so we can put a nul-termination in it later */
char *port = portdup;
/* handle the negation case */
if (port[0] == '!') {
dp->flags |= PORT_FLAG_NOT;
port++;
}
/* see if the address is an ipv4 or ipv6 address */
if ((port2 = strchr(port, ':')) != NULL) {
/* 1.2.3.4-1.2.3.6 range format */
port[port2 - port] = '\0';
port2++;
dp->port = atoi(port);
if (strcmp(port2,"") != 0)
dp->port2 = atoi(port2);
else
dp->port2 = 65535;
/* a>b is illegal, a=b is ok */
if (dp->port > dp->port2)
goto error;
} else {
if (strcasecmp(port,"any") == 0) {
dp->port = 0;
dp->port2 = 65535;
} else {
dp->port = dp->port2 = atoi(port);
}
}
free(portdup);
return dp;
error:
if (portdup) free(portdup);
return NULL;
}
DetectPort *DetectPortCopy(DetectPort *src) {
if (src == NULL)
return NULL;
DetectPort *dst = DetectPortInit();
if (dst == NULL) {
goto error;
}
memcpy(dst,src,sizeof(DetectPort));
dst->sh = NULL;
if (src->next != NULL)
dst->next = DetectPortCopy(src->next);
return dst;
error:
return NULL;
}
DetectPort *DetectPortCopySingle(DetectPort *src) {
if (src == NULL)
return NULL;
DetectPort *dst = DetectPortInit();
if (dst == NULL) {
goto error;
}
memcpy(dst,src,sizeof(DetectPort));
dst->sh = NULL;
dst->next = NULL;
dst->prev = NULL;
SigGroupHeadCopySigs(src->sh,&dst->sh);
return dst;
error:
return NULL;
}
int DetectPortSetupTmp (Signature *s, SigMatch *m, char *addressstr)
{
return 0;
}
int DetectPortMatch (DetectPort *dp, u_int16_t port) {
17 years ago
if (port >= dp->port &&
port <= dp->port2) {
return 1;
}
return 0;
}
void DetectPortPrint(DetectPort *dp) {
if (dp == NULL)
return;
if (dp->flags & PORT_FLAG_ANY) {
printf("ANY");
} else {
printf("%u-%u", dp->port, dp->port2);
}
}
/* find the group matching address in a group head */
DetectPort *
DetectPortLookupGroup(DetectPort *dp, u_int16_t port) {
DetectPort *p = dp;
if (dp == NULL)
return NULL;
for ( ; p != NULL; p = p->next) {
if (DetectPortMatch(p,port) == 1) {
//printf("DetectPortLookupGroup: match, port %u, dp ", port);
//DetectPortPrint(p); printf("\n");
return p;
}
}
return NULL;
}
/* XXX eeewww global! move to DetectionEngineCtx once we have that! */
static DetectPort **port_hash;
static DetectPort *port_list;
#define PORT_HASH_SIZE 1024
/* XXX dynamic size based on number of sigs? */
int DetectPortHashInit(void) {
port_hash = (DetectPort **)malloc(sizeof(DetectPort *) * PORT_HASH_SIZE);
if (port_hash == NULL) {
goto error;
}
memset(port_hash,0,sizeof(DetectPort *) * PORT_HASH_SIZE);
port_list = NULL;
return 0;
error:
return -1;
}
void DetectPortHashFree(void) {
free(port_hash);
port_hash = NULL;
}
void DetectPortHashReset(void) {
if (port_hash != NULL) {
memset(port_hash,0,sizeof(DetectPort *) * PORT_HASH_SIZE);
}
port_list = NULL;
}
DetectPort **DetectPortHashGetPtr(void) {
return port_hash;
}
DetectPort *DetectPortHashGetListPtr(void) {
return port_list;
}
u_int32_t DetectPortHashGetSize(void) {
return PORT_HASH_SIZE;
}
static inline u_int32_t DetectPortHash(DetectPort *p) {
u_int32_t hash = p->port * p->port2;
return (hash % PORT_HASH_SIZE);
}
int DetectPortHashAdd(DetectPort *p) {
u_int32_t hash = DetectPortHash(p);
//printf("DetectPortHashAdd: hash %u\n", hash);
detect_port_hash_add_cnt++;
/* list */
p->next = port_list;
port_list = p;
/* easy: no collision */
if (port_hash[hash] == NULL) {
port_hash[hash] = p;
return 0;
}
detect_port_hash_add_coll_cnt++;
/* harder: collision */
DetectPort *h = port_hash[hash], *ph = NULL;
for ( ; h != NULL; h = h->hnext) {
#if 0
if (DetectPortCmp(p,h) == PORT_EB) {
if (h == port_hash[hash]) {
p->hnext = h;
port_hash[hash] = p;
} else {
p->hnext = ph->hnext;
ph->hnext = p;
}
detect_port_hash_add_insert_cnt++;
return 0;
}
#endif
ph = h;
}
ph->hnext = p;
return 0;
}
static inline int DetectPortHashCmp(DetectPort *a,DetectPort *b) {
if (a->port2 == b->port2 && a->port == b->port && a->flags == b->flags)
return 1;
return 0;
}
DetectPort *DetectPortHashLookup(DetectPort *p) {
u_int32_t hash = DetectPortHash(p);
//printf("DetectPortHashLookup: hash %u\n", hash);
detect_port_hash_lookup_cnt++;
/* easy: no sgh at our hash */
if (port_hash[hash] == NULL) {
detect_port_hash_lookup_miss_cnt++;
//printf("DetectPortHashLookup: not found\n");
return NULL;
}
/* see if we have the sgh we're looking for */
DetectPort *h = port_hash[hash];
for ( ; h != NULL; h = h->hnext) {
detect_port_hash_lookup_loop_cnt++;
if (DetectPortHashCmp(p,h) == 1) {
//printf("DetectPortHashLookup: found at %p\n", h);
detect_port_hash_lookup_hit_cnt++;
return h;
}
}
//printf("DetectPortHashLookup: not found\n");
return NULL;
}
/* XXX eeewww global! move to DetectionEngineCtx once we have that! */
static DetectPort **sport_hash;
static DetectPort *sport_list;
#define SPORT_HASH_SIZE 1024
/* XXX dynamic size based on number of sigs? */
int DetectPortSpHashInit(void) {
sport_hash = (DetectPort **)malloc(sizeof(DetectPort *) * SPORT_HASH_SIZE);
if (sport_hash == NULL) {
goto error;
}
memset(sport_hash,0,sizeof(DetectPort *) * SPORT_HASH_SIZE);
sport_list = NULL;
//printf("DetectSPortHashInit: sport_hash %p\n", sport_hash);
return 0;
error:
printf("DetectSPortHashInit: error sport_hash %p\n", sport_hash);
return -1;
}
void DetectPortSpHashFree(void) {
free(sport_hash);
sport_hash = NULL;
}
void DetectPortSpHashReset(void) {
if (sport_hash != NULL) {
memset(sport_hash,0,sizeof(DetectPort *) * SPORT_HASH_SIZE);
}
sport_list = NULL;
}
DetectPort **DetectPortSpHashGetPtr(void) {
return sport_hash;
}
DetectPort *DetectPortSpHashGetListPtr(void) {
return sport_list;
}
u_int32_t DetectPortSpHashGetSize(void) {
return SPORT_HASH_SIZE;
}
static inline u_int32_t DetectPortSpHash(DetectPort *p) {
u_int32_t hash = p->port * p->port2;
return (hash % SPORT_HASH_SIZE);
}
int DetectPortSpHashAdd(DetectPort *p) {
u_int32_t hash = DetectPortSpHash(p);
//printf("DetectSPortHashAdd: hash %u\n", hash);
detect_port_hash_add_cnt++;
/* list */
p->next = sport_list;
sport_list = p;
/* easy: no collision */
if (sport_hash[hash] == NULL) {
sport_hash[hash] = p;
return 0;
}
detect_port_hash_add_coll_cnt++;
/* harder: collision */
DetectPort *h = sport_hash[hash], *ph = NULL;
for ( ; h != NULL; h = h->hnext) {
#if 0
if (DetectPortCmp(p,h) == PORT_EB) {
if (h == port_hash[hash]) {
p->hnext = h;
port_hash[hash] = p;
} else {
p->hnext = ph->hnext;
ph->hnext = p;
}
detect_port_hash_add_insert_cnt++;
return 0;
}
#endif
ph = h;
}
ph->hnext = p;
return 0;
}
DetectPort *DetectPortSpHashLookup(DetectPort *p) {
u_int32_t hash = DetectPortSpHash(p);
//printf("DetectSPortHashLookup: hash %u, sport_hash %p, size %u port %p\n", hash, sport_hash, SPORT_HASH_SIZE, p);
detect_port_hash_lookup_cnt++;
/* easy: no sgh at our hash */
if (sport_hash[hash] == NULL) {
detect_port_hash_lookup_miss_cnt++;
//printf("DetectSPortHashLookup: not found\n");
return NULL;
}
/* see if we have the sgh we're looking for */
DetectPort *h = sport_hash[hash];
for ( ; h != NULL; h = h->hnext) {
detect_port_hash_lookup_loop_cnt++;
if (DetectPortHashCmp(p,h) == 1) {
//printf("DetectSPortHashLookup: found at %p\n", h);
detect_port_hash_lookup_hit_cnt++;
return h;
}
}
//printf("DetectSPortHashLookup: not found\n");
return NULL;
}
int DetectPortJoin(DetectPort *target, DetectPort *source) {
if (target == NULL || source == NULL)
return -1;
target->cnt += source->cnt;
SigGroupHeadCopySigs(source->sh,&target->sh);
//DetectPort *port = source->port;
//for ( ; port != NULL; port = port->next) {
// DetectPortInsertCopy(&target->port, port);
//}
if (source->port < target->port)
target->port = source->port;
if (source->port2 > target->port2)
target->port2 = source->port2;
return -1;
}
/* TESTS */
int PortTestParse01 (void) {
DetectPort *dd = NULL;
int r = DetectPortParse(&dd,"80");
if (r == 0) {
DetectPortFree(dd);
return 1;
}
return 0;
}
int PortTestParse02 (void) {
DetectPort *dd = NULL;
int result = 0;
int r = DetectPortParse(&dd,"80");
if (r == 0) {
r = DetectPortParse(&dd,"22");
if (r == 0) {
result = 1;
}
DetectPortCleanupList(dd);
return result;
}
return result;
}
int PortTestParse03 (void) {
DetectPort *dd = NULL;
int result = 0;
int r = DetectPortParse(&dd,"80:88");
if (r == 0) {
r = DetectPortParse(&dd,"85:100");
if (r == 0) {
result = 1;
}
DetectPortCleanupList(dd);
return result;
}
return result;
}
int PortTestParse04 (void) {
DetectPort *dd = NULL;
int r = DetectPortParse(&dd,"!80:81");
if (r == 0) {
DetectPortCleanupList(dd);
return 1;
}
return 0;
}
int PortTestParse05 (void) {
DetectPort *dd = NULL;
int result = 0;
int r = DetectPortParse(&dd,"!80:81");
if (r != 0)
goto end;
if (dd->next == NULL)
goto end;
if (dd->port != 0 || dd->port2 != 79)
goto end;
if (dd->next->port != 82 || dd->next->port2 != 65535)
goto end;
DetectPortCleanupList(dd);
result = 1;
end:
return result;
}
int PortTestParse06 (void) {
DetectPort *dd = NULL, *copy = NULL;
int result = 0;
int r = DetectPortParse(&dd,"22");
if (r != 0)
goto end;
r = DetectPortParse(&dd,"80");
if (r != 0)
goto end;
r = DetectPortParse(&dd,"143");
if (r != 0)
goto end;
copy = DetectPortCopy(dd);
if (copy == NULL)
goto end;
if (DetectPortCmp(dd,copy) != PORT_EQ)
goto end;
if (copy->next == NULL)
goto end;
if (DetectPortCmp(dd->next,copy->next) != PORT_EQ)
goto end;
if (copy->next->next == NULL)
goto end;
if (DetectPortCmp(dd->next->next,copy->next->next) != PORT_EQ)
goto end;
if (copy->port != 22 || copy->next->port != 80 || copy->next->next->port != 143)
goto end;
result = 1;
end:
DetectPortCleanupList(dd);
return result;
}
void DetectPortTests(void) {
UtRegisterTest("PortTestParse01", PortTestParse01, 1);
UtRegisterTest("PortTestParse02", PortTestParse02, 1);
UtRegisterTest("PortTestParse03", PortTestParse03, 1);
UtRegisterTest("PortTestParse04", PortTestParse04, 1);
UtRegisterTest("PortTestParse05", PortTestParse05, 1);
UtRegisterTest("PortTestParse06", PortTestParse06, 1);
}