1 /* tvbparse.c
2 *
3 * Copyright 2005, Luis E. Garcia Ontanon <luis@ontanon.org>
4 *
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12 #include "config.h"
13
14 #include <stdlib.h>
15 #include <string.h>
16 #include <glib.h>
17
18 #include <epan/wmem_scopes.h>
19 #include <epan/proto.h>
20 #include <epan/packet_info.h>
21 #include <epan/tvbparse.h>
22 #include <wsutil/ws_assert.h>
23
24
25 #define TVBPARSE_DEBUG_ALL 0xffffffff
26
27 #if 0
28 #define TVBPARSE_DEBUG_ 0x80000000
29 #define TVBPARSE_DEBUG_ 0x40000000
30 #define TVBPARSE_DEBUG_ 0x20000000
31 #define TVBPARSE_DEBUG_ 0x10000000
32 #endif
33
34 #define TVBPARSE_DEBUG_CHAR 0x08000000
35 #define TVBPARSE_DEBUG_CHARS 0x04000000
36 #define TVBPARSE_DEBUG_NOT_CHAR 0x02000000
37 #define TVBPARSE_DEBUG_NOT_CHARS 0x01000000
38 #define TVBPARSE_DEBUG_STRING 0x00800000
39 #define TVBPARSE_DEBUG_CASESTRING 0x00400000
40 #define TVBPARSE_DEBUG_ONEOF 0x00200000
41 #define TVBPARSE_DEBUG_HASH 0x00100000
42 #define TVBPARSE_DEBUG_SEQ 0x00080000
43 #define TVBPARSE_DEBUG_SOME 0x00040000
44 #define TVBPARSE_DEBUG_UNTIL 0x00020000
45 #if 0
46 #define TVBPARSE_DEBUG_ 0x00010000
47 #define TVBPARSE_DEBUG_ 0x00008000
48 #define TVBPARSE_DEBUG_ 0x00004000
49 #define TVBPARSE_DEBUG_ 0x00002000
50 #define TVBPARSE_DEBUG_ 0x00001000
51 #endif
52 #define TVBPARSE_DEBUG_TT 0x00000800
53 #define TVBPARSE_DEBUG_CB 0x00000400
54 #define TVBPARSE_DEBUG_GET 0x00000200
55 #define TVBPARSE_DEBUG_FIND 0x00000100
56 #define TVBPARSE_DEBUG_NEWTOK 0x00000080
57 #define TVBPARSE_DEBUG_IGNORE 0x00000040
58 #define TVBPARSE_DEBUG_PEEK 0x00000020
59 #if 0
60 #define TVBPARSE_DEBUG_ 0x00000010
61 #define TVBPARSE_DEBUG_ 0x00000008
62 #define TVBPARSE_DEBUG_ 0x00000004
63 #define TVBPARSE_DEBUG_ 0x00000002
64 #define TVBPARSE_DEBUG_ 0x00000001
65 #endif
66
67 /*
68 #define TVBPARSE_DEBUG (TVBPARSE_DEBUG_SOME)
69 */
70
71 #define TVBPARSE_MAX_RECURSION_DEPTH 100 // Arbitrary. Matches DAAP and PNIO.
72
new_tok(tvbparse_t * tt,int id,int offset,int len,const tvbparse_wanted_t * wanted)73 static tvbparse_elem_t* new_tok(tvbparse_t* tt,
74 int id,
75 int offset,
76 int len,
77 const tvbparse_wanted_t* wanted) {
78 tvbparse_elem_t* tok;
79
80 #ifdef TVBPARSE_DEBUG
81 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NEWTOK) ws_warning("new_tok: id=%i offset=%u len=%u",id,offset,len);
82 #endif
83
84 tok = wmem_new(tt->scope, tvbparse_elem_t);
85
86 tok->parser = tt;
87 tok->tvb = tt->tvb;
88 tok->id = id;
89 tok->offset = offset;
90 tok->len = len;
91 tok->data = NULL;
92 tok->sub = NULL;
93 tok->next = NULL;
94 tok->wanted = wanted;
95 tok->last = tok;
96
97 return tok;
98 }
99
ignore_fcn(tvbparse_t * tt,int offset)100 static int ignore_fcn(tvbparse_t* tt, int offset) {
101 int len = 0;
102 int consumed;
103 tvbparse_elem_t* ignored = NULL;
104
105 if (!tt->ignore) return 0;
106
107 #ifdef TVBPARSE_DEBUG
108 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_IGNORE) ws_warning("ignore: enter");
109 #endif
110
111 while ((consumed = tt->ignore->condition(tt,offset,tt->ignore,&ignored)) > 0) {
112 len += consumed;
113 offset += consumed;
114 #ifdef TVBPARSE_DEBUG
115 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_IGNORE) ws_warning("ignore: consumed=%i",consumed);
116 #endif
117
118 }
119
120 #ifdef TVBPARSE_DEBUG
121 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_IGNORE) ws_warning("ignore: len=%i",len);
122 #endif
123
124 return len;
125 }
126
127
cond_char(tvbparse_t * tt,const int offset,const tvbparse_wanted_t * wanted,tvbparse_elem_t ** tok)128 static int cond_char (tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
129 gchar c,t;
130 guint i;
131
132 #ifdef TVBPARSE_DEBUG
133 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHAR) ws_warning("cond_char: control='%s'",wanted->control.str);
134 #endif
135
136 if ( offset + 1 > tt->end_offset )
137 return -1;
138
139 t = (gchar) tvb_get_guint8(tt->tvb,offset);
140
141 for(i = 0; (c = wanted->control.str[i]) && offset <= tt->end_offset; i++) {
142 if ( c == t ) {
143 *tok = new_tok(tt,wanted->id,offset,1,wanted);
144 #ifdef TVBPARSE_DEBUG
145 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHAR) ws_warning("cond_char: GOT: '%c'",c);
146 #endif
147 return 1;
148 }
149 }
150
151 return -1;
152 }
153
tvbparse_char(const int id,const gchar * chr,const void * data,tvbparse_action_t before_cb,tvbparse_action_t after_cb)154 tvbparse_wanted_t* tvbparse_char(const int id,
155 const gchar* chr,
156 const void* data,
157 tvbparse_action_t before_cb,
158 tvbparse_action_t after_cb) {
159 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
160
161 w->condition = cond_char;
162 w->id = id;
163 w->control.str = chr;
164 w->len = 1;
165 w->data = data;
166 w->before = before_cb;
167 w->after = after_cb;
168
169 return w;
170 }
171
cond_chars_common(tvbparse_t * tt,int offset,const tvbparse_wanted_t * wanted,tvbparse_elem_t ** tok)172 static int cond_chars_common(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
173 guint length = 0;
174 int start = offset;
175 int left = tt->end_offset - offset;
176
177 #ifdef TVBPARSE_DEBUG
178 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHARS) ws_warning("cond_chars_common: control='%s'",wanted->control.str);
179 #endif
180
181 if ( offset + (int)wanted->min > tt->end_offset )
182 return -1;
183
184 left = left < (int) wanted->max ? left : (int) wanted->max;
185
186 while( left > 0 ) {
187 guint8 t = tvb_get_guint8(tt->tvb,offset++);
188
189 if (!wanted->control.str[t])
190 break;
191
192 length++;
193 left--;
194 };
195
196 if (length < wanted->min) {
197 return -1;
198 } else {
199 *tok = new_tok(tt,wanted->id,start,length,wanted);
200 #ifdef TVBPARSE_DEBUG
201 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHARS) ws_warning("cond_chars_common: GOT len=%i",length);
202 #endif
203 return length;
204 }
205 }
206
tvbparse_chars(const int id,const guint min_len,const guint max_len,const gchar * chr,const void * data,tvbparse_action_t before_cb,tvbparse_action_t after_cb)207 tvbparse_wanted_t* tvbparse_chars(const int id,
208 const guint min_len,
209 const guint max_len,
210 const gchar* chr,
211 const void* data,
212 tvbparse_action_t before_cb,
213 tvbparse_action_t after_cb)
214 {
215 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
216 char *accept_str;
217 gsize i;
218
219 accept_str = (char *)wmem_alloc(wmem_epan_scope(), 256);
220 memset(accept_str, 0x00, 256);
221 for (i = 0; chr[i]; i++)
222 accept_str[(unsigned)chr[i]] = (char)0xFF;
223
224 w->condition = cond_chars_common;
225 w->id = id;
226 w->control.str = accept_str;
227 w->min = min_len ? min_len : 1;
228 w->max = max_len ? max_len : G_MAXINT/2;
229 w->data = data;
230 w->before = before_cb;
231 w->after = after_cb;
232
233 return w;
234 }
235
236
cond_not_char(tvbparse_t * tt,const int offset,const tvbparse_wanted_t * wanted,tvbparse_elem_t ** tok)237 static int cond_not_char(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
238 gchar c, t;
239 guint i;
240 gboolean not_matched = FALSE;
241
242 #ifdef TVBPARSE_DEBUG
243 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NOT_CHAR) ws_warning("cond_not_char: control='%s'",wanted->control.str);
244 #endif
245
246 if ( offset >= tt->end_offset ) {
247 return -1;
248 }
249
250 t = (gchar) tvb_get_guint8(tt->tvb,offset);
251
252 for(i = 0; (c = wanted->control.str[i]); i++) {
253 if ( c == t ) {
254 not_matched = TRUE;
255 }
256 }
257
258 if (not_matched) {
259 return -1;
260 } else {
261 *tok = new_tok(tt,wanted->id,offset,1,wanted);
262 #ifdef TVBPARSE_DEBUG
263 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NOT_CHAR) ws_warning("cond_not_char: GOT='%c'",t);
264 #endif
265 return 1;
266 }
267 }
268
tvbparse_not_char(const int id,const gchar * chr,const void * data,tvbparse_action_t before_cb,tvbparse_action_t after_cb)269 tvbparse_wanted_t* tvbparse_not_char(const int id,
270 const gchar* chr,
271 const void* data,
272 tvbparse_action_t before_cb,
273 tvbparse_action_t after_cb) {
274 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
275
276 w->condition = cond_not_char;
277 w->id = id;
278 w->control.str = chr;
279 w->data = data;
280 w->before = before_cb;
281 w->after = after_cb;
282
283 return w;
284 }
285
tvbparse_not_chars(const int id,const guint min_len,const guint max_len,const gchar * chr,const void * data,tvbparse_action_t before_cb,tvbparse_action_t after_cb)286 tvbparse_wanted_t* tvbparse_not_chars(const int id,
287 const guint min_len,
288 const guint max_len,
289 const gchar* chr,
290 const void* data,
291 tvbparse_action_t before_cb,
292 tvbparse_action_t after_cb)
293 {
294 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
295 char *accept_str;
296 gsize i;
297
298 /* cond_chars_common() use accept string, so mark all elements with, and later unset from reject */
299 accept_str = (char *)wmem_alloc(wmem_epan_scope(), 256);
300 memset(accept_str, 0xFF, 256);
301 for (i = 0; chr[i]; i++)
302 accept_str[(unsigned) chr[i]] = '\0';
303
304 w->condition = cond_chars_common;
305 w->id = id;
306 w->control.str = accept_str;
307 w->len = 0;
308 w->min = min_len ? min_len : 1;
309 w->max = max_len ? max_len : G_MAXINT/2;
310 w->data = data;
311 w->before = before_cb;
312 w->after = after_cb;
313
314 return w;
315 }
316
317
cond_string(tvbparse_t * tt,const int offset,const tvbparse_wanted_t * wanted,tvbparse_elem_t ** tok)318 static int cond_string(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
319 int len = wanted->len;
320 #ifdef TVBPARSE_DEBUG
321 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_STRING) ws_warning("cond_string: control='%s'",wanted->control.str);
322 #endif
323
324 if ( offset + wanted->len > tt->end_offset )
325 return -1;
326
327 if ( tvb_strneql(tt->tvb, offset, wanted->control.str, len) == 0 ) {
328 *tok = new_tok(tt,wanted->id,offset,len,wanted);
329 #ifdef TVBPARSE_DEBUG
330 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_STRING) ws_warning("cond_string: GOT len=%i",len);
331 #endif
332 return len;
333 } else {
334 return -1;
335 }
336 }
337
tvbparse_string(const int id,const gchar * str,const void * data,tvbparse_action_t before_cb,tvbparse_action_t after_cb)338 tvbparse_wanted_t* tvbparse_string(const int id,
339 const gchar* str,
340 const void* data,
341 tvbparse_action_t before_cb,
342 tvbparse_action_t after_cb) {
343 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
344
345 w->condition = cond_string;
346 w->id = id;
347 w->control.str = str;
348 w->len = (int) strlen(str);
349 w->data = data;
350 w->before = before_cb;
351 w->after = after_cb;
352
353 return w;
354 }
355
cond_casestring(tvbparse_t * tt,const int offset,const tvbparse_wanted_t * wanted,tvbparse_elem_t ** tok)356 static int cond_casestring(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
357 int len = wanted->len;
358 #ifdef TVBPARSE_DEBUG
359 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CASESTRING) ws_warning("cond_casestring: control='%s'",wanted->control.str);
360 #endif
361
362 if ( offset + len > tt->end_offset )
363 return -1;
364
365 if ( tvb_strncaseeql(tt->tvb, offset, wanted->control.str, len) == 0 ) {
366 *tok = new_tok(tt,wanted->id,offset,len,wanted);
367 #ifdef TVBPARSE_DEBUG
368 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CASESTRING) ws_warning("cond_casestring: GOT len=%i",len);
369 #endif
370 return len;
371 } else {
372 *tok = NULL;
373 return -1;
374 }
375 }
376
tvbparse_casestring(const int id,const gchar * str,const void * data,tvbparse_action_t before_cb,tvbparse_action_t after_cb)377 tvbparse_wanted_t* tvbparse_casestring(const int id,
378 const gchar* str,
379 const void* data,
380 tvbparse_action_t before_cb,
381 tvbparse_action_t after_cb) {
382 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
383
384 w->condition = cond_casestring;
385 w->id = id;
386 w->control.str = str;
387 w->len = (int) strlen(str);
388 w->data = data;
389 w->before = before_cb;
390 w->after = after_cb;
391
392 return w;
393 }
394
cond_one_of(tvbparse_t * tt,const int offset,const tvbparse_wanted_t * wanted,tvbparse_elem_t ** tok)395 static int cond_one_of(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
396 guint i;
397 #ifdef TVBPARSE_DEBUG
398 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_ONEOF) ws_warning("cond_one_of: START");
399 #endif
400
401 if ( offset > tt->end_offset )
402 return -1;
403
404 if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
405 return -1;
406
407 for(i=0; i < wanted->control.elems->len; i++) {
408 tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_ptr_array_index(wanted->control.elems,i);
409 tvbparse_elem_t* new_elem = NULL;
410 int curr_len;
411
412 if ( offset + w->len > tt->end_offset )
413 continue;
414
415 curr_len = w->condition(tt, offset, w, &new_elem);
416
417 if (curr_len >= 0) {
418 *tok = new_tok(tt, wanted->id, new_elem->offset, new_elem->len, wanted);
419 (*tok)->sub = new_elem;
420 #ifdef TVBPARSE_DEBUG
421 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_ONEOF) ws_warning("cond_one_of: GOT len=%i",curr_len);
422 #endif
423 tt->recursion_depth--;
424 return curr_len;
425 }
426 }
427
428 tt->recursion_depth--;
429 return -1;
430 }
431
432 static gboolean
tvbparse_wanted_cleanup_cb(wmem_allocator_t * allocator _U_,wmem_cb_event_t event _U_,void * user_data)433 tvbparse_wanted_cleanup_cb(wmem_allocator_t* allocator _U_, wmem_cb_event_t event _U_, void *user_data)
434 {
435 tvbparse_wanted_t* w = (tvbparse_wanted_t *)user_data;
436 g_ptr_array_free(w->control.elems, TRUE);
437 return FALSE;
438 }
439
tvbparse_set_oneof(const int id,const void * data,tvbparse_action_t before_cb,tvbparse_action_t after_cb,...)440 tvbparse_wanted_t* tvbparse_set_oneof(const int id,
441 const void* data,
442 tvbparse_action_t before_cb,
443 tvbparse_action_t after_cb,
444 ...) {
445 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
446 tvbparse_t* el;
447 va_list ap;
448
449 w->condition = cond_one_of;
450 w->id = id;
451 w->data = data;
452 w->before = before_cb;
453 w->after = after_cb;
454 w->control.elems = g_ptr_array_new();
455 wmem_register_callback(wmem_epan_scope(), tvbparse_wanted_cleanup_cb, w);
456
457 va_start(ap,after_cb);
458
459 while(( el = va_arg(ap,tvbparse_t*) )) {
460 g_ptr_array_add(w->control.elems,el);
461 };
462
463 va_end(ap);
464
465 return w;
466 }
467
cond_hash(tvbparse_t * tt,const int offset,const tvbparse_wanted_t * wanted,tvbparse_elem_t ** tok)468 static int cond_hash(tvbparse_t* tt, const int offset, const tvbparse_wanted_t* wanted, tvbparse_elem_t** tok) {
469 int key_len;
470 gchar* key = NULL;
471 tvbparse_elem_t* key_elem = NULL;
472 tvbparse_wanted_t* value_wanted = NULL;
473 int value_len;
474 tvbparse_elem_t* value_elem = NULL;
475 int tot_len;
476 tvbparse_elem_t* ret_tok;
477
478 #ifdef TVBPARSE_DEBUG
479 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) ws_warning("cond_hash: START");
480 #endif
481
482 if ( offset > tt->end_offset )
483 return -1;
484
485 if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
486 return -1;
487
488 key_len = wanted->control.hash.key->condition(tt, offset, wanted->control.hash.key, &key_elem);
489
490 if (key_len < 0) {
491 tt->recursion_depth--;
492 return -1;
493 }
494
495 key = tvb_get_string_enc(tt->scope,key_elem->parser->tvb,key_elem->offset,key_elem->len, ENC_ASCII);
496 #ifdef TVBPARSE_DEBUG
497 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) ws_warning("cond_hash: got key='%s'",key);
498 #endif
499
500 if ((value_wanted = (tvbparse_wanted_t *)wmem_map_lookup(wanted->control.hash.table,key))) {
501 value_len = value_wanted->condition(tt, offset + key_len, value_wanted, &value_elem);
502 } else if (wanted->control.hash.other) {
503 value_len = wanted->control.hash.other->condition(tt, offset+key_len, wanted->control.hash.other, &value_elem);
504 if (value_len < 0) {
505 tt->recursion_depth--;
506 return -1;
507 }
508 } else {
509 tt->recursion_depth--;
510 return -1;
511 }
512
513 tt->recursion_depth--;
514
515 tot_len = key_len + value_len;
516
517 ret_tok = new_tok(tt, value_elem->id, offset, tot_len, wanted);
518 ret_tok->sub = key_elem;
519 ret_tok->sub->last->next = value_elem;
520
521 *tok = ret_tok;
522 #ifdef TVBPARSE_DEBUG
523 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) ws_warning("cond_hash: GOT len=%i",tot_len);
524 #endif
525
526 return tot_len;
527 }
528
tvbparse_hashed(const int id,const void * data,tvbparse_action_t before_cb,tvbparse_action_t after_cb,tvbparse_wanted_t * key,tvbparse_wanted_t * other,...)529 tvbparse_wanted_t* tvbparse_hashed(const int id,
530 const void* data,
531 tvbparse_action_t before_cb,
532 tvbparse_action_t after_cb,
533 tvbparse_wanted_t* key,
534 tvbparse_wanted_t* other,
535 ...) {
536 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
537 gchar* name;
538 tvbparse_wanted_t* el;
539 va_list ap;
540
541 w->condition = cond_hash;
542 w->id = id;
543 w->data = data;
544 w->before = before_cb;
545 w->after = after_cb;
546 w->control.hash.table = wmem_map_new(wmem_epan_scope(), g_str_hash,g_str_equal);
547 w->control.hash.key = key;
548 w->control.hash.other = other;
549
550 va_start(ap,other);
551
552 while(( name = va_arg(ap,gchar*) )) {
553 el = va_arg(ap,tvbparse_wanted_t*);
554 wmem_map_insert(w->control.hash.table,name,el);
555 }
556
557 va_end(ap);
558
559 return w;
560 }
561
tvbparse_hashed_add(tvbparse_wanted_t * w,...)562 void tvbparse_hashed_add(tvbparse_wanted_t* w, ...) {
563 tvbparse_wanted_t* el;
564 va_list ap;
565 gchar* name;
566
567 va_start(ap,w);
568
569 while (( name = va_arg(ap,gchar*) )) {
570 el = va_arg(ap,tvbparse_wanted_t*);
571 wmem_map_insert(w->control.hash.table,name,el);
572 }
573
574 va_end(ap);
575 }
576
cond_seq(tvbparse_t * tt,int offset,const tvbparse_wanted_t * wanted,tvbparse_elem_t ** tok)577 static int cond_seq(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
578 guint i;
579 int len = 0;
580 int start = offset;
581 tvbparse_elem_t* ret_tok = NULL;
582
583 #ifdef TVBPARSE_DEBUG
584 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SEQ) ws_warning("cond_seq: START");
585 #endif
586
587 if ( offset > tt->end_offset )
588 return -1;
589
590 if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
591 return -1;
592
593 for(i=0; i < wanted->control.elems->len; i++) {
594 tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_ptr_array_index(wanted->control.elems,i);
595 tvbparse_elem_t* new_elem = NULL;
596
597 if ( offset + w->len > tt->end_offset ) {
598 tt->recursion_depth--;
599 return -1;
600 }
601
602 len = w->condition(tt, offset, w, &new_elem);
603
604 if (len >= 0) {
605 if (ret_tok) {
606 if (new_elem->len)
607 ret_tok->len = (new_elem->offset - ret_tok->offset) + new_elem->len;
608 ret_tok->sub->last->next = new_elem;
609 ret_tok->sub->last = new_elem;
610 } else {
611 ret_tok = new_tok(tt, wanted->id, new_elem->offset, new_elem->len, wanted);
612 ret_tok->sub = new_elem;
613 new_elem->last = new_elem;
614 }
615 } else {
616 tt->recursion_depth--;
617 return -1;
618 }
619
620 offset += len;
621 offset += ignore_fcn(tt,offset);
622 }
623
624 tt->recursion_depth--;
625
626 *tok = ret_tok;
627
628 #ifdef TVBPARSE_DEBUG
629 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SEQ) ws_warning("cond_seq: GOT len=%i",offset - start);
630 #endif
631
632 return offset - start;
633 }
634
635
tvbparse_set_seq(const int id,const void * data,tvbparse_action_t before_cb,tvbparse_action_t after_cb,...)636 tvbparse_wanted_t* tvbparse_set_seq(const int id,
637 const void* data,
638 tvbparse_action_t before_cb,
639 tvbparse_action_t after_cb,
640 ...) {
641 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
642 tvbparse_wanted_t* el = NULL;
643 va_list ap;
644
645 w->condition = cond_seq;
646 w->id = id;
647 w->data = data;
648 w->before = before_cb;
649 w->after = after_cb;
650 w->control.elems = g_ptr_array_new();
651 wmem_register_callback(wmem_epan_scope(), tvbparse_wanted_cleanup_cb, w);
652
653 va_start(ap,after_cb);
654
655 while(( el = va_arg(ap,tvbparse_wanted_t*) )) {
656 g_ptr_array_add(w->control.elems,el);
657 };
658
659 va_end(ap);
660 return w;
661 }
662
cond_some(tvbparse_t * tt,int offset,const tvbparse_wanted_t * wanted,tvbparse_elem_t ** tok)663 static int cond_some(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
664 guint got_so_far = 0;
665 int start = offset;
666 tvbparse_elem_t* ret_tok = NULL;
667 #ifdef TVBPARSE_DEBUG
668 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SOME) ws_warning("cond_some: START");
669 #endif
670
671 if ( offset > tt->end_offset )
672 return -1;
673
674 if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
675 return -1;
676
677 if ( wanted->min == 0 ) {
678 ret_tok = new_tok(tt,wanted->id,offset,0,wanted);
679 }
680
681 while (got_so_far < wanted->max) {
682 tvbparse_elem_t* new_elem = NULL;
683 int consumed;
684
685 if ( offset > tt->end_offset ) {
686 tt->recursion_depth--;
687 return -1;
688 }
689
690 consumed = wanted->control.subelem->condition(tt, offset, wanted->control.subelem, &new_elem);
691
692 if(consumed >= 0) {
693 if (ret_tok) {
694 if (new_elem->len)
695 ret_tok->len = (new_elem->offset - ret_tok->offset) + new_elem->len;
696
697 if (ret_tok->sub) {
698 ret_tok->sub->last->next = new_elem;
699 ret_tok->sub->last = new_elem;
700 } else {
701 ret_tok->sub = new_elem;
702 }
703 } else {
704 ret_tok = new_tok(tt, wanted->id, new_elem->offset, new_elem->len, wanted);
705 ret_tok->sub = new_elem;
706 }
707 } else {
708 break;
709 }
710
711 offset += consumed;
712 got_so_far++;
713 }
714
715 tt->recursion_depth--;
716
717 #ifdef TVBPARSE_DEBUG
718 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SOME) ws_warning("cond_some: got num=%u",got_so_far);
719 #endif
720
721 if(got_so_far < wanted->min) {
722 return -1;
723 }
724
725 *tok = ret_tok;
726 #ifdef TVBPARSE_DEBUG
727 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SOME) ws_warning("cond_some: GOT len=%i",offset - start);
728 #endif
729 return offset - start;
730 }
731
tvbparse_some(const int id,const guint from,const guint to,const void * data,tvbparse_action_t before_cb,tvbparse_action_t after_cb,const tvbparse_wanted_t * el)732 tvbparse_wanted_t* tvbparse_some(const int id,
733 const guint from,
734 const guint to,
735 const void* data,
736 tvbparse_action_t before_cb,
737 tvbparse_action_t after_cb,
738 const tvbparse_wanted_t* el) {
739
740 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
741
742 ws_assert(from <= to);
743
744 w->condition = cond_some;
745 w->id = id;
746 w->min = from;
747 w->max = to;
748 w->data = data;
749 w->before = before_cb;
750 w->after = after_cb;
751 w->control.subelem = el;
752
753 return w;
754 }
755
756
cond_until(tvbparse_t * tt,const int offset,const tvbparse_wanted_t * wanted,tvbparse_elem_t ** tok)757 static int cond_until(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
758 tvbparse_elem_t* new_elem = NULL;
759 int len = 0;
760 int target_offset = offset;
761 #ifdef TVBPARSE_DEBUG
762 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) ws_warning("cond_until: START");
763 #endif
764
765 if ( offset + wanted->control.until.subelem->len > tt->end_offset )
766 return -1;
767
768 if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
769 return -1;
770
771 do {
772 len = wanted->control.until.subelem->condition(tt, target_offset++, wanted->control.until.subelem, &new_elem);
773 } while(len < 0 && target_offset+1 < tt->end_offset);
774
775 tt->recursion_depth--;
776
777 if (len >= 0) {
778
779 new_elem->id = wanted->id;
780 new_elem->next = NULL;
781 new_elem->last = NULL;
782 new_elem->wanted = wanted;
783 new_elem->offset = offset;
784
785 (*tok) = new_elem;
786
787 switch (wanted->control.until.mode) {
788 case TP_UNTIL_INCLUDE:
789 new_elem->len = target_offset - offset - 1 + len;
790 #ifdef TVBPARSE_DEBUG
791 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) ws_warning("cond_until: GOT len=%i",target_offset - offset -1 + len);
792 #endif
793 return target_offset - offset -1 + len;
794 case TP_UNTIL_SPEND:
795 new_elem->len = target_offset - offset - 1;
796 #ifdef TVBPARSE_DEBUG
797 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) ws_warning("cond_until: GOT len=%i",target_offset - offset -1 + len);
798 #endif
799 return target_offset - offset - 1 + len;
800 case TP_UNTIL_LEAVE:
801 new_elem->len = target_offset - offset - 1;
802 #ifdef TVBPARSE_DEBUG
803 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) ws_warning("cond_until: GOT len=%i",target_offset - offset -1);
804 #endif
805 return target_offset - offset -1;
806 default:
807 DISSECTOR_ASSERT_NOT_REACHED();
808 return -1;
809 }
810
811 } else {
812 return -1;
813 }
814 }
815
tvbparse_until(const int id,const void * data,tvbparse_action_t before_cb,tvbparse_action_t after_cb,const tvbparse_wanted_t * el,until_mode_t until_mode)816 tvbparse_wanted_t* tvbparse_until(const int id,
817 const void* data,
818 tvbparse_action_t before_cb,
819 tvbparse_action_t after_cb,
820 const tvbparse_wanted_t* el,
821 until_mode_t until_mode) {
822 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
823
824 w->condition = cond_until;
825 w->control.until.mode = until_mode;
826 w->control.until.subelem = el;
827 w->id = id;
828 w->data = data;
829 w->before = before_cb;
830 w->after = after_cb;
831
832 return w;
833 }
834
tvbparse_quoted(const int id,const void * data,tvbparse_action_t before_cb,tvbparse_action_t after_cb,const char quote,const char esc)835 tvbparse_wanted_t* tvbparse_quoted(const int id,
836 const void* data,
837 tvbparse_action_t before_cb,
838 tvbparse_action_t after_cb,
839 const char quote,
840 const char esc) {
841
842 gchar* esc_quot = wmem_strdup_printf(wmem_epan_scope(), "%c%c",esc,quote);
843 gchar* quot = wmem_strdup_printf(wmem_epan_scope(), "%c",quote);
844 tvbparse_wanted_t* want_quot = tvbparse_char(-1,quot,NULL,NULL,NULL);
845
846 return tvbparse_set_oneof(id, data, before_cb, after_cb,
847 tvbparse_set_seq(-1, NULL, NULL, NULL,
848 want_quot,
849 tvbparse_set_seq(-1,NULL,NULL,NULL,
850 tvbparse_set_oneof(-1, NULL, NULL, NULL,
851 tvbparse_string(-1,esc_quot,NULL,NULL,NULL),
852 tvbparse_not_chars(-1,0,0,quot,NULL,NULL,NULL),
853 NULL),
854 NULL),
855 want_quot,
856 NULL),
857 tvbparse_set_seq(-1, NULL, NULL, NULL,
858 want_quot,
859 want_quot,
860 NULL),
861 NULL);
862 }
863
tvbparse_shrink_token_cb(void * tvbparse_data _U_,const void * wanted_data _U_,tvbparse_elem_t * tok)864 void tvbparse_shrink_token_cb(void* tvbparse_data _U_,
865 const void* wanted_data _U_,
866 tvbparse_elem_t* tok) {
867 tok->offset += 1;
868 tok->len -= 2;
869 }
870
tvbparse_init(wmem_allocator_t * scope,tvbuff_t * tvb,const int offset,int len,void * data,const tvbparse_wanted_t * ignore)871 tvbparse_t* tvbparse_init(wmem_allocator_t *scope,
872 tvbuff_t* tvb,
873 const int offset,
874 int len,
875 void* data,
876 const tvbparse_wanted_t* ignore) {
877 tvbparse_t* tt = wmem_new(scope, tvbparse_t);
878
879 #ifdef TVBPARSE_DEBUG
880 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_TT) ws_warning("tvbparse_init: offset=%i len=%i",offset,len);
881 #endif
882
883 tt->scope = scope;
884 tt->tvb = tvb;
885 tt->offset = offset;
886 len = (len == -1) ? (int) tvb_captured_length(tvb) : len;
887 tt->end_offset = offset + len;
888 tt->data = data;
889 tt->ignore = ignore;
890 tt->recursion_depth = 0;
891 return tt;
892 }
893
tvbparse_reset(tvbparse_t * tt,const int offset,int len)894 gboolean tvbparse_reset(tvbparse_t* tt,
895 const int offset,
896 int len) {
897
898 #ifdef TVBPARSE_DEBUG
899 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_TT) ws_warning("tvbparse_init: offset=%i len=%i",offset,len);
900 #endif
901
902 len = (len == -1) ? (int) tvb_captured_length(tt->tvb) : len;
903
904 if( tvb_captured_length_remaining(tt->tvb, offset) >= len) {
905 tt->offset = offset;
906 tt->end_offset = offset + len;
907 return TRUE;
908 } else {
909 return FALSE;
910 }
911 }
912
tvbparse_curr_offset(tvbparse_t * tt)913 guint tvbparse_curr_offset(tvbparse_t* tt) {
914 return tt->offset;
915 }
916
execute_callbacks(tvbparse_t * tt,tvbparse_elem_t * curr)917 static void execute_callbacks(tvbparse_t* tt, tvbparse_elem_t* curr) {
918 wmem_stack_t *stack = wmem_stack_new(tt->scope);
919
920 while (curr) {
921 if(curr->wanted->before) {
922 #ifdef TVBPARSE_DEBUG
923 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) ws_warning("execute_callbacks: BEFORE: id=%i offset=%i len=%i",curr->id,curr->offset,curr->len);
924 #endif
925 curr->wanted->before(tt->data, curr->wanted->data, curr);
926 }
927
928 if(curr->sub) {
929 wmem_stack_push(stack, curr);
930 curr = curr->sub;
931 continue;
932 } else {
933 #ifdef TVBPARSE_DEBUG
934 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) ws_warning("execute_callbacks: AFTER: id=%i offset=%i len=%i",curr->id,curr->offset,curr->len);
935 #endif
936 if(curr->wanted->after) curr->wanted->after(tt->data, curr->wanted->data, curr);
937 }
938
939 curr = curr->next;
940
941 while( !curr && wmem_stack_count(stack) > 0 ) {
942 curr = (tvbparse_elem_t *)wmem_stack_pop(stack);
943 #ifdef TVBPARSE_DEBUG
944 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) ws_warning("execute_callbacks: AFTER: id=%i offset=%i len=%i",curr->id,curr->offset,curr->len);
945 #endif
946 if( curr->wanted->after ) curr->wanted->after(tt->data, curr->wanted->data, curr);
947 curr = curr->next;
948 }
949 }
950
951 }
952
tvbparse_peek(tvbparse_t * tt,const tvbparse_wanted_t * wanted)953 gboolean tvbparse_peek(tvbparse_t* tt,
954 const tvbparse_wanted_t* wanted) {
955 tvbparse_elem_t* tok = NULL;
956 int consumed;
957 int offset = tt->offset;
958
959 #ifdef TVBPARSE_DEBUG
960 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) ws_warning("tvbparse_peek: ENTER offset=%i",offset);
961 #endif
962
963 offset += ignore_fcn(tt,offset);
964
965 #ifdef TVBPARSE_DEBUG
966 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) ws_warning("tvbparse_peek: after ignore offset=%i",offset);
967 #endif
968
969 consumed = wanted->condition(tt,offset,wanted,&tok);
970
971 if (consumed >= 0) {
972 #ifdef TVBPARSE_DEBUG
973 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) ws_warning("tvbparse_peek: GOT len=%i",consumed);
974 #endif
975 return TRUE;
976 } else {
977 #ifdef TVBPARSE_DEBUG
978 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) ws_warning("tvbparse_peek: NOT GOT");
979 #endif
980 return FALSE;
981 }
982
983 }
984
tvbparse_get(tvbparse_t * tt,const tvbparse_wanted_t * wanted)985 tvbparse_elem_t* tvbparse_get(tvbparse_t* tt,
986 const tvbparse_wanted_t* wanted) {
987 tvbparse_elem_t* tok = NULL;
988 int consumed;
989 int offset = tt->offset;
990
991 #ifdef TVBPARSE_DEBUG
992 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) ws_warning("tvbparse_get: ENTER offset=%i",offset);
993 #endif
994
995 offset += ignore_fcn(tt,offset);
996
997 #ifdef TVBPARSE_DEBUG
998 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) ws_warning("tvbparse_get: after ignore offset=%i",offset);
999 #endif
1000
1001 consumed = wanted->condition(tt,offset,wanted,&tok);
1002
1003 if (consumed >= 0) {
1004 #ifdef TVBPARSE_DEBUG
1005 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) ws_warning("tvbparse_get: GOT len=%i",consumed);
1006 #endif
1007 execute_callbacks(tt,tok);
1008 tt->offset = offset + consumed;
1009 #ifdef TVBPARSE_DEBUG
1010 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) ws_warning("tvbparse_get: DONE offset=%i", tt->offset);
1011 #endif
1012 return tok;
1013 } else {
1014 return NULL;
1015 }
1016
1017 }
1018
1019
tvbparse_find(tvbparse_t * tt,const tvbparse_wanted_t * wanted)1020 tvbparse_elem_t* tvbparse_find(tvbparse_t* tt, const tvbparse_wanted_t* wanted) {
1021 tvbparse_elem_t* tok = NULL;
1022 int len = 0;
1023 int offset = tt->offset;
1024 int target_offset = offset -1;
1025
1026 #ifdef TVBPARSE_DEBUG
1027 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) ws_warning("tvbparse_get: ENTER offset=%i", tt->offset);
1028 #endif
1029
1030 do {
1031 len = wanted->condition(tt, target_offset+1, wanted, &tok);
1032 } while(len < 0 && ++target_offset < tt->end_offset);
1033
1034 if (len >= 0) {
1035 #ifdef TVBPARSE_DEBUG
1036 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) ws_warning("tvbparse_get: FOUND offset=%i len=%i", target_offset,len);
1037 #endif
1038 execute_callbacks(tt,tok);
1039 tt->offset = target_offset + len;
1040
1041 #ifdef TVBPARSE_DEBUG
1042 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) ws_warning("tvbparse_get: DONE offset=%i", tt->offset);
1043 #endif
1044 return tok;
1045 } else {
1046 #ifdef TVBPARSE_DEBUG
1047 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) ws_warning("tvbparse_get: NOT FOUND");
1048 #endif
1049 return NULL;
1050 }
1051 }
1052
1053 struct _elem_tree_stack_frame {
1054 proto_tree* tree;
1055 tvbparse_elem_t* elem;
1056 };
1057
tvbparse_tree_add_elem(proto_tree * tree,tvbparse_elem_t * curr)1058 void tvbparse_tree_add_elem(proto_tree* tree, tvbparse_elem_t* curr) {
1059 wmem_stack_t *stack = wmem_stack_new(curr->parser->scope);
1060 struct _elem_tree_stack_frame* frame = wmem_new(curr->parser->scope, struct _elem_tree_stack_frame);
1061 proto_item* pi;
1062 frame->tree = tree;
1063 frame->elem = curr;
1064
1065 while (curr) {
1066 pi = proto_tree_add_format_text(frame->tree,curr->parser->tvb,curr->offset,curr->len);
1067
1068 if(curr->sub) {
1069 frame->elem = curr;
1070 wmem_stack_push(stack, frame);
1071 frame = wmem_new(curr->parser->scope, struct _elem_tree_stack_frame);
1072 frame->tree = proto_item_add_subtree(pi,0);
1073 curr = curr->sub;
1074 continue;
1075 }
1076
1077 curr = curr->next;
1078
1079 while( !curr && wmem_stack_count(stack) > 0 ) {
1080 frame = (struct _elem_tree_stack_frame *)wmem_stack_pop(stack);
1081 curr = frame->elem->next;
1082 }
1083
1084 }
1085 }
1086
1087 /*
1088 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1089 *
1090 * Local variables:
1091 * c-basic-offset: 4
1092 * tab-width: 8
1093 * indent-tabs-mode: nil
1094 * End:
1095 *
1096 * vi: set shiftwidth=4 tabstop=8 expandtab:
1097 * :indentSize=4:tabSize=8:noTabs=true:
1098 */
1099