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