]>
Commit | Line | Data |
---|---|---|
8e10844f VJ |
1 | /* Copyright (c) 2009 Victor Julien */ |
2 | ||
ecf86f9c | 3 | #include "suricata-common.h" |
8e10844f | 4 | #include "debug.h" |
c1e485cc | 5 | #include "util-unittest.h" |
8e10844f VJ |
6 | #include "decode.h" |
7 | #include "threads.h" | |
8 | ||
9 | #include "util-print.h" | |
10 | #include "util-pool.h" | |
11 | ||
6a53ab9c | 12 | #include "stream-tcp.h" |
8e10844f VJ |
13 | #include "stream-tcp-private.h" |
14 | #include "stream.h" | |
a16e7b74 | 15 | #include "stream-tcp-reassemble.h" |
8e10844f VJ |
16 | |
17 | #include "app-layer-protos.h" | |
18 | #include "app-layer-parser.h" | |
19 | ||
705471e4 | 20 | #include "util-spm.h" |
9f78d47c | 21 | |
91bc83e5 VJ |
22 | #include "util-debug.h" |
23 | ||
cae8e06c | 24 | static uint16_t app_layer_sid = 0; |
356a8bf3 GS |
25 | static AppLayerProto al_proto_table[ALPROTO_MAX]; /**< Application layer protocol |
26 | table mapped to their | |
27 | corresponding parsers */ | |
cae8e06c VJ |
28 | |
29 | #define MAX_PARSERS 100 | |
30 | static AppLayerParserTableElement al_parser_table[MAX_PARSERS]; | |
31 | static uint16_t al_max_parsers = 0; /* incremented for every registered parser */ | |
32 | ||
5a9a23f9 | 33 | static Pool *al_result_pool = NULL; |
cae8e06c VJ |
34 | static SCMutex al_result_pool_mutex = PTHREAD_MUTEX_INITIALIZER; |
35 | #ifdef DEBUG | |
36 | static uint32_t al_result_pool_elmts = 0; | |
37 | #endif /* DEBUG */ | |
38 | ||
5a9a23f9 | 39 | |
9f78d47c | 40 | /** \brief Alloc a AppLayerParserResultElmt func for the pool */ |
c1e485cc GS |
41 | static void *AlpResultElmtPoolAlloc(void *null) |
42 | { | |
43 | AppLayerParserResultElmt *e = (AppLayerParserResultElmt *)malloc | |
44 | (sizeof(AppLayerParserResultElmt)); | |
5a9a23f9 VJ |
45 | if (e == NULL) { |
46 | return NULL; | |
47 | } | |
48 | ||
9f78d47c | 49 | memset(e, 0, sizeof(AppLayerParserResultElmt)); |
cae8e06c VJ |
50 | |
51 | #ifdef DEBUG | |
52 | al_result_pool_elmts++; | |
53 | SCLogDebug("al_result_pool_elmts %"PRIu32"", al_result_pool_elmts); | |
54 | #endif /* DEBUG */ | |
5a9a23f9 VJ |
55 | return e; |
56 | } | |
5a9a23f9 | 57 | |
c1e485cc GS |
58 | static void AlpResultElmtPoolFree(void *e) |
59 | { | |
9f78d47c VJ |
60 | AppLayerParserResultElmt *re = (AppLayerParserResultElmt *)e; |
61 | ||
62 | if (re->flags & ALP_RESULT_ELMT_ALLOC) { | |
63 | if (re->data_ptr != NULL) | |
64 | free(re->data_ptr); | |
65 | } | |
66 | free(re); | |
cae8e06c VJ |
67 | |
68 | #ifdef DEBUG | |
69 | al_result_pool_elmts--; | |
70 | SCLogDebug("al_result_pool_elmts %"PRIu32"", al_result_pool_elmts); | |
71 | #endif /* DEBUG */ | |
9f78d47c VJ |
72 | } |
73 | ||
c1e485cc GS |
74 | static AppLayerParserResultElmt *AlpGetResultElmt(void) |
75 | { | |
cae8e06c | 76 | SCMutexLock(&al_result_pool_mutex); |
9f78d47c | 77 | AppLayerParserResultElmt *e = (AppLayerParserResultElmt *)PoolGet(al_result_pool); |
cae8e06c VJ |
78 | SCMutexUnlock(&al_result_pool_mutex); |
79 | ||
4914d8d9 | 80 | if (e == NULL) { |
bcc5bbef | 81 | return NULL; |
4914d8d9 | 82 | } |
9f78d47c | 83 | e->next = NULL; |
5a9a23f9 VJ |
84 | return e; |
85 | } | |
86 | ||
c1e485cc GS |
87 | static void AlpReturnResultElmt(AppLayerParserResultElmt *e) |
88 | { | |
9f78d47c VJ |
89 | if (e->flags & ALP_RESULT_ELMT_ALLOC) { |
90 | if (e->data_ptr != NULL) | |
91 | free(e->data_ptr); | |
92 | } | |
93 | e->flags = 0; | |
94 | e->data_ptr = NULL; | |
95 | e->data_len = 0; | |
96 | e->next = NULL; | |
97 | ||
cae8e06c | 98 | SCMutexLock(&al_result_pool_mutex); |
9f78d47c | 99 | PoolReturn(al_result_pool, (void *)e); |
cae8e06c | 100 | SCMutexUnlock(&al_result_pool_mutex); |
9f78d47c VJ |
101 | } |
102 | ||
c1e485cc GS |
103 | static void AlpAppendResultElmt(AppLayerParserResult *r, AppLayerParserResultElmt *e) |
104 | { | |
9f78d47c VJ |
105 | if (r->head == NULL) { |
106 | r->head = e; | |
107 | r->tail = e; | |
108 | r->cnt = 1; | |
109 | } else { | |
110 | r->tail->next = e; | |
111 | r->tail = e; | |
112 | r->cnt++; | |
113 | } | |
114 | } | |
115 | ||
116 | /** | |
117 | * \param alloc Is ptr alloc'd (1) or a ptr to static mem (0). | |
574bcea0 VJ |
118 | * \retval -1 error |
119 | * \retval 0 ok | |
9f78d47c | 120 | */ |
c1e485cc GS |
121 | static int AlpStoreField(AppLayerParserResult *output, uint16_t idx, |
122 | uint8_t *ptr, uint32_t len, uint8_t alloc) | |
123 | { | |
574bcea0 VJ |
124 | SCEnter(); |
125 | ||
9f78d47c | 126 | AppLayerParserResultElmt *e = AlpGetResultElmt(); |
fc2f7f29 | 127 | if (e == NULL) { |
d8433c72 | 128 | SCLogError(SC_ERR_POOL_EMPTY, "App layer \"al_result_pool\" is empty"); |
574bcea0 | 129 | SCReturnInt(-1); |
fc2f7f29 | 130 | } |
9f78d47c VJ |
131 | |
132 | if (alloc == 1) | |
133 | e->flags |= ALP_RESULT_ELMT_ALLOC; | |
134 | ||
135 | e->name_idx = idx; | |
136 | e->data_ptr = ptr; | |
137 | e->data_len = len; | |
138 | AlpAppendResultElmt(output, e); | |
139 | ||
574bcea0 | 140 | SCReturnInt(0); |
9f78d47c VJ |
141 | } |
142 | ||
086ba5f4 VJ |
143 | /** \brief Parse a field up to we reach the size limit |
144 | * | |
145 | * \retval 1 Field found and stored. | |
146 | * \retval 0 Field parsing in progress. | |
147 | * \retval -1 error | |
148 | */ | |
c1e485cc GS |
149 | int AlpParseFieldBySize(AppLayerParserResult *output, AppLayerParserState *pstate, |
150 | uint16_t field_idx, uint32_t size, uint8_t *input, | |
151 | uint32_t input_len, uint32_t *offset) | |
152 | { | |
574bcea0 VJ |
153 | SCEnter(); |
154 | ||
086ba5f4 VJ |
155 | if ((pstate->store_len + input_len) < size) { |
156 | if (pstate->store_len == 0) { | |
157 | pstate->store = malloc(input_len); | |
574bcea0 | 158 | if (pstate->store == NULL) { |
fc2f7f29 | 159 | SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed!"); |
574bcea0 VJ |
160 | SCReturnInt(-1); |
161 | } | |
086ba5f4 VJ |
162 | |
163 | memcpy(pstate->store, input, input_len); | |
164 | pstate->store_len = input_len; | |
165 | } else { | |
166 | pstate->store = realloc(pstate->store, (input_len + pstate->store_len)); | |
574bcea0 | 167 | if (pstate->store == NULL) { |
fc2f7f29 | 168 | SCLogError(SC_ERR_MEM_ALLOC, "Memory reallocation failed!"); |
574bcea0 VJ |
169 | SCReturnInt(-1); |
170 | } | |
086ba5f4 VJ |
171 | |
172 | memcpy(pstate->store+pstate->store_len, input, input_len); | |
173 | pstate->store_len += input_len; | |
174 | } | |
175 | } else { | |
176 | if (pstate->store_len == 0) { | |
574bcea0 VJ |
177 | int r = AlpStoreField(output, field_idx, input, size, /* static mem */0); |
178 | if (r == -1) { | |
d0404d84 | 179 | SCLogError(SC_ERR_ALPARSER, "Failed to store field value"); |
574bcea0 VJ |
180 | SCReturnInt(-1); |
181 | } | |
086ba5f4 | 182 | (*offset) += size; |
574bcea0 VJ |
183 | |
184 | SCReturnInt(1); | |
086ba5f4 VJ |
185 | } else { |
186 | uint32_t diff = size - pstate->store_len; | |
187 | ||
188 | pstate->store = realloc(pstate->store, (diff + pstate->store_len)); | |
574bcea0 | 189 | if (pstate->store == NULL) { |
fc2f7f29 | 190 | SCLogError(SC_ERR_MEM_ALLOC, "Memory reallocation failed!"); |
574bcea0 VJ |
191 | SCReturnInt(-1); |
192 | } | |
086ba5f4 VJ |
193 | |
194 | memcpy(pstate->store+pstate->store_len, input, diff); | |
195 | pstate->store_len += diff; | |
196 | ||
c1e485cc GS |
197 | int r = AlpStoreField(output, field_idx, pstate->store, |
198 | pstate->store_len, /* alloc mem */1); | |
574bcea0 | 199 | if (r == -1) { |
d0404d84 | 200 | SCLogError(SC_ERR_ALPARSER, "Failed to store field value"); |
574bcea0 VJ |
201 | SCReturnInt(-1); |
202 | } | |
086ba5f4 VJ |
203 | |
204 | (*offset) += diff; | |
205 | ||
206 | pstate->store = NULL; | |
207 | pstate->store_len = 0; | |
574bcea0 VJ |
208 | |
209 | SCReturnInt(1); | |
086ba5f4 VJ |
210 | } |
211 | } | |
212 | ||
574bcea0 | 213 | SCReturnInt(0); |
086ba5f4 VJ |
214 | } |
215 | ||
9f78d47c VJ |
216 | /** \brief Parse a field up to the EOF |
217 | * | |
218 | * \retval 1 Field found and stored. | |
219 | * \retval 0 Field parsing in progress. | |
220 | * \retval -1 error | |
221 | */ | |
c1e485cc GS |
222 | int AlpParseFieldByEOF(AppLayerParserResult *output, AppLayerParserState *pstate, |
223 | uint16_t field_idx, uint8_t *input, uint32_t input_len) | |
224 | { | |
574bcea0 VJ |
225 | SCEnter(); |
226 | ||
9f78d47c VJ |
227 | if (pstate->store_len == 0) { |
228 | if (pstate->flags & APP_LAYER_PARSER_EOF) { | |
574bcea0 VJ |
229 | SCLogDebug("store_len 0 and EOF"); |
230 | ||
231 | int r = AlpStoreField(output, field_idx, input, input_len, 0); | |
232 | if (r == -1) { | |
d0404d84 | 233 | SCLogError(SC_ERR_ALPARSER, "Failed to store field value"); |
574bcea0 VJ |
234 | SCReturnInt(-1); |
235 | } | |
236 | ||
237 | SCReturnInt(1); | |
9f78d47c | 238 | } else { |
574bcea0 VJ |
239 | SCLogDebug("store_len 0 but no EOF"); |
240 | ||
9f78d47c VJ |
241 | /* delimiter field not found, so store the result for the next run */ |
242 | pstate->store = malloc(input_len); | |
574bcea0 | 243 | if (pstate->store == NULL) { |
fc2f7f29 | 244 | SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed!"); |
574bcea0 VJ |
245 | SCReturnInt(-1); |
246 | } | |
9f78d47c VJ |
247 | |
248 | memcpy(pstate->store, input, input_len); | |
249 | pstate->store_len = input_len; | |
250 | } | |
251 | } else { | |
252 | if (pstate->flags & APP_LAYER_PARSER_EOF) { | |
574bcea0 VJ |
253 | SCLogDebug("store_len %" PRIu32 " and EOF", pstate->store_len); |
254 | ||
9f78d47c | 255 | pstate->store = realloc(pstate->store, (input_len + pstate->store_len)); |
574bcea0 | 256 | if (pstate->store == NULL) { |
fc2f7f29 | 257 | SCLogError(SC_ERR_MEM_ALLOC, "Memory reallocation failed!"); |
574bcea0 VJ |
258 | SCReturnInt(-1); |
259 | } | |
9f78d47c VJ |
260 | |
261 | memcpy(pstate->store+pstate->store_len, input, input_len); | |
262 | pstate->store_len += input_len; | |
263 | ||
574bcea0 VJ |
264 | int r = AlpStoreField(output, field_idx, pstate->store, pstate->store_len, 1); |
265 | if (r == -1) { | |
d0404d84 | 266 | SCLogError(SC_ERR_ALPARSER, "Failed to store field value"); |
574bcea0 VJ |
267 | SCReturnInt(-1); |
268 | } | |
269 | ||
9f78d47c VJ |
270 | pstate->store = NULL; |
271 | pstate->store_len = 0; | |
574bcea0 VJ |
272 | |
273 | SCReturnInt(1); | |
9f78d47c | 274 | } else { |
574bcea0 VJ |
275 | SCLogDebug("store_len %" PRIu32 " but no EOF", pstate->store_len); |
276 | ||
9f78d47c VJ |
277 | /* delimiter field not found, so store the result for the next run */ |
278 | pstate->store = realloc(pstate->store, (input_len + pstate->store_len)); | |
574bcea0 | 279 | if (pstate->store == NULL) { |
fc2f7f29 | 280 | SCLogError(SC_ERR_MEM_ALLOC, "Memory reallocation failed!"); |
574bcea0 VJ |
281 | SCReturnInt(-1); |
282 | } | |
9f78d47c VJ |
283 | |
284 | memcpy(pstate->store+pstate->store_len, input, input_len); | |
285 | pstate->store_len += input_len; | |
286 | } | |
287 | ||
288 | } | |
289 | ||
574bcea0 | 290 | SCReturnInt(0); |
9f78d47c VJ |
291 | } |
292 | ||
293 | /** \brief Parse a field up to a delimeter. | |
294 | * | |
295 | * \retval 1 Field found and stored. | |
296 | * \retval 0 Field parsing in progress. | |
297 | * \retval -1 error | |
298 | */ | |
c1e485cc GS |
299 | int AlpParseFieldByDelimiter(AppLayerParserResult *output, AppLayerParserState *pstate, |
300 | uint16_t field_idx, const uint8_t *delim, uint8_t delim_len, | |
301 | uint8_t *input, uint32_t input_len, uint32_t *offset) | |
302 | { | |
574bcea0 | 303 | SCEnter(); |
c1e485cc GS |
304 | SCLogDebug("pstate->store_len %" PRIu32 ", delim_len %" PRIu32 "", |
305 | pstate->store_len, delim_len); | |
9f78d47c VJ |
306 | |
307 | if (pstate->store_len == 0) { | |
705471e4 | 308 | uint8_t *ptr = SpmSearch(input, input_len, (uint8_t*)delim, delim_len); |
9f78d47c | 309 | if (ptr != NULL) { |
fa5939ca | 310 | uint32_t len = ptr - input; |
c1e485cc | 311 | SCLogDebug(" len %" PRIu32 "", len); |
9f78d47c | 312 | |
574bcea0 VJ |
313 | int r = AlpStoreField(output, field_idx, input, len, 0); |
314 | if (r == -1) { | |
d0404d84 | 315 | SCLogError(SC_ERR_ALPARSER, "Failed to store field value"); |
574bcea0 VJ |
316 | SCReturnInt(-1); |
317 | } | |
9f78d47c | 318 | (*offset) += (len + delim_len); |
574bcea0 | 319 | SCReturnInt(1); |
9f78d47c VJ |
320 | } else { |
321 | if (pstate->flags & APP_LAYER_PARSER_EOF) { | |
c1e485cc | 322 | SCLogDebug("delim not found and EOF"); |
574bcea0 | 323 | SCReturnInt(0); |
9f78d47c VJ |
324 | } |
325 | ||
c1e485cc | 326 | SCLogDebug("delim not found, continue"); |
9f78d47c VJ |
327 | |
328 | /* delimiter field not found, so store the result for the next run */ | |
329 | pstate->store = malloc(input_len); | |
574bcea0 | 330 | if (pstate->store == NULL) { |
fc2f7f29 | 331 | SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed!"); |
574bcea0 VJ |
332 | SCReturnInt(-1); |
333 | } | |
9f78d47c VJ |
334 | |
335 | memcpy(pstate->store, input, input_len); | |
336 | pstate->store_len = input_len; | |
337 | } | |
338 | } else { | |
705471e4 | 339 | uint8_t *ptr = SpmSearch(input, input_len, (uint8_t*)delim, delim_len); |
9f78d47c | 340 | if (ptr != NULL) { |
fa5939ca | 341 | uint32_t len = ptr - input; |
c1e485cc GS |
342 | SCLogDebug("len %" PRIu32 " + %" PRIu32 " = %" PRIu32 "", len, |
343 | pstate->store_len, len + pstate->store_len); | |
9f78d47c VJ |
344 | |
345 | pstate->store = realloc(pstate->store, (len + pstate->store_len)); | |
574bcea0 | 346 | if (pstate->store == NULL) { |
fc2f7f29 | 347 | SCLogError(SC_ERR_MEM_ALLOC, "Memory reallocation failed!"); |
574bcea0 VJ |
348 | SCReturnInt(-1); |
349 | } | |
9f78d47c VJ |
350 | |
351 | memcpy(pstate->store+pstate->store_len, input, len); | |
352 | pstate->store_len += len; | |
353 | ||
c1e485cc GS |
354 | int r = AlpStoreField(output, field_idx, pstate->store, |
355 | pstate->store_len, 1); | |
574bcea0 | 356 | if (r == -1) { |
d0404d84 | 357 | SCLogError(SC_ERR_ALPARSER, "Failed to store field value"); |
574bcea0 VJ |
358 | SCReturnInt(-1); |
359 | } | |
9f78d47c VJ |
360 | pstate->store = NULL; |
361 | pstate->store_len = 0; | |
362 | ||
363 | (*offset) += (len + delim_len); | |
574bcea0 | 364 | SCReturnInt(1); |
9f78d47c VJ |
365 | } else { |
366 | if (pstate->flags & APP_LAYER_PARSER_EOF) { | |
367 | /* if the input len is smaller than the delim len we search the | |
368 | * pstate->store since we may match there. */ | |
369 | if (delim_len > input_len) { | |
c1e485cc GS |
370 | /* delimiter field not found, so store the result for the |
371 | * next run */ | |
372 | pstate->store = realloc(pstate->store, (input_len + | |
373 | pstate->store_len)); | |
574bcea0 | 374 | if (pstate->store == NULL) { |
fc2f7f29 | 375 | SCLogError(SC_ERR_MEM_ALLOC, "Memory reallocation failed!"); |
574bcea0 VJ |
376 | SCReturnInt(-1); |
377 | } | |
9f78d47c VJ |
378 | |
379 | memcpy(pstate->store+pstate->store_len, input, input_len); | |
380 | pstate->store_len += input_len; | |
c1e485cc | 381 | SCLogDebug("input_len < delim_len, checking pstate->store"); |
9f78d47c VJ |
382 | |
383 | if (pstate->store_len >= delim_len) { | |
705471e4 | 384 | ptr = SpmSearch(pstate->store, pstate->store_len, (uint8_t*)delim, |
c1e485cc | 385 | delim_len); |
9f78d47c | 386 | if (ptr != NULL) { |
c1e485cc | 387 | SCLogDebug("now we found the delim"); |
9f78d47c | 388 | |
fa5939ca | 389 | uint32_t len = ptr - pstate->store; |
c1e485cc GS |
390 | int r = AlpStoreField(output, field_idx, |
391 | pstate->store, len, 1); | |
574bcea0 | 392 | if (r == -1) { |
d0404d84 | 393 | SCLogError(SC_ERR_ALPARSER, "Failed to store " |
fc2f7f29 | 394 | "field value"); |
574bcea0 VJ |
395 | SCReturnInt(-1); |
396 | } | |
397 | ||
9f78d47c VJ |
398 | pstate->store = NULL; |
399 | pstate->store_len = 0; | |
400 | ||
401 | (*offset) += (input_len); | |
402 | ||
c1e485cc | 403 | SCLogDebug("offset %" PRIu32 "", (*offset)); |
574bcea0 | 404 | SCReturnInt(1); |
9f78d47c VJ |
405 | } |
406 | goto free_and_return; | |
407 | } | |
408 | goto free_and_return; | |
409 | } | |
410 | free_and_return: | |
c1e485cc | 411 | SCLogDebug("not found and EOF, so free what we have so far."); |
9f78d47c VJ |
412 | free(pstate->store); |
413 | pstate->store = NULL; | |
414 | pstate->store_len = 0; | |
574bcea0 | 415 | SCReturnInt(0); |
9f78d47c VJ |
416 | } |
417 | ||
418 | /* delimiter field not found, so store the result for the next run */ | |
419 | pstate->store = realloc(pstate->store, (input_len + pstate->store_len)); | |
574bcea0 | 420 | if (pstate->store == NULL) { |
fc2f7f29 | 421 | SCLogError(SC_ERR_MEM_ALLOC, "Memory reallocation failed!"); |
574bcea0 VJ |
422 | SCReturnInt(-1); |
423 | } | |
9f78d47c VJ |
424 | |
425 | memcpy(pstate->store+pstate->store_len, input, input_len); | |
426 | pstate->store_len += input_len; | |
427 | ||
428 | /* if the input len is smaller than the delim len we search the | |
429 | * pstate->store since we may match there. */ | |
430 | if (delim_len > input_len && delim_len <= pstate->store_len) { | |
c1e485cc | 431 | SCLogDebug("input_len < delim_len, checking pstate->store"); |
9f78d47c | 432 | |
705471e4 | 433 | ptr = SpmSearch(pstate->store, pstate->store_len, (uint8_t*)delim, delim_len); |
9f78d47c | 434 | if (ptr != NULL) { |
c1e485cc | 435 | SCLogDebug("now we found the delim"); |
9f78d47c | 436 | |
fa5939ca | 437 | uint32_t len = ptr - pstate->store; |
574bcea0 VJ |
438 | int r = AlpStoreField(output, field_idx, pstate->store, len, 1); |
439 | if (r == -1) { | |
d0404d84 | 440 | SCLogError(SC_ERR_ALPARSER, "Failed to store field value"); |
574bcea0 VJ |
441 | SCReturnInt(-1); |
442 | } | |
9f78d47c VJ |
443 | pstate->store = NULL; |
444 | pstate->store_len = 0; | |
445 | ||
446 | (*offset) += (input_len); | |
447 | ||
c1e485cc | 448 | SCLogDebug("ffset %" PRIu32 "", (*offset)); |
574bcea0 | 449 | SCReturnInt(1); |
9f78d47c VJ |
450 | } |
451 | } | |
452 | } | |
453 | ||
454 | } | |
455 | ||
574bcea0 | 456 | SCReturnInt(0); |
9f78d47c VJ |
457 | } |
458 | ||
8e10844f VJ |
459 | /** \brief Get the Parsers id for storing the parser state. |
460 | * | |
461 | * \retval Parser subsys id | |
462 | */ | |
c1e485cc GS |
463 | uint16_t AppLayerParserGetStorageId(void) |
464 | { | |
8e10844f VJ |
465 | return app_layer_sid; |
466 | } | |
467 | ||
c1e485cc GS |
468 | uint16_t AppLayerGetProtoByName(const char *name) |
469 | { | |
f1f7df07 VJ |
470 | uint8_t u = 1; |
471 | SCLogDebug("looking for name %s", name); | |
472 | ||
473 | for ( ; u < ALPROTO_MAX; u++) { | |
474 | if (al_proto_table[u].name == NULL) | |
475 | continue; | |
476 | ||
477 | SCLogDebug("name %s proto %"PRIu16"", | |
478 | al_proto_table[u].name, u); | |
479 | ||
480 | if (strcasecmp(name,al_proto_table[u].name) == 0) { | |
481 | SCLogDebug("match, returning %"PRIu16"", u); | |
482 | return u; | |
483 | } | |
484 | } | |
485 | ||
486 | return ALPROTO_UNKNOWN; | |
487 | } | |
488 | ||
8e10844f VJ |
489 | /** \brief Description: register a parser. |
490 | * | |
491 | * \param name full parser name, e.g. "http.request_line" | |
c1e485cc GS |
492 | * \todo do we need recursive, so a "http" and a "request_line" where the engine |
493 | * knows it's actually "http.request_line"... same difference maybe. | |
8e10844f VJ |
494 | * \param AppLayerParser pointer to the parser function |
495 | * \param max_outputs max number of unique outputs the parser can generate | |
496 | * | |
497 | * \retval 0 on success | |
498 | * \retval -1 on error | |
499 | */ | |
c1e485cc | 500 | int AppLayerRegisterParser(char *name, uint16_t proto, uint16_t parser_id, |
fc2f7f29 | 501 | int (*AppLayerParser)(Flow *f, void *protocol_state, |
c1e485cc | 502 | AppLayerParserState *parser_state, uint8_t *input, |
18fe3818 VJ |
503 | uint32_t input_len, AppLayerParserResult *output), |
504 | char *dependency) | |
c1e485cc | 505 | { |
8e10844f VJ |
506 | |
507 | al_max_parsers++; | |
508 | ||
5fc30051 WM |
509 | if(al_max_parsers >= MAX_PARSERS){ |
510 | SCLogInfo("Failed to register %s al_parser_table array full",name); | |
511 | exit(EXIT_FAILURE); | |
512 | } | |
513 | ||
8e10844f | 514 | al_parser_table[al_max_parsers].name = name; |
5a9a23f9 VJ |
515 | al_parser_table[al_max_parsers].proto = proto; |
516 | al_parser_table[al_max_parsers].parser_local_id = parser_id; | |
8e10844f | 517 | al_parser_table[al_max_parsers].AppLayerParser = AppLayerParser; |
5a9a23f9 | 518 | |
c1e485cc GS |
519 | SCLogDebug("registered %p at proto %" PRIu32 ", al_proto_table idx " |
520 | "%" PRIu32 ", storage_id %" PRIu32 ", parser_local_id %" PRIu32 "", | |
521 | AppLayerParser, proto, al_max_parsers, | |
522 | al_proto_table[proto].storage_id, parser_id); | |
8e10844f VJ |
523 | return 0; |
524 | } | |
525 | ||
526 | /** \brief Description: register a protocol parser. | |
527 | * | |
528 | * \param name full parser name, e.g. "http.request_line" | |
c1e485cc GS |
529 | * \todo do we need recursive, so a "http" and a "request_line" where the engine |
530 | * knows it's actually "http.request_line"... same difference maybe. | |
8e10844f | 531 | * \param AppLayerParser pointer to the parser function |
8e10844f VJ |
532 | * |
533 | * \retval 0 on success | |
534 | * \retval -1 on error | |
535 | */ | |
c1e485cc | 536 | int AppLayerRegisterProto(char *name, uint8_t proto, uint8_t flags, |
fc2f7f29 | 537 | int (*AppLayerParser)(Flow *f, void *protocol_state, |
c1e485cc | 538 | AppLayerParserState *parser_state, uint8_t *input, |
18fe3818 | 539 | uint32_t input_len, AppLayerParserResult *output)) |
c1e485cc | 540 | { |
8e10844f VJ |
541 | |
542 | al_max_parsers++; | |
543 | ||
5fc30051 WM |
544 | if(al_max_parsers >= MAX_PARSERS){ |
545 | SCLogInfo("Failed to register %s al_parser_table array full",name); | |
546 | exit(EXIT_FAILURE); | |
547 | } | |
548 | ||
8e10844f VJ |
549 | al_parser_table[al_max_parsers].name = name; |
550 | al_parser_table[al_max_parsers].AppLayerParser = AppLayerParser; | |
551 | ||
f1f7df07 VJ |
552 | al_proto_table[proto].name = name; |
553 | ||
8e10844f VJ |
554 | /* create proto, direction -- parser mapping */ |
555 | if (flags & STREAM_TOSERVER) { | |
556 | al_proto_table[proto].to_server = al_max_parsers; | |
557 | } else if (flags & STREAM_TOCLIENT) { | |
558 | al_proto_table[proto].to_client = al_max_parsers; | |
559 | } | |
560 | ||
561 | if (al_proto_table[proto].storage_id == 0) { | |
562 | al_proto_table[proto].storage_id = StreamL7RegisterModule(); | |
563 | } | |
564 | ||
c1e485cc | 565 | SCLogDebug("registered %p at proto %" PRIu32 " flags %02X, al_proto_table " |
48248687 | 566 | "idx %" PRIu32 ", storage_id %" PRIu32 " %s", AppLayerParser, proto, |
c1e485cc | 567 | flags, al_max_parsers, al_proto_table[proto].storage_id, name); |
8e10844f VJ |
568 | return 0; |
569 | } | |
570 | ||
c1e485cc GS |
571 | void AppLayerRegisterStateFuncs(uint16_t proto, void *(*StateAlloc)(void), |
572 | void (*StateFree)(void *)) | |
573 | { | |
9f78d47c VJ |
574 | al_proto_table[proto].StateAlloc = StateAlloc; |
575 | al_proto_table[proto].StateFree = StateFree; | |
576 | } | |
577 | ||
c1e485cc GS |
578 | uint16_t AlpGetStateIdx(uint16_t proto) |
579 | { | |
9f78d47c VJ |
580 | return al_proto_table[proto].storage_id; |
581 | } | |
582 | ||
c1e485cc GS |
583 | AppLayerParserStateStore *AppLayerParserStateStoreAlloc(void) |
584 | { | |
585 | AppLayerParserStateStore *s = (AppLayerParserStateStore *)malloc | |
586 | (sizeof(AppLayerParserStateStore)); | |
8e10844f VJ |
587 | if (s == NULL) |
588 | return NULL; | |
589 | ||
9f78d47c | 590 | memset(s, 0, sizeof(AppLayerParserStateStore)); |
8e10844f VJ |
591 | return s; |
592 | } | |
593 | ||
b102ea21 VJ |
594 | /** \brief free a AppLayerParserStateStore structure |
595 | * \param s AppLayerParserStateStore structure to free */ | |
c1e485cc GS |
596 | void AppLayerParserStateStoreFree(AppLayerParserStateStore *s) |
597 | { | |
b102ea21 VJ |
598 | if (s->to_server.store != NULL) |
599 | free(s->to_server.store); | |
600 | if (s->to_client.store != NULL) | |
601 | free(s->to_client.store); | |
602 | ||
603 | free(s); | |
604 | } | |
605 | ||
c1e485cc GS |
606 | static void AppLayerParserResultCleanup(AppLayerParserResult *result) |
607 | { | |
9f78d47c VJ |
608 | AppLayerParserResultElmt *e = result->head; |
609 | while (e != NULL) { | |
610 | AppLayerParserResultElmt *next_e = e->next; | |
611 | ||
612 | result->head = next_e; | |
613 | if (next_e == NULL) | |
614 | result->tail = NULL; | |
615 | result->cnt--; | |
616 | ||
617 | AlpReturnResultElmt(e); | |
618 | e = next_e; | |
619 | } | |
620 | } | |
621 | ||
fc2f7f29 | 622 | static int AppLayerDoParse(Flow *f, void *app_layer_state, AppLayerParserState *parser_state, |
c1e485cc | 623 | uint8_t *input, uint32_t input_len, uint16_t parser_idx, |
c352bff6 | 624 | uint16_t proto) |
c1e485cc GS |
625 | { |
626 | SCEnter(); | |
9f78d47c VJ |
627 | int retval = 0; |
628 | AppLayerParserResult result = { NULL, NULL, 0 }; | |
629 | ||
c1e485cc | 630 | SCLogDebug("parser_idx %" PRIu32 "", parser_idx); |
9f78d47c VJ |
631 | //PrintRawDataFp(stdout, input,input_len); |
632 | ||
633 | /* invoke the parser */ | |
fc2f7f29 | 634 | int r = al_parser_table[parser_idx].AppLayerParser(f, app_layer_state, |
18fe3818 | 635 | parser_state, input, input_len, &result); |
c1e485cc GS |
636 | if (r < 0) { |
637 | if (r == -1) { | |
638 | AppLayerParserResultCleanup(&result); | |
639 | SCReturnInt(-1); | |
640 | } else { | |
641 | BUG_ON(r); /* this is not supposed to happen!! */ | |
642 | } | |
643 | } | |
9f78d47c VJ |
644 | |
645 | /* process the result elements */ | |
646 | AppLayerParserResultElmt *e = result.head; | |
647 | for (; e != NULL; e = e->next) { | |
c1e485cc GS |
648 | SCLogDebug("e %p e->name_idx %" PRIu32 ", e->data_ptr %p, e->data_len " |
649 | "%" PRIu32 ", map_size %" PRIu32 "", e, e->name_idx, | |
650 | e->data_ptr, e->data_len, al_proto_table[proto].map_size); | |
9f78d47c VJ |
651 | |
652 | /* no parser defined for this field. */ | |
c1e485cc GS |
653 | if (e->name_idx >= al_proto_table[proto].map_size || |
654 | al_proto_table[proto].map[e->name_idx] == NULL) | |
655 | { | |
656 | SCLogDebug("no parser for proto %" PRIu32 ", parser_local_id " | |
657 | "%" PRIu32 "", proto, e->name_idx); | |
9f78d47c VJ |
658 | continue; |
659 | } | |
660 | ||
fa5939ca | 661 | uint16_t idx = al_proto_table[proto].map[e->name_idx]->parser_id; |
9f78d47c VJ |
662 | |
663 | /* prepare */ | |
fa5939ca | 664 | uint16_t tmp = parser_state->parse_field; |
9f78d47c VJ |
665 | parser_state->parse_field = 0; |
666 | parser_state->flags |= APP_LAYER_PARSER_EOF; | |
667 | ||
fc2f7f29 | 668 | r = AppLayerDoParse(f, app_layer_state, parser_state, e->data_ptr, |
c352bff6 | 669 | e->data_len, idx, proto); |
9f78d47c VJ |
670 | |
671 | /* restore */ | |
672 | parser_state->flags &= ~APP_LAYER_PARSER_EOF; | |
673 | parser_state->parse_field = tmp; | |
674 | ||
675 | /* bail out on a serious error */ | |
676 | if (r < 0) { | |
c1e485cc GS |
677 | if (r == -1) { |
678 | retval = -1; | |
679 | break; | |
680 | } else { | |
681 | BUG_ON(r); | |
682 | } | |
9f78d47c VJ |
683 | } |
684 | } | |
685 | ||
686 | AppLayerParserResultCleanup(&result); | |
c1e485cc | 687 | SCReturnInt(retval); |
9f78d47c VJ |
688 | } |
689 | ||
8e10844f VJ |
690 | /** |
691 | * \brief Layer 7 Parsing main entry point. | |
692 | * | |
9f78d47c VJ |
693 | * \param f Properly initialized and locked flow. |
694 | * \param proto L7 proto, e.g. ALPROTO_HTTP | |
695 | * \param flags Stream flags | |
696 | * \param input Input L7 data | |
697 | * \param input_len Length of the input data. | |
698 | * | |
699 | * \retval -1 error | |
700 | * \retval 0 ok | |
8e10844f | 701 | */ |
c1e485cc | 702 | int AppLayerParse(Flow *f, uint8_t proto, uint8_t flags, uint8_t *input, |
c352bff6 | 703 | uint32_t input_len) |
c1e485cc | 704 | { |
91bc83e5 | 705 | SCEnter(); |
8e10844f | 706 | |
fa5939ca | 707 | uint16_t parser_idx = 0; |
8e10844f VJ |
708 | AppLayerProto *p = &al_proto_table[proto]; |
709 | ||
b102ea21 | 710 | TcpSession *ssn = f->protoctx; |
8e10844f | 711 | if (ssn == NULL) { |
c1e485cc | 712 | SCLogDebug("no TCP session"); |
91bc83e5 | 713 | goto error; |
8e10844f VJ |
714 | } |
715 | ||
716 | /* Get the parser state (if any) */ | |
c1e485cc | 717 | AppLayerParserStateStore *parser_state_store = NULL; |
8e10844f | 718 | |
c1e485cc GS |
719 | if (ssn->aldata != NULL) { |
720 | parser_state_store = (AppLayerParserStateStore *) | |
721 | ssn->aldata[app_layer_sid]; | |
722 | if (parser_state_store == NULL) { | |
723 | parser_state_store = AppLayerParserStateStoreAlloc(); | |
724 | if (parser_state_store == NULL) | |
725 | goto error; | |
726 | ||
c1e485cc | 727 | ssn->aldata[app_layer_sid] = (void *)parser_state_store; |
c1e485cc GS |
728 | } |
729 | } else { | |
730 | SCLogDebug("No App Layer Data"); | |
1b39e602 GS |
731 | /* Nothing is there to clean up, so just return from here after setting |
732 | * up the no reassembly flags */ | |
733 | StreamTcpSetSessionNoReassemblyFlag(ssn, flags & STREAM_TOCLIENT ? 1 : 0); | |
734 | StreamTcpSetSessionNoReassemblyFlag(ssn, flags & STREAM_TOSERVER ? 1 : 0); | |
735 | SCReturnInt(-1); | |
9f78d47c VJ |
736 | } |
737 | ||
738 | AppLayerParserState *parser_state = NULL; | |
739 | if (flags & STREAM_TOSERVER) { | |
48248687 | 740 | SCLogDebug("to_server msg (flow %p)", f); |
ba7e8012 | 741 | |
9f78d47c VJ |
742 | parser_state = &parser_state_store->to_server; |
743 | if (!(parser_state->flags & APP_LAYER_PARSER_USE)) { | |
8e10844f | 744 | parser_idx = p->to_server; |
9f78d47c VJ |
745 | parser_state->cur_parser = parser_idx; |
746 | parser_state->flags |= APP_LAYER_PARSER_USE; | |
747 | } else { | |
c1e485cc GS |
748 | SCLogDebug("using parser %" PRIu32 " we stored before (to_server)", |
749 | parser_state->cur_parser); | |
9f78d47c | 750 | parser_idx = parser_state->cur_parser; |
8e10844f VJ |
751 | } |
752 | } else { | |
48248687 | 753 | SCLogDebug("to_client msg (flow %p)", f); |
ba7e8012 | 754 | |
9f78d47c VJ |
755 | parser_state = &parser_state_store->to_client; |
756 | if (!(parser_state->flags & APP_LAYER_PARSER_USE)) { | |
757 | parser_idx = p->to_client; | |
758 | parser_state->cur_parser = parser_idx; | |
759 | parser_state->flags |= APP_LAYER_PARSER_USE; | |
760 | } else { | |
c1e485cc GS |
761 | SCLogDebug("using parser %" PRIu32 " we stored before (to_client)", |
762 | parser_state->cur_parser); | |
9f78d47c VJ |
763 | parser_idx = parser_state->cur_parser; |
764 | } | |
8e10844f VJ |
765 | } |
766 | ||
086ba5f4 | 767 | if (parser_idx == 0 || parser_state->flags & APP_LAYER_PARSER_DONE) { |
c1e485cc | 768 | SCLogDebug("no parser for protocol %" PRIu32 "", proto); |
91bc83e5 | 769 | SCReturnInt(0); |
8e10844f VJ |
770 | } |
771 | ||
9f78d47c VJ |
772 | if (flags & STREAM_EOF) |
773 | parser_state->flags |= APP_LAYER_PARSER_EOF; | |
8e10844f | 774 | |
9f78d47c | 775 | /* See if we already have a 'app layer' state */ |
7715e8f0 | 776 | void *app_layer_state = NULL; |
b102ea21 | 777 | app_layer_state = ssn->aldata[p->storage_id]; |
b3cb29b7 | 778 | |
9f78d47c | 779 | if (app_layer_state == NULL) { |
48248687 VJ |
780 | /* lock the allocation of state as we may |
781 | * alloc more than one otherwise */ | |
9f78d47c | 782 | app_layer_state = p->StateAlloc(); |
48248687 | 783 | if (app_layer_state == NULL) { |
91bc83e5 | 784 | goto error; |
48248687 | 785 | } |
9f78d47c | 786 | |
b102ea21 | 787 | ssn->aldata[p->storage_id] = app_layer_state; |
48248687 VJ |
788 | SCLogDebug("alloced new app layer state %p (p->storage_id %u, name %s)", app_layer_state, p->storage_id, al_proto_table[ssn->alproto].name); |
789 | } else { | |
790 | SCLogDebug("using existing app layer state %p (p->storage_id %u, name %s))", app_layer_state, p->storage_id, al_proto_table[ssn->alproto].name); | |
8e10844f VJ |
791 | } |
792 | ||
9f78d47c | 793 | /* invoke the recursive parser */ |
fc2f7f29 | 794 | int r = AppLayerDoParse(f, app_layer_state, parser_state, input, input_len, |
c352bff6 | 795 | parser_idx, proto); |
8e10844f | 796 | if (r < 0) |
91bc83e5 | 797 | goto error; |
8e10844f | 798 | |
a16e7b74 GS |
799 | /* set the packets to no inspection and reassembly for the TLS sessions */ |
800 | if (parser_state->flags & APP_LAYER_PARSER_NO_INSPECTION) { | |
a16e7b74 | 801 | FlowSetNoPayloadInspectionFlag(f); |
a16e7b74 GS |
802 | |
803 | /* Set the no reassembly flag for both the stream in this TcpSession */ | |
804 | if (parser_state->flags & APP_LAYER_PARSER_NO_REASSEMBLY) { | |
805 | StreamTcpSetSessionNoReassemblyFlag(ssn, | |
806 | flags & STREAM_TOCLIENT ? 1 : 0); | |
807 | StreamTcpSetSessionNoReassemblyFlag(ssn, | |
808 | flags & STREAM_TOSERVER ? 1 : 0); | |
809 | } | |
810 | } | |
811 | ||
91bc83e5 VJ |
812 | SCReturnInt(0); |
813 | error: | |
c1e485cc | 814 | if (ssn != NULL) { |
c1e485cc GS |
815 | /* Clear the app layer protocol state memory and the given function also |
816 | * cleans the parser state memory */ | |
48248687 VJ |
817 | if (f->use_cnt == 0) |
818 | AppLayerParserCleanupState(ssn); | |
c1e485cc GS |
819 | |
820 | /* Set the no reassembly flag for both the stream in this TcpSession */ | |
821 | StreamTcpSetSessionNoReassemblyFlag(ssn, flags & STREAM_TOCLIENT ? 1 : 0); | |
822 | StreamTcpSetSessionNoReassemblyFlag(ssn, flags & STREAM_TOSERVER ? 1 : 0); | |
823 | ||
824 | if (f->src.family == AF_INET) { | |
ba7e8012 VJ |
825 | char src[16]; |
826 | char dst[16]; | |
ad3e4639 | 827 | inet_ntop(AF_INET, (const void*)&f->src.addr_data32[0], src, |
c1e485cc | 828 | sizeof (src)); |
ad3e4639 | 829 | inet_ntop(AF_INET, (const void*)&f->dst.addr_data32[0], dst, |
c1e485cc | 830 | sizeof (dst)); |
c1e485cc | 831 | |
d0404d84 | 832 | SCLogError(SC_ERR_ALPARSER, "Error occured in parsing \"%s\" app layer " |
c1e485cc GS |
833 | "protocol, using network protocol %"PRIu8", source IP " |
834 | "address %s, destination IP address %s, src port %"PRIu16" and " | |
835 | "dst port %"PRIu16"", al_proto_table[ssn->alproto].name, | |
1b39e602 | 836 | f->proto, src, dst, f->sp, f->dp); |
ad3e4639 GS |
837 | |
838 | } else { | |
ba7e8012 VJ |
839 | char dst6[46]; |
840 | char src6[46]; | |
841 | ||
ad3e4639 GS |
842 | inet_ntop(AF_INET6, (const void*)&f->src.addr_data32, src6, |
843 | sizeof (src6)); | |
844 | inet_ntop(AF_INET6, (const void*)&f->dst.addr_data32, dst6, | |
845 | sizeof (dst6)); | |
846 | ||
d0404d84 | 847 | SCLogError(SC_ERR_ALPARSER, "Error occured in parsing \"%s\" app layer " |
ad3e4639 GS |
848 | "protocol, using network protocol %"PRIu8", source IPv6 " |
849 | "address %s, destination IPv6 address %s, src port %"PRIu16" and " | |
850 | "dst port %"PRIu16"", al_proto_table[ssn->alproto].name, | |
851 | f->proto, src6, dst6, f->sp, f->dp); | |
852 | } | |
c1e485cc GS |
853 | } |
854 | ||
91bc83e5 | 855 | SCReturnInt(-1); |
8e10844f VJ |
856 | } |
857 | ||
c1e485cc GS |
858 | void RegisterAppLayerParsers(void) |
859 | { | |
8e10844f VJ |
860 | /** \todo move to general init function */ |
861 | memset(&al_proto_table, 0, sizeof(al_proto_table)); | |
862 | memset(&al_parser_table, 0, sizeof(al_parser_table)); | |
863 | ||
864 | app_layer_sid = StreamL7RegisterModule(); | |
5a9a23f9 VJ |
865 | |
866 | /** setup result pool | |
867 | * \todo Per thread pool */ | |
66cc3921 | 868 | al_result_pool = PoolInit(1000,250,AlpResultElmtPoolAlloc,NULL,AlpResultElmtPoolFree); |
5a9a23f9 VJ |
869 | } |
870 | ||
c1e485cc GS |
871 | void AppLayerParserCleanupState(TcpSession *ssn) |
872 | { | |
b102ea21 | 873 | if (ssn == NULL) { |
c1e485cc | 874 | SCLogDebug("no ssn"); |
b102ea21 VJ |
875 | return; |
876 | } | |
877 | ||
878 | AppLayerProto *p = &al_proto_table[ssn->alproto]; | |
879 | if (p == NULL) { | |
c1e485cc | 880 | SCLogDebug("no parser state for %"PRIu16"", ssn->alproto); |
b102ea21 VJ |
881 | return; |
882 | } | |
883 | ||
884 | /* free the parser protocol state */ | |
c1e485cc | 885 | if (p->StateFree != NULL && ssn->aldata != NULL) { |
b102ea21 | 886 | if (ssn->aldata[p->storage_id] != NULL) { |
c1e485cc | 887 | SCLogDebug("calling StateFree"); |
b102ea21 VJ |
888 | p->StateFree(ssn->aldata[p->storage_id]); |
889 | ssn->aldata[p->storage_id] = NULL; | |
890 | } | |
891 | } | |
892 | ||
893 | if (ssn->aldata != NULL) { | |
894 | if (ssn->aldata[app_layer_sid] != NULL) { | |
c1e485cc | 895 | SCLogDebug("calling AppLayerParserStateStoreFree"); |
b102ea21 VJ |
896 | AppLayerParserStateStoreFree(ssn->aldata[app_layer_sid]); |
897 | ssn->aldata[app_layer_sid] = NULL; | |
898 | } | |
899 | ||
6a53ab9c | 900 | StreamTcpDecrMemuse((uint32_t)(StreamL7GetStorageSize() * sizeof(void *))); |
b102ea21 VJ |
901 | free(ssn->aldata); |
902 | ssn->aldata = NULL; | |
903 | } | |
904 | } | |
905 | ||
9f78d47c VJ |
906 | /** \brief Create a mapping between the individual parsers local field id's |
907 | * and the global field parser id's. | |
908 | * | |
909 | */ | |
c1e485cc GS |
910 | void AppLayerParsersInitPostProcess(void) |
911 | { | |
fa5939ca | 912 | uint16_t u16 = 0; |
5a9a23f9 VJ |
913 | |
914 | /* build local->global mapping */ | |
915 | for (u16 = 1; u16 <= al_max_parsers; u16++) { | |
916 | /* no local parser */ | |
917 | if (al_parser_table[u16].parser_local_id == 0) | |
918 | continue; | |
919 | ||
c1e485cc GS |
920 | if (al_parser_table[u16].parser_local_id > |
921 | al_proto_table[al_parser_table[u16].proto].map_size) | |
922 | { | |
923 | al_proto_table[al_parser_table[u16].proto].map_size = | |
924 | al_parser_table[u16].parser_local_id; | |
925 | } | |
926 | SCLogDebug("map_size %" PRIu32 "", al_proto_table | |
927 | [al_parser_table[u16].proto].map_size); | |
5a9a23f9 VJ |
928 | } |
929 | ||
930 | /* for each proto, alloc the map array */ | |
931 | for (u16 = 0; u16 < ALPROTO_MAX; u16++) { | |
932 | if (al_proto_table[u16].map_size == 0) | |
933 | continue; | |
934 | ||
935 | al_proto_table[u16].map_size++; | |
c1e485cc GS |
936 | al_proto_table[u16].map = (AppLayerLocalMap **)malloc |
937 | (al_proto_table[u16].map_size * | |
938 | sizeof(AppLayerLocalMap *)); | |
5a9a23f9 | 939 | if (al_proto_table[u16].map == NULL) { |
c1e485cc | 940 | SCLogError(SC_ERR_MEM_ALLOC, "memory error"); |
5a9a23f9 VJ |
941 | exit(1); |
942 | } | |
c1e485cc GS |
943 | memset(al_proto_table[u16].map, 0, al_proto_table[u16].map_size * |
944 | sizeof(AppLayerLocalMap *)); | |
5a9a23f9 | 945 | |
fa5939ca | 946 | uint16_t u = 0; |
5a9a23f9 VJ |
947 | for (u = 1; u <= al_max_parsers; u++) { |
948 | /* no local parser */ | |
949 | if (al_parser_table[u].parser_local_id == 0) | |
950 | continue; | |
951 | ||
952 | if (al_parser_table[u].proto != u16) | |
953 | continue; | |
954 | ||
fa5939ca | 955 | uint16_t parser_local_id = al_parser_table[u].parser_local_id; |
c1e485cc | 956 | SCLogDebug("parser_local_id: %" PRIu32 "", parser_local_id); |
5a9a23f9 VJ |
957 | |
958 | if (parser_local_id < al_proto_table[u16].map_size) { | |
959 | al_proto_table[u16].map[parser_local_id] = malloc(sizeof(AppLayerLocalMap)); | |
960 | if (al_proto_table[u16].map[parser_local_id] == NULL) { | |
c1e485cc | 961 | SCLogError(SC_ERR_MEM_ALLOC, "XXX memory error"); |
5a9a23f9 VJ |
962 | exit(1); |
963 | } | |
964 | ||
965 | al_proto_table[u16].map[parser_local_id]->parser_id = u; | |
966 | } | |
967 | } | |
968 | } | |
969 | ||
970 | for (u16 = 0; u16 < ALPROTO_MAX; u16++) { | |
971 | if (al_proto_table[u16].map_size == 0) | |
972 | continue; | |
973 | ||
974 | if (al_proto_table[u16].map == NULL) | |
975 | continue; | |
976 | ||
fa5939ca | 977 | uint16_t x = 0; |
5a9a23f9 VJ |
978 | for (x = 0; x < al_proto_table[u16].map_size; x++) { |
979 | if (al_proto_table[u16].map[x] == NULL) | |
980 | continue; | |
981 | ||
c1e485cc | 982 | SCLogDebug("al_proto_table[%" PRIu32 "].map[%" PRIu32 "]->parser_id:" |
48248687 | 983 | " %" PRIu32 "", u16, x, al_proto_table[u16].map[x]->parser_id); |
5a9a23f9 VJ |
984 | } |
985 | } | |
8e10844f VJ |
986 | } |
987 | ||
c1e485cc GS |
988 | /* UNITTESTS*/ |
989 | #ifdef UNITTESTS | |
990 | ||
991 | typedef struct TestState_ { | |
992 | uint8_t test; | |
993 | }TestState; | |
994 | ||
995 | /** | |
996 | * \brief Test parser function to test the memory deallocation of app layer | |
997 | * parser of occurence of an error. | |
998 | */ | |
fc2f7f29 | 999 | static int TestProtocolParser(Flow *f, void *test_state, AppLayerParserState *pstate, |
c1e485cc | 1000 | uint8_t *input, uint32_t input_len, |
18fe3818 | 1001 | AppLayerParserResult *output) |
c1e485cc GS |
1002 | { |
1003 | return -1; | |
1004 | } | |
1005 | ||
1006 | /** \brief Function to allocates the Test protocol state memory | |
1007 | */ | |
1008 | static void *TestProtocolStateAlloc(void) | |
1009 | { | |
1010 | void *s = malloc(sizeof(TestState)); | |
1011 | if (s == NULL) | |
1012 | return NULL; | |
1013 | ||
1014 | memset(s, 0, sizeof(TestState)); | |
1015 | return s; | |
1016 | } | |
1017 | ||
1018 | /** \brief Function to free the Test Protocol state memory | |
1019 | */ | |
1020 | static void TestProtocolStateFree(void *s) | |
1021 | { | |
1022 | free(s); | |
1023 | } | |
1024 | ||
1025 | /** \test Test the deallocation of app layer parser memory on occurance of | |
1026 | * error in the parsing process. | |
1027 | */ | |
1028 | static int AppLayerParserTest01 (void) | |
1029 | { | |
1030 | int result = 1; | |
1031 | Flow f; | |
1032 | uint8_t testbuf[] = { 0x11 }; | |
1033 | uint32_t testlen = sizeof(testbuf); | |
1034 | TcpSession ssn; | |
1035 | struct in_addr addr; | |
1036 | struct in_addr addr1; | |
1037 | Address src; | |
1038 | Address dst; | |
1039 | ||
1040 | memset(&f, 0, sizeof(f)); | |
1041 | memset(&ssn, 0, sizeof(ssn)); | |
1042 | memset(&src, 0, sizeof(src)); | |
1043 | memset(&dst, 0, sizeof(dst)); | |
1044 | ||
1045 | /* Register the Test protocol state and parser functions */ | |
1046 | AppLayerRegisterProto("test", ALPROTO_TEST, STREAM_TOSERVER, | |
1047 | TestProtocolParser); | |
1048 | AppLayerRegisterStateFuncs(ALPROTO_TEST, TestProtocolStateAlloc, | |
1049 | TestProtocolStateFree); | |
1050 | ||
1051 | ssn.alproto = ALPROTO_TEST; | |
c1e485cc GS |
1052 | f.protoctx = (void *)&ssn; |
1053 | ||
1054 | inet_pton(AF_INET, "1.2.3.4", &addr.s_addr); | |
1055 | src.family = AF_INET; | |
1056 | src.addr_data32[0] = addr.s_addr; | |
1057 | inet_pton(AF_INET, "4.3.2.1", &addr1.s_addr); | |
1058 | dst.family = AF_INET; | |
1059 | dst.addr_data32[0] = addr1.s_addr; | |
1060 | f.src = src; | |
1061 | f.dst = dst; | |
1062 | f.sp = htons(20); | |
1063 | f.dp = htons(40); | |
1064 | f.proto = IPPROTO_TCP; | |
1065 | ||
6a53ab9c VJ |
1066 | StreamTcpInitConfig(TRUE); |
1067 | StreamL7DataPtrInit(&ssn); | |
1068 | ||
c1e485cc | 1069 | int r = AppLayerParse(&f, ALPROTO_TEST, STREAM_TOSERVER|STREAM_EOF, testbuf, |
c352bff6 | 1070 | testlen); |
c1e485cc GS |
1071 | if (r != -1) { |
1072 | printf("returned %" PRId32 ", expected -1: \n", r); | |
1073 | result = 0; | |
1074 | goto end; | |
1075 | } | |
1076 | ||
1077 | if (!(ssn.flags & STREAMTCP_FLAG_NOSERVER_REASSEMBLY) || | |
1078 | !(ssn.flags & STREAMTCP_FLAG_NOCLIENT_REASSEMBLY)) | |
1079 | { | |
1080 | printf("flags should be set, but they are not !\n"); | |
1081 | result = 0; | |
1082 | goto end; | |
1083 | } | |
1084 | ||
1085 | if (ssn.aldata != NULL) { | |
1086 | printf("App Layer state has not been cleared\n"); | |
1087 | result = 0; | |
1088 | goto end; | |
1089 | } | |
1090 | end: | |
6a53ab9c VJ |
1091 | StreamL7DataPtrFree(&ssn); |
1092 | StreamTcpFreeConfig(TRUE); | |
c1e485cc GS |
1093 | return result; |
1094 | } | |
1095 | ||
1096 | #endif /* UNITESTS */ | |
1097 | ||
1098 | void AppLayerParserRegisterTests(void) | |
1099 | { | |
1100 | #ifdef UNITTESTS | |
1101 | UtRegisterTest("AppLayerParserTest01", AppLayerParserTest01, 1); | |
1102 | #endif /* UNITTESTS */ | |
1103 | } |