suricata
util-var-name.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2016 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  *
23  * Generic variable name utility functions
24  */
25 
26 #include "suricata-common.h"
27 #include "detect.h"
28 #include "util-hashlist.h"
29 #include "util-var-name.h"
30 
31 /* the way this can be used w/o locking lookups:
32  * - Lookups use only g_varnamestore_current which is read only
33  * - Detection setups a new ctx in staging, which will include the 'current'
34  * entries keeping ID's stable
35  * - Detection hot swaps staging into current after a new detect engine was
36  * created. Current remains available through 'old'.
37  * - When detect reload is complete (threads are all moved over), 'old' can
38  * be freed.
39  */
40 
41 typedef struct VarNameStore_ {
44  uint32_t max_id;
45  uint32_t de_ctx_version; /**< de_ctx version 'owning' this */
46 } VarNameStore;
47 
48 static int initialized = 0;
49 /* currently VarNameStore that is READ ONLY. This way lookups can
50  * be done w/o locking or synchronization */
51 SC_ATOMIC_DECLARE(VarNameStore *, g_varnamestore_current);
52 
53 /* old VarNameStore on the way out */
54 static VarNameStore *g_varnamestore_old = NULL;
55 
56 /* new VarNameStore that is being prepared. Multiple DetectLoader threads
57  * may be updating it so a lock is used for synchronization. */
58 static VarNameStore *g_varnamestore_staging = NULL;
59 static SCMutex g_varnamestore_staging_m = SCMUTEX_INITIALIZER;
60 
61 /** \brief Name2idx mapping structure for flowbits, flowvars and pktvars. */
62 typedef struct VariableName_ {
63  char *name;
64  uint8_t type; /* flowbit, pktvar, etc */
65  uint32_t idx;
66 } VariableName;
67 
68 #define VARNAME_HASHSIZE 0x1000
69 #define VARID_HASHSIZE 0x1000
70 
71 static uint32_t VariableNameHash(HashListTable *ht, void *buf, uint16_t buflen)
72 {
73  VariableName *fn = (VariableName *)buf;
74  uint32_t hash = strlen(fn->name) + fn->type;
75  uint16_t u;
76 
77  for (u = 0; u < buflen; u++) {
78  hash += fn->name[u];
79  }
80 
81  return (hash % VARNAME_HASHSIZE);
82 }
83 
84 static char VariableNameCompare(void *buf1, uint16_t len1, void *buf2, uint16_t len2)
85 {
86  VariableName *fn1 = (VariableName *)buf1;
87  VariableName *fn2 = (VariableName *)buf2;
88 
89  if (fn1->type != fn2->type)
90  return 0;
91 
92  if (strcmp(fn1->name,fn2->name) == 0)
93  return 1;
94 
95  return 0;
96 }
97 
98 static uint32_t VariableIdxHash(HashListTable *ht, void *buf, uint16_t buflen)
99 {
100  VariableName *fn = (VariableName *)buf;
101  uint32_t hash = fn->idx + fn->type;
102  return (hash % VARID_HASHSIZE);
103 }
104 
105 static char VariableIdxCompare(void *buf1, uint16_t len1, void *buf2, uint16_t len2)
106 {
107  VariableName *fn1 = (VariableName *)buf1;
108  VariableName *fn2 = (VariableName *)buf2;
109 
110  if (fn1->type != fn2->type)
111  return 0;
112 
113  if (fn1->idx == fn2->idx)
114  return 1;
115 
116  return 0;
117 }
118 
119 static void VariableNameFree(void *data)
120 {
121  VariableName *fn = (VariableName *)data;
122 
123  if (fn == NULL)
124  return;
125 
126  if (fn->name != NULL) {
127  SCFree(fn->name);
128  fn->name = NULL;
129  }
130 
131  SCFree(fn);
132 }
133 
134 /** \brief Initialize the Name idx hash.
135  */
136 static VarNameStore *VarNameStoreInit(void)
137 {
138  VarNameStore *v = SCCalloc(1, sizeof(*v));
139  if (v == NULL)
140  return NULL;
141 
142  v->names = HashListTableInit(VARNAME_HASHSIZE, VariableNameHash, VariableNameCompare, VariableNameFree);
143  if (v->names == NULL) {
144  SCFree(v);
145  return NULL;
146  }
147 
148  v->ids = HashListTableInit(VARID_HASHSIZE, VariableIdxHash, VariableIdxCompare, NULL);
149  if (v->ids == NULL) {
151  SCFree(v);
152  return NULL;
153  }
154 
155  v->max_id = 0;
156  return v;
157 }
158 
159 static void VarNameStoreDoFree(VarNameStore *v)
160 {
161  if (v) {
164  SCFree(v);
165  }
166 }
167 
168 
169 /** \brief Get a name idx for a name. If the name is already used reuse the idx.
170  * \param name nul terminated string with the name
171  * \param type variable type
172  * \retval 0 in case of error
173  * \retval idx the idx or 0
174  */
175 static uint32_t VariableNameGetIdx(VarNameStore *v, const char *name, enum VarTypes type)
176 {
177  uint32_t idx = 0;
178 
179  VariableName *fn = SCMalloc(sizeof(VariableName));
180  if (unlikely(fn == NULL))
181  goto error;
182 
183  memset(fn, 0, sizeof(VariableName));
184 
185  fn->type = type;
186  fn->name = SCStrdup(name);
187  if (fn->name == NULL)
188  goto error;
189 
190  VariableName *lookup_fn = (VariableName *)HashListTableLookup(v->names, (void *)fn, 0);
191  if (lookup_fn == NULL) {
192  v->max_id++;
193 
194  idx = fn->idx = v->max_id;
195  HashListTableAdd(v->names, (void *)fn, 0);
196  HashListTableAdd(v->ids, (void *)fn, 0);
197  SCLogDebug("new registration %s id %u type %u", fn->name, fn->idx, fn->type);
198  } else {
199  idx = lookup_fn->idx;
200  VariableNameFree(fn);
201  }
202 
203  return idx;
204 error:
205  VariableNameFree(fn);
206  return 0;
207 }
208 
209 /** \brief Get a name from the idx.
210  * \param idx index of the variable whose name is to be fetched
211  * \param type variable type
212  * \retval NULL in case of error
213  * \retval name of the variable if successful.
214  * \todo no alloc on lookup
215  */
216 static char *VariableIdxGetName(VarNameStore *v, uint32_t idx, enum VarTypes type)
217 {
218  VariableName *fn = SCMalloc(sizeof(VariableName));
219  if (unlikely(fn == NULL))
220  goto error;
221 
222  char *name = NULL;
223  memset(fn, 0, sizeof(VariableName));
224 
225  fn->type = type;
226  fn->idx = idx;
227 
228  VariableName *lookup_fn = (VariableName *)HashListTableLookup(v->ids, (void *)fn, 0);
229  if (lookup_fn != NULL) {
230  name = SCStrdup(lookup_fn->name);
231  if (unlikely(name == NULL))
232  goto error;
233 
234  VariableNameFree(fn);
235  } else {
236  goto error;
237  }
238 
239  return name;
240 error:
241  VariableNameFree(fn);
242  return NULL;
243 }
244 
245 /** \brief setup staging store. Include current store if there is one.
246  */
248 {
249  SCMutexLock(&g_varnamestore_staging_m);
250 
251  if (!initialized) {
252  SC_ATOMIC_INIT(g_varnamestore_current);
253  initialized = 1;
254  }
255 
256  if (g_varnamestore_staging != NULL &&
257  g_varnamestore_staging->de_ctx_version == de_ctx_version) {
258  SCMutexUnlock(&g_varnamestore_staging_m);
259  return 0;
260  }
261 
262  VarNameStore *nv = VarNameStoreInit();
263  if (nv == NULL) {
264  SCMutexUnlock(&g_varnamestore_staging_m);
265  return -1;
266  }
267  g_varnamestore_staging = nv;
269 
270  VarNameStore *current = SC_ATOMIC_GET(g_varnamestore_current);
271  if (current) {
272  /* add all entries from the current hash into this new one. */
274  while (b) {
276 
277  VariableName *newvar = SCCalloc(1, sizeof(*newvar));
278  BUG_ON(newvar == NULL);
279  memcpy(newvar, var, sizeof(*newvar));
280  newvar->name = SCStrdup(var->name);
281  BUG_ON(newvar->name == NULL);
282 
283  HashListTableAdd(nv->names, (void *)newvar, 0);
284  HashListTableAdd(nv->ids, (void *)newvar, 0);
285  nv->max_id = MAX(nv->max_id, newvar->idx);
286  SCLogDebug("xfer %s id %u type %u", newvar->name, newvar->idx, newvar->type);
287 
289  }
290  }
291 
292  SCLogDebug("set up staging with detect engine ver %u", nv->de_ctx_version);
293  SCMutexUnlock(&g_varnamestore_staging_m);
294  return 0;
295 }
296 
297 const char *VarNameStoreLookupById(const uint32_t id, const enum VarTypes type)
298 {
299  VarNameStore *current = SC_ATOMIC_GET(g_varnamestore_current);
300  BUG_ON(current == NULL);
301  VariableName lookup = { NULL, type, id };
302  VariableName *found = (VariableName *)HashListTableLookup(current->ids, (void *)&lookup, 0);
303  if (found == NULL) {
304  return NULL;
305  }
306  return found->name;
307 }
308 
309 uint32_t VarNameStoreLookupByName(const char *name, const enum VarTypes type)
310 {
311  VarNameStore *current = SC_ATOMIC_GET(g_varnamestore_current);
312  BUG_ON(current == NULL);
313  VariableName lookup = { (char *)name, type, 0 };
314  VariableName *found = (VariableName *)HashListTableLookup(current->names, (void *)&lookup, 0);
315  if (found == NULL) {
316  return 0;
317  }
318  SCLogDebug("found %u for %s type %u", found->idx, name, type);
319  return found->idx;
320 }
321 
322 /** \brief add to staging or return existing id if already in there */
323 uint32_t VarNameStoreSetupAdd(const char *name, const enum VarTypes type)
324 {
325  uint32_t id;
326  SCMutexLock(&g_varnamestore_staging_m);
327  id = VariableNameGetIdx(g_varnamestore_staging, name, type);
328  SCMutexUnlock(&g_varnamestore_staging_m);
329  return id;
330 }
331 
332 char *VarNameStoreSetupLookup(uint32_t idx, const enum VarTypes type)
333 {
334  SCMutexLock(&g_varnamestore_staging_m);
335  char *name = VariableIdxGetName(g_varnamestore_staging, idx, type);
336  SCMutexUnlock(&g_varnamestore_staging_m);
337  return name;
338 }
339 
341 {
342  SCMutexLock(&g_varnamestore_staging_m);
343  if (g_varnamestore_old) {
344  VarNameStoreDoFree(g_varnamestore_old);
345  g_varnamestore_old = NULL;
346  }
347  g_varnamestore_old = SC_ATOMIC_GET(g_varnamestore_current);
348  SC_ATOMIC_SET(g_varnamestore_current, g_varnamestore_staging);
349  g_varnamestore_staging = NULL;
350  SCMutexUnlock(&g_varnamestore_staging_m);
351 }
352 
354 {
355  SCMutexLock(&g_varnamestore_staging_m);
356  SCLogDebug("freeing g_varnamestore_old %p", g_varnamestore_old);
357  if (g_varnamestore_old) {
358  VarNameStoreDoFree(g_varnamestore_old);
359  g_varnamestore_old = NULL;
360  }
361  SCMutexUnlock(&g_varnamestore_staging_m);
362 }
363 
365 {
366  SCLogDebug("freeing detect engine version %u", de_ctx_version);
367  SCMutexLock(&g_varnamestore_staging_m);
368  if (g_varnamestore_old && g_varnamestore_old->de_ctx_version == de_ctx_version) {
369  VarNameStoreDoFree(g_varnamestore_old);
370  g_varnamestore_old = NULL;
371  SCLogDebug("freeing detect engine version %u: old done", de_ctx_version);
372  }
373 
374  /* if at this point we have a staging area which matches our version
375  * we didn't complete the setup and are cleaning up the mess. */
376  if (g_varnamestore_staging && g_varnamestore_staging->de_ctx_version == de_ctx_version) {
377  VarNameStoreDoFree(g_varnamestore_staging);
378  g_varnamestore_staging = NULL;
379  SCLogDebug("freeing detect engine version %u: staging done", de_ctx_version);
380  }
381 
382  VarNameStore *current = SC_ATOMIC_GET(g_varnamestore_current);
383  if (current && current->de_ctx_version == de_ctx_version) {
384  VarNameStoreDoFree(current);
385  SC_ATOMIC_SET(g_varnamestore_current, NULL);
386  SCLogDebug("freeing detect engine version %u: current done", de_ctx_version);
387  }
388  SCMutexUnlock(&g_varnamestore_staging_m);
389 }
VarTypes
Definition: util-var.h:27
#define SCMutex
#define SCLogDebug(...)
Definition: util-debug.h:335
#define MAX(x, y)
HashListTableBucket * HashListTableGetListHead(HashListTable *ht)
#define BUG_ON(x)
#define unlikely(expr)
Definition: util-optimize.h:35
#define HashListTableGetListData(hb)
Definition: util-hashlist.h:59
char * VarNameStoreSetupLookup(uint32_t idx, const enum VarTypes type)
void * HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
#define SCMutexLock(mut)
HashListTable * names
Definition: util-var-name.c:42
void VarNameStoreActivateStaging(void)
uint32_t VarNameStoreLookupByName(const char *name, const enum VarTypes type)
int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen)
struct VariableName_ VariableName
Name2idx mapping structure for flowbits, flowvars and pktvars.
#define SC_ATOMIC_INIT(name)
Initialize the previously declared atomic variable and it&#39;s lock.
Definition: util-atomic.h:81
#define SCCalloc(nm, a)
Definition: util-mem.h:253
int VarNameStoreSetupStaging(uint32_t de_ctx_version)
setup staging store. Include current store if there is one.
#define SCMutexUnlock(mut)
#define HashListTableGetListNext(hb)
Definition: util-hashlist.h:58
#define SCMUTEX_INITIALIZER
void VarNameStoreFree(uint32_t de_ctx_version)
uint8_t type
void VarNameStoreFreeOld(void)
HashListTable * HashListTableInit(uint32_t size, uint32_t(*Hash)(struct HashListTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
Definition: util-hashlist.c:35
struct VarNameStore_ VarNameStore
SC_ATOMIC_DECLARE(VarNameStore *, g_varnamestore_current)
#define SCMalloc(a)
Definition: util-mem.h:222
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
Definition: util-atomic.h:207
#define SCFree(a)
Definition: util-mem.h:322
const char * VarNameStoreLookupById(const uint32_t id, const enum VarTypes type)
Name2idx mapping structure for flowbits, flowvars and pktvars.
Definition: util-var-name.c:62
uint32_t VarNameStoreSetupAdd(const char *name, const enum VarTypes type)
add to staging or return existing id if already in there
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:192
HashListTable * ids
Definition: util-var-name.c:43
#define SCStrdup(a)
Definition: util-mem.h:268
void HashListTableFree(HashListTable *ht)
Definition: util-hashlist.c:82
#define VARNAME_HASHSIZE
Definition: util-var-name.c:68
uint32_t max_id
Definition: util-var-name.c:44
uint32_t de_ctx_version
Definition: util-var-name.c:45
uint32_t idx
Definition: util-var-name.c:65
#define VARID_HASHSIZE
Definition: util-var-name.c:69