TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags
[wireshark-sm.git] / wiretap / k12text.l
blob0eb5139b3a9c1747d3b287a1f4f46a3269c5b17e
1 %top {
2 /* Include this before everything else, for various large-file definitions */
3 #include "config.h"
4 #include <wireshark.h>
7 /*
8  * We want a reentrant scanner.
9  */
10 %option reentrant
13  * We don't use input, so don't generate code for it.
14  */
15 %option noinput
18  * We don't use unput, so don't generate code for it.
19  */
20 %option nounput
23  * We don't read interactively from the terminal.
24  */
25 %option never-interactive
28  * We want to stop processing when we get to the end of the input.
29  */
30 %option noyywrap
33  * The type for the state we keep for a scanner.
34  */
35 %option extra-type="k12text_state_t *"
38  * Prefix scanner routines with "k12text_" rather than "yy", so this scanner
39  * can coexist with other scanners.
40  */
41 %option prefix="k12text_"
43 /* Options useful for debugging                         */
44 /* noline:  Prevent generation of #line directives      */
45 /*          Seems to be required when using the         */
46 /*          Windows VS debugger so as to be able        */
47 /*          to properly step through the code and       */
48 /*          set breakpoints & etc using the             */
49 /*          k12text.c file rather than the              */
50 /*          k12text.l file                              */
51 /*      XXX: %option noline gives an error message:     */
52 /*          "unrecognized %option: line"                */
53 /*          with flex 2.5.35; the --noline              */
54 /*          command-line option works OK.               */
55 /*                                                      */
56 /* debug:   Do output of "rule acceptance" info         */
57 /*          during parse                                */
58 /*                                                      */
59 /* %option noline  */
60 /* %option debug   */
63  * We have to override the memory allocators so that we don't get
64  * "unused argument" warnings from the yyscanner argument (which
65  * we don't use, as we have a global memory allocator).
66  *
67  * We provide, as macros, our own versions of the routines generated by Flex,
68  * which just call malloc()/realloc()/free() (as the Flex versions do),
69  * discarding the extra argument.
70  */
71 %option noyyalloc
72 %option noyyrealloc
73 %option noyyfree
76 /* k12text.l
77  *
78  * Wiretap Library
79  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
80  *
81  * SPDX-License-Identifier: GPL-2.0-or-later
82  */
84  /*
85   * TODO:
86   *   - fix timestamps after midnight
87   *   - verify encapsulations
88   */
90 #include <stdlib.h>
91 #include <string.h>
92 #include <errno.h>
93 #include <time.h>
94 #include "wtap-int.h"
95 #include "wtap.h"
96 #include "file_wrappers.h"
97 #include <wsutil/buffer.h>
98 #include "k12.h"
100 #ifndef HAVE_UNISTD_H
101 #define YY_NO_UNISTD_H
102 #endif
105  * Disable diagnostics in the code generated by Flex.
106  */
107 DIAG_OFF_FLEX()
110  * State kept by the scanner.
111  */
112 typedef struct {
113         FILE_T fh;
114         int err;
115         char *err_info;
116         int start_state;
118         unsigned g_h;
119         unsigned g_m;
120         unsigned g_s;
121         unsigned g_ms;
122         unsigned g_ns;
123         int g_encap;
124         uint8_t *bb;
125         unsigned ii;
126         bool is_k12text;
127         bool at_eof;
128         unsigned junk_chars;
129         char* error_str;
130         uint64_t file_bytes_read;
131         bool ok_frame;
132 } k12text_state_t;
134 #define KERROR(text) do { yyextra->error_str = g_strdup(text); yyterminate(); } while(0)
135 #define SET_HOURS(text) yyextra->g_h = (unsigned) strtoul(text,NULL,10)
136 #define SET_MINUTES(text) yyextra->g_m = (unsigned) strtoul(text,NULL,10)
137 #define SET_SECONDS(text) yyextra->g_s = (unsigned) strtoul(text,NULL,10)
138 #define SET_MS(text) yyextra->g_ms = (unsigned) strtoul(text,NULL,10)
139 #define SET_NS(text) yyextra->g_ns = (unsigned) strtoul(text,NULL,10)
140 #define ADD_BYTE(text) do {if (yyextra->ii >= WTAP_MAX_PACKET_SIZE_STANDARD) {KERROR("frame too large");} yyextra->bb[yyextra->ii++] = (uint8_t)strtoul(text,NULL,16); } while(0)
141 #define FINALIZE_FRAME() do { yyextra->ok_frame = true; } while (0)
142 /*~ #define ECHO*/
143 #define YY_USER_ACTION yyextra->file_bytes_read += yyleng;
144 #define YY_USER_INIT { \
145         k12text_state_t *scanner_state = k12text_get_extra(yyscanner); \
146         BEGIN(scanner_state->start_state); \
148 #define YY_INPUT(buf,result,max_size) { \
149         k12text_state_t *scanner_state = k12text_get_extra(yyscanner); \
150         int c = file_getc(scanner_state->fh); \
151         if (c == EOF) { \
152                 scanner_state->err = file_error(scanner_state->fh, \
153                     &scanner_state->err_info); \
154                 if (scanner_state->err == 0) \
155                         scanner_state->err = WTAP_ERR_SHORT_READ; \
156                 result = YY_NULL; \
157         } else { \
158                 buf[0] = c; \
159                 result = 1; \
160         } \
162 #define MAX_JUNK 400000
163 #define ECHO
166  * Private per-file data.
167  */
168 typedef struct {
169         /*
170          * The file position after the end of the previous frame processed by
171          * k12text_read.
172          *
173          * We need to keep this around, and seek to it at the beginning of
174          * each call to k12text_read(), since the lexer undoubtedly did some
175          * amount of look-ahead when processing the previous frame.
176          */
177         int64_t next_frame_offset;
178 } k12text_t;
181  * Sleazy hack to suppress compiler warnings in yy_fatal_error().
182  */
183 #define YY_EXIT_FAILURE ((void)yyscanner, 2)
186  * Macros for the allocators, to discard the extra argument.
187  */
188 #define k12text_alloc(size, yyscanner)          (void *)malloc(size)
189 #define k12text_realloc(ptr, size, yyscanner)   (void *)realloc((char *)(ptr), (size))
190 #define k12text_free(ptr, yyscanner)            free((char *)ptr)
192 static int k12text_file_type_subtype = -1;
194 void register_k12text(void);
197 start_timestamp \053[\055]{9}\053[\055]{15,100}\053[\055]{10,100}\053
198 oneormoredigits [0-9]+:
199 twodigits [0-9][0-9]
200 colon :
201 comma ,
202 threedigits [0-9][0-9][0-9]
203 start_bytes \174\060\040\040\040\174
204 bytes_junk \174[A-F0-9][A-F0-9\040][A-F0-9\040][A-F0-9\040]\174
205 byte [a-f0-9][a-f0-9]\174
206 end_bytes \015?\012\015?\012
207 eth ETHER
208 mtp2 MTP-L2
209 sscop SSCOP
210 sscfnni SSCF
211 hdlc HDLC
213 %START MAGIC NEXT_FRAME HOURS MINUTES M2S SECONDS S2M MS M2N NS ENCAP STARTBYTES BYTE
215 <MAGIC>{start_timestamp}  { yyextra->is_k12text = true; yyterminate(); }
217 <MAGIC>. { if (++ yyextra->junk_chars > MAX_JUNK) { yyextra->is_k12text = false;  yyterminate(); } }
219 <NEXT_FRAME>{start_timestamp} {BEGIN(HOURS); }
220 <HOURS>{oneormoredigits} { SET_HOURS(yytext); BEGIN(MINUTES); }
221 <MINUTES>{twodigits} { SET_MINUTES(yytext); BEGIN(M2S);}
222 <M2S>{colon} { BEGIN(SECONDS);}
223 <SECONDS>{twodigits} { SET_SECONDS(yytext); BEGIN(S2M); }
224 <S2M>{comma}  { BEGIN(MS); }
225 <MS>{threedigits} { SET_MS(yytext); BEGIN(M2N);  }
226 <M2N>{comma}  { BEGIN(NS); }
227 <NS>{threedigits} { SET_NS(yytext); BEGIN(ENCAP);}
228 <ENCAP>{eth} {yyextra->g_encap = WTAP_ENCAP_ETHERNET; BEGIN(STARTBYTES); }
229 <ENCAP>{mtp2} {yyextra->g_encap = WTAP_ENCAP_MTP2; BEGIN(STARTBYTES); }
230 <ENCAP>{sscop} {yyextra->g_encap = WTAP_ENCAP_ATM_PDUS; BEGIN(STARTBYTES); }
231 <ENCAP>{sscfnni} {yyextra->g_encap = WTAP_ENCAP_MTP3; BEGIN(STARTBYTES); }
232 <ENCAP>{hdlc} {yyextra->g_encap = WTAP_ENCAP_CHDLC; BEGIN(STARTBYTES); }
233 <ENCAP,STARTBYTES>{start_bytes} { BEGIN(BYTE); }
234 <BYTE>{byte} { ADD_BYTE(yytext); }
235 <BYTE>{bytes_junk} ;
236 <BYTE>{end_bytes} { FINALIZE_FRAME(); yyterminate(); }
238 . {  if (++yyextra->junk_chars > MAX_JUNK) { KERROR("too much junk");  } }
239 <<EOF>> { yyextra->at_eof = true; yyterminate(); }
244  * Turn diagnostics back on, so we check the code that we've written.
245  */
246 DIAG_ON_FLEX()
248 /* Fill in pkthdr */
250 static bool
251 k12text_set_headers(wtap_rec *rec, k12text_state_t *state,
252     int *err, char **err_info)
254         rec->rec_type = REC_TYPE_PACKET;
255         rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
256         rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
258         rec->ts.secs = 946681200 + (3600*state->g_h) + (60*state->g_m) + state->g_s;
259         rec->ts.nsecs = 1000000*state->g_ms + 1000*state->g_ns;
261         rec->rec_header.packet_header.caplen = rec->rec_header.packet_header.len = state->ii;
263         rec->rec_header.packet_header.pkt_encap = state->g_encap;
265         /* The file-encap is WTAP_ENCAP_PER_PACKET */
266         switch(state->g_encap) {
267             case WTAP_ENCAP_ETHERNET:
268                     rec->rec_header.packet_header.pseudo_header.eth.fcs_len = 0;
269                     break;
270             case WTAP_ENCAP_MTP3:
271             case WTAP_ENCAP_CHDLC:
272                     /* no pseudo_header to fill in for these types */
273                     break;
274             case WTAP_ENCAP_MTP2:      /* not (yet) supported           */
275                     /* XXX: I don't know how to fill in the             */
276                     /* pseudo_header for these types.                   */
277                     *err = WTAP_ERR_UNSUPPORTED;
278                     *err_info = g_strdup("k12text: MTP2 packets not yet supported");
279                     return false;
280             case WTAP_ENCAP_ATM_PDUS:  /* not (yet) supported           */
281                     /* XXX: I don't know how to fill in the             */
282                     /* pseudo_header for these types.                   */
283                     *err = WTAP_ERR_UNSUPPORTED;
284                     *err_info = g_strdup("k12text: SSCOP packets not yet supported");
285                     return false;
286             default:
287                     *err = WTAP_ERR_UNSUPPORTED;
288                     *err_info = g_strdup("k12text: unknown encapsulation type");
289                     return false;
290         }
291         return true;
294 /* Note: k12text_reset is called each time data is to be processed from */
295 /*       a file. This ensures that no "state" from a previous read is   */
296 /*       used (such as the lexer look-ahead buffer, file_handle, file   */
297 /*       position and so on. This allows a single lexer buffer to be    */
298 /*       used even when multiple files are open simultaneously (as for  */
299 /*       a file merge).                                                 */
301 static bool
302 k12text_run_scanner(k12text_state_t *state, FILE_T fh, int start_state,
303     int *err, char **err_info)
305         yyscan_t scanner = NULL;
307         if (yylex_init(&scanner) != 0) {
308                 /* errno is set if this fails */
309                 *err = errno;
310                 *err_info = NULL;
311                 return false;
312         }
313         state->fh = fh;
314         state->err = 0;
315         state->err_info = NULL;
316         state->start_state = start_state;
318         state->g_encap = WTAP_ENCAP_UNKNOWN;
319         state->ok_frame = false;
320         state->is_k12text = false;
321         state->at_eof = false;
322         state->junk_chars = 0;
323         state->error_str = NULL;
324         state->file_bytes_read=0;
325         state->g_h=0;
326         state->g_m=0;
327         state->g_s=0;
328         state->g_ns=0;
329         state->g_ms=0;
330         state->ii=0;
332         /* Associate the state with the scanner */
333         k12text_set_extra(state, scanner);
335         yylex(scanner);
336         yylex_destroy(scanner);
337         if (state->err != 0 && state->err != WTAP_ERR_SHORT_READ) {
338                 /* I/O error. */
339                 *err = state->err;
340                 *err_info = state->err_info;
341                 return false;
342         }
343         return true;
346 static bool
347 k12text_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, char ** err_info, int64_t *data_offset)
349         k12text_t *k12text = (k12text_t *)wth->priv;
350         k12text_state_t state;
352         /*
353          * We seek to the file position after the end of the previous frame
354          * processed by k12text_read(), since the lexer undoubtedly did some
355          * amount of look-ahead when processing the previous frame.
356          *
357          * We also clear out any lexer state (eg: look-ahead buffer) and
358          * init vars set by lexer.
359          */
361         if ( file_seek(wth->fh, k12text->next_frame_offset, SEEK_SET, err) == -1) {
362                 return false;
363         }
364         state.bb = (uint8_t*)g_malloc(WTAP_MAX_PACKET_SIZE_STANDARD);
366         if (!k12text_run_scanner(&state, wth->fh, NEXT_FRAME, err, err_info)) {
367                 g_free(state.bb);
368                 return false;
369         }
371         if (state.ok_frame == false) {
372                 if (state.at_eof) {
373                         *err = 0;
374                         *err_info = NULL;
375                 } else {
376                         *err = WTAP_ERR_BAD_FILE;
377                         *err_info = state.error_str;
378                 }
379                 g_free(state.bb);
380                 return false;
381         }
383         *data_offset = k12text->next_frame_offset;           /* file position for beginning of this frame   */
384         k12text->next_frame_offset += state.file_bytes_read; /* file position after end of this frame       */
386         if (!k12text_set_headers(rec, &state, err, err_info)) {
387                 g_free(state.bb);
388                 return false;
389         }
390         ws_buffer_assure_space(buf, rec->rec_header.packet_header.caplen);
391         memcpy(ws_buffer_start_ptr(buf), state.bb, rec->rec_header.packet_header.caplen);
393         g_free(state.bb);
394         return true;
397 static bool
398 k12text_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec, Buffer *buf, int *err, char **err_info)
400         k12text_state_t state;
402         if ( file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) {
403                 return false;
404         }
405         state.bb = (uint8_t*)g_malloc(WTAP_MAX_PACKET_SIZE_STANDARD);
407         if (!k12text_run_scanner(&state, wth->random_fh, NEXT_FRAME, err, err_info)) {
408                 g_free(state.bb);
409                 return false;
410         }
412         if (state.ok_frame == false) {
413                 *err = WTAP_ERR_BAD_FILE;
414                 if (state.at_eof) {
415                         /* What happened ? The desired frame was previously read without a problem */
416                         *err_info = g_strdup("Unexpected EOF (program error ?)");
417                 } else {
418                         *err_info = state.error_str;
419                 }
420                 g_free(state.bb);
421                 return false;
422         }
424         if (!k12text_set_headers(rec, &state, err, err_info)) {
425                 g_free(state.bb);
426                 return false;
427         }
428         ws_buffer_assure_space(buf, rec->rec_header.packet_header.caplen);
429         memcpy(ws_buffer_start_ptr(buf), state.bb, rec->rec_header.packet_header.caplen);
431         g_free(state.bb);
432         return true;
435 wtap_open_return_val
436 k12text_open(wtap *wth, int *err, char **err_info)
438         k12text_t *k12text;
439         k12text_state_t state;
441         state.bb = (uint8_t*)g_malloc(WTAP_MAX_PACKET_SIZE_STANDARD);
442         if (!k12text_run_scanner(&state, wth->fh, MAGIC, err, err_info)) {
443                 g_free(state.bb);
444                 return WTAP_OPEN_ERROR;
445         }
447         if (!state.is_k12text) {
448                 /* *err might have been set to WTAP_ERR_SHORT_READ */
449                 *err = 0;
450                 g_free(state.bb);
451                 return WTAP_OPEN_NOT_MINE;
452         }
454         if ( file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
455                 g_free(state.bb);
456                 return WTAP_OPEN_ERROR;
457         }
459         k12text = g_new(k12text_t, 1);
460         wth->priv = (void *)k12text;
461         k12text->next_frame_offset = 0;
462         wth->file_type_subtype = k12text_file_type_subtype;
463         wth->file_encap = WTAP_ENCAP_PER_PACKET;
464         wth->snapshot_length = 0;
465         wth->subtype_read = k12text_read;
466         wth->subtype_seek_read = k12text_seek_read;
467         wth->file_tsprec = WTAP_TSPREC_NSEC;
469         g_free(state.bb);
470         return WTAP_OPEN_MINE;
474 static const struct { int e; const char* s; } encaps[] = {
475         { WTAP_ENCAP_ETHERNET, "ETHER" },
476         { WTAP_ENCAP_MTP2, "MTP-L2" },
477         { WTAP_ENCAP_ATM_PDUS, "SSCOP" },
478         { WTAP_ENCAP_MTP3, "SSCF" },
479         { WTAP_ENCAP_CHDLC, "HDLC" },
480         /* ... */
481         { 0, NULL }
484 static bool
485 k12text_dump(wtap_dumper *wdh, const wtap_rec *rec,
486              const uint8_t *pd, int *err, char **err_info _U_) {
487 #define K12BUF_SIZE 196808
488         char *buf;
489         size_t left = K12BUF_SIZE;
490         size_t wl;
491         char *p;
492         const char* str_enc;
493         unsigned i;
494         unsigned ns;
495         unsigned ms;
496         bool ret;
497         struct tm *tmp;
499         /* Don't write anything bigger than we're willing to read. */
500         if (rec->rec_header.packet_header.caplen > WTAP_MAX_PACKET_SIZE_STANDARD) {
501                 *err = WTAP_ERR_PACKET_TOO_LARGE;
502                 return false;
503         }
505         str_enc = NULL;
506         for(i=0; encaps[i].s; i++) {
507                 if (rec->rec_header.packet_header.pkt_encap == encaps[i].e) {
508                         str_enc = encaps[i].s;
509                         break;
510                 }
511         }
512         if (str_enc == NULL) {
513                 /*
514                  * That encapsulation type is not supported.  Fail.
515                  */
516                 *err = WTAP_ERR_UNWRITABLE_ENCAP;
517                 return false;
518         }
520         buf = (char *)g_malloc(K12BUF_SIZE);
521         p = buf;
523         ms = rec->ts.nsecs / 1000000;
524         ns = (rec->ts.nsecs - (1000000*ms))/1000;
526         tmp = gmtime(&rec->ts.secs);
527         if (tmp == NULL)
528                 snprintf(p, 90, "+---------+---------------+----------+\r\nXX:XX:XX,");
529         else
530                 strftime(p, 90, "+---------+---------------+----------+\r\n%H:%M:%S,", tmp);
531         wl = strlen(p);
532         p += wl;
533         left -= wl;
535         wl = snprintf(p, left, "%.3d,%.3d   %s\r\n|0   |", ms, ns, str_enc);
536         p += wl;
537         left -= wl;
539         for(i = 0; i < rec->rec_header.packet_header.caplen && left > 2; i++) {
540                 wl = snprintf(p, left, "%.2x|", pd[i]);
541                 p += wl;
542                 left -= wl;
543         }
545         wl = snprintf(p, left, "\r\n\r\n");
546         left -= wl;
548         ret = wtap_dump_file_write(wdh, buf, K12BUF_SIZE - left, err);
550         g_free(buf);
551         return ret;
555 static bool
556 k12text_dump_open(wtap_dumper *wdh, int *err _U_, char **err_info _U_)
558     wdh->subtype_write = k12text_dump;
560     return true;
563 static int
564 k12text_dump_can_write_encap(int encap)
566     switch (encap) {
567         case WTAP_ENCAP_PER_PACKET:
568         case WTAP_ENCAP_ETHERNET:
569         case WTAP_ENCAP_MTP3:
570         case WTAP_ENCAP_CHDLC:
571                 return 0;
572         case WTAP_ENCAP_MTP2:
573         case WTAP_ENCAP_ATM_PDUS:
574         default:
575                 return WTAP_ERR_UNWRITABLE_ENCAP;
576     }
579 static const struct supported_block_type k12text_blocks_supported[] = {
580     /*
581      * We support packet blocks, with no comments or other options.
582      */
583     { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
586 static const struct file_type_subtype_info k12text_info = {
587     "K12 text file", "k12text", "txt", NULL,
588     false, BLOCKS_SUPPORTED(k12text_blocks_supported),
589     k12text_dump_can_write_encap, k12text_dump_open, NULL
592 void register_k12text(void)
594     k12text_file_type_subtype = wtap_register_file_type_subtype(&k12text_info);
596     /*
597      * Register name for backwards compatibility with the
598      * wtap_filetypes table in Lua.
599      */
600     wtap_register_backwards_compatibility_lua_name("K12TEXT",
601                                                    k12text_file_type_subtype);