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 static uint32_t VariableNameHash(HashListTable *ht, void *buf, uint16_t buflen)
69 {
70  VariableName *fn = (VariableName *)buf;
71  uint32_t hash = strlen(fn->name) + fn->type;
72  uint16_t u;
73 
74  for (u = 0; u < buflen; u++) {
75  hash += fn->name[u];
76  }
77 
78  return hash;
79 }
80 
81 static char VariableNameCompare(void *buf1, uint16_t len1, void *buf2, uint16_t len2)
82 {
83  VariableName *fn1 = (VariableName *)buf1;
84  VariableName *fn2 = (VariableName *)buf2;
85 
86  if (fn1->type != fn2->type)
87  return 0;
88 
89  if (strcmp(fn1->name,fn2->name) == 0)
90  return 1;
91 
92  return 0;
93 }
94 
95 static uint32_t VariableIdxHash(HashListTable *ht, void *buf, uint16_t buflen)
96 {
97  VariableName *fn = (VariableName *)buf;
98  uint32_t hash = fn->idx + fn->type;
99  return hash;
100 }
101 
102 static char VariableIdxCompare(void *buf1, uint16_t len1, void *buf2, uint16_t len2)
103 {
104  VariableName *fn1 = (VariableName *)buf1;
105  VariableName *fn2 = (VariableName *)buf2;
106 
107  if (fn1->type != fn2->type)
108  return 0;
109 
110  if (fn1->idx == fn2->idx)
111  return 1;
112 
113  return 0;
114 }
115 
116 static void VariableNameFree(void *data)
117 {
118  VariableName *fn = (VariableName *)data;
119 
120  if (fn == NULL)
121  return;
122 
123  if (fn->name != NULL) {
124  SCFree(fn->name);
125  fn->name = NULL;
126  }
127 
128  SCFree(fn);
129 }
130 
131 /** \brief Initialize the Name idx hash.
132  */
133 static VarNameStore *VarNameStoreInit(void)
134 {
135  VarNameStore *v = SCCalloc(1, sizeof(*v));
136  if (v == NULL)
137  return NULL;
138 
139  v->names = HashListTableInit(4096, VariableNameHash, VariableNameCompare, VariableNameFree);
140  if (v->names == NULL) {
141  SCFree(v);
142  return NULL;
143  }
144 
145  v->ids = HashListTableInit(4096, VariableIdxHash, VariableIdxCompare, NULL);
146  if (v->ids == NULL) {
148  SCFree(v);
149  return NULL;
150  }
151 
152  v->max_id = 0;
153  return v;
154 }
155 
156 static void VarNameStoreDoFree(VarNameStore *v)
157 {
158  if (v) {
161  SCFree(v);
162  }
163 }
164 
165 
166 /** \brief Get a name idx for a name. If the name is already used reuse the idx.
167  * \param name nul terminated string with the name
168  * \param type variable type
169  * \retval 0 in case of error
170  * \retval idx the idx or 0
171  */
172 static uint32_t VariableNameGetIdx(VarNameStore *v, const char *name, enum VarTypes type)
173 {
174  uint32_t idx = 0;
175 
176  VariableName *fn = SCMalloc(sizeof(VariableName));
177  if (unlikely(fn == NULL))
178  goto error;
179 
180  memset(fn, 0, sizeof(VariableName));
181 
182  fn->type = type;
183  fn->name = SCStrdup(name);
184  if (fn->name == NULL)
185  goto error;
186 
187  VariableName *lookup_fn = (VariableName *)HashListTableLookup(v->names, (void *)fn, 0);
188  if (lookup_fn == NULL) {
189  v->max_id++;
190 
191  idx = fn->idx = v->max_id;
192  HashListTableAdd(v->names, (void *)fn, 0);
193  HashListTableAdd(v->ids, (void *)fn, 0);
194  SCLogDebug("new registration %s id %u type %u", fn->name, fn->idx, fn->type);
195  } else {
196  idx = lookup_fn->idx;
197  VariableNameFree(fn);
198  }
199 
200  return idx;
201 error:
202  VariableNameFree(fn);
203  return 0;
204 }
205 
206 /** \brief Get a name from the idx.
207  * \param idx index of the variable whose name is to be fetched
208  * \param type variable type
209  * \retval NULL in case of error
210  * \retval name of the variable if successful.
211  * \todo no alloc on lookup
212  */
213 static char *VariableIdxGetName(VarNameStore *v, uint32_t idx, enum VarTypes type)
214 {
215  VariableName *fn = SCMalloc(sizeof(VariableName));
216  if (unlikely(fn == NULL))
217  goto error;
218 
219  char *name = NULL;
220  memset(fn, 0, sizeof(VariableName));
221 
222  fn->type = type;
223  fn->idx = idx;
224 
225  VariableName *lookup_fn = (VariableName *)HashListTableLookup(v->ids, (void *)fn, 0);
226  if (lookup_fn != NULL) {
227  name = SCStrdup(lookup_fn->name);
228  if (unlikely(name == NULL))
229  goto error;
230 
231  VariableNameFree(fn);
232  } else {
233  goto error;
234  }
235 
236  return name;
237 error:
238  VariableNameFree(fn);
239  return NULL;
240 }
241 
242 /** \brief setup staging store. Include current store if there is one.
243  */
245 {
246  SCMutexLock(&g_varnamestore_staging_m);
247 
248  if (!initialized) {
249  SC_ATOMIC_INIT(g_varnamestore_current);
250  initialized = 1;
251  }
252 
253  if (g_varnamestore_staging != NULL &&
254  g_varnamestore_staging->de_ctx_version == de_ctx_version) {
255  SCMutexUnlock(&g_varnamestore_staging_m);
256  return 0;
257  }
258 
259  VarNameStore *nv = VarNameStoreInit();
260  if (nv == NULL) {
261  SCMutexUnlock(&g_varnamestore_staging_m);
262  return -1;
263  }
264  g_varnamestore_staging = nv;
266 
267  VarNameStore *current = SC_ATOMIC_GET(g_varnamestore_current);
268  if (current) {
269  /* add all entries from the current hash into this new one. */
271  while (b) {
273 
274  VariableName *newvar = SCCalloc(1, sizeof(*newvar));
275  BUG_ON(newvar == NULL);
276  memcpy(newvar, var, sizeof(*newvar));
277  newvar->name = SCStrdup(var->name);
278  BUG_ON(newvar->name == NULL);
279 
280  HashListTableAdd(nv->names, (void *)newvar, 0);
281  HashListTableAdd(nv->ids, (void *)newvar, 0);
282  nv->max_id = MAX(nv->max_id, newvar->idx);
283  SCLogDebug("xfer %s id %u type %u", newvar->name, newvar->idx, newvar->type);
284 
286  }
287  }
288 
289  SCLogDebug("set up staging with detect engine ver %u", nv->de_ctx_version);
290  SCMutexUnlock(&g_varnamestore_staging_m);
291  return 0;
292 }
293 
294 const char *VarNameStoreLookupById(const uint32_t id, const enum VarTypes type)
295 {
296  VarNameStore *current = SC_ATOMIC_GET(g_varnamestore_current);
297  BUG_ON(current == NULL);
298  VariableName lookup = { NULL, type, id };
299  VariableName *found = (VariableName *)HashListTableLookup(current->ids, (void *)&lookup, 0);
300  if (found == NULL) {
301  return NULL;
302  }
303  return found->name;
304 }
305 
306 uint32_t VarNameStoreLookupByName(const char *name, const enum VarTypes type)
307 {
308  VarNameStore *current = SC_ATOMIC_GET(g_varnamestore_current);
309  BUG_ON(current == NULL);
310  VariableName lookup = { (char *)name, type, 0 };
311  VariableName *found = (VariableName *)HashListTableLookup(current->names, (void *)&lookup, 0);
312  if (found == NULL) {
313  return 0;
314  }
315  SCLogDebug("found %u for %s type %u", found->idx, name, type);
316  return found->idx;
317 }
318 
319 /** \brief add to staging or return existing id if already in there */
320 uint32_t VarNameStoreSetupAdd(const char *name, const enum VarTypes type)
321 {
322  uint32_t id;
323  SCMutexLock(&g_varnamestore_staging_m);
324  id = VariableNameGetIdx(g_varnamestore_staging, name, type);
325  SCMutexUnlock(&g_varnamestore_staging_m);
326  return id;
327 }
328 
329 char *VarNameStoreSetupLookup(uint32_t idx, const enum VarTypes type)
330 {
331  SCMutexLock(&g_varnamestore_staging_m);
332  char *name = VariableIdxGetName(g_varnamestore_staging, idx, type);
333  SCMutexUnlock(&g_varnamestore_staging_m);
334  return name;
335 }
336 
338 {
339  SCMutexLock(&g_varnamestore_staging_m);
340  if (g_varnamestore_old) {
341  VarNameStoreDoFree(g_varnamestore_old);
342  g_varnamestore_old = NULL;
343  }
344  g_varnamestore_old = SC_ATOMIC_GET(g_varnamestore_current);
345  SC_ATOMIC_SET(g_varnamestore_current, g_varnamestore_staging);
346  g_varnamestore_staging = NULL;
347  SCMutexUnlock(&g_varnamestore_staging_m);
348 }
349 
351 {
352  SCMutexLock(&g_varnamestore_staging_m);
353  SCLogDebug("freeing g_varnamestore_old %p", g_varnamestore_old);
354  if (g_varnamestore_old) {
355  VarNameStoreDoFree(g_varnamestore_old);
356  g_varnamestore_old = NULL;
357  }
358  SCMutexUnlock(&g_varnamestore_staging_m);
359 }
360 
362 {
363  SCLogDebug("freeing detect engine version %u", de_ctx_version);
364  SCMutexLock(&g_varnamestore_staging_m);
365  if (g_varnamestore_old && g_varnamestore_old->de_ctx_version == de_ctx_version) {
366  VarNameStoreDoFree(g_varnamestore_old);
367  g_varnamestore_old = NULL;
368  SCLogDebug("freeing detect engine version %u: old done", de_ctx_version);
369  }
370 
371  /* if at this point we have a staging area which matches our version
372  * we didn't complete the setup and are cleaning up the mess. */
373  if (g_varnamestore_staging && g_varnamestore_staging->de_ctx_version == de_ctx_version) {
374  VarNameStoreDoFree(g_varnamestore_staging);
375  g_varnamestore_staging = NULL;
376  SCLogDebug("freeing detect engine version %u: staging done", de_ctx_version);
377  }
378 
379  VarNameStore *current = SC_ATOMIC_GET(g_varnamestore_current);
380  if (current && current->de_ctx_version == de_ctx_version) {
381  VarNameStoreDoFree(current);
382  SC_ATOMIC_SET(g_varnamestore_current, NULL);
383  SCLogDebug("freeing detect engine version %u: current done", de_ctx_version);
384  }
385  SCMutexUnlock(&g_varnamestore_staging_m);
386 }
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:197
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:166
#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:228
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:212
void HashListTableFree(HashListTable *ht)
Definition: util-hashlist.c:82
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