### Bug Summary

File: | builds/wireshark/wireshark/ui/text_import.c
Warning: | line 1356, column 32 Addition of a null pointer (from variable 'str') and a nonzero integer value results in undefined behavior

### Annotated Source Code

Press '?' to see keyboard shortcuts

Show analyzer invocation
clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name text_import.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-22/lib/clang/22 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -D CARES_NO_DEPRECATED -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -I /builds/wireshark/wireshark/ui -I /builds/wireshark/wireshark/build/ui -I /builds/wireshark/wireshark/wiretap -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-22/lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu17 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /builds/wireshark/wireshark/sbout/2026-08-13-100404-3660-1 -x c /builds/wireshark/wireshark/ui/text_import.c

Keyboard shortcuts:

- Use 'j/k' keys for keyboard navigation
- Use 'Shift+S' to show/hide relevant lines
- Use '?' to toggle this window

Close
Show only relevant lines Show control flow arrows

1 | /* text_import.c
2 | * State machine for text import
3 | * November 2010, Jaap Keuter <jaap.keuter@xs4all.nl>
4 | * Modified March 2021, Paul Weiß <paulniklasweiss@gmail.com>
5 | *
6 | * Wireshark - Network traffic analyzer
7 | * By Gerald Combs <gerald@wireshark.org>
8 | * Copyright 1998 Gerald Combs
9 | *
10 | * Based on text2pcap.c by Ashok Narayanan <ashokn@cisco.com>
11 | *
12 | * SPDX-License-Identifier: GPL-2.0-or-later
13 | */
14 |
15 | /*******************************************************************************
16 | *
17 | * This code reads in an ASCII hexdump of this common format:
18 | *
19 | * 00000000 00 E0 1E A7 05 6F 00 10 5A A0 B9 12 08 00 46 00 .....o..Z.....F.
20 | * 00000010 03 68 00 00 00 00 0A 2E EE 33 0F 19 08 7F 0F 19 .h.......3......
21 | * 00000020 03 80 94 04 00 00 10 01 16 A2 0A 00 03 50 00 0C .............P..
22 | * 00000030 01 01 0F 19 03 80 11 01 1E 61 00 0C 03 01 0F 19 .........a......
23 | *
24 | * Each bytestring line consists of an offset, one or more bytes, and
25 | * text at the end. An offset is defined as a hex string of more than
26 | * two characters. A byte is defined as a hex string of exactly two
27 | * characters. The text at the end is ignored, as is any text before
28 | * the offset. Bytes read from a bytestring line are added to the
29 | * current packet only if all the following conditions are satisfied:
30 | *
31 | * - No text appears between the offset and the bytes (any bytes appearing after
32 | * such text would be ignored)
33 | *
34 | * - The offset must be arithmetically correct, i.e. if the offset is 00000020,
35 | * then exactly 32 bytes must have been read into this packet before this.
36 | * If the offset is wrong, the packet is immediately terminated
37 | *
38 | * A packet start is signaled by a zero offset.
39 | *
40 | * Lines starting with #TEXT2PCAP are directives. These allow the user
41 | * to embed instructions into the capture file which allows text2pcap
42 | * to take some actions (e.g. specifying the encapsulation
43 | * etc.). Currently no directives are implemented.
44 | *
45 | * Lines beginning with # which are not directives are ignored as
46 | * comments. Currently all non-hexdump text is ignored by text2pcap;
47 | * in the future, text processing may be added, but lines prefixed
48 | * with '#' will still be ignored.
49 | *
50 | * The output is a libpcap packet containing Ethernet frames by
51 | * default. This program takes options which allow the user to add
52 | * dummy Ethernet, IP and UDP, TCP or SCTP headers to the packets in order
53 | * to allow dumps of L3 or higher protocols to be decoded.
54 | *
55 | * Considerable flexibility is built into this code to read hexdumps
56 | * of slightly different formats. For example, any text prefixing the
57 | * hexdump line is dropped (including mail forwarding '>'). The offset
58 | * can be any hex number of four digits or greater.
59 | *
60 | * This converter cannot read a single packet greater than
61 | * WTAP_MAX_PACKET_SIZE_STANDARD. The snapshot length is automatically
62 | * set to WTAP_MAX_PACKET_SIZE_STANDARD.
63 | */
64 |
65 | /*******************************************************************************
66 | * Alternatively this parses a Textfile based on a prel regex containing named
67 | * capturing groups like so:
68 | * (?<seqno>\d+)\s*(?<dir><|>)\s*(?<time>\d+:\d\d:\d\d.\d+)\s+(?<data>[0-9a-fA-F]+)\\s+
69 | *
70 | * Fields are decoded using a lenient parser, but only one attempt is made.
71 | * Except for in data invalid values will be replaced by default ones.
72 | * data currently only accepts plain HEX, OCT or BIN encoded data.
73 | * common field separators are ignored. Note however that 0x or 0b prefixing is
74 | * not supported and no automatic format detection is attempted.
75 | */
76 |
77 | #include "config.h"
78 | #define WS_LOG_DOMAIN"Main" LOG_DOMAIN_MAIN"Main"
79 | #include "text_import.h"
80 |
81 | #include <stdio.h>
82 | #include <stdlib.h>
83 | #include <string.h>
84 | #include <wsutil/file_util.h>
85 | #include <wsutil/buffer.h>
86 | #include <wsutil/strtoi.h>
87 | #include <ws_exit_codes.h>
88 |
89 | #include <time.h>
90 | #include <glib.h>
91 |
92 | #include <errno(*__errno_location ()).h>
93 | #include <assert.h>
94 |
95 | #include <epan/tvbuff.h>
96 | #include <epan/iana-info.h>
97 | #include <wsutil/crc32.h>
98 | #include <epan/in_cksum.h>
99 |
100 | #include <wsutil/report_message.h>
101 | #include <wsutil/exported_pdu_tlvs.h>
102 |
103 | #include <wsutil/nstime.h>
104 | #include <wsutil/str_util.h>
105 | #include <wsutil/time_util.h>
106 | #include <wsutil/ws_strptime.h>
107 |
108 | #include <wsutil/version_info.h>
109 | #include <wsutil/cpu_info.h>
110 | #include <wsutil/os_version_info.h>
111 |
112 | #include "text_import_scanner.h"
113 | #include "text_import_scanner_lex.h"
114 | #include "text_import_regex.h"
115 |
116 | /*--- Options --------------------------------------------------------------------*/
117 |
118 | /* maximum time precision we can handle = 10^(-SUBSEC_PREC) */
119 | #define SUBSEC_PREC9 9
120 |
121 | static text_import_info_t *info_p;
122 |
123 | /* Dummy Ethernet header */
124 | static bool_Bool hdr_ethernet;
125 | static const uint8_t hdr_eth_dest_addr[6] = {0x20, 0x52, 0x45, 0x43, 0x56, 0x00};
126 | static const uint8_t hdr_eth_src_addr[6] = {0x20, 0x53, 0x45, 0x4E, 0x44, 0x00};
127 | static uint32_t hdr_ethernet_proto;
128 |
129 | /* Dummy IP header */
130 | static bool_Bool hdr_ip;
131 | static bool_Bool hdr_ipv6;
132 | static unsigned hdr_ip_proto;
133 |
134 | /* Destination and source addresses for IP header */
135 | static const ws_in6_addr NO_IPv6_ADDRESS = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
136 | /* These IPv6 default addresses are unique local addresses generated using
137 | * the pseudo-random method from Section 3.2.2 of RFC 4193
138 | */
139 | static const ws_in6_addr IPv6_SRC = {{0xfd, 0xce, 0xd8, 0x62, 0x14, 0x1b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}};
140 | static const ws_in6_addr IPv6_DST = {{0xfd, 0xce, 0xd8, 0x62, 0x14, 0x1b, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}};
141 |
142 | /* Dummy UDP header */
143 | static bool_Bool hdr_udp;
144 |
145 | /* Dummy TCP header */
146 | static bool_Bool hdr_tcp;
147 |
148 | /* TCP sequence numbers when has_direction is true */
149 | static uint32_t tcp_in_seq_num;
150 | static uint32_t tcp_out_seq_num;
151 |
152 | /* Dummy SCTP header */
153 | static bool_Bool hdr_sctp;
154 |
155 | /* Dummy DATA chunk header */
156 | static bool_Bool hdr_data_chunk;
157 | static uint8_t hdr_data_chunk_type;
158 | static uint8_t hdr_data_chunk_bits;
159 | static uint32_t hdr_data_chunk_tsn;
160 | static uint16_t hdr_data_chunk_sid;
161 | static uint16_t hdr_data_chunk_ssn;
162 |
163 | /* Dummy ExportPdu header */
164 | static bool_Bool hdr_export_pdu;
165 |
166 | /* Hex+ASCII text dump identification, to handle an edge case where
167 | * the ASCII representation contains patterns that look like bytes. */
168 | static uint8_t* pkt_lnstart;
169 |
170 | static bool_Bool has_direction;
171 | static uint32_t direction = PACK_FLAGS_RECEPTION_TYPE_UNSPECIFIED0;
172 | static bool_Bool has_seqno;
173 | static uint64_t seqno;
174 | /*--- Local data -----------------------------------------------------------------*/
175 |
176 | /* This is where we store the packet currently being built */
177 | static uint8_t *packet_buf;
178 | static Buffer prefix_buf;
179 | static uint32_t curr_offset;
180 | static uint32_t packet_start;
181 | static bool_Bool offset_warned;
182 | static import_status_t start_new_packet(bool_Bool);
183 |
184 | /* This buffer contains strings present before the packet offset 0 */
185 | #define PACKET_PREAMBLE_MAX_LEN2048 2048
186 | static uint8_t packet_preamble[PACKET_PREAMBLE_MAX_LEN2048+1];
187 | static int packet_preamble_len;
188 |
189 | /* Time code of packet, derived from packet_preamble */
190 | static time_t ts_sec;
191 | static uint32_t ts_nsec;
192 | static bool_Bool ts_fmt_iso;
193 | static struct tm timecode_default;
194 | static bool_Bool timecode_warned;
195 | /* The time delta to add to packets without a valid time code.
196 | * This can be no smaller than the time resolution of the dump
197 | * file, so the default is 1000 nanoseconds, or 1 microsecond.
198 | * XXX: We should at least get this from the resolution of the file we're
199 | * writing to, and possibly allow the user to set a different value.
200 | */
201 | static uint32_t ts_tick = 1000;
202 |
203 | /* HDR_ETH Offset base to parse */
204 | static uint32_t offset_base = 16;
205 |
206 | /* ----- State machine -----------------------------------------------------------*/
207 |
208 | /* Current state of parser */
209 | typedef enum {
210 | INIT, /* Waiting for start of new packet */
211 | START_OF_LINE, /* Starting from beginning of line */
212 | READ_OFFSET, /* Just read the offset */
213 | READ_BYTE, /* Just read a byte */
214 | READ_TEXT /* Just read text - ignore until EOL */
215 | } parser_state_t;
216 | static parser_state_t state = INIT;
217 |
218 | static const char * const state_str[] = {
219 | "Init",
220 | "Start-of-line",
221 | "Offset",
222 | "Byte",
223 | "Text"
224 | };
225 |
226 | static const char * const token_str[] = {
227 | "",
228 | "Byte",
229 | "Bytes",
230 | "Offset",
231 | "Directive",
232 | "Text",
233 | "End-of-line",
234 | "End-of-file"
235 | };
236 |
237 | /* ----- Skeleton Packet Headers --------------------------------------------------*/
238 |
239 | typedef struct {
240 | uint8_t dest_addr[6];
241 | uint8_t src_addr[6];
242 | uint16_t ethertype;
243 | } hdr_ethernet_t;
244 |
245 | static hdr_ethernet_t HDR_ETHERNET;
246 |
247 | typedef struct {
248 | uint8_t ver_hdrlen;
249 | uint8_t dscp;
250 | uint16_t packet_length;
251 | uint16_t identification;
252 | uint8_t flags;
253 | uint8_t fragment;
254 | uint8_t ttl;
255 | uint8_t protocol;
256 | uint16_t hdr_checksum;
257 | uint32_t src_addr;
258 | uint32_t dest_addr;
259 | } hdr_ip_t;
260 |
261 | /* Default IPv4 addresses if none supplied */
262 | #if G_BYTE_ORDER1234 == G_BIG_ENDIAN4321
263 | #define IP_ID0x3412 0x1234
264 | #define IP_SRC0x0101010a 0x0a010101
265 | #define IP_DST0x0202020a 0x0a020202
266 | #else
267 | #define IP_ID0x3412 0x3412
268 | #define IP_SRC0x0101010a 0x0101010a
269 | #define IP_DST0x0202020a 0x0202020a
270 | #endif
271 |
272 | static hdr_ip_t HDR_IP =
273 | {0x45, 0, 0, IP_ID0x3412, 0, 0, 0xff, 0, 0, IP_SRC0x0101010a, IP_DST0x0202020a};
274 |
275 | static struct { /* pseudo header for checksum calculation */
276 | uint32_t src_addr;
277 | uint32_t dest_addr;
278 | uint8_t zero;
279 | uint8_t protocol;
280 | uint16_t length;
281 | } pseudoh;
282 |
283 |
284 | /* headers taken from glibc */
285 |
286 | typedef struct {
287 | union {
288 | struct ip6_hdrctl {
289 | uint32_t ip6_un1_flow; /* 24 bits of flow-ID */
290 | uint16_t ip6_un1_plen; /* payload length */
291 | uint8_t ip6_un1_nxt; /* next header */
292 | uint8_t ip6_un1_hlim; /* hop limit */
293 | } ip6_un1;
294 | uint8_t ip6_un2_vfc; /* 4 bits version, 4 bits priority */
295 | } ip6_ctlun;
296 | ws_in6_addr ip6_src; /* source address */
297 | ws_in6_addr ip6_dst; /* destination address */
298 | } hdr_ipv6_t;
299 |
300 | static hdr_ipv6_t HDR_IPv6;
301 |
302 | /* https://tools.ietf.org/html/rfc2460#section-8.1 */
303 | static struct { /* pseudo header ipv6 for checksum calculation */
304 | struct e_in6_addr src_addr6;
305 | struct e_in6_addr dst_addr6;
306 | uint32_t length;
307 | uint8_t zero[3];
308 | uint8_t next_header;
309 | } pseudoh6;
310 |
311 | #define ICMP6_ND_ROUTER_SOLICIT133 133
312 | #define ICMP6_ND_ROUTER_ADVERT134 134
313 | #define ICMP6_ND_NEIGHBOR_SOLICIT135 135
314 | #define ICMP6_ND_NEIGHBOR_ADVERT136 136
315 | #define ICMP6_ND_REDIRECT137 137
316 | #define ICMP6_IND_SOLICIT141 141
317 | #define ICMP6_IND_ADVERT142 142
318 | #define ICMP6_CERT_PATH_SOL148 148
319 | #define ICMP6_CERT_PATH_AD149 149
320 |
321 | typedef struct {
322 | uint16_t source_port;
323 | uint16_t dest_port;
324 | uint16_t length;
325 | uint16_t checksum;
326 | } hdr_udp_t;
327 |
328 | static hdr_udp_t HDR_UDP = {0, 0, 0, 0};
329 |
330 | typedef struct {
331 | uint16_t source_port;
332 | uint16_t dest_port;
333 | uint32_t seq_num;
334 | uint32_t ack_num;
335 | uint8_t hdr_length;
336 | uint8_t flags;
337 | uint16_t window;
338 | uint16_t checksum;
339 | uint16_t urg;
340 | } hdr_tcp_t;
341 |
342 | static hdr_tcp_t HDR_TCP = {0, 0, 0, 0, 0x50, 0, 0, 0, 0};
343 |
344 | typedef struct {
345 | uint16_t src_port;
346 | uint16_t dest_port;
347 | uint32_t tag;
348 | uint32_t checksum;
349 | } hdr_sctp_t;
350 |
351 | static hdr_sctp_t HDR_SCTP = {0, 0, 0, 0};
352 |
353 | typedef struct {
354 | uint8_t type;
355 | uint8_t bits;
356 | uint16_t length;
357 | uint32_t tsn;
358 | uint16_t sid;
359 | uint16_t ssn;
360 | uint32_t ppid;
361 | } hdr_data_chunk_t;
362 |
363 | static hdr_data_chunk_t HDR_DATA_CHUNK = {0, 0, 0, 0, 0, 0, 0};
364 |
365 | typedef struct {
366 | uint16_t tag_type;
367 | uint16_t payload_len;
368 | } hdr_export_pdu_t;
369 |
370 | static hdr_export_pdu_t HDR_EXPORT_PDU = {0, 0};
371 |
372 | #define EXPORT_PDU_END_OF_OPTIONS_SIZE4 4
373 |
374 | /*----------------------------------------------------------------------
375 | * Parse a single hex number
376 | * Will abort the program if it can't parse the number
377 | * Pass in true if this is an offset, false if not
378 | */
379 | static import_status_t
380 | parse_num(const char *str, int offset, uint32_t* num)
381 | {
382 | char *c;
383 |
384 | if (str == NULL((void*)0)) {
385 | report_failure("FATAL ERROR: str is NULL");
386 | return IMPORT_FAILURE;
387 | }
388 |
389 | errno(*__errno_location ()) = 0;
390 | unsigned long ulnum = strtoul(str, &c, offset ? offset_base : 16);
391 | if (errno(*__errno_location ()) != 0) {
392 | report_failure("Unable to convert %s to base %u: %s", str,
393 | offset ? offset_base : 16, g_strerror(errno(*__errno_location ())));
394 | return IMPORT_FAILURE;
395 | }
396 | if (c == str) {
397 | report_failure("Unable to convert %s to base %u", str,
398 | offset ? offset_base : 16);
399 | return IMPORT_FAILURE;
400 | }
401 | if (ulnum > UINT32_MAX(4294967295U)) {
402 | report_failure("%s too large", str);
403 | return IMPORT_FAILURE;
404 | }
405 | *num = (uint32_t) ulnum;
406 | return IMPORT_SUCCESS;
407 | }
408 |
409 | /*----------------------------------------------------------------------
410 | * Write this byte into current packet
411 | */
412 | static import_status_t
413 | write_byte(const char *str)
414 | {
415 | uint32_t num;
416 |
417 | if (parse_num(str, false0, &num) != IMPORT_SUCCESS)
418 | return IMPORT_FAILURE;
419 |
420 | packet_buf[curr_offset] = (uint8_t) num;
421 | curr_offset++;
422 | if (curr_offset >= info_p->max_frame_length) /* packet full */
423 | if (start_new_packet(true1) != IMPORT_SUCCESS)
424 | return IMPORT_FAILURE;
425 |
426 | return IMPORT_SUCCESS;
427 | }
428 |
429 | static import_status_t
430 | write_bytes(const char *str)
431 | {
432 | uint32_t num;
433 |
434 | if (parse_num(str, false0, &num) != IMPORT_SUCCESS)
435 | return IMPORT_FAILURE;
436 |
437 | int len = (int)strlen(str);
438 | /* There's always extra room in the packet_buf for the dummy headers
439 | * compared to max_frame_length, so we could copy all the bytes at
440 | * once and then check for overflow afterwards (copying it off).
441 | * That would be moderately faster due to optimization on most
442 | * compilers (and we could use the routines from wsutil/pint.h)
443 | */
444 | if (info_p->hexdump.little_endian) {
445 | for (int i = 0; i < 4*len; i += 8) {
446 | packet_buf[curr_offset] = (uint8_t)(num >> i);
447 | curr_offset++;
448 | if (curr_offset >= info_p->max_frame_length) /* packet full */
449 | if (start_new_packet(true1) != IMPORT_SUCCESS)
450 | return IMPORT_FAILURE;
451 | }
452 | } else {
453 | for (int i = 4*len - 8; i >= 0; i -= 8) {
454 | packet_buf[curr_offset] = (uint8_t)(num >> i);
455 | curr_offset++;
456 | if (curr_offset >= info_p->max_frame_length) /* packet full */
457 | if (start_new_packet(true1) != IMPORT_SUCCESS)
458 | return IMPORT_FAILURE;
459 | }
460 | }
461 |
462 | return IMPORT_SUCCESS;
463 | }
464 |
465 | /* RFC 4861 Neighbor Discovery, RFC 3122 Inverse Neighbor Discovery,
466 | * and RFC 3971 SEND Certification Path messages require IPv6 Hop
467 | * Limit 255. Generate RFC-compliant dummy IPv6 headers for these
468 | * ICMPv6 message types without changing the default Hop Limit for
469 | * unrelated IPv6 traffic.
470 | */
471 | static bool_Bool
472 | icmpv6_dummy_hlim_must_be_255(const uint8_t *payload, uint32_t payload_len)
473 | {
474 | if (hdr_ip_proto != IP_PROTO_IPV6_ICMP58 || payload_len == 0) {
475 | return false0;
476 | }
477 |
478 | switch (payload[0]) {
479 | case ICMP6_ND_ROUTER_SOLICIT133:
480 | case ICMP6_ND_ROUTER_ADVERT134:
481 | case ICMP6_ND_NEIGHBOR_SOLICIT135:
482 | case ICMP6_ND_NEIGHBOR_ADVERT136:
483 | case ICMP6_ND_REDIRECT137:
484 | case ICMP6_IND_SOLICIT141:
485 | case ICMP6_IND_ADVERT142:
486 | case ICMP6_CERT_PATH_SOL148:
487 | case ICMP6_CERT_PATH_AD149:
488 | return true1;
489 | default:
490 | return false0;
491 | }
492 | }
493 |
494 | /*----------------------------------------------------------------------
495 | * Remove bytes from the current packet
496 | */
497 | static void
498 | unwrite_bytes (uint32_t nbytes)
499 | {
500 | curr_offset -= nbytes;
501 | }
502 |
503 | /*----------------------------------------------------------------------
504 | * Determine SCTP chunk padding length
505 | */
506 | static uint32_t
507 | number_of_padding_bytes (uint32_t length)
508 | {
509 | uint32_t remainder;
510 |
511 | remainder = length % 4;
512 |
513 | if (remainder == 0)
514 | return 0;
515 | else
516 | return 4 - remainder;
517 | }
518 |
519 | /*----------------------------------------------------------------------
520 | * Write current packet out
521 | *
522 | * @param cont [IN] true if a packet is being written because the max frame
523 | * length was reached, and the original packet from the input file is
524 | * continued in a later frame. Used to set fragmentation fields in dummy
525 | * headers (currently only implemented for SCTP; IPv4 could be added later.)
526 | */
527 | static import_status_t
528 | write_current_packet(bool_Bool cont)
529 | {
530 | int prefix_length = 0;
531 | int proto_length = 0;
532 | int ip_length = 0;
533 | int eth_trailer_length = 0;
534 | int i, padding_length;
535 |
536 | if (curr_offset > 0) {
537 | /* Write the packet */
538 |
539 | /* Is direction indication on with an inbound packet? */
540 | bool_Bool isOutbound = has_direction && (direction == PACK_FLAGS_DIRECTION_OUTBOUND2);
541 |
542 | ws_buffer_clean(&prefix_buf);
543 |
544 | /* Compute packet length */
545 | prefix_length = 0;
546 | if (hdr_export_pdu) {
547 | prefix_length += (int)sizeof(HDR_EXPORT_PDU) + (int)strlen(info_p->payload) + EXPORT_PDU_END_OF_OPTIONS_SIZE4;
548 | proto_length = prefix_length + curr_offset;
549 | }
550 | if (hdr_data_chunk) { prefix_length += (int)sizeof(HDR_DATA_CHUNK); }
551 | if (hdr_sctp) { prefix_length += (int)sizeof(HDR_SCTP); }
552 | if (hdr_udp) { prefix_length += (int)sizeof(HDR_UDP); proto_length = prefix_length + curr_offset; }
553 | if (hdr_tcp) { prefix_length += (int)sizeof(HDR_TCP); proto_length = prefix_length + curr_offset; }
554 | if (hdr_ip) {
555 | prefix_length += (int)sizeof(HDR_IP);
556 | ip_length = prefix_length + curr_offset + ((hdr_data_chunk) ? number_of_padding_bytes(curr_offset) : 0);
557 | } else if (hdr_ipv6) {
558 | ip_length = prefix_length + curr_offset + ((hdr_data_chunk) ? number_of_padding_bytes(curr_offset) : 0);
559 | /* IPv6 payload length field does not include the header itself.
560 | * It does include extension headers, but we don't put any
561 | * (if we later do fragments, that would change.)
562 | */
563 | prefix_length += (int)sizeof(HDR_IPv6);
564 | }
565 | if (hdr_ethernet) { prefix_length += (int)sizeof(HDR_ETHERNET); }
566 |
567 | if (hdr_ethernet) {
568 | /* Pad trailer */
569 | if (prefix_length + curr_offset < 60) {
570 | eth_trailer_length = 60 - (prefix_length + curr_offset);
571 | }
572 | }
573 |
574 | /* Write Ethernet header */
575 | if (hdr_ethernet) {
576 | if (isOutbound)
577 | {
578 | memcpy(HDR_ETHERNET.dest_addr, hdr_eth_src_addr, 6);
579 | memcpy(HDR_ETHERNET.src_addr, hdr_eth_dest_addr, 6);
580 | } else {
581 | memcpy(HDR_ETHERNET.dest_addr, hdr_eth_dest_addr, 6);
582 | memcpy(HDR_ETHERNET.src_addr, hdr_eth_src_addr, 6);
583 | }
584 | HDR_ETHERNET.ethertype = g_htons(hdr_ethernet_proto)(((((guint16) ( (guint16) ((guint16) (hdr_ethernet_proto) >> 8) | (guint16) ((guint16) (hdr_ethernet_proto) << 8))) )));
585 | ws_buffer_append(&prefix_buf, (uint8_t*)&HDR_ETHERNET, sizeof(HDR_ETHERNET));
586 | }
587 |
588 | /* Write IP header */
589 | if (hdr_ip) {
590 | vec_t cksum_vector[1];
591 |
592 | if (isOutbound) {
593 | HDR_IP.src_addr = info_p->ip_dest_addr.ipv4 ? info_p->ip_dest_addr.ipv4 : IP_DST0x0202020a;
594 | HDR_IP.dest_addr = info_p->ip_src_addr.ipv4 ? info_p->ip_src_addr.ipv4 : IP_SRC0x0101010a;
595 | }
596 | else {
597 | HDR_IP.src_addr = info_p->ip_src_addr.ipv4 ? info_p->ip_src_addr.ipv4 : IP_SRC0x0101010a;
598 | HDR_IP.dest_addr = info_p->ip_dest_addr.ipv4 ? info_p->ip_dest_addr.ipv4 : IP_DST0x0202020a;
599 | }
600 | HDR_IP.packet_length = g_htons(ip_length)(((((guint16) ( (guint16) ((guint16) (ip_length) >> 8) | (guint16) ((guint16) (ip_length) << 8))))));
601 | HDR_IP.protocol = (uint8_t) hdr_ip_proto;
602 | HDR_IP.hdr_checksum = 0;
603 | cksum_vector[0].ptr = (uint8_t *)&HDR_IP; cksum_vector[0].len = sizeof(HDR_IP);
604 | HDR_IP.hdr_checksum = in_cksum(cksum_vector, 1);
605 |
606 | ws_buffer_append(&prefix_buf, (uint8_t*)&HDR_IP, sizeof(HDR_IP));
607 |
608 | /* initialize pseudo header for checksum calculation */
609 | pseudoh.src_addr = HDR_IP.src_addr;
610 | pseudoh.dest_addr = HDR_IP.dest_addr;
611 | pseudoh.zero = 0;
612 | pseudoh.protocol = (uint8_t) hdr_ip_proto;
613 | pseudoh.length = g_htons(proto_length)(((((guint16) ( (guint16) ((guint16) (proto_length) >> 8 ) | (guint16) ((guint16) (proto_length) << 8))))));
614 | } else if (hdr_ipv6) {
615 | if (memcmp(&info_p->ip_dest_addr.ipv6, &NO_IPv6_ADDRESS, sizeof(ws_in6_addr))) {
616 | memcpy(isOutbound ? &HDR_IPv6.ip6_src : &HDR_IPv6.ip6_dst, &info_p->ip_dest_addr.ipv6, sizeof(ws_in6_addr));
617 | } else {
618 | memcpy(isOutbound ? &HDR_IPv6.ip6_src : &HDR_IPv6.ip6_dst, &IPv6_DST, sizeof(ws_in6_addr));
619 | }
620 | if (memcmp(&info_p->ip_src_addr.ipv6, &NO_IPv6_ADDRESS, sizeof(ws_in6_addr))) {
621 | memcpy(isOutbound ? &HDR_IPv6.ip6_dst : &HDR_IPv6.ip6_src, &info_p->ip_src_addr.ipv6, sizeof(ws_in6_addr));
622 | } else {
623 | memcpy(isOutbound ? &HDR_IPv6.ip6_dst : &HDR_IPv6.ip6_src, &IPv6_SRC, sizeof(ws_in6_addr));
624 | }
625 |
626 | HDR_IPv6.ip6_ctlun.ip6_un2_vfc &= 0x0F;
627 | HDR_IPv6.ip6_ctlun.ip6_un2_vfc |= (6<< 4);
628 | HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_plen = g_htons(ip_length)(((((guint16) ( (guint16) ((guint16) (ip_length) >> 8) | (guint16) ((guint16) (ip_length) << 8))))));
629 | HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_nxt = (uint8_t) hdr_ip_proto;
630 | HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_hlim =
631 | icmpv6_dummy_hlim_must_be_255(packet_buf, curr_offset) ? 255 : 32;
632 |
633 | ws_buffer_append(&prefix_buf, (uint8_t*)&HDR_IPv6, sizeof(HDR_IPv6));
634 |
635 | /* initialize pseudo ipv6 header for checksum calculation */
636 | pseudoh6.src_addr6 = HDR_IPv6.ip6_src;
637 | pseudoh6.dst_addr6 = HDR_IPv6.ip6_dst;
638 | memset(pseudoh6.zero, 0, sizeof(pseudoh6.zero));
639 | pseudoh6.next_header = (uint8_t) hdr_ip_proto;
640 | pseudoh6.length = g_htons(proto_length)(((((guint16) ( (guint16) ((guint16) (proto_length) >> 8 ) | (guint16) ((guint16) (proto_length) << 8))))));
641 | }
642 |
643 | /* Write UDP header */
644 | if (hdr_udp) {
645 | vec_t cksum_vector[3];
646 |
647 | HDR_UDP.source_port = isOutbound ? g_htons(info_p->dst_port)(((((guint16) ( (guint16) ((guint16) (info_p->dst_port) >> 8) | (guint16) ((guint16) (info_p->dst_port) << 8)) )))): g_htons(info_p->src_port)(((((guint16) ( (guint16) ((guint16) (info_p->src_port) >> 8) | (guint16) ((guint16) (info_p->src_port) << 8)) ))));
648 | HDR_UDP.dest_port = isOutbound ? g_htons(info_p->src_port)(((((guint16) ( (guint16) ((guint16) (info_p->src_port) >> 8) | (guint16) ((guint16) (info_p->src_port) << 8)) )))) : g_htons(info_p->dst_port)(((((guint16) ( (guint16) ((guint16) (info_p->dst_port) >> 8) | (guint16) ((guint16) (info_p->dst_port) << 8)) ))));
649 | HDR_UDP.length = g_htons(proto_length)(((((guint16) ( (guint16) ((guint16) (proto_length) >> 8 ) | (guint16) ((guint16) (proto_length) << 8))))));
650 |
651 | HDR_UDP.checksum = 0;
652 | if (hdr_ipv6) {
653 | cksum_vector[0].ptr = (uint8_t *)&pseudoh6; cksum_vector[0].len = sizeof(pseudoh6);
654 | } else {
655 | cksum_vector[0].ptr = (uint8_t *)&pseudoh; cksum_vector[0].len = sizeof(pseudoh);
656 | }
657 | cksum_vector[1].ptr = (uint8_t *)&HDR_UDP; cksum_vector[1].len = sizeof(HDR_UDP);
658 | cksum_vector[2].ptr = packet_buf; cksum_vector[2].len = curr_offset;
659 | HDR_UDP.checksum = in_cksum(cksum_vector, 3);
660 |
661 | ws_buffer_append(&prefix_buf, (uint8_t*)&HDR_UDP, sizeof(HDR_UDP));
662 | }
663 |
664 | /* Write TCP header */
665 | if (hdr_tcp) {
666 | vec_t cksum_vector[3];
667 |
668 | HDR_TCP.source_port = isOutbound ? g_htons(info_p->dst_port)(((((guint16) ( (guint16) ((guint16) (info_p->dst_port) >> 8) | (guint16) ((guint16) (info_p->dst_port) << 8)) )))): g_htons(info_p->src_port)(((((guint16) ( (guint16) ((guint16) (info_p->src_port) >> 8) | (guint16) ((guint16) (info_p->src_port) << 8)) ))));
669 | HDR_TCP.dest_port = isOutbound ? g_htons(info_p->src_port)(((((guint16) ( (guint16) ((guint16) (info_p->src_port) >> 8) | (guint16) ((guint16) (info_p->src_port) << 8)) )))) : g_htons(info_p->dst_port)(((((guint16) ( (guint16) ((guint16) (info_p->dst_port) >> 8) | (guint16) ((guint16) (info_p->dst_port) << 8)) ))));
670 | /* set ack number if we have direction */
671 | if (has_direction) {
672 | HDR_TCP.flags = 0x10;
673 | HDR_TCP.ack_num = g_ntohl(isOutbound ? tcp_out_seq_num : tcp_in_seq_num)((((((guint32) ( (((guint32) (isOutbound ? tcp_out_seq_num : tcp_in_seq_num ) & (guint32) 0x000000ffU) << 24) | (((guint32) (isOutbound ? tcp_out_seq_num : tcp_in_seq_num) & (guint32) 0x0000ff00U ) << 8) | (((guint32) (isOutbound ? tcp_out_seq_num : tcp_in_seq_num ) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (isOutbound ? tcp_out_seq_num : tcp_in_seq_num) & (guint32) 0xff000000U ) >> 24)))))));
674 | HDR_TCP.ack_num = g_htonl(HDR_TCP.ack_num)(((((guint32) ( (((guint32) (HDR_TCP.ack_num) & (guint32) 0x000000ffU) << 24) | (((guint32) (HDR_TCP.ack_num) & (guint32) 0x0000ff00U) << 8) | (((guint32) (HDR_TCP.ack_num ) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (HDR_TCP .ack_num) & (guint32) 0xff000000U) >> 24))))));
675 | }
676 | else {
677 | HDR_TCP.flags = 0;
678 | HDR_TCP.ack_num = 0;
679 | }
680 | HDR_TCP.seq_num = isOutbound ? tcp_in_seq_num : tcp_out_seq_num;
681 | HDR_TCP.window = g_htons(0x2000)(((((guint16) ( (guint16) ((guint16) (0x2000) >> 8) | ( guint16) ((guint16) (0x2000) << 8))))));
682 |
683 | HDR_TCP.checksum = 0;
684 | if (hdr_ipv6) {
685 | cksum_vector[0].ptr = (uint8_t *)&pseudoh6; cksum_vector[0].len = sizeof(pseudoh6);
686 | } else {
687 | cksum_vector[0].ptr = (uint8_t *)&pseudoh; cksum_vector[0].len = sizeof(pseudoh);
688 | }
689 | cksum_vector[1].ptr = (uint8_t *)&HDR_TCP; cksum_vector[1].len = sizeof(HDR_TCP);
690 | cksum_vector[2].ptr = packet_buf; cksum_vector[2].len = curr_offset;
691 | HDR_TCP.checksum = in_cksum(cksum_vector, 3);
692 |
693 | ws_buffer_append(&prefix_buf, (uint8_t*)&HDR_TCP, sizeof(HDR_TCP));
694 | if (isOutbound) {
695 | tcp_in_seq_num = g_ntohl(tcp_in_seq_num)((((((guint32) ( (((guint32) (tcp_in_seq_num) & (guint32) 0x000000ffU) << 24) | (((guint32) (tcp_in_seq_num) & (guint32) 0x0000ff00U) << 8) | (((guint32) (tcp_in_seq_num ) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (tcp_in_seq_num ) & (guint32) 0xff000000U) >> 24))))))) + curr_offset;
696 | tcp_in_seq_num = g_htonl(tcp_in_seq_num)(((((guint32) ( (((guint32) (tcp_in_seq_num) & (guint32) 0x000000ffU ) << 24) | (((guint32) (tcp_in_seq_num) & (guint32) 0x0000ff00U) << 8) | (((guint32) (tcp_in_seq_num) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (tcp_in_seq_num ) & (guint32) 0xff000000U) >> 24))))));
697 | }
698 | else {
699 | tcp_out_seq_num = g_ntohl(tcp_out_seq_num)((((((guint32) ( (((guint32) (tcp_out_seq_num) & (guint32 ) 0x000000ffU) << 24) | (((guint32) (tcp_out_seq_num) & (guint32) 0x0000ff00U) << 8) | (((guint32) (tcp_out_seq_num ) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (tcp_out_seq_num ) & (guint32) 0xff000000U) >> 24))))))) + curr_offset;
700 | tcp_out_seq_num = g_htonl(tcp_out_seq_num)(((((guint32) ( (((guint32) (tcp_out_seq_num) & (guint32) 0x000000ffU) << 24) | (((guint32) (tcp_out_seq_num) & (guint32) 0x0000ff00U) << 8) | (((guint32) (tcp_out_seq_num ) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (tcp_out_seq_num ) & (guint32) 0xff000000U) >> 24))))));
701 | }
702 | }
703 |
704 | /* Compute DATA chunk header and append padding */
705 | if (hdr_data_chunk) {
706 | hdr_data_chunk_bits = 0;
707 | if (packet_start == 0) {
708 | hdr_data_chunk_bits |= 0x02;
709 | }
710 | if (!cont) {
711 | hdr_data_chunk_bits |= 0x01;
712 | }
713 | HDR_DATA_CHUNK.type = hdr_data_chunk_type;
714 | HDR_DATA_CHUNK.bits = hdr_data_chunk_bits;
715 | HDR_DATA_CHUNK.length = g_htons(curr_offset + sizeof(HDR_DATA_CHUNK))(((((guint16) ( (guint16) ((guint16) (curr_offset + sizeof(HDR_DATA_CHUNK )) >> 8) | (guint16) ((guint16) (curr_offset + sizeof(HDR_DATA_CHUNK )) << 8))))));
716 | HDR_DATA_CHUNK.tsn = g_htonl(hdr_data_chunk_tsn)(((((guint32) ( (((guint32) (hdr_data_chunk_tsn) & (guint32 ) 0x000000ffU) << 24) | (((guint32) (hdr_data_chunk_tsn ) & (guint32) 0x0000ff00U) << 8) | (((guint32) (hdr_data_chunk_tsn ) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (hdr_data_chunk_tsn ) & (guint32) 0xff000000U) >> 24))))));
717 | HDR_DATA_CHUNK.sid = g_htons(hdr_data_chunk_sid)(((((guint16) ( (guint16) ((guint16) (hdr_data_chunk_sid) >> 8) | (guint16) ((guint16) (hdr_data_chunk_sid) << 8))) )));
718 | HDR_DATA_CHUNK.ssn = g_htons(hdr_data_chunk_ssn)(((((guint16) ( (guint16) ((guint16) (hdr_data_chunk_ssn) >> 8) | (guint16) ((guint16) (hdr_data_chunk_ssn) << 8))) )));
719 | HDR_DATA_CHUNK.ppid = g_htonl(info_p->ppi)(((((guint32) ( (((guint32) (info_p->ppi) & (guint32) 0x000000ffU ) << 24) | (((guint32) (info_p->ppi) & (guint32) 0x0000ff00U) << 8) | (((guint32) (info_p->ppi) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (info_p-> ppi) & (guint32) 0xff000000U) >> 24))))));
720 | hdr_data_chunk_tsn++;
721 | if (!cont) {
722 | hdr_data_chunk_ssn++;
723 | }
724 | padding_length = number_of_padding_bytes(curr_offset);
725 | for (i=0; i<padding_length; i++)
726 | packet_buf[curr_offset+i] = 0;
727 | curr_offset += padding_length;
728 | }
729 |
730 | /* Write SCTP header */
731 | if (hdr_sctp) {
732 | HDR_SCTP.src_port = isOutbound ? g_htons(info_p->dst_port)(((((guint16) ( (guint16) ((guint16) (info_p->dst_port) >> 8) | (guint16) ((guint16) (info_p->dst_port) << 8)) )))): g_htons(info_p->src_port)(((((guint16) ( (guint16) ((guint16) (info_p->src_port) >> 8) | (guint16) ((guint16) (info_p->src_port) << 8)) ))));
733 | HDR_SCTP.dest_port = isOutbound ? g_htons(info_p->src_port)(((((guint16) ( (guint16) ((guint16) (info_p->src_port) >> 8) | (guint16) ((guint16) (info_p->src_port) << 8)) )))) : g_htons(info_p->dst_port)(((((guint16) ( (guint16) ((guint16) (info_p->dst_port) >> 8) | (guint16) ((guint16) (info_p->dst_port) << 8)) ))));
734 | HDR_SCTP.tag = g_htonl(info_p->tag)(((((guint32) ( (((guint32) (info_p->tag) & (guint32) 0x000000ffU ) << 24) | (((guint32) (info_p->tag) & (guint32) 0x0000ff00U) << 8) | (((guint32) (info_p->tag) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (info_p-> tag) & (guint32) 0xff000000U) >> 24))))));
735 | HDR_SCTP.checksum = g_htonl(0)(((((guint32) ( (((guint32) (0) & (guint32) 0x000000ffU) << 24) | (((guint32) (0) & (guint32) 0x0000ff00U) << 8 ) | (((guint32) (0) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (0) & (guint32) 0xff000000U) >> 24)))) ));
736 |
737 | HDR_SCTP.checksum = crc32c_calculate(&HDR_SCTP, sizeof(HDR_SCTP), CRC32C_PRELOAD0xffffffff);
738 | if (hdr_data_chunk)
739 | HDR_SCTP.checksum = crc32c_calculate(&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK), HDR_SCTP.checksum);
740 | HDR_SCTP.checksum = g_htonl(~crc32c_calculate(packet_buf, curr_offset, HDR_SCTP.checksum))(((((guint32) ( (((guint32) (~crc32c_calculate(packet_buf, curr_offset , HDR_SCTP.checksum)) & (guint32) 0x000000ffU) << 24 ) | (((guint32) (~crc32c_calculate(packet_buf, curr_offset, HDR_SCTP .checksum)) & (guint32) 0x0000ff00U) << 8) | (((guint32 ) (~crc32c_calculate(packet_buf, curr_offset, HDR_SCTP.checksum )) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (~crc32c_calculate (packet_buf, curr_offset, HDR_SCTP.checksum)) & (guint32) 0xff000000U) >> 24))))));
741 |
742 | ws_buffer_append(&prefix_buf, (uint8_t*)&HDR_SCTP, sizeof(HDR_SCTP));
743 | }
744 |
745 | /* Write DATA chunk header */
746 | if (hdr_data_chunk) {
747 | ws_buffer_append(&prefix_buf, (uint8_t*)&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK));
748 | }
749 |
750 | /* Write ExportPDU header */
751 | if (hdr_export_pdu) {
752 | unsigned payload_len = (unsigned)strlen(info_p->payload);
753 | HDR_EXPORT_PDU.tag_type = g_htons(EXP_PDU_TAG_DISSECTOR_NAME)(((((guint16) ( (guint16) ((guint16) (12) >> 8) | (guint16 ) ((guint16) (12) << 8))))));
754 | HDR_EXPORT_PDU.payload_len = g_htons(payload_len)(((((guint16) ( (guint16) ((guint16) (payload_len) >> 8 ) | (guint16) ((guint16) (payload_len) << 8))))));
755 | ws_buffer_append(&prefix_buf, (uint8_t*)&HDR_EXPORT_PDU, sizeof(HDR_EXPORT_PDU));
756 | ws_buffer_append(&prefix_buf, (uint8_t*)info_p->payload, payload_len);
757 | /* Add end-of-options tag */
758 | ws_buffer_assure_space(&prefix_buf, 4);
759 | memset(ws_buffer_end_ptr(&prefix_buf), 0x00, 4);
760 | ws_buffer_increase_length(&prefix_buf, 4);
761 | }
762 |
763 | HDR_TCP.seq_num = g_ntohl(HDR_TCP.seq_num)((((((guint32) ( (((guint32) (HDR_TCP.seq_num) & (guint32 ) 0x000000ffU) << 24) | (((guint32) (HDR_TCP.seq_num) & (guint32) 0x0000ff00U) << 8) | (((guint32) (HDR_TCP.seq_num ) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (HDR_TCP .seq_num) & (guint32) 0xff000000U) >> 24))))))) + curr_offset;
764 | HDR_TCP.seq_num = g_htonl(HDR_TCP.seq_num)(((((guint32) ( (((guint32) (HDR_TCP.seq_num) & (guint32) 0x000000ffU) << 24) | (((guint32) (HDR_TCP.seq_num) & (guint32) 0x0000ff00U) << 8) | (((guint32) (HDR_TCP.seq_num ) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (HDR_TCP .seq_num) & (guint32) 0xff000000U) >> 24))))));
765 |
766 | /* Write the record */
767 | int data_length;
768 | wtap_rec rec;
769 | int err;
770 | char *err_info;
771 |
772 | ws_assert(prefix_length == (int)ws_buffer_length(&prefix_buf))do { if ((1) && !(prefix_length == (int)ws_buffer_length (&prefix_buf))) ws_log_fatal_full("Main", LOG_LEVEL_ERROR , "ui/text_import.c", 772, __func__, "assertion failed: %s", "prefix_length == (int)ws_buffer_length(&prefix_buf)" ); } while (0);
773 |
774 | data_length = prefix_length + curr_offset + eth_trailer_length;
775 | wtap_rec_init(&rec, data_length);
776 |
777 | if (info_p->encapsulation == WTAP_ENCAP_SYSTEMD_JOURNAL203) {
778 | wtap_setup_systemd_journal_export_rec(&rec);
779 | rec.block = wtap_block_create(WTAP_BLOCK_SYSTEMD_JOURNAL_EXPORT);
780 | rec.rec_header.systemd_journal_export_header.record_len = data_length;
781 | rec.presence_flags = WTAP_HAS_CAP_LEN0x00000002|WTAP_HAS_TS0x00000001;
782 | /* XXX: Ignore our direction, packet id, and timestamp. For a
783 | * systemd Journal Export Block the timestamp comes from the
784 | * __REALTIME_TIMESTAMP= field. We don't check to see if that
785 | * field is there (it MUST be, but we don't check whether our
786 | * input is malformed in general), but since the presence flags
787 | * aren't really used when writing, it doesn't matter.
788 | */
789 | } else {
790 | wtap_setup_packet_rec(&rec, info_p->encapsulation);
791 | rec.block = wtap_block_create(WTAP_BLOCK_PACKET);
792 | rec.rec_header.packet_header.caplen = rec.rec_header.packet_header.len = data_length;
793 | rec.ts.secs = ts_sec;
794 | rec.ts.nsecs = ts_nsec;
795 | rec.presence_flags = WTAP_HAS_CAP_LEN0x00000002|WTAP_HAS_INTERFACE_ID0x00000004|WTAP_HAS_TS0x00000001;
796 | if (has_direction) {
797 | wtap_block_add_uint32_option(rec.block, OPT_PKT_FLAGS2, direction);
798 | }
799 | if (has_seqno) {
800 | wtap_block_add_uint64_option(rec.block, OPT_PKT_PACKETID5, seqno);
801 | }
802 | }
803 |
804 | ws_buffer_append_buffer(&rec.data, &prefix_buf);
805 | ws_buffer_append(&rec.data, packet_buf, curr_offset);
806 |
807 | /* Write Ethernet trailer */
808 | if (hdr_ethernet && eth_trailer_length > 0) {
809 | ws_buffer_assure_space(&rec.data, eth_trailer_length);
810 | memset(ws_buffer_end_ptr(&rec.data), 0, eth_trailer_length);
811 | ws_buffer_increase_length(&rec.data, eth_trailer_length);
812 | }
813 |
814 |
815 | if (!wtap_dump(info_p->wdh, &rec, &err, &err_info)) {
816 | report_cfile_write_failure(info_p->import_text_filename,
817 | info_p->output_filename, err, err_info,
818 | info_p->num_packets_read,
819 | wtap_dump_file_type_subtype(info_p->wdh));
820 | wtap_rec_cleanup(&rec);
821 | return IMPORT_FAILURE;
822 | }
823 | wtap_rec_cleanup(&rec);
824 | info_p->num_packets_written++;
825 | }
826 |
827 | packet_start += curr_offset;
828 | curr_offset = 0;
829 | return IMPORT_SUCCESS;
830 | }
831 |
832 |
833 | /*----------------------------------------------------------------------
834 | * Append a token to the packet preamble.
835 | */
836 | static import_status_t
837 | append_to_preamble(char *str)
838 | {
839 | size_t toklen;
840 |
841 | if (packet_preamble_len != 0) {
842 | if (packet_preamble_len == PACKET_PREAMBLE_MAX_LEN2048)
843 | return IMPORT_SUCCESS; /* no room to add more preamble */
844 | /* XXX: Just keep going? This is probably not a problem, unless
845 | * someone had >2000 bytes of whitespace before the timestamp... */
846 | /* Add a blank separator between the previous token and this token. */
847 | packet_preamble[packet_preamble_len++] = ' ';
848 | }
849 | if(str == NULL((void*)0)){
850 | report_failure("FATAL ERROR: str is NULL");
851 | return IMPORT_FAILURE;
852 | }
853 | toklen = strlen(str);
854 | if (toklen != 0) {
855 | if (packet_preamble_len + toklen > PACKET_PREAMBLE_MAX_LEN2048)
856 | return IMPORT_SUCCESS; /* no room to add token to the preamble */
857 | /* XXX: Just keep going? This is probably not a problem, as above.*/
858 | (void) g_strlcpy((char*)&packet_preamble[packet_preamble_len], str, PACKET_PREAMBLE_MAX_LEN2048);
859 | packet_preamble_len += (int) toklen;
860 | if (ws_log_get_level() >= LOG_LEVEL_NOISY) {
861 | char *c;
862 | char xs[PACKET_PREAMBLE_MAX_LEN2048];
863 | (void) g_strlcpy(xs, (const char*)packet_preamble, PACKET_PREAMBLE_MAX_LEN2048);
864 | while ((c = strchr(xs, '\r')) != NULL((void*)0)) *c=' ';
865 | ws_noisy("[[append_to_preamble: \"%s\"]]", xs)do { if (1) { ws_log_full("Main", LOG_LEVEL_NOISY, "ui/text_import.c" , 865, __func__, "[[append_to_preamble: \"%s\"]]", xs); } } while (0);
866 | }
867 | }
868 |
869 | return IMPORT_SUCCESS;
870 | }
871 |
872 | #define INVALID_VALUE(-1) (-1)
873 |
874 | /*
875 | * This includes not just true whitespace values, but also any other
876 | * character silently ignored if part of the data group match, such as
877 | * byte separators or the '=' used for padding at the end of Base64.
878 | */
879 | #define WHITESPACE_VALUE(-2) (-2)
880 |
881 | /*
882 | * Information on how to parse any plainly encoded binary data
883 | *
884 | * one Unit is least_common_multiple(bits_per_char, 8) bits.
885 | */
886 | struct plain_decoding_data {
887 | const char* name;
888 | unsigned chars_per_unit;
889 | unsigned bytes_per_unit : 3; /* Internally a uint64_t is used to hold units */
890 | unsigned bits_per_char : 6;
891 | int8_t table[256];
892 | };
893 |
894 | #define _INVALID_INIT2(-1), (-1) INVALID_VALUE(-1), INVALID_VALUE(-1)
895 | #define _INVALID_INIT4(-1), (-1), (-1), (-1) _INVALID_INIT2(-1), (-1), _INVALID_INIT2(-1), (-1)
896 | #define _INVALID_INIT8(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) _INVALID_INIT4(-1), (-1), (-1), (-1), _INVALID_INIT4(-1), (-1), (-1), (-1)
897 | #define _INVALID_INIT16(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1) _INVALID_INIT8(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), _INVALID_INIT8(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1)
898 | #define _INVALID_INIT32(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1) _INVALID_INIT16(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), _INVALID_INIT16(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1)
899 | #define _INVALID_INIT64(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1) _INVALID_INIT32(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), _INVALID_INIT32(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1)
900 | #define _INVALID_INIT128(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1) _INVALID_INIT64(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), _INVALID_INIT64(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1)
901 | #define _INVALID_INIT256(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) _INVALID_INIT128(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), _INVALID_INIT128(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1)
902 |
903 | #define INVALID_INIT(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) _INVALID_INIT256(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1)
904 | // this is a gcc/clang extension:
905 | // [0 ... 255] = INVALID_VALUE
906 |
907 | #define WHITESPACE_INIT[' '] = (-2), ['\t'] = (-2), ['\n'] = (-2), ['\v'] = (-2), ['\f' ] = (-2), ['\r'] = (-2) \
908 | [' '] = WHITESPACE_VALUE(-2), \
909 | ['\t'] = WHITESPACE_VALUE(-2), \
910 | ['\n'] = WHITESPACE_VALUE(-2), \
911 | ['\v'] = WHITESPACE_VALUE(-2), \
912 | ['\f'] = WHITESPACE_VALUE(-2), \
913 | ['\r'] = WHITESPACE_VALUE(-2)
914 |
915 |
916 | /*
917 | * Some compilers warn about initializing the same subobject
918 | * more than once with designated initializers.
919 | *
920 | * We're doing that - INVALID_INIT initializes everything to
921 | * INVALID_VALUE, but then we override selected elements -
922 | * but we know what we're doing, so just suppress that
923 | * warning.
924 | */
925 | DIAG_OFF_INIT_TWICEclang diagnostic push clang diagnostic ignored "-Winitializer-overrides"
926 |
927 | static const struct plain_decoding_data hex_decode_info = {
928 | .chars_per_unit = 2,
929 | .bytes_per_unit = 1,
930 | .bits_per_char = 4,
931 | .table = {
932 | INVALID_INIT(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1),
933 | WHITESPACE_INIT[' '] = (-2), ['\t'] = (-2), ['\n'] = (-2), ['\v'] = (-2), ['\f' ] = (-2), ['\r'] = (-2),
934 | [':'] = WHITESPACE_VALUE(-2),
935 | ['0'] = 0,1,2,3,4,5,6,7,8,9,
936 | ['A'] = 10,11,12,13,14,15,
937 | ['a'] = 10,11,12,13,14,15
938 | }
939 | };
940 |
941 | static const struct plain_decoding_data bin_decode_info = {
942 | .chars_per_unit = 8,
943 | .bytes_per_unit = 1,
944 | .bits_per_char = 1,
945 | .table = {
946 | INVALID_INIT(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1),
947 | WHITESPACE_INIT[' '] = (-2), ['\t'] = (-2), ['\n'] = (-2), ['\v'] = (-2), ['\f' ] = (-2), ['\r'] = (-2),
948 | ['0'] = 0, 1
949 | }
950 | };
951 |
952 | static const struct plain_decoding_data oct_decode_info = {
953 | .chars_per_unit = 8,
954 | .bytes_per_unit = 3,
955 | .bits_per_char = 3,
956 | .table = {
957 | INVALID_INIT(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1),
958 | WHITESPACE_INIT[' '] = (-2), ['\t'] = (-2), ['\n'] = (-2), ['\v'] = (-2), ['\f' ] = (-2), ['\r'] = (-2),
959 | ['0'] = 0,1,2,3,4,5,6,7
960 | }
961 | };
962 |
963 | static const struct plain_decoding_data base64_decode_info = {
964 | .chars_per_unit = 4,
965 | .bytes_per_unit = 3,
966 | .bits_per_char = 6,
967 | .table = {
968 | INVALID_INIT(-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), ( -1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (- 1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1 ), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1) , (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1),
969 | WHITESPACE_INIT[' '] = (-2), ['\t'] = (-2), ['\n'] = (-2), ['\v'] = (-2), ['\f' ] = (-2), ['\r'] = (-2),
970 | ['A'] = 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,
971 | ['a'] = 26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
972 | ['0'] = 52,53,54,55,56,57,58,59,60,61,
973 | ['+'] = 62,
974 | ['/'] = 63,
975 | ['='] = WHITESPACE_VALUE(-2) /* padding at the end, the decoder doesn't need this, so just ignores it */
976 | }
977 | };
978 |
979 | DIAG_ON_INIT_TWICEclang diagnostic pop
980 |
981 | /*******************************************************************************
982 | * The modularized part of this mess, used by the wrapper around the regex
983 | * engine in text_import_regex.c to hook into this state-machine backend.
984 | *
985 | * Should the rest be modularized as well? Maybe, but then start with pcap2text.c
986 | */
987 |
988 | /**
989 | * This function parses encoded data according to <encoding> into binary data.
990 | * It will continue until one of the following conditions is met:
991 | * - src is depleted
992 | * - dest cannot hold another full unit of data
993 | * - an invalid character is read
994 | * When this happens any complete bytes will be recovered from the remaining
995 | * possibly incomplete unit and stored to dest (there will be no incomplete unit
996 | * if dest is full). Any remaining bits will be discarded.
997 | * src and dest will be advanced to where parsing including this last incomplete
998 | * unit stopped.
999 | * If you want to continue parsing (meaning incomplete units were due to call
1000 | * fragmentation and not actually due to EOT) you have to resume the parser at
1001 | * *src_last_unit and dest - result % bytes_per_unit
1002 | */
1003 | static int parse_plain_data(unsigned char** src, const unsigned char* src_end,
1004 | uint8_t** dest, const uint8_t* dest_end, const struct plain_decoding_data* encoding,
1005 | unsigned char** src_last_unit) {
1006 | int status = 1;
1007 | int units = 0;
1008 | /* unit buffer */
1009 | uint64_t c_val = 0;
1010 | unsigned c_chars = 0;
1011 | /**
1012 | * Src data |- - -|- - -|- - -|- - -|- - -|- - -|- - -|- - -|
1013 | * Bytes |- - - - - - - -|- - - - - - - -|- - - - - - - -|
1014 | * Units |- - - - - - - - - - - - - - - - - - - - - - - -|
1015 | */
1016 | uint64_t val;
1017 | int j;
1018 | if (ws_log_get_level() >= LOG_LEVEL_NOISY) {
1019 | char* debug_str = wmem_strndup(NULL((void*)0), (const char*)*src, (src_end-*src));
1020 | ws_noisy("parsing data: %s", debug_str)do { if (1) { ws_log_full("Main", LOG_LEVEL_NOISY, "ui/text_import.c" , 1020, __func__, "parsing data: %s", debug_str); } } while ( 0);
1021 | wmem_free(NULL((void*)0), debug_str);
1022 | }
1023 | while (*src < src_end && *dest + encoding->bytes_per_unit <= dest_end) {
1024 | /*
1025 | * XXX - This reads one octet at a time. If the GRegex compile flag
1026 | * G_REGEX_RAW wasn't given, the match was done using UTF-8 characters.
1027 | * That's useful, I suppose, if the input file has UTF-8 text (comments,
1028 | * etc.) that ought to be ignored - but it means that character classes
1029 | * like \d and \s can match Unicode characters that might (but probably
1030 | * aren't) in the data. Those will cause an invalid value warning and
1031 | * abort, which is easier than adding full UTF-8 support here.
1032 | */
1033 | val = encoding->table[**src];
1034 | switch (val) {
1035 | case INVALID_VALUE(-1):
1036 | report_failure("Unexpected char %d in data", **src);
1037 | status = -1;
1038 | goto remainder;
1039 | case WHITESPACE_VALUE(-2):
1040 | break;
1041 | default:
1042 | c_val = c_val << encoding->bits_per_char | val;
1043 | ++c_chars;
1044 | /* another full unit */
1045 | if (c_chars == encoding->chars_per_unit) {
1046 | ++units;
1047 | if (src_last_unit)
1048 | *src_last_unit = *src;
1049 | c_chars = 0;
1050 | for (j = encoding->bytes_per_unit; j > 0; --j) {
1051 | **dest = (char) (c_val >> (j * 8 - 8));
1052 | *dest += 1;
1053 | }
1054 | }
1055 | }
1056 | *src += 1;
1057 | }
1058 | remainder:
1059 | for (j = c_chars * encoding->bits_per_char; j >= 8; j -= 8) {
1060 | **dest = (char) (c_val >> (j - 8));
1061 | *dest += 1;
1062 | }
1063 | return status * units;
1064 | }
1065 |
1066 | void parse_data(unsigned char* start_field, unsigned char* end_field, enum data_encoding encoding) {
1067 | uint8_t* dest = &packet_buf[curr_offset];
1068 | uint8_t* dest_end = &packet_buf[info_p->max_frame_length];
1069 |
1070 | const struct plain_decoding_data* table; /* should be further down */
1071 | switch (encoding) {
1072 | case ENCODING_PLAIN_HEX:
1073 | case ENCODING_PLAIN_OCT:
1074 | case ENCODING_PLAIN_BIN:
1075 | case ENCODING_BASE64:
1076 | /* const struct plain_decoding_data* table; // This can't be here because gcc says no */
1077 | switch (encoding) {
1078 | case ENCODING_PLAIN_HEX:
1079 | table = &hex_decode_info;
1080 | break;
1081 | case ENCODING_PLAIN_OCT:
1082 | table = &oct_decode_info;
1083 | break;
1084 | case ENCODING_PLAIN_BIN:
1085 | table = &bin_decode_info;
1086 | break;
1087 | case ENCODING_BASE64:
1088 | table = &base64_decode_info;
1089 | break;
1090 | default:
1091 | return;
1092 | }
1093 | info_p->num_packets_read++;
1094 | while (1) {
1095 | parse_plain_data(&start_field, end_field, &dest, dest_end, table, NULL((void*)0));
1096 | curr_offset = (int) (dest - packet_buf);
1097 | if (curr_offset == info_p->max_frame_length) {
1098 | write_current_packet(true1);
1099 | dest = &packet_buf[curr_offset];
1100 | } else
1101 | break;
1102 | }
1103 | break;
1104 | default:
1105 | ws_critical("not implemented/invalid encoding type")do { if (1) { ws_log_full("Main", LOG_LEVEL_CRITICAL, "ui/text_import.c" , 1105, __func__, "not implemented/invalid encoding type"); } } while (0);
1106 | return;
1107 | }
1108 | }
1109 |
1110 | #define setFlags(VAL, MASK, FLAGS)((VAL) & ~(MASK)) | ((FLAGS) & (MASK)) \
1111 | ((VAL) & ~(MASK)) | ((FLAGS) & (MASK))
1112 |
1113 | static void _parse_dir(const unsigned char* start_field, const unsigned char* end_field _U___attribute__((unused)), const char* in_indicator, const char* out_indicator, uint32_t* dir) {
1114 |
1115 | for (; *in_indicator && *start_field != *in_indicator; ++in_indicator);
1116 | if (*in_indicator) {
1117 | *dir = setFlags(*dir, PACK_FLAGS_DIRECTION_MASK << PACK_FLAGS_DIRECTION_SHIFT, PACK_FLAGS_DIRECTION_INBOUND)((*dir) & ~(0x00000003 << 0)) | ((1) & (0x00000003 << 0));
1118 | return;
1119 | }
1120 | for (; *out_indicator && *start_field != *out_indicator; ++out_indicator);
1121 | if (*out_indicator) {
1122 | *dir = setFlags(*dir, PACK_FLAGS_DIRECTION_MASK << PACK_FLAGS_DIRECTION_SHIFT, PACK_FLAGS_DIRECTION_OUTBOUND)((*dir) & ~(0x00000003 << 0)) | ((2) & (0x00000003 << 0));
1123 | return;
1124 | }
1125 | *dir = setFlags(*dir, PACK_FLAGS_DIRECTION_MASK << PACK_FLAGS_DIRECTION_SHIFT, PACK_FLAGS_DIRECTION_UNKNOWN)((*dir) & ~(0x00000003 << 0)) | ((0) & (0x00000003 << 0));
1126 | }
1127 |
1128 | void parse_dir(const unsigned char* start_field, const unsigned char* end_field, const char* in_indicator, const char* out_indicator) {
1129 | _parse_dir(start_field, end_field, in_indicator, out_indicator, &direction);
1130 | }
1131 |
1132 | #define PARSE_BUF64 64
1133 |
1134 | /* Attempt to parse a time according to the given format. If the conversion
1135 | * succeeds, set sec and nsec appropriately and return true. If it fails,
1136 | * leave sec and nsec unchanged and return false.
1137 | */
1138 | static bool_Bool
1139 | _parse_time(const unsigned char* start_field, const unsigned char* end_field, const char* _format, time_t* sec, unsigned* nsec) {
1140 | struct tm timecode;
1141 | time_t sec_buf;
1142 | int nsec_buf = 0;
1143 |
1144 | char field[PARSE_BUF64];
1145 | char format[PARSE_BUF64];
1146 |
1147 | char* subsecs_fmt;
1148 | int subseclen = -1;
1149 |
1150 | char *cursor;
1151 | char *p;
1152 | int i;
1153 |
1154 | (void) g_strlcpy(field, (const char*)start_field, MIN(end_field - start_field + 1, PARSE_BUF)(((end_field - start_field + 1) < (64)) ? (end_field - start_field + 1) : (64)));
1155 | if (ts_fmt_iso) {
1156 | nstime_t ts_iso;
1157 | if (!iso8601_to_nstime(&ts_iso, field, ISO8601_DATETIME_AUTO)) {
1158 | return false0;
1159 | }
1160 | *sec = ts_iso.secs;
1161 | *nsec = (unsigned)ts_iso.nsecs;
1162 | } else {
1163 | (void) g_strlcpy(format, _format, PARSE_BUF64);
1164 |
1165 | /*
1166 | * Initialize to today, local time, just in case not all fields
1167 | * of the date and time are specified.
1168 | */
1169 | timecode = timecode_default;
1170 | cursor = &field[0];
1171 |
1172 | /*
1173 | * %f is for fractions of seconds not supported by strptime
1174 | */
1175 | subsecs_fmt = g_strrstr(format, "%f");
1176 | if (subsecs_fmt) {
1177 | *subsecs_fmt = 0;
1178 | }
1179 |
1180 | cursor = ws_strptime_p(cursor, format, &timecode);
1181 |
1182 | if (cursor == NULL((void*)0)) {
1183 | return false0;
1184 | }
1185 |
1186 | if (subsecs_fmt != NULL((void*)0)) {
1187 | /*
1188 | * Parse subsecs and any following format
1189 | */
1190 | nsec_buf = (unsigned) strtol(cursor, &p, 10);
1191 | if (p == cursor) {
1192 | return false0;
1193 | }
1194 |
1195 | subseclen = (int) (p - cursor);
1196 | cursor = p;
1197 | cursor = ws_strptime_p(cursor, subsecs_fmt + 2, &timecode);
1198 | if (cursor == NULL((void*)0)) {
1199 | return false0;
1200 | }
1201 | }
1202 |
1203 | if (subseclen > 0) {
1204 | /*
1205 | * Convert that number to a number
1206 | * of nanoseconds; if it's N digits
1207 | * long, it's in units of 10^(-N) seconds,
1208 | * so, to convert it to units of
1209 | * 10^-9 seconds, we multiply by
1210 | * 10^(9-N).
1211 | */
1212 | if (subseclen > SUBSEC_PREC9) {
1213 | /*
1214 | * *More* than 9 digits; 9-N is
1215 | * negative, so we divide by
1216 | * 10^(N-9).
1217 | */
1218 | for (i = subseclen - SUBSEC_PREC9; i != 0; i--)
1219 | nsec_buf /= 10;
1220 | } else if (subseclen < SUBSEC_PREC9) {
1221 | for (i = SUBSEC_PREC9 - subseclen; i != 0; i--)
1222 | nsec_buf *= 10;
1223 | }
1224 | }
1225 |
1226 | if ( -1 == (sec_buf = mktime(&timecode)) ) {
1227 | return false0;
1228 | }
1229 |
1230 | *sec = sec_buf;
1231 | *nsec = (unsigned)nsec_buf;
1232 | }
1233 |
1234 | ws_noisy("parsed time %s Format(%s), time(%ju), subsecs(%u)\n", field, _format, (uintmax_t)*sec, (uint32_t)*nsec)do { if (1) { ws_log_full("Main", LOG_LEVEL_NOISY, "ui/text_import.c" , 1234, __func__, "parsed time %s Format(%s), time(%ju), subsecs(%u)\n" , field, _format, (uintmax_t)*sec, (uint32_t)*nsec); } } while (0);
1235 |
1236 | return true1;
1237 | }
1238 |
1239 | void parse_time(const unsigned char* start_field, const unsigned char* end_field, const char* format) {
1240 | if (format == NULL((void*)0) || !_parse_time(start_field, end_field, format, &ts_sec, &ts_nsec)) {
1241 | ts_nsec += ts_tick;
1242 | }
1243 | }
1244 |
1245 | void parse_seqno(const unsigned char* start_field, const unsigned char* end_field) {
1246 | /* Note the start and end are from g_match_info_fetch_named_pos(); the end
1247 | * position is the byte after the final byte of the match, so no adding 1.
1248 | */
1249 | if (!ws_buftou64(start_field, end_field - start_field, NULL((void*)0), &seqno)) {
1250 | const char* errstr = g_strerror(errno(*__errno_location ()));
1251 | report_warning("seqno parsing failed (%s)", errstr);
1252 | ws_warning("seqno parsing failed for input packet %d (%s).", info_p->num_packets_read, errstr)do { if (1) { ws_log_full("Main", LOG_LEVEL_WARNING, "ui/text_import.c" , 1252, __func__, "seqno parsing failed for input packet %d (%s)." , info_p->num_packets_read, errstr); } } while (0);
1253 | }
1254 | }
1255 |
1256 | void flush_packet(void) {
1257 | write_current_packet(false0);
1258 | }
1259 |
1260 | /*----------------------------------------------------------------------
1261 | * Parse the preamble to get the timecode.
1262 | */
1263 |
1264 | static void
1265 | parse_preamble (void)
1266 | {
1267 | int i;
1268 | bool_Bool got_time = false0;
1269 |
1270 | /*
1271 | * Null-terminate the preamble.
1272 | */
1273 | packet_preamble[packet_preamble_len] = '\0';
1274 |
1275 | if (has_direction) {
1276 | _parse_dir(&packet_preamble[0], &packet_preamble[1], "iI", "oO", &direction);
1277 | i = (direction == PACK_FLAGS_DIRECTION_UNKNOWN0) ? 0 : 1;
1278 | while (packet_preamble[i] == ' ' ||
1279 | packet_preamble[i] == '\r' ||
1280 | packet_preamble[i] == '\t') {
1281 | i++;
1282 | }
1283 | packet_preamble_len -= i;
1284 | /* Also move the trailing '\0'. */
1285 | memmove(packet_preamble, packet_preamble + i, packet_preamble_len + 1);
1286 | }
1287 |
1288 | /*
1289 | * If no time stamp format was specified, don't attempt to parse
1290 | * the packet preamble to extract a time stamp.
1291 | */
1292 |
1293 | /* Ensure preamble has more than two chars before attempting to parse.
1294 | * This should cover line breaks etc that get counted.
1295 | */
1296 | if ( info_p->timestamp_format != NULL((void*)0) && strlen((const char*)packet_preamble) > 2 ) {
1297 | got_time = _parse_time(packet_preamble, packet_preamble + strlen((const char*)packet_preamble), info_p->timestamp_format, &ts_sec, &ts_nsec);
1298 | if (!got_time) {
1299 | /* Let's only have a possible GUI popup once, other messages to log
1300 | */
1301 | if (!timecode_warned) {
1302 | report_warning("Time conversions (%s) failed, advancing time by %d ns from previous packet on failure. First failure was for %s on input packet %d.", info_p->timestamp_format, ts_tick, packet_preamble, info_p->num_packets_read);
1303 | timecode_warned = true1;
1304 | }
1305 | ws_warning("Time conversion (%s) failed for %s on input packet %d.", info_p->timestamp_format, packet_preamble, info_p->num_packets_read)do { if (1) { ws_log_full("Main", LOG_LEVEL_WARNING, "ui/text_import.c" , 1305, __func__, "Time conversion (%s) failed for %s on input packet %d." , info_p->timestamp_format, packet_preamble, info_p->num_packets_read ); } } while (0);
1306 | }
1307 | }
1308 | if (ws_log_get_level() >= LOG_LEVEL_NOISY) {
1309 | char *c;
1310 | while ((c = strchr((const char*)packet_preamble, '\r')) != NULL((void*)0)) *c=' ';
1311 | ws_noisy("[[parse_preamble: \"%s\"]]", packet_preamble)do { if (1) { ws_log_full("Main", LOG_LEVEL_NOISY, "ui/text_import.c" , 1311, __func__, "[[parse_preamble: \"%s\"]]", packet_preamble ); } } while (0);
1312 | ws_noisy("Format(%s), time(%ju), subsecs(%u)", info_p->timestamp_format, (uintmax_t)ts_sec, ts_nsec)do { if (1) { ws_log_full("Main", LOG_LEVEL_NOISY, "ui/text_import.c" , 1312, __func__, "Format(%s), time(%ju), subsecs(%u)", info_p ->timestamp_format, (uintmax_t)ts_sec, ts_nsec); } } while (0);
1313 | }
1314 |
1315 | if (!got_time) {
1316 | ts_nsec += ts_tick;
1317 | }
1318 |
1319 | /* Clear Preamble */
1320 | packet_preamble_len = 0;
1321 | }
1322 |
1323 | /*----------------------------------------------------------------------
1324 | * Start a new packet
1325 | *
1326 | * @param cont [IN] true if a new packet is starting because the max frame
1327 | * length was reached on the current packet, and the original packet from the
1328 | * input file is continued in a later frame. Passed to write_current_packet,
1329 | * where it is used to set fragmentation fields in dummy headers (currently
1330 | * only implemented for SCTP; IPv4 could be added later.)
1331 | */
1332 | static import_status_t
1333 | start_new_packet(bool_Bool cont)
1334 | {
1335 | ws_debug("Start new packet (cont = %s).", cont ? "true" : "false")do { if (1) { ws_log_full("Main", LOG_LEVEL_DEBUG, "ui/text_import.c" , 1335, __func__, "Start new packet (cont = %s).", cont ? "true" : "false"); } } while (0);
1336 |
1337 | /* Write out the current packet, if required */
1338 | if (write_current_packet(cont) != IMPORT_SUCCESS)
1339 | return IMPORT_FAILURE;
1340 | info_p->num_packets_read++;
1341 |
1342 | /* Ensure we parse the packet preamble as it may contain the time */
1343 | /* THIS IMPLIES A STATE TRANSITION OUTSIDE THE STATE MACHINE */
1344 | parse_preamble();
1345 |
1346 | return IMPORT_SUCCESS;
1347 | }
1348 |
1349 | /*----------------------------------------------------------------------
1350 | * Process a directive
1351 | */
1352 | static void
1353 | process_directive (char *str _U___attribute__((unused)))
1354 | {
1355 | char **tokens;
1356 | tokens = g_strsplit_set(str+10, "\r\n", 2);
12 | ← | Addition of a null pointer (from variable 'str') and a nonzero integer value results in undefined behavior
1357 | ws_message("--- Directive [%s] currently unsupported ---", tokens[0])do { if (1) { ws_log_full("Main", LOG_LEVEL_MESSAGE, ((void*) 0), -1, ((void*)0), "--- Directive [%s] currently unsupported ---" , tokens[0]); } } while (0);
1358 | g_strfreev(tokens);
1359 | }
1360 |
1361 | /*----------------------------------------------------------------------
1362 | * If this is a hex+ASCII dump, after finishing a line of packet bytes,
1363 | * test if the beginning of the hex portion would produce ASCII that
1364 | * would be treated as byte tokens (e.g., "61 62 20 ... ab "), and if so,
1365 | * look for the bytes and remove them from the output.
1366 | */
1367 | static void
1368 | process_rollback(bool_Bool by_eol)
1369 | {
1370 | int rollback = 0;
1371 | int pending_rollback = 0;
1372 | int line_size;
1373 | int i;
1374 | GString *s2;
1375 | char tmp_str[3];
1376 |
1377 | /* Here a line of pkt bytes reading is finished */
1378 | rollback = 0;
1379 | /* s2 is the ASCII string, s1 is the HEX string, e.g, when
1380 | s2 = "ab ", s1 = "616220"
1381 | we should find out the largest tail of s1 matches the head
1382 | of s2, it means the matched part in tail is the ASCII dump
1383 | of the head byte. Those matched should be rolled back. */
1384 | line_size = curr_offset-(int)(pkt_lnstart-packet_buf);
1385 | s2 = g_string_new(NULL((void*)0));
1386 | /* gather the possible pattern */
1387 | /* This is a simplified version of the lexical analysis done by the scanner
1388 | * and has to produce the same tokens. (Simpler because we only match bytes,
1389 | * space, and everything else.) Perhaps we should do lexical analysis with
1390 | * yy_scan_bytes. */
1391 | /* Note we have the bytes after any swapping of little endian byte groups
1392 | * has been done. That's what we want; various hexdump programs (hexdump,
1393 | * od, xxd) always output the ASCII dump in the natural order even if
1394 | * byte groups are little endian. */
1395 | i = 0;
1396 | while (i + 1 + rollback < line_size) {
1397 | if (pkt_lnstart[i] == ' ') {
1398 | /* Skip any spaces. We don't skip '\t', because in the ASCII dump
1399 | * those are converted to '.' and so wouldn't create extra byte
1400 | * tokens. */
1401 | i++;
1402 | continue;
1403 | }
1404 | tmp_str[0] = pkt_lnstart[i];
1405 | tmp_str[1] = pkt_lnstart[i+1];
1406 | tmp_str[2] = '\0';
1407 | /* it is a valid convertible string */
1408 | if (!g_ascii_isxdigit(tmp_str[0])((g_ascii_table[(guchar) (tmp_str[0])] & G_ASCII_XDIGIT) != 0) || !g_ascii_isxdigit(tmp_str[1])((g_ascii_table[(guchar) (tmp_str[1])] & G_ASCII_XDIGIT) != 0)) {
1409 | break;
1410 | }
1411 | g_string_append_c(s2, (char)strtoul(tmp_str, (char **)NULL, 16))g_string_append_c_inline (s2, (char)strtoul(tmp_str, (char ** )((void*)0), 16));
1412 | i += 2;
1413 | if (by_eol) {
1414 | rollback++;
1415 | } else {
1416 | pending_rollback++;
1417 | /* If we had a text token before EOL, then without ' ' after the
1418 | * byte it won't parse as a byte token in the ASCII dump.
1419 | * If we transitioned straight from T_BYTE to T_EOL, then we already
1420 | * know the entire ASCII dump parsed as bytes. */
1421 | if (!(i + rollback < line_size)) {
1422 | break;
1423 | }
1424 | if (pkt_lnstart[i] == ' ') {
1425 | rollback += pending_rollback;
1426 | pending_rollback = 0;
1427 | i++;
1428 | } else if (pending_rollback >= 4) {
1429 | break;
1430 | }
1431 | }
1432 | }
1433 | /* If the packet line start contains a possible byte pattern, the line end
1434 | should contain the matched pattern if the user gave the -a flag.
1435 | The line will be considered invalid if the byte pattern cannot find
1436 | a matched one in the line of packet buffer.
1437 |
1438 | XXX - We could instead do nothing (or warn) if the pattern isn't found.
1439 | That's probably better than dropping the entire line if the -a flag was
1440 | given despite there being no ASCII dump or if there is an ASCII dump but
1441 | separated by a delimiter like '|' that would prevent detecting it as
1442 | bytes. It's still better to avoid passing the flag if there is no ASCII
1443 | dump to avoid the extremely rare false detection where the actual bytes
1444 | look like a matching ASCII dump.
1445 | */
1446 | if (rollback > 0) {
1447 | if (strncmp((const char*)(pkt_lnstart+line_size-rollback), s2->str, rollback) == 0) {
1448 | unwrite_bytes(rollback);
1449 | } else {
1450 | /* Not matched. This line contains invalid packet bytes, so
1451 | discard the whole line */
1452 | /* The GUI only reports identical warnings once to save lots of pop-ups.
1453 | * Keep the unique information in a console message. */
1454 | report_warning("Expected ASCII rollback not found. Was ASCII identification enabled unnecessarily?");
1455 | ws_message("Expected %i byte%s to rollback at the end of line offset 0x%0X in packet %u.", rollback, plurality(rollback, "", "s"), curr_offset - line_size, info_p->num_packets_read)do { if (1) { ws_log_full("Main", LOG_LEVEL_MESSAGE, ((void*) 0), -1, ((void*)0), "Expected %i byte%s to rollback at the end of line offset 0x%0X in packet %u." , rollback, ((rollback) == 1 ? ("") : ("s")), curr_offset - line_size , info_p->num_packets_read); } } while (0);
1456 | unwrite_bytes(line_size);
1457 | }
1458 | }
1459 | g_string_free(s2, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (s2), ((!(0)))) : g_string_free_and_steal (s2)) : (g_string_free ) ((s2), ((!(0)))));
1460 | }
1461 |
1462 | /*----------------------------------------------------------------------
1463 | * Parse a single token (called from the scanner)
1464 | */
1465 | import_status_t
1466 | parse_token(token_t token, char *str)
1467 | {
1468 | uint32_t num;
1469 | char **tokens;
1470 |
1471 | /*
1472 | * This is implemented as a simple state machine of five states.
1473 | * State transitions are caused by tokens being received from the
1474 | * scanner. The code should be self_documenting.
1475 | */
1476 |
1477 | if (ws_log_get_level() >= LOG_LEVEL_NOISY) {
1 | Assuming the condition is true | →
2 | ← | Taking true branch | →
1478 | /* Sanitize - remove all '\r' */
1479 | char *c;
1480 | if (str!=NULL((void*)0)) { while ((c = strchr(str, '\r')) != NULL((void*)0)) *c=' '; }
3 | ← | Assuming 'str' is equal to NULL | →
4 | ← | Taking false branch | →
1481 |
1482 | ws_noisy("(%s, %s \"%s\") -> (",do { if (1) { ws_log_full("Main", LOG_LEVEL_NOISY, "ui/text_import.c" , 1483, __func__, "(%s, %s \"%s\") -> (", state_str[state] , token_str[token], str ? str : ""); } } while (0)
5 | ← | Taking true branch | →
6 | ← | '?' condition is false | →
7 | ← | Loop condition is false. Exiting loop | →
1483 | state_str[state], token_str[token], str ? str : "")do { if (1) { ws_log_full("Main", LOG_LEVEL_NOISY, "ui/text_import.c" , 1483, __func__, "(%s, %s \"%s\") -> (", state_str[state] , token_str[token], str ? str : ""); } } while (0);
1484 | }
1485 |
1486 | switch(state) {
8 | ← | Control jumps to 'case START_OF_LINE:' at line 1561 | →
1487 |
1488 | /* ----- Waiting for new packet -------------------------------------------*/
1489 | case INIT:
1490 | switch(token) {
1491 | case T_TEXT:
1492 | append_to_preamble(str);
1493 | break;
1494 | case T_DIRECTIVE:
1495 | process_directive(str);
1496 | break;
1497 | case T_OFFSET:
1498 | case T_BYTES:
1499 | if (offset_base == 0) {
1500 | append_to_preamble(str);
1501 | /* If we're still in the INIT state, maybe there's something
1502 | * odd like a time format with no separators. That wouldn't
1503 | * work in a mode with an offset, but give it a try.
1504 | */
1505 | tokens = g_strsplit_set(str, ": \t\r\n", 2);
1506 | if (!offset_warned) {
1507 | report_warning("Running in no offset mode but read offset (%s) at start of file, treating as preamble", tokens[0]);
1508 | offset_warned = true1;
1509 | }
1510 | ws_warning("Running in no offset mode but read offset (%s) at start of file, treating as preamble", tokens[0])do { if (1) { ws_log_full("Main", LOG_LEVEL_WARNING, "ui/text_import.c" , 1510, __func__, "Running in no offset mode but read offset (%s) at start of file, treating as preamble" , tokens[0]); } } while (0);
1511 | g_strfreev(tokens);
1512 | break;
1513 | }
1514 | if (parse_num(str, true1, &num) != IMPORT_SUCCESS)
1515 | return IMPORT_FAILURE;
1516 | if (num == 0) {
1517 | /* New packet starts here */
1518 | /* XXX - This could just be any other run of three or more
1519 | * zeros in a preamble. That only creates a problem if followed
1520 | * by something that looks like bytes (otherwise a zero length
1521 | * packet is ignored.)
1522 | */
1523 | if (start_new_packet(false0) != IMPORT_SUCCESS)
1524 | return IMPORT_FAILURE;
1525 | packet_start = 0;
1526 | state = READ_OFFSET;
1527 | pkt_lnstart = packet_buf + num;
1528 | } else {
1529 | /* Not a new packet; assume it's part of a preamble that
1530 | * looks like an offset token. (#17140)
1531 | */
1532 | append_to_preamble(str);
1533 | }
1534 | break;
1535 | case T_BYTE:
1536 | if (offset_base == 0) {
1537 | /* In no offset mode, assume this starts our packet */
1538 | if (start_new_packet(false0) != IMPORT_SUCCESS)
1539 | return IMPORT_FAILURE;
1540 | if (write_byte(str) != IMPORT_SUCCESS)
1541 | return IMPORT_FAILURE;
1542 | state = READ_BYTE;
1543 | pkt_lnstart = packet_buf;
1544 | break;
1545 | }
1546 | /* Otherwise, this is probably text that looks like a byte,
1547 | * e.g. a day or month with certain timestamp formats.
1548 | */
1549 | append_to_preamble(str);
1550 | break;
1551 | case T_EOF:
1552 | if (write_current_packet(false0) != IMPORT_SUCCESS)
1553 | return IMPORT_FAILURE;
1554 | break;
1555 | default:
1556 | break;
1557 | }
1558 | break;
1559 |
1560 | /* ----- Processing packet, start of new line -----------------------------*/
1561 | case START_OF_LINE:
1562 | switch(token) {
9 | ← | Control jumps to 'case T_DIRECTIVE:' at line 1574 | →
1563 | case T_TEXT:
1564 | /* If the only text allowed on the same line before an offset (other
1565 | * than the zero offset that begins a packet) were mailfwd ('>') and
1566 | * blanks, we could ignore those, and and switch back to INIT state
1567 | * here to decrease ambiguity. (That is, assume that other text at
1568 | * line start indicates the end of an old packet and start of new.)
1569 | */
1570 | if (offset_base != 0) {
1571 | append_to_preamble(str);
1572 | }
1573 | break;
1574 | case T_DIRECTIVE:
1575 | process_directive(str);
10 | ← | Passing null pointer value via 1st parameter 'str' | →
11 | ← | Calling 'process_directive' | →
1576 | break;
1577 | case T_OFFSET:
1578 | case T_BYTES:
1579 | if (offset_base == 0) {
1580 | /* After starting the packet there's no point adding it to
1581 | * the preamble in this mode (we only do one packet.)
1582 | * Use a generic warning message to suppress the many
1583 | * expected duplicates. */
1584 | tokens = g_strsplit_set(str, ": \t\r\n", 2);
1585 | if (!offset_warned) {
1586 | report_warning("Running in no offset mode but read offset (%s) at start of line, ignoring", tokens[0]);
1587 | offset_warned = true1;
1588 | }
1589 | ws_warning("Running in no offset mode but read offset (%s) at start of line, ignoring.", tokens[0])do { if (1) { ws_log_full("Main", LOG_LEVEL_WARNING, "ui/text_import.c" , 1589, __func__, "Running in no offset mode but read offset (%s) at start of line, ignoring." , tokens[0]); } } while (0);
1590 | g_strfreev(tokens);
1591 | break;
1592 | }
1593 | if (parse_num(str, true1, &num) != IMPORT_SUCCESS)
1594 | return IMPORT_FAILURE;
1595 | if (num == 0) {
1596 | /* New packet starts here */
1597 | /* XXX - This could just be any other run of three or more
1598 | * zeros in a preamble. That only creates a problem if followed
1599 | * by something that looks like bytes (otherwise a zero length
1600 | * packet is ignored.) */
1601 | if (start_new_packet(false0) != IMPORT_SUCCESS)
1602 | return IMPORT_FAILURE;
1603 | packet_start = 0;
1604 | state = READ_OFFSET;
1605 | } else if ((num - packet_start) != curr_offset) {
1606 | /*
1607 | * The offset we read isn't the one we expected.
1608 | * This may only mean that we mistakenly interpreted
1609 | * some text as byte values (e.g., if the text dump
1610 | * of packet data included a number with spaces around
1611 | * it). If the offset is less than what we expected,
1612 | * assume that's the problem, and throw away the putative
1613 | * extra byte values. (If identify_ascii is true, then
1614 | * process_rollback does something similar, except that
1615 | * it actually looks at the relevant bytes of the last
1616 | * line and works if the mistaken text is on the last
1617 | * line with an offset.)
1618 | *
1619 | * hexdump and od (but not xxd or tcpdump) print an extra
1620 | * offset with the total length followed by no bytes. This
1621 | * is necessary when those programs print multiple byte
1622 | * units instead of individual bytes. They will zero pad
1623 | * the last byte group, and the offset on the extra line
1624 | * is used to remove the excess null bytes. This also
1625 | * works for that case.
1626 | *
1627 | * In both of the above cases, the true offset should be
1628 | * between the previous line offset start and the current
1629 | * offset, as we only add bytes when a line started with
1630 | * the correct offset (except in no offset mode, where we
1631 | * don't get here.)
1632 | *
1633 | * XXX - It could be part of a preamble. There is a narrow
1634 | * window for false detection here, but it's possible if the
1635 | * line has, e.g., the packet length for the next packet.
1636 | */
1637 | if (num < curr_offset && (num >= (uint32_t)(pkt_lnstart - packet_buf))) {
1638 | unwrite_bytes(curr_offset - num);
1639 | state = READ_OFFSET;
1640 | } else {
1641 | /* Bad offset; switch to INIT state */
1642 | report_warning("Inconsistent offset. Ending current packet.");
1643 | ws_message("Inconsistent offset. Expecting %0X, got %0X. Ending current packet (%i).",do { if (1) { ws_log_full("Main", LOG_LEVEL_MESSAGE, ((void*) 0), -1, ((void*)0), "Inconsistent offset. Expecting %0X, got %0X. Ending current packet (%i)." , curr_offset, num, info_p->num_packets_read); } } while ( 0)
1644 | curr_offset, num, info_p->num_packets_read)do { if (1) { ws_log_full("Main", LOG_LEVEL_MESSAGE, ((void*) 0), -1, ((void*)0), "Inconsistent offset. Expecting %0X, got %0X. Ending current packet (%i)." , curr_offset, num, info_p->num_packets_read); } } while ( 0);
1645 | if (write_current_packet(false0) != IMPORT_SUCCESS)
1646 | return IMPORT_FAILURE;
1647 |
1648 | /* Instead of being an offset, it might be part of the preamble
1649 | * that looks like an offset, e.g. a year. (#17140)
1650 | */
1651 | append_to_preamble(str);
1652 | state = INIT;
1653 | }
1654 | } else {
1655 | /* Continues the previous packet at the correct offset */
1656 |
1657 | /* Clear Preamble (text in the middle of a packet isn't preamble) */
1658 | packet_preamble_len = 0;
1659 |
1660 | state = READ_OFFSET;
1661 | }
1662 | pkt_lnstart = packet_buf + num;
1663 | break;
1664 | case T_BYTE:
1665 | if (offset_base == 0) {
1666 | if (write_byte(str) != IMPORT_SUCCESS)
1667 | return IMPORT_FAILURE;
1668 | state = READ_BYTE;
1669 | pkt_lnstart = packet_buf;
1670 | break;
1671 | }
1672 | /* Since we expect an offset, assume this is text between packets
1673 | * that looks like a byte, e.g. a month or day.
1674 | */
1675 | append_to_preamble(str);
1676 | break;
1677 | case T_EOF:
1678 | if (write_current_packet(false0) != IMPORT_SUCCESS)
1679 | return IMPORT_FAILURE;
1680 | break;
1681 | default:
1682 | break;
1683 | }
1684 | break;
1685 |
1686 | /* ----- Processing packet, read offset -----------------------------------*/
1687 | case READ_OFFSET:
1688 | switch(token) {
1689 | case T_BYTE:
1690 | /* Record the byte */
1691 | state = READ_BYTE;
1692 | if (write_byte(str) != IMPORT_SUCCESS)
1693 | return IMPORT_FAILURE;
1694 | break;
1695 | case T_BYTES:
1696 | state = READ_BYTE;
1697 | if (write_bytes(str) != IMPORT_SUCCESS)
1698 | return IMPORT_FAILURE;
1699 | break;
1700 | case T_TEXT:
1701 | case T_DIRECTIVE:
1702 | case T_OFFSET:
1703 | state = READ_TEXT;
1704 | break;
1705 | case T_EOL:
1706 | state = START_OF_LINE;
1707 | break;
1708 | case T_EOF:
1709 | if (write_current_packet(false0) != IMPORT_SUCCESS)
1710 | return IMPORT_FAILURE;
1711 | break;
1712 | default:
1713 | break;
1714 | }
1715 | break;
1716 |
1717 | /* ----- Processing packet, read byte -------------------------------------*/
1718 | case READ_BYTE:
1719 | switch(token) {
1720 | case T_BYTE:
1721 | /* Record the byte */
1722 | if (write_byte(str) != IMPORT_SUCCESS)
1723 | return IMPORT_FAILURE;
1724 | break;
1725 | case T_BYTES:
1726 | if (write_bytes(str) != IMPORT_SUCCESS)
1727 | return IMPORT_FAILURE;
1728 | break;
1729 | case T_TEXT:
1730 | case T_DIRECTIVE:
1731 | case T_OFFSET:
1732 | state = READ_TEXT;
1733 | if (info_p->hexdump.identify_ascii) {
1734 | process_rollback(false0);
1735 | }
1736 | break;
1737 | case T_EOL:
1738 | state = START_OF_LINE;
1739 | if (info_p->hexdump.identify_ascii) {
1740 | process_rollback(true1);
1741 | }
1742 | break;
1743 | case T_EOF:
1744 | if (write_current_packet(false0) != IMPORT_SUCCESS)
1745 | return IMPORT_FAILURE;
1746 | break;
1747 | default:
1748 | break;
1749 | }
1750 | break;
1751 |
1752 | /* ----- Processing packet, read text -------------------------------------*/
1753 | case READ_TEXT:
1754 | switch(token) {
1755 | case T_EOL:
1756 | state = START_OF_LINE;
1757 | break;
1758 | case T_EOF:
1759 | if (write_current_packet(false0) != IMPORT_SUCCESS)
1760 | return IMPORT_FAILURE;
1761 | break;
1762 | default:
1763 | break;
1764 | }
1765 | break;
1766 |
1767 | default:
1768 | report_failure("FATAL ERROR: Bad state (%d)", state);
1769 | return IMPORT_FAILURE;
1770 | }
1771 |
1772 | ws_noisy(", %s)", state_str[state])do { if (1) { ws_log_full("Main", LOG_LEVEL_NOISY, "ui/text_import.c" , 1772, __func__, ", %s)", state_str[state]); } } while (0);
1773 |
1774 | return IMPORT_SUCCESS;
1775 | }
1776 |
1777 | /*----------------------------------------------------------------------
1778 | * Import a text file.
1779 | */
1780 | int
1781 | text_import(text_import_info_t * const info)
1782 | {
1783 | import_status_t status;
1784 | int ret;
1785 | struct tm *now_tm;
1786 |
1787 | /* Lets start from the beginning */
1788 | state = INIT;
1789 | curr_offset = 0;
1790 | packet_start = 0;
1791 | packet_preamble_len = 0;
1792 | direction = PACK_FLAGS_DIRECTION_UNKNOWN0;
1793 | ts_sec = time(0); /* initialize to current time */
1794 | now_tm = localtime(&ts_sec);
1795 | if (now_tm == NULL((void*)0)) {
1796 | /*
1797 | * This shouldn't happen - on UN*X, this should Just Work, and
1798 | * on 32 bit Windows built with 32 bit time_t, it won't work if ts_sec
1799 | * is before the Epoch, but it's long after 1970 (and even 32 bit
1800 | * Windows builds with 64 bit time_t by default now), so....
1801 | */
1802 | report_failure("localtime(right now) failed");
1803 | return WS_EXIT_INIT_FAILED8;
1804 | }
1805 | timecode_default = *now_tm;
1806 | timecode_default.tm_isdst = -1; /* Unknown for now, depends on time given to the strptime() function */
1807 | ts_nsec = 0;
1808 |
1809 | /* Get input parameters. */
1810 | info_p = info;
1811 |
1812 | if (info_p->max_frame_length > WTAP_MAX_PACKET_SIZE_STANDARD262144U) {
1813 | /* Our callers should guarantee this. */
1814 | report_failure("max frame length too large (%u > %u)", info_p->max_frame_length, WTAP_MAX_PACKET_SIZE_STANDARD262144U);
1815 | return WS_EXIT_INIT_FAILED8;
1816 | }
1817 |
1818 | /* Dummy headers */
1819 | hdr_ethernet = false0;
1820 | hdr_ip = false0;
1821 | hdr_udp = false0;
1822 | hdr_tcp = false0;
1823 | hdr_sctp = false0;
1824 | hdr_data_chunk = false0;
1825 | hdr_export_pdu = false0;
1826 |
1827 | if (info->mode == TEXT_IMPORT_HEXDUMP) {
1828 | switch (info->hexdump.offset_type)
1829 | {
1830 | case OFFSET_NONE:
1831 | offset_base = 0;
1832 | break;
1833 | case OFFSET_HEX:
1834 | offset_base = 16;
1835 | break;
1836 | case OFFSET_OCT:
1837 | offset_base = 8;
1838 | break;
1839 | case OFFSET_DEC:
1840 | offset_base = 10;
1841 | break;
1842 | }
1843 | has_direction = info->hexdump.has_direction;
1844 |
1845 | } else if (info->mode == TEXT_IMPORT_REGEX) {
1846 | has_direction = g_regex_get_string_number(info->regex.format, "dir") >= 0;
1847 | has_seqno = g_regex_get_string_number(info->regex.format, "seqno") >= 0;
1848 | }
1849 |
1850 | if (info->timestamp_format == NULL((void*)0) || g_ascii_strcasecmp(info->timestamp_format, "ISO")) {
1851 | ts_fmt_iso = false0;
1852 | } else {
1853 | ts_fmt_iso = true1;
1854 | }
1855 | offset_warned = false0;
1856 | timecode_warned = false0;
1857 |
1858 | /* XXX: It would be good to know the time precision of the file,
1859 | * to use for the time delta for packets without timestamps. (ts_tick)
1860 | * That could either be added to text_import_info_t or a method
1861 | * added to get it from wtap_dumper (which is opaque.)
1862 | */
1863 |
1864 | switch (info->dummy_header_type)
1865 | {
1866 | case HEADER_ETH:
1867 | hdr_ethernet = true1;
1868 | hdr_ethernet_proto = info->pid;
1869 | break;
1870 |
1871 | case HEADER_IPV4:
1872 | hdr_ip = true1;
1873 | hdr_ip_proto = info->protocol;
1874 | break;
1875 |
1876 | case HEADER_UDP:
1877 | hdr_udp = true1;
1878 | hdr_tcp = false0;
1879 | hdr_ip = true1;
1880 | hdr_ip_proto = 17;
1881 | break;
1882 |
1883 | case HEADER_TCP:
1884 | hdr_tcp = true1;
1885 | hdr_udp = false0;
1886 | hdr_ip = true1;
1887 | hdr_ip_proto = 6;
1888 | break;
1889 |
1890 | case HEADER_SCTP:
1891 | hdr_sctp = true1;
1892 | hdr_ip = true1;
1893 | hdr_ip_proto = 132;
1894 | break;
1895 |
1896 | case HEADER_SCTP_DATA:
1897 | hdr_sctp = true1;
1898 | hdr_data_chunk = true1;
1899 | hdr_ip = true1;
1900 | hdr_ip_proto = 132;
1901 | break;
1902 |
1903 | case HEADER_EXPORT_PDU:
1904 | hdr_export_pdu = true1;
1905 | break;
1906 |
1907 | default:
1908 | break;
1909 | }
1910 |
1911 | if (hdr_ip) {
1912 | if (info->ipv6) {
1913 | hdr_ipv6 = true1;
1914 | hdr_ip = false0;
1915 | hdr_ethernet_proto = 0x86DD;
1916 | } else {
1917 | hdr_ethernet_proto = 0x0800;
1918 | }
1919 |
1920 | switch (info->encapsulation) {
1921 |
1922 | case (WTAP_ENCAP_ETHERNET1):
1923 | hdr_ethernet = true1;
1924 | break;
1925 |
1926 | case (WTAP_ENCAP_RAW_IP7):
1927 | break;
1928 |
1929 | case (WTAP_ENCAP_RAW_IP4129):
1930 | if (info->ipv6) {
1931 | report_failure("Encapsulation %s only supports IPv4 headers, not IPv6", wtap_encap_name(info->encapsulation));
1932 | return WS_EXIT_INVALID_OPTION1;
1933 | }
1934 | break;
1935 |
1936 | case (WTAP_ENCAP_RAW_IP6130):
1937 | if (!info->ipv6) {
1938 | report_failure("Encapsulation %s only supports IPv6 headers, not IPv4", wtap_encap_name(info->encapsulation));
1939 | return WS_EXIT_INVALID_OPTION1;
1940 | }
1941 | break;
1942 |
1943 | default:
1944 | report_failure("Dummy IP header not supported with encapsulation: %s (%s)", wtap_encap_name(info->encapsulation), wtap_encap_description(info->encapsulation));
1945 | return WS_EXIT_INVALID_OPTION1;
1946 | }
1947 | }
1948 |
1949 | info->num_packets_read = 0;
1950 | info->num_packets_written = 0;
1951 |
1952 | packet_buf = (uint8_t *)g_malloc(WTAP_MAX_PACKET_SIZE_STANDARD262144U);
1953 |
1954 | ws_buffer_init(&prefix_buf, 2048);
1955 |
1956 | if (!packet_buf)
1957 | {
1958 | /* XXX: This doesn't happen, because g_malloc aborts the program on
1959 | * error, unlike malloc or g_try_malloc.
1960 | */
1961 | report_failure("FATAL ERROR: no memory for packet buffer");
1962 | return WS_EXIT_INIT_FAILED8;
1963 | }
1964 |
1965 | if (info->mode == TEXT_IMPORT_HEXDUMP) {
1966 | status = text_import_scan(info->hexdump.import_text_FILE);
1967 | switch(status) {
1968 | case (IMPORT_SUCCESS):
1969 | ret = 0;
1970 | break;
1971 | case (IMPORT_FAILURE):
1972 | ret = WS_EXIT_INVALID_FILE3;
1973 | break;
1974 | case (IMPORT_INIT_FAILED):
1975 | report_failure("Can't initialize scanner: %s", g_strerror(errno(*__errno_location ())));
1976 | ret = WS_EXIT_INIT_FAILED8;
1977 | break;
1978 | default:
1979 | ret = 0;
1980 | }
1981 | } else if (info->mode == TEXT_IMPORT_REGEX) {
1982 | ret = text_import_regex(info);
1983 | if (ret > 0) {
1984 | info->num_packets_read = ret;
1985 | ret = 0;
1986 | } else if (ret < 0) {
1987 | ret = WS_EXIT_INVALID_FILE3;
1988 | }
1989 | } else {
1990 | ret = WS_EXIT_INVALID_OPTION1;
1991 | }
1992 | g_free(packet_buf)(__builtin_object_size ((packet_buf), 0) != ((size_t) - 1)) ? g_free_sized (packet_buf, __builtin_object_size ((packet_buf ), 0)) : (g_free) (packet_buf);
1993 | ws_buffer_free(&prefix_buf);
1994 | return ret;
1995 | }
1996 |
1997 | /* Write the SHB and IDB to the wtap_dump_params before opening the wtap dump
1998 | * file. While dummy headers can be written automatically, this writes out
1999 | * some extra information including an optional interface name.
2000 | */
2001 | int
2002 | text_import_pre_open(wtap_dump_params * const params, int file_type_subtype, const char* const input_filename, const char* const interface_name)
2003 | {
2004 | wtap_block_t shb_hdr;
2005 | wtap_block_t int_data;
2006 | wtapng_if_descr_mandatory_t *int_data_mand;
2007 | char *comment;
2008 | GString *info_str;
2009 |
2010 | if (wtap_file_type_subtype_supports_block(file_type_subtype, WTAP_BLOCK_SECTION) != BLOCK_NOT_SUPPORTED &&
2011 | wtap_file_type_subtype_supports_option(file_type_subtype, WTAP_BLOCK_SECTION, OPT_COMMENT1) != OPTION_NOT_SUPPORTED) {
2012 |
2013 | shb_hdr = wtap_block_create(WTAP_BLOCK_SECTION);
2014 |
2015 | comment = ws_strdup_printf("Generated from input file %s.", input_filename)wmem_strdup_printf(((void*)0), "Generated from input file %s." , input_filename);
2016 | wtap_block_add_string_option(shb_hdr, OPT_COMMENT1, comment, strlen(comment));
2017 | g_free(comment)(__builtin_object_size ((comment), 0) != ((size_t) - 1)) ? g_free_sized (comment, __builtin_object_size ((comment), 0)) : (g_free) ( comment);
2018 |
2019 | info_str = g_string_new("");
2020 | get_cpu_info(info_str);
2021 | if (info_str->str) {
2022 | wtap_block_add_string_option(shb_hdr, OPT_SHB_HARDWARE2, info_str->str, info_str->len);
2023 | }
2024 | g_string_free(info_str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (info_str), ((!(0)))) : g_string_free_and_steal (info_str)) : (g_string_free) ((info_str), ((!(0)))));
2025 |
2026 | info_str = g_string_new("");
2027 | get_os_version_info(info_str);
2028 | if (info_str->str) {
2029 | wtap_block_add_string_option(shb_hdr, OPT_SHB_OS3, info_str->str, info_str->len);
2030 | }
2031 | g_string_free(info_str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (info_str), ((!(0)))) : g_string_free_and_steal (info_str)) : (g_string_free) ((info_str), ((!(0)))));
2032 |
2033 | wtap_block_add_string_option_format(shb_hdr, OPT_SHB_USERAPPL4, "%s", get_appname_and_version());
2034 |
2035 | params->shb_hdrs = g_array_new(false0, false0, sizeof(wtap_block_t));
2036 | g_array_append_val(params->shb_hdrs, shb_hdr)g_array_append_vals (params->shb_hdrs, &(shb_hdr), 1);
2037 | }
2038 |
2039 | /* wtap_dump_init_dumper() will create a interface block if the file type
2040 | * supports it and one isn't created already, but since we have the
2041 | * option of including the interface name, create it ourself.
2042 | *
2043 | * (XXX: IDBs should be optional for wtap_dump_init_dumper(), e.g. if
2044 | * the encap type is WTAP_ENCAP_SYSTEMD_JOURNAL, which doesn't use
2045 | * interfaces. But it's not, so always create it here.)
2046 | */
2047 | if (wtap_file_type_subtype_supports_block(file_type_subtype, WTAP_BLOCK_IF_ID_AND_INFO) != BLOCK_NOT_SUPPORTED) {
2048 | int_data = wtap_block_create(WTAP_BLOCK_IF_ID_AND_INFO);
2049 | int_data_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(int_data);
2050 |
2051 | int_data_mand->wtap_encap = params->encap;
2052 | int_data_mand->time_units_per_second = 1000000000;
2053 | int_data_mand->snap_len = params->snaplen;
2054 |
2055 | if (interface_name != NULL((void*)0)) {
2056 | wtap_block_add_string_option(int_data, OPT_IDB_NAME2, interface_name, strlen(interface_name));
2057 | } else {
2058 | wtap_block_add_string_option(int_data, OPT_IDB_NAME2, "Fake IF, text2pcap", strlen("Fake IF, text2pcap"));
2059 | }
2060 | if (params->tsprec >= 0 && params->tsprec <= WS_TSPREC_MAX9) {
2061 | /*
2062 | * This is a valid time precision.
2063 | */
2064 |
2065 | /*
2066 | * Compute 10^{params->tsprec}.
2067 | */
2068 | int_data_mand->time_units_per_second = 1;
2069 | for (int i = 0; i < params->tsprec; i++)
2070 | int_data_mand->time_units_per_second *= 10;
2071 |
2072 | if (params->tsprec != WTAP_TSPREC_USEC6) {
2073 | /*
2074 | * Microsecond precision is the default, so we only
2075 | * add an option if the precision isn't microsecond
2076 | * precision.
2077 | */
2078 | wtap_block_add_uint8_option(int_data, OPT_IDB_TSRESOL9, params->tsprec);
2079 | }
2080 | } else {
2081 | /*
2082 | * Either WTAP_TSPREC_PER_PACKET, WTAP_TSPREC_UNKNOWN,
2083 | * or not a valid precision.
2084 | *
2085 | * Don't do this.
2086 | */
2087 | ws_assert_not_reached()ws_log_fatal_full("Main", LOG_LEVEL_ERROR, "ui/text_import.c" , 2087, __func__, "assertion \"not reached\" failed");
2088 | }
2089 |
2090 | params->idb_inf = g_new(wtapng_iface_descriptions_t,1)((wtapng_iface_descriptions_t *) g_malloc_n ((1), sizeof (wtapng_iface_descriptions_t )));
2091 | params->idb_inf->interface_data = g_array_new(false0, false0, sizeof(wtap_block_t));
2092 | g_array_append_val(params->idb_inf->interface_data, int_data)g_array_append_vals (params->idb_inf->interface_data, & (int_data), 1);
2093 |
2094 | }
2095 |
2096 | return EXIT_SUCCESS0;
2097 | }