MSWSP: heur dissectors take a data pointer
[wireshark-wip.git] / text2pcap.c
blob1ed829628604b74e18fef52f456bace5e7313389
1 /**-*-C-*-**********************************************************************
3 * text2pcap.c
5 * Utility to convert an ASCII hexdump into a libpcap-format capture file
7 * (c) Copyright 2001 Ashok Narayanan <ashokn@cisco.com>
9 * $Id$
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 *******************************************************************************/
31 /*******************************************************************************
33 * This utility reads in an ASCII hexdump of this common format:
35 * 00000000 00 E0 1E A7 05 6F 00 10 5A A0 B9 12 08 00 46 00 .....o..Z.....F.
36 * 00000010 03 68 00 00 00 00 0A 2E EE 33 0F 19 08 7F 0F 19 .h.......3...\x7f..
37 * 00000020 03 80 94 04 00 00 10 01 16 A2 0A 00 03 50 00 0C .............P..
38 * 00000030 01 01 0F 19 03 80 11 01 1E 61 00 0C 03 01 0F 19 .........a......
40 * Each bytestring line consists of an offset, one or more bytes, and
41 * text at the end. An offset is defined as a hex string of more than
42 * two characters. A byte is defined as a hex string of exactly two
43 * characters. The text at the end is ignored, as is any text before
44 * the offset. Bytes read from a bytestring line are added to the
45 * current packet only if all the following conditions are satisfied:
47 * - No text appears between the offset and the bytes (any bytes appearing after
48 * such text would be ignored)
50 * - The offset must be arithmetically correct, i.e. if the offset is 00000020, then
51 * exactly 32 bytes must have been read into this packet before this. If the offset
52 * is wrong, the packet is immediately terminated
54 * A packet start is signaled by a zero offset.
56 * Lines starting with #TEXT2PCAP are directives. These allow the user
57 * to embed instructions into the capture file which allows text2pcap
58 * to take some actions (e.g. specifying the encapsulation
59 * etc.). Currently no directives are implemented.
61 * Lines beginning with # which are not directives are ignored as
62 * comments. Currently all non-hexdump text is ignored by text2pcap;
63 * in the future, text processing may be added, but lines prefixed
64 * with '#' will still be ignored.
66 * The output is a libpcap packet containing Ethernet frames by
67 * default. This program takes options which allow the user to add
68 * dummy Ethernet, IP and UDP or TCP headers to the packets in order
69 * to allow dumps of L3 or higher protocols to be decoded.
71 * Considerable flexibility is built into this code to read hexdumps
72 * of slightly different formats. For example, any text prefixing the
73 * hexdump line is dropped (including mail forwarding '>'). The offset
74 * can be any hex number of four digits or greater.
76 * This converter cannot read a single packet greater than 64KiB-1. Packet
77 * snaplength is automatically set to 64KiB-1.
80 #include "config.h"
83 * Just make sure we include the prototype for strptime as well
84 * (needed for glibc 2.2) but make sure we do this only if not
85 * yet defined.
87 #ifndef __USE_XOPEN
88 # define __USE_XOPEN
89 #endif
90 #ifndef _XOPEN_SOURCE
91 # ifndef __sun
92 # define _XOPEN_SOURCE 600
93 # endif
94 #endif
97 * Defining _XOPEN_SOURCE is needed on some platforms, e.g. platforms
98 * using glibc, to expand the set of things system header files define.
100 * Unfortunately, on other platforms, such as some versions of Solaris
101 * (including Solaris 10), it *reduces* that set as well, causing
102 * strptime() not to be declared, presumably because the version of the
103 * X/Open spec that _XOPEN_SOURCE implies doesn't include strptime() and
104 * blah blah blah namespace pollution blah blah blah.
106 * So we define __EXTENSIONS__ so that "strptime()" is declared.
108 #ifndef __EXTENSIONS__
109 # define __EXTENSIONS__
110 #endif
112 #include <ctype.h>
113 #include <stdio.h>
114 #include <stdlib.h>
115 #include <string.h>
116 #include <wsutil/file_util.h>
118 #include <time.h>
119 #include <glib.h>
121 #ifdef HAVE_UNISTD_H
122 # include <unistd.h>
123 #endif
125 #include <errno.h>
126 #include <assert.h>
128 #ifndef HAVE_GETOPT
129 #include "wsutil/wsgetopt.h"
130 #endif
132 #ifdef NEED_STRPTIME_H
133 # include "wsutil/strptime.h"
134 #endif
136 #include "pcapio.h"
137 #include "text2pcap.h"
138 #include "svnversion.h"
140 #ifdef _WIN32
141 #include <wsutil/unicode-utils.h>
142 #endif /* _WIN32 */
144 #ifdef HAVE_ARPA_INET_H
145 #include <arpa/inet.h>
146 #endif
148 #ifdef HAVE_WINSOCK2_H
149 #include <winsock2.h> /* needed to define AF_ values on Windows */
150 #endif
152 #ifndef HAVE_INET_ATON_H
153 # include "wsutil/inet_aton.h"
154 #endif
156 #ifdef HAVE_SYS_SOCKET_H
157 #include <sys/socket.h>
158 #endif
160 #ifdef NEED_INET_V6DEFS_H
161 # include "wsutil/inet_v6defs.h"
162 #endif
164 /*--- Options --------------------------------------------------------------------*/
166 /* File format */
167 static gboolean use_pcapng = FALSE;
169 /* Debug level */
170 static int debug = 0;
171 /* Be quiet */
172 static int quiet = FALSE;
174 /* Dummy Ethernet header */
175 static int hdr_ethernet = FALSE;
176 static guint32 hdr_ethernet_proto = 0;
178 /* Dummy IP header */
179 static int hdr_ip = FALSE;
180 static int hdr_ipv6 = FALSE;
181 static long hdr_ip_proto = 0;
183 /* Destination and source addresses for IP header */
184 static guint32 hdr_ip_dest_addr = 0;
185 static guint32 hdr_ip_src_addr = 0;
186 static guint8 hdr_ipv6_dest_addr[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
187 static guint8 hdr_ipv6_src_addr[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
188 static guint8 NO_IPv6_ADDRESS[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
190 /* Dummy UDP header */
191 static int hdr_udp = FALSE;
192 static guint32 hdr_dest_port = 0;
193 static guint32 hdr_src_port = 0;
195 /* Dummy TCP header */
196 static int hdr_tcp = FALSE;
198 /* Dummy SCTP header */
199 static int hdr_sctp = FALSE;
200 static guint32 hdr_sctp_src = 0;
201 static guint32 hdr_sctp_dest = 0;
202 static guint32 hdr_sctp_tag = 0;
204 /* Dummy DATA chunk header */
205 static int hdr_data_chunk = FALSE;
206 static guint8 hdr_data_chunk_type = 0;
207 static guint8 hdr_data_chunk_bits = 0;
208 static guint32 hdr_data_chunk_tsn = 0;
209 static guint16 hdr_data_chunk_sid = 0;
210 static guint16 hdr_data_chunk_ssn = 0;
211 static guint32 hdr_data_chunk_ppid = 0;
213 /* ASCII text dump identification */
214 static int identify_ascii = FALSE;
216 static gboolean has_direction = FALSE;
217 static guint32 direction = 0;
219 /*--- Local date -----------------------------------------------------------------*/
221 /* This is where we store the packet currently being built */
222 #define MAX_PACKET 65535
223 static guint8 packet_buf[MAX_PACKET];
224 static guint32 header_length;
225 static guint32 ip_offset;
226 static guint32 curr_offset;
227 static guint32 max_offset = MAX_PACKET;
228 static guint32 packet_start = 0;
229 static void start_new_packet(gboolean);
231 /* This buffer contains strings present before the packet offset 0 */
232 #define PACKET_PREAMBLE_MAX_LEN 2048
233 static guint8 packet_preamble[PACKET_PREAMBLE_MAX_LEN+1];
234 static int packet_preamble_len = 0;
236 /* Number of packets read and written */
237 static guint32 num_packets_read = 0;
238 static guint32 num_packets_written = 0;
239 static guint64 bytes_written = 0;
241 /* Time code of packet, derived from packet_preamble */
242 static time_t ts_sec = 0;
243 static guint32 ts_usec = 0;
244 static char *ts_fmt = NULL;
245 static struct tm timecode_default;
247 static guint8* pkt_lnstart;
249 /* Input file */
250 static const char *input_filename;
251 static FILE *input_file = NULL;
252 /* Output file */
253 static const char *output_filename;
254 static FILE *output_file = NULL;
256 /* Offset base to parse */
257 static guint32 offset_base = 16;
259 extern FILE *yyin;
261 /* ----- State machine -----------------------------------------------------------*/
263 /* Current state of parser */
264 typedef enum {
265 INIT, /* Waiting for start of new packet */
266 START_OF_LINE, /* Starting from beginning of line */
267 READ_OFFSET, /* Just read the offset */
268 READ_BYTE, /* Just read a byte */
269 READ_TEXT /* Just read text - ignore until EOL */
270 } parser_state_t;
271 static parser_state_t state = INIT;
273 static const char *state_str[] = {"Init",
274 "Start-of-line",
275 "Offset",
276 "Byte",
277 "Text"
280 static const char *token_str[] = {"",
281 "Byte",
282 "Offset",
283 "Directive",
284 "Text",
285 "End-of-line"
288 /* ----- Skeleton Packet Headers --------------------------------------------------*/
290 typedef struct {
291 guint8 dest_addr[6];
292 guint8 src_addr[6];
293 guint16 l3pid;
294 } hdr_ethernet_t;
296 static hdr_ethernet_t HDR_ETHERNET = {
297 {0x0a, 0x02, 0x02, 0x02, 0x02, 0x02},
298 {0x0a, 0x01, 0x01, 0x01, 0x01, 0x01},
301 typedef struct {
302 guint8 ver_hdrlen;
303 guint8 dscp;
304 guint16 packet_length;
305 guint16 identification;
306 guint8 flags;
307 guint8 fragment;
308 guint8 ttl;
309 guint8 protocol;
310 guint16 hdr_checksum;
311 guint32 src_addr;
312 guint32 dest_addr;
313 } hdr_ip_t;
315 static hdr_ip_t HDR_IP = {0x45, 0, 0, 0x3412, 0, 0, 0xff, 0, 0,
316 #ifdef WORDS_BIGENDIAN
317 0x0a010101, 0x0a020202
318 #else
319 0x0101010a, 0x0202020a
320 #endif
323 static struct { /* pseudo header for checksum calculation */
324 guint32 src_addr;
325 guint32 dest_addr;
326 guint8 zero;
327 guint8 protocol;
328 guint16 length;
329 } pseudoh;
332 /* headers taken from glibc */
334 /* IPv6 address */
335 struct hdr_in6_addr
337 union
339 guint8 __u6_addr8[16];
340 guint16 __u6_addr16[8];
341 guint32 __u6_addr32[4];
342 } __in6_u;
345 typedef struct {
346 union {
347 struct ip6_hdrctl {
348 guint32 ip6_un1_flow; /* 24 bits of flow-ID */
349 guint16 ip6_un1_plen; /* payload length */
350 guint8 ip6_un1_nxt; /* next header */
351 guint8 ip6_un1_hlim; /* hop limit */
352 } ip6_un1;
353 guint8 ip6_un2_vfc; /* 4 bits version, 4 bits priority */
354 } ip6_ctlun;
355 struct hdr_in6_addr ip6_src; /* source address */
356 struct hdr_in6_addr ip6_dst; /* destination address */
357 } hdr_ipv6_t;
359 static hdr_ipv6_t HDR_IPv6;
361 static struct { /* pseudo header ipv6 for checksum calculation */
362 struct hdr_in6_addr src_addr6;
363 struct hdr_in6_addr dst_addr6;
364 guint32 protocol;
365 guint32 zero;
366 } pseudoh6;
369 typedef struct {
370 guint16 source_port;
371 guint16 dest_port;
372 guint16 length;
373 guint16 checksum;
374 } hdr_udp_t;
376 static hdr_udp_t HDR_UDP = {0, 0, 0, 0};
378 typedef struct {
379 guint16 source_port;
380 guint16 dest_port;
381 guint32 seq_num;
382 guint32 ack_num;
383 guint8 hdr_length;
384 guint8 flags;
385 guint16 window;
386 guint16 checksum;
387 guint16 urg;
388 } hdr_tcp_t;
390 static hdr_tcp_t HDR_TCP = {0, 0, 0, 0, 0x50, 0, 0, 0, 0};
392 typedef struct {
393 guint16 src_port;
394 guint16 dest_port;
395 guint32 tag;
396 guint32 checksum;
397 } hdr_sctp_t;
399 static hdr_sctp_t HDR_SCTP = {0, 0, 0, 0};
401 typedef struct {
402 guint8 type;
403 guint8 bits;
404 guint16 length;
405 guint32 tsn;
406 guint16 sid;
407 guint16 ssn;
408 guint32 ppid;
409 } hdr_data_chunk_t;
411 static hdr_data_chunk_t HDR_DATA_CHUNK = {0, 0, 0, 0, 0, 0, 0};
413 static char tempbuf[64];
415 /*----------------------------------------------------------------------
416 * Stuff for writing a PCap file
418 #define PCAP_MAGIC 0xa1b2c3d4
419 #define PCAP_SNAPLEN 0xffff
421 /* "libpcap" file header (minus magic number). */
422 struct pcap_hdr {
423 guint32 magic; /* magic */
424 guint16 version_major; /* major version number */
425 guint16 version_minor; /* minor version number */
426 guint32 thiszone; /* GMT to local correction */
427 guint32 sigfigs; /* accuracy of timestamps */
428 guint32 snaplen; /* max length of captured packets, in octets */
429 guint32 network; /* data link type */
432 /* "libpcap" record header. */
433 struct pcaprec_hdr {
434 guint32 ts_sec; /* timestamp seconds */
435 guint32 ts_usec; /* timestamp microseconds */
436 guint32 incl_len; /* number of octets of packet saved in file */
437 guint32 orig_len; /* actual length of packet */
440 /* Link-layer type; see http://www.tcpdump.org/linktypes.html for details */
441 static guint32 pcap_link_type = 1; /* Default is LINKTYPE_ETHERNET */
443 /*----------------------------------------------------------------------
444 * Parse a single hex number
445 * Will abort the program if it can't parse the number
446 * Pass in TRUE if this is an offset, FALSE if not
448 static guint32
449 parse_num (const char *str, int offset)
451 guint32 num;
452 char *c;
454 num = (guint32)strtoul(str, &c, offset ? offset_base : 16);
455 if (c==str) {
456 fprintf(stderr, "FATAL ERROR: Bad hex number? [%s]\n", str);
457 exit(-1);
459 return num;
462 /*----------------------------------------------------------------------
463 * Write this byte into current packet
465 static void
466 write_byte (const char *str)
468 guint32 num;
470 num = parse_num(str, FALSE);
471 packet_buf[curr_offset] = (guint8) num;
472 curr_offset ++;
473 if (curr_offset - header_length >= max_offset) /* packet full */
474 start_new_packet(TRUE);
477 /*----------------------------------------------------------------------
478 * Write a number of bytes into current packet
481 static void
482 write_bytes(const char bytes[], guint32 nbytes)
484 guint32 i;
486 if (curr_offset + nbytes < MAX_PACKET) {
487 for (i = 0; i < nbytes; i++) {
488 packet_buf[curr_offset] = bytes[i];
489 curr_offset++;
494 /*----------------------------------------------------------------------
495 * Remove bytes from the current packet
497 static void
498 unwrite_bytes (guint32 nbytes)
500 curr_offset -= nbytes;
503 /*----------------------------------------------------------------------
504 * Compute one's complement checksum (from RFC1071)
506 static guint16
507 in_checksum (void *buf, guint32 count)
509 guint32 sum = 0;
510 guint16 *addr = (guint16 *)buf;
512 while (count > 1) {
513 /* This is the inner loop */
514 sum += g_ntohs(* (guint16 *) addr);
515 addr++;
516 count -= 2;
519 /* Add left-over byte, if any */
520 if (count > 0)
521 sum += g_ntohs(* (guint8 *) addr);
523 /* Fold 32-bit sum to 16 bits */
524 while (sum>>16)
525 sum = (sum & 0xffff) + (sum >> 16);
527 sum = ~sum;
528 return g_htons(sum);
531 /* The CRC32C code is taken from draft-ietf-tsvwg-sctpcsum-01.txt.
532 * That code is copyrighted by D. Otis and has been modified.
535 #define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])
536 static guint32 crc_c[256] =
538 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
539 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
540 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
541 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
542 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
543 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
544 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
545 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
546 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
547 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
548 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
549 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
550 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
551 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
552 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
553 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
554 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
555 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
556 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
557 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
558 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
559 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
560 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
561 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
562 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
563 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
564 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
565 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
566 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
567 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
568 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
569 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
570 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
571 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
572 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
573 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
574 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
575 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
576 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
577 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
578 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
579 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
580 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
581 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
582 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
583 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
584 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
585 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
586 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
587 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
588 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
589 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
590 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
591 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
592 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
593 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
594 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
595 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
596 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
597 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
598 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
599 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
600 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
601 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L,
604 static guint32
605 crc32c(const guint8* buf, unsigned int len, guint32 crc32_init)
607 unsigned int i;
608 guint32 crc32;
610 crc32 = crc32_init;
611 for (i = 0; i < len; i++)
612 CRC32C(crc32, buf[i]);
614 return ( crc32 );
617 static guint32
618 finalize_crc32c(guint32 crc32)
620 guint32 result;
621 guint8 byte0,byte1,byte2,byte3;
623 result = ~crc32;
624 byte0 = result & 0xff;
625 byte1 = (result>>8) & 0xff;
626 byte2 = (result>>16) & 0xff;
627 byte3 = (result>>24) & 0xff;
628 result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
629 return ( result );
632 static guint16
633 number_of_padding_bytes (guint32 length)
635 guint16 remainder;
637 remainder = length % 4;
639 if (remainder == 0)
640 return 0;
641 else
642 return 4 - remainder;
645 /*----------------------------------------------------------------------
646 * Write current packet out
648 static void
649 write_current_packet(gboolean cont)
651 guint32 length = 0;
652 guint16 padding_length = 0;
653 int err;
654 guint16 ihatemacros;
655 gboolean success;
657 if (curr_offset > header_length) {
658 /* Write the packet */
660 /* if defined IPv6 we should rewrite hdr_ethernet_proto anyways */
661 if(hdr_ipv6) {
662 hdr_ethernet_proto = 0x86DD;
663 hdr_ip = FALSE;
666 /* Compute packet length */
667 length = curr_offset;
668 if (hdr_sctp) {
669 padding_length = number_of_padding_bytes(length - header_length );
670 } else {
671 padding_length = 0;
673 /* Reset curr_offset, since we now write the headers */
674 curr_offset = 0;
676 /* Write Ethernet header */
677 if (hdr_ethernet) {
678 HDR_ETHERNET.l3pid = g_htons(hdr_ethernet_proto);
679 write_bytes((const char *)&HDR_ETHERNET, sizeof(HDR_ETHERNET));
682 /* Write IP header */
683 if (hdr_ip) {
684 if(hdr_ip_src_addr) HDR_IP.src_addr = hdr_ip_src_addr;
685 if(hdr_ip_dest_addr) HDR_IP.dest_addr = hdr_ip_dest_addr;
687 HDR_IP.packet_length = g_htons(length - ip_offset + padding_length);
688 HDR_IP.protocol = (guint8) hdr_ip_proto;
689 HDR_IP.hdr_checksum = 0;
690 HDR_IP.hdr_checksum = in_checksum(&HDR_IP, sizeof(HDR_IP));
691 write_bytes((const char *)&HDR_IP, sizeof(HDR_IP));
692 } else if (hdr_ipv6) {
693 if(memcmp(hdr_ipv6_src_addr, NO_IPv6_ADDRESS, sizeof(struct hdr_in6_addr)))
694 memcpy(&HDR_IPv6.ip6_src, &hdr_ipv6_src_addr, sizeof(struct hdr_in6_addr));
695 if(memcmp(hdr_ipv6_dest_addr, NO_IPv6_ADDRESS, sizeof(struct hdr_in6_addr)))
696 memcpy(&HDR_IPv6.ip6_dst, &hdr_ipv6_dest_addr, sizeof(struct hdr_in6_addr));
698 HDR_IPv6.ip6_ctlun.ip6_un2_vfc &= 0x0F;
699 HDR_IPv6.ip6_ctlun.ip6_un2_vfc |= (6<< 4);
700 HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_plen = g_htons(length - ip_offset + padding_length);
701 HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_nxt = (guint8) hdr_ip_proto;
702 HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_hlim = 32;
703 write_bytes((const char *)&HDR_IPv6, sizeof(HDR_IPv6));
705 /* initialize pseudo ipv6 header for checksum calculation */
706 pseudoh6.src_addr6 = HDR_IPv6.ip6_src;
707 pseudoh6.dst_addr6 = HDR_IPv6.ip6_dst;
708 pseudoh6.zero = 0;
709 pseudoh6.protocol = (guint8) hdr_ip_proto;
710 ihatemacros = g_ntohs(HDR_IPv6.ip6_ctlun.ip6_un1.ip6_un1_plen);
711 pseudoh.length = g_htons(length - ihatemacros + sizeof(HDR_UDP));
714 if(!hdr_ipv6) {
715 /* initialize pseudo header for checksum calculation */
716 pseudoh.src_addr = HDR_IP.src_addr;
717 pseudoh.dest_addr = HDR_IP.dest_addr;
718 pseudoh.zero = 0;
719 pseudoh.protocol = (guint8) hdr_ip_proto;
720 pseudoh.length = g_htons(length - header_length + sizeof(HDR_UDP));
723 /* Write UDP header */
724 if (hdr_udp) {
725 guint16 x16;
726 guint32 u;
728 /* initialize the UDP header */
729 HDR_UDP.source_port = g_htons(hdr_src_port);
730 HDR_UDP.dest_port = g_htons(hdr_dest_port);
731 HDR_UDP.length = pseudoh.length;
732 HDR_UDP.checksum = 0;
733 /* Note: g_ntohs()/g_htons() macro arg may be eval'd twice so calc value before invoking macro */
734 x16 = hdr_ipv6 ? in_checksum(&pseudoh6, sizeof(pseudoh6)) : in_checksum(&pseudoh, sizeof(pseudoh));
735 u = g_ntohs(x16);
736 x16 = in_checksum(&HDR_UDP, sizeof(HDR_UDP));
737 u += g_ntohs(x16);
738 x16 = in_checksum(packet_buf + header_length, length - header_length);
739 u += g_ntohs(x16);
740 x16 = (u & 0xffff) + (u>>16);
741 HDR_UDP.checksum = g_htons(x16);
742 if (HDR_UDP.checksum == 0) /* differentiate between 'none' and 0 */
743 HDR_UDP.checksum = g_htons(1);
744 write_bytes((const char *)&HDR_UDP, sizeof(HDR_UDP));
747 /* Write TCP header */
748 if (hdr_tcp) {
749 guint16 x16;
750 guint32 u;
752 /* initialize pseudo header for checksum calculation */
753 pseudoh.src_addr = HDR_IP.src_addr;
754 pseudoh.dest_addr = HDR_IP.dest_addr;
755 pseudoh.zero = 0;
756 pseudoh.protocol = (guint8) hdr_ip_proto;
757 pseudoh.length = g_htons(length - header_length + sizeof(HDR_TCP));
758 /* initialize the TCP header */
759 HDR_TCP.source_port = g_htons(hdr_src_port);
760 HDR_TCP.dest_port = g_htons(hdr_dest_port);
761 /* HDR_TCP.seq_num already correct */
762 HDR_TCP.window = g_htons(0x2000);
763 HDR_TCP.checksum = 0;
764 /* Note: g_ntohs()/g_htons() macro arg may be eval'd twice so calc value before invoking macro */
765 x16 = in_checksum(&pseudoh, sizeof(pseudoh));
766 u = g_ntohs(x16);
767 x16 = in_checksum(&HDR_TCP, sizeof(HDR_TCP));
768 u += g_ntohs(x16);
769 x16 = in_checksum(packet_buf + header_length, length - header_length);
770 u += g_ntohs(x16);
771 x16 = (u & 0xffff) + (u>>16);
772 HDR_TCP.checksum = g_htons(x16);
773 if (HDR_TCP.checksum == 0) /* differentiate between 'none' and 0 */
774 HDR_TCP.checksum = g_htons(1);
775 write_bytes((const char *)&HDR_TCP, sizeof(HDR_TCP));
776 HDR_TCP.seq_num = g_ntohl(HDR_TCP.seq_num) + length - header_length;
777 HDR_TCP.seq_num = g_htonl(HDR_TCP.seq_num);
780 /* Compute DATA chunk header */
781 if (hdr_data_chunk) {
782 hdr_data_chunk_bits = 0;
783 if (packet_start == 0) {
784 hdr_data_chunk_bits |= 0x02;
786 if (!cont) {
787 hdr_data_chunk_bits |= 0x01;
789 HDR_DATA_CHUNK.type = hdr_data_chunk_type;
790 HDR_DATA_CHUNK.bits = hdr_data_chunk_bits;
791 HDR_DATA_CHUNK.length = g_htons(length - header_length + sizeof(HDR_DATA_CHUNK));
792 HDR_DATA_CHUNK.tsn = g_htonl(hdr_data_chunk_tsn);
793 HDR_DATA_CHUNK.sid = g_htons(hdr_data_chunk_sid);
794 HDR_DATA_CHUNK.ssn = g_htons(hdr_data_chunk_ssn);
795 HDR_DATA_CHUNK.ppid = g_htonl(hdr_data_chunk_ppid);
796 hdr_data_chunk_tsn++;
797 if (!cont) {
798 hdr_data_chunk_ssn++;
802 /* Write SCTP common header */
803 if (hdr_sctp) {
804 guint32 zero = 0;
806 HDR_SCTP.src_port = g_htons(hdr_sctp_src);
807 HDR_SCTP.dest_port = g_htons(hdr_sctp_dest);
808 HDR_SCTP.tag = g_htonl(hdr_sctp_tag);
809 HDR_SCTP.checksum = g_htonl(0);
810 HDR_SCTP.checksum = crc32c((guint8 *)&HDR_SCTP, sizeof(HDR_SCTP), ~0L);
811 if (hdr_data_chunk) {
812 HDR_SCTP.checksum = crc32c((guint8 *)&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK), HDR_SCTP.checksum);
813 HDR_SCTP.checksum = crc32c((guint8 *)packet_buf + header_length, length - header_length, HDR_SCTP.checksum);
814 HDR_SCTP.checksum = crc32c((guint8 *)&zero, padding_length, HDR_SCTP.checksum);
815 } else {
816 HDR_SCTP.checksum = crc32c((guint8 *)packet_buf + header_length, length - header_length, HDR_SCTP.checksum);
818 HDR_SCTP.checksum = finalize_crc32c(HDR_SCTP.checksum);
819 HDR_SCTP.checksum = g_htonl(HDR_SCTP.checksum);
820 write_bytes((const char *)&HDR_SCTP, sizeof(HDR_SCTP));
823 /* Write DATA chunk header */
824 if (hdr_data_chunk) {
825 write_bytes((const char *)&HDR_DATA_CHUNK, sizeof(HDR_DATA_CHUNK));
828 /* Reset curr_offset, since we now write the trailers */
829 curr_offset = length;
831 /* Write DATA chunk padding */
832 if (hdr_data_chunk && (padding_length > 0)) {
833 memset(tempbuf, 0, padding_length);
834 write_bytes((const char *)&tempbuf, padding_length);
835 length += padding_length;
838 /* Write Ethernet trailer */
839 if (hdr_ethernet && (length < 60)) {
840 memset(tempbuf, 0, 60 - length);
841 write_bytes((const char *)&tempbuf, 60 - length);
842 length = 60;
844 if (use_pcapng) {
845 success = pcapng_write_enhanced_packet_block(output_file,
846 NULL,
847 ts_sec, ts_usec,
848 length, length,
850 1000000,
851 packet_buf, direction,
852 &bytes_written, &err);
853 } else {
854 success = libpcap_write_packet(output_file,
855 ts_sec, ts_usec,
856 length, length,
857 packet_buf,
858 &bytes_written, &err);
860 if (!success) {
861 fprintf(stderr, "File write error [%s] : %s\n",
862 output_filename, g_strerror(err));
863 exit(-1);
865 if (ts_fmt == NULL) {
866 /* fake packet counter */
867 ts_usec++;
869 if (!quiet) {
870 fprintf(stderr, "Wrote packet of %u bytes.\n", length);
872 num_packets_written ++;
875 packet_start += curr_offset - header_length;
876 curr_offset = header_length;
877 return;
880 /*----------------------------------------------------------------------
881 * Write file header and trailer
883 static void
884 write_file_header (void)
886 int err;
887 gboolean success;
889 if (use_pcapng) {
890 #ifdef SVNVERSION
891 const char *appname = "text2pcap (" SVNVERSION " from " SVNPATH ")";
892 #else
893 const char *appname = "text2pcap";
894 #endif
895 char comment[100];
897 g_snprintf(comment, sizeof(comment), "Generated from input file %s.", input_filename);
898 success = pcapng_write_session_header_block(output_file,
899 comment,
900 NULL,
901 NULL,
902 appname,
904 &bytes_written,
905 &err);
906 if (success) {
907 success = pcapng_write_interface_description_block(output_file,
908 NULL,
909 NULL,
910 NULL,
912 NULL,
913 pcap_link_type,
914 PCAP_SNAPLEN,
915 &bytes_written,
918 &err);
920 } else {
921 success = libpcap_write_file_header(output_file, pcap_link_type, PCAP_SNAPLEN,
922 FALSE, &bytes_written, &err);
924 if (!success) {
925 fprintf(stderr, "File write error [%s] : %s\n",
926 output_filename, g_strerror(err));
927 exit(-1);
931 static void
932 write_file_trailer (void)
934 int err;
935 gboolean success;
937 if (use_pcapng) {
938 success = pcapng_write_interface_statistics_block(output_file,
940 &bytes_written,
941 "Counters provided by text2pcap",
944 num_packets_written,
945 num_packets_written - num_packets_written,
946 &err);
948 } else {
949 success = TRUE;
951 if (!success) {
952 fprintf(stderr, "File write error [%s] : %s\n",
953 output_filename, g_strerror(err));
954 exit(-1);
956 return;
959 /*----------------------------------------------------------------------
960 * Append a token to the packet preamble.
962 static void
963 append_to_preamble(char *str)
965 size_t toklen;
967 if (packet_preamble_len != 0) {
968 if (packet_preamble_len == PACKET_PREAMBLE_MAX_LEN)
969 return; /* no room to add more preamble */
970 /* Add a blank separator between the previous token and this token. */
971 packet_preamble[packet_preamble_len++] = ' ';
973 toklen = strlen(str);
974 if (toklen != 0) {
975 if (packet_preamble_len + toklen > PACKET_PREAMBLE_MAX_LEN)
976 return; /* no room to add the token to the preamble */
977 g_strlcpy(&packet_preamble[packet_preamble_len], str, PACKET_PREAMBLE_MAX_LEN);
978 packet_preamble_len += (int) toklen;
979 if (debug >= 2) {
980 char *c;
981 char xs[PACKET_PREAMBLE_MAX_LEN];
982 g_strlcpy(xs, packet_preamble, PACKET_PREAMBLE_MAX_LEN);
983 while ((c = strchr(xs, '\r')) != NULL) *c=' ';
984 fprintf (stderr, "[[append_to_preamble: \"%s\"]]", xs);
989 /*----------------------------------------------------------------------
990 * Parse the preamble to get the timecode.
993 static void
994 parse_preamble (void)
996 struct tm timecode;
997 char *subsecs;
998 char *p;
999 int subseclen;
1000 int i;
1003 * Null-terminate the preamble.
1005 packet_preamble[packet_preamble_len] = '\0';
1006 if (debug > 0)
1007 fprintf(stderr, "[[parse_preamble: \"%s\"]]\n", packet_preamble);
1009 if (has_direction) {
1010 switch (packet_preamble[0]) {
1011 case 'i':
1012 case 'I':
1013 direction = 0x00000001;
1014 packet_preamble[0] = ' ';
1015 break;
1016 case 'o':
1017 case 'O':
1018 direction = 0x00000002;
1019 packet_preamble[0] = ' ';
1020 break;
1021 default:
1022 direction = 0x00000000;
1023 break;
1025 i = 0;
1026 while (packet_preamble[i] == ' ' ||
1027 packet_preamble[i] == '\r' ||
1028 packet_preamble[i] == '\t') {
1029 i++;
1031 packet_preamble_len -= i;
1032 /* Also move the trailing '\0'. */
1033 memmove(packet_preamble, packet_preamble + i, packet_preamble_len + 1);
1038 * If no "-t" flag was specified, don't attempt to parse the packet
1039 * preamble to extract a time stamp.
1041 if (ts_fmt == NULL) {
1042 /* Clear Preamble */
1043 packet_preamble_len = 0;
1044 return;
1048 * Initialize to today localtime, just in case not all fields
1049 * of the date and time are specified.
1052 timecode = timecode_default;
1053 ts_usec = 0;
1055 /* Ensure preamble has more than two chars before attempting to parse.
1056 * This should cover line breaks etc that get counted.
1058 if (strlen(packet_preamble) > 2) {
1059 /* Get Time leaving subseconds */
1060 subsecs = strptime( packet_preamble, ts_fmt, &timecode );
1061 if (subsecs != NULL) {
1062 /* Get the long time from the tm structure */
1063 /* (will return -1 if failure) */
1064 ts_sec = mktime( &timecode );
1065 } else
1066 ts_sec = -1; /* we failed to parse it */
1068 /* This will ensure incorrectly parsed dates get set to zero */
1069 if (-1 == ts_sec) {
1070 /* Sanitize - remove all '\r' */
1071 char *c;
1072 while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
1073 fprintf (stderr, "Failure processing time \"%s\" using time format \"%s\"\n (defaulting to Jan 1,1970 00:00:00 GMT)\n",
1074 packet_preamble, ts_fmt);
1075 if (debug >= 2) {
1076 fprintf(stderr, "timecode: %02d/%02d/%d %02d:%02d:%02d %d\n",
1077 timecode.tm_mday, timecode.tm_mon, timecode.tm_year,
1078 timecode.tm_hour, timecode.tm_min, timecode.tm_sec, timecode.tm_isdst);
1080 ts_sec = 0; /* Jan 1,1970: 00:00 GMT; tshark/wireshark will display date/time as adjusted by timezone */
1081 ts_usec = 0;
1082 } else {
1083 /* Parse subseconds */
1084 ts_usec = (guint32)strtol(subsecs, &p, 10);
1085 if (subsecs == p) {
1086 /* Error */
1087 ts_usec = 0;
1088 } else {
1090 * Convert that number to a number
1091 * of microseconds; if it's N digits
1092 * long, it's in units of 10^(-N) seconds,
1093 * so, to convert it to units of
1094 * 10^-6 seconds, we multiply by
1095 * 10^(6-N).
1097 subseclen = (int) (p - subsecs);
1098 if (subseclen > 6) {
1100 * *More* than 6 digits; 6-N is
1101 * negative, so we divide by
1102 * 10^(N-6).
1104 for (i = subseclen - 6; i != 0; i--)
1105 ts_usec /= 10;
1106 } else if (subseclen < 6) {
1107 for (i = 6 - subseclen; i != 0; i--)
1108 ts_usec *= 10;
1113 if (debug >= 2) {
1114 char *c;
1115 while ((c = strchr(packet_preamble, '\r')) != NULL) *c=' ';
1116 fprintf(stderr, "[[parse_preamble: \"%s\"]]\n", packet_preamble);
1117 fprintf(stderr, "Format(%s), time(%u), subsecs(%u)\n", ts_fmt, (guint32)ts_sec, ts_usec);
1121 /* Clear Preamble */
1122 packet_preamble_len = 0;
1125 /*----------------------------------------------------------------------
1126 * Start a new packet
1128 static void
1129 start_new_packet(gboolean cont)
1131 if (debug >= 1)
1132 fprintf(stderr, "Start new packet (cont = %s).\n", cont ? "TRUE" : "FALSE");
1134 /* Write out the current packet, if required */
1135 write_current_packet(cont);
1136 num_packets_read ++;
1138 /* Ensure we parse the packet preamble as it may contain the time */
1139 parse_preamble();
1142 /*----------------------------------------------------------------------
1143 * Process a directive
1145 static void
1146 process_directive (char *str)
1148 fprintf(stderr, "\n--- Directive [%s] currently unsupported ---\n", str + 10);
1151 /*----------------------------------------------------------------------
1152 * Parse a single token (called from the scanner)
1154 void
1155 parse_token (token_t token, char *str)
1157 guint32 num;
1158 int by_eol;
1159 int rollback = 0;
1160 int line_size;
1161 int i;
1162 char* s2;
1163 char tmp_str[3];
1166 * This is implemented as a simple state machine of five states.
1167 * State transitions are caused by tokens being received from the
1168 * scanner. The code should be self_documenting.
1171 if (debug >= 2) {
1172 /* Sanitize - remove all '\r' */
1173 char *c;
1174 if (str!=NULL) { while ((c = strchr(str, '\r')) != NULL) *c=' '; }
1176 fprintf(stderr, "(%s, %s \"%s\") -> (",
1177 state_str[state], token_str[token], str ? str : "");
1180 switch(state) {
1182 /* ----- Waiting for new packet -------------------------------------------*/
1183 case INIT:
1184 switch(token) {
1185 case T_TEXT:
1186 append_to_preamble(str);
1187 break;
1188 case T_DIRECTIVE:
1189 process_directive(str);
1190 break;
1191 case T_OFFSET:
1192 num = parse_num(str, TRUE);
1193 if (num == 0) {
1194 /* New packet starts here */
1195 start_new_packet(FALSE);
1196 state = READ_OFFSET;
1197 pkt_lnstart = packet_buf + num;
1199 break;
1200 case T_EOL:
1201 /* Some describing text may be parsed as offset, but the invalid
1202 offset will be checked in the state of START_OF_LINE, so
1203 we add this transition to gain flexibility */
1204 state = START_OF_LINE;
1205 break;
1206 default:
1207 break;
1209 break;
1211 /* ----- Processing packet, start of new line -----------------------------*/
1212 case START_OF_LINE:
1213 switch(token) {
1214 case T_TEXT:
1215 append_to_preamble(str);
1216 break;
1217 case T_DIRECTIVE:
1218 process_directive(str);
1219 break;
1220 case T_OFFSET:
1221 num = parse_num(str, TRUE);
1222 if (num == 0) {
1223 /* New packet starts here */
1224 start_new_packet(FALSE);
1225 packet_start = 0;
1226 state = READ_OFFSET;
1227 } else if ((num - packet_start) != curr_offset - header_length) {
1229 * The offset we read isn't the one we expected.
1230 * This may only mean that we mistakenly interpreted
1231 * some text as byte values (e.g., if the text dump
1232 * of packet data included a number with spaces around
1233 * it). If the offset is less than what we expected,
1234 * assume that's the problem, and throw away the putative
1235 * extra byte values.
1237 if (num < curr_offset) {
1238 unwrite_bytes(curr_offset - num);
1239 state = READ_OFFSET;
1240 } else {
1241 /* Bad offset; switch to INIT state */
1242 if (debug >= 1)
1243 fprintf(stderr, "Inconsistent offset. Expecting %0X, got %0X. Ignoring rest of packet\n",
1244 curr_offset, num);
1245 write_current_packet(FALSE);
1246 state = INIT;
1248 } else
1249 state = READ_OFFSET;
1250 pkt_lnstart = packet_buf + num;
1251 break;
1252 case T_EOL:
1253 state = START_OF_LINE;
1254 break;
1255 default:
1256 break;
1258 break;
1260 /* ----- Processing packet, read offset -----------------------------------*/
1261 case READ_OFFSET:
1262 switch(token) {
1263 case T_BYTE:
1264 /* Record the byte */
1265 state = READ_BYTE;
1266 write_byte(str);
1267 break;
1268 case T_TEXT:
1269 case T_DIRECTIVE:
1270 case T_OFFSET:
1271 state = READ_TEXT;
1272 break;
1273 case T_EOL:
1274 state = START_OF_LINE;
1275 break;
1276 default:
1277 break;
1279 break;
1281 /* ----- Processing packet, read byte -------------------------------------*/
1282 case READ_BYTE:
1283 switch(token) {
1284 case T_BYTE:
1285 /* Record the byte */
1286 write_byte(str);
1287 break;
1288 case T_TEXT:
1289 case T_DIRECTIVE:
1290 case T_OFFSET:
1291 case T_EOL:
1292 by_eol = 0;
1293 state = READ_TEXT;
1294 if (token == T_EOL) {
1295 by_eol = 1;
1296 state = START_OF_LINE;
1298 if (identify_ascii) {
1299 /* Here a line of pkt bytes reading is finished
1300 compare the ascii and hex to avoid such situation:
1301 "61 62 20 ab ", when ab is ascii dump then it should
1302 not be treat as byte */
1303 rollback = 0;
1304 /* s2 is the ASCII string, s1 is the HEX string, e.g, when
1305 s2 = "ab ", s1 = "616220"
1306 we should find out the largest tail of s1 matches the head
1307 of s2, it means the matched part in tail is the ASCII dump
1308 of the head byte. These matched should be rollback */
1309 line_size = curr_offset-(int)(pkt_lnstart-packet_buf);
1310 s2 = (char*)g_malloc((line_size+1)/4+1);
1311 /* gather the possible pattern */
1312 for (i = 0; i < (line_size+1)/4; i++) {
1313 tmp_str[0] = pkt_lnstart[i*3];
1314 tmp_str[1] = pkt_lnstart[i*3+1];
1315 tmp_str[2] = '\0';
1316 /* it is a valid convertable string */
1317 if (!isxdigit(tmp_str[0]) || !isxdigit(tmp_str[0])) {
1318 break;
1320 s2[i] = (char)strtoul(tmp_str, (char **)NULL, 16);
1321 rollback++;
1322 /* the 3rd entry is not a delimiter, so the possible byte pattern will not shown */
1323 if (!(pkt_lnstart[i*3+2] == ' ')) {
1324 if (by_eol != 1)
1325 rollback--;
1326 break;
1329 /* If packet line start contains possible byte pattern, the line end
1330 should contain the matched pattern if the user open the -a flag.
1331 The packet will be possible invalid if the byte pattern cannot find
1332 a matched one in the line of packet buffer.*/
1333 if (rollback > 0) {
1334 if (strncmp(pkt_lnstart+line_size-rollback, s2, rollback) == 0) {
1335 unwrite_bytes(rollback);
1337 /* Not matched. This line contains invalid packet bytes, so
1338 discard the whole line */
1339 else {
1340 unwrite_bytes(line_size);
1343 g_free(s2);
1345 break;
1346 default:
1347 break;
1349 break;
1351 /* ----- Processing packet, read text -------------------------------------*/
1352 case READ_TEXT:
1353 switch(token) {
1354 case T_EOL:
1355 state = START_OF_LINE;
1356 break;
1357 default:
1358 break;
1360 break;
1362 default:
1363 fprintf(stderr, "FATAL ERROR: Bad state (%d)", state);
1364 exit(-1);
1367 if (debug>=2)
1368 fprintf(stderr, ", %s)\n", state_str[state]);
1372 /*----------------------------------------------------------------------
1373 * Print usage string and exit
1375 static void
1376 usage (void)
1378 fprintf(stderr,
1379 "Text2pcap %s"
1380 #ifdef SVNVERSION
1381 " (" SVNVERSION " from " SVNPATH ")"
1382 #endif
1383 "\n"
1384 "Generate a capture file from an ASCII hexdump of packets.\n"
1385 "See http://www.wireshark.org for more information.\n"
1386 "\n"
1387 "Usage: text2pcap [options] <infile> <outfile>\n"
1388 "\n"
1389 "where <infile> specifies input filename (use - for standard input)\n"
1390 " <outfile> specifies output filename (use - for standard output)\n"
1391 "\n"
1392 "Input:\n"
1393 " -o hex|oct|dec parse offsets as (h)ex, (o)ctal or (d)ecimal;\n"
1394 " default is hex.\n"
1395 " -t <timefmt> treat the text before the packet as a date/time code;\n"
1396 " the specified argument is a format string of the sort\n"
1397 " supported by strptime.\n"
1398 " Example: The time \"10:15:14.5476\" has the format code\n"
1399 " \"%%H:%%M:%%S.\"\n"
1400 " NOTE: The subsecond component delimiter, '.', must be\n"
1401 " given, but no pattern is required; the remaining\n"
1402 " number is assumed to be fractions of a second.\n"
1403 " NOTE: Date/time fields from the current date/time are\n"
1404 " used as the default for unspecified fields.\n"
1405 " -D the text before the packet starts with an I or an O,\n"
1406 " indicating that the packet is inbound or outbound.\n"
1407 " This is only stored if the output format is PCAP-NG.\n"
1408 " -a enable ASCII text dump identification.\n"
1409 " The start of the ASCII text dump can be identified\n"
1410 " and excluded from the packet data, even if it looks\n"
1411 " like a HEX dump.\n"
1412 " NOTE: Do not enable it if the input file does not\n"
1413 " contain the ASCII text dump.\n"
1414 "\n"
1415 "Output:\n"
1416 " -l <typenum> link-layer type number; default is 1 (Ethernet). See\n"
1417 " http://www.tcpdump.org/linktypes.html for a list of\n"
1418 " numbers. Use this option if your dump is a complete\n"
1419 " hex dump of an encapsulated packet and you wish to\n"
1420 " specify the exact type of encapsulation.\n"
1421 " Example: -l 7 for ARCNet packets.\n"
1422 " -m <max-packet> max packet length in output; default is %d\n"
1423 "\n"
1424 "Prepend dummy header:\n"
1425 " -e <l3pid> prepend dummy Ethernet II header with specified L3PID\n"
1426 " (in HEX).\n"
1427 " Example: -e 0x806 to specify an ARP packet.\n"
1428 " -i <proto> prepend dummy IP header with specified IP protocol\n"
1429 " (in DECIMAL).\n"
1430 " Automatically prepends Ethernet header as well.\n"
1431 " Example: -i 46\n"
1432 " -4 <srcip>,<destip> prepend dummy IPv4 header with specified\n"
1433 " dest and source address.\n"
1434 " Example: -4 10.0.0.1,10.0.0.2\n"
1435 " -6 <srcip>,<destip> replace IPv6 header with specified\n"
1436 " dest and source address.\n"
1437 " Example: -6 fe80:0:0:0:202:b3ff:fe1e:8329, 2001:0db8:85a3:0000:0000:8a2e:0370:7334\n"
1438 " -u <srcp>,<destp> prepend dummy UDP header with specified\n"
1439 " source and destination ports (in DECIMAL).\n"
1440 " Automatically prepends Ethernet & IP headers as well.\n"
1441 " Example: -u 1000,69 to make the packets look like\n"
1442 " TFTP/UDP packets.\n"
1443 " -T <srcp>,<destp> prepend dummy TCP header with specified\n"
1444 " source and destination ports (in DECIMAL).\n"
1445 " Automatically prepends Ethernet & IP headers as well.\n"
1446 " Example: -T 50,60\n"
1447 " -s <srcp>,<dstp>,<tag> prepend dummy SCTP header with specified\n"
1448 " source/dest ports and verification tag (in DECIMAL).\n"
1449 " Automatically prepends Ethernet & IP headers as well.\n"
1450 " Example: -s 30,40,34\n"
1451 " -S <srcp>,<dstp>,<ppi> prepend dummy SCTP header with specified\n"
1452 " source/dest ports and verification tag 0.\n"
1453 " Automatically prepends a dummy SCTP DATA\n"
1454 " chunk header with payload protocol identifier ppi.\n"
1455 " Example: -S 30,40,34\n"
1456 "\n"
1457 "Miscellaneous:\n"
1458 " -h display this help and exit.\n"
1459 " -d show detailed debug of parser states.\n"
1460 " -q generate no output at all (automatically disables -d).\n"
1461 " -n use PCAP-NG instead of PCAP as output format.\n"
1463 VERSION, MAX_PACKET);
1465 exit(-1);
1468 /*----------------------------------------------------------------------
1469 * Parse CLI options
1471 static void
1472 parse_options (int argc, char *argv[])
1474 int c;
1475 char *p;
1477 #ifdef _WIN32
1478 arg_list_utf_16to8(argc, argv);
1479 create_app_running_mutex();
1480 #endif /* _WIN32 */
1482 /* Scan CLI parameters */
1483 while ((c = getopt(argc, argv, "aDdhqe:i:l:m:no:u:s:S:t:T:4:6:")) != -1) {
1484 switch(c) {
1485 case '?': usage(); break;
1486 case 'h': usage(); break;
1487 case 'd': if (!quiet) debug++; break;
1488 case 'D': has_direction = TRUE; break;
1489 case 'q': quiet = TRUE; debug = FALSE; break;
1490 case 'l': pcap_link_type = (guint32)strtol(optarg, NULL, 0); break;
1491 case 'm': max_offset = (guint32)strtol(optarg, NULL, 0); break;
1492 case 'n': use_pcapng = TRUE; break;
1493 case 'o':
1494 if (optarg[0]!='h' && optarg[0] != 'o' && optarg[0] != 'd') {
1495 fprintf(stderr, "Bad argument for '-o': %s\n", optarg);
1496 usage();
1498 switch(optarg[0]) {
1499 case 'o': offset_base = 8; break;
1500 case 'h': offset_base = 16; break;
1501 case 'd': offset_base = 10; break;
1503 break;
1504 case 'e':
1505 hdr_ethernet = TRUE;
1506 if (sscanf(optarg, "%x", &hdr_ethernet_proto) < 1) {
1507 fprintf(stderr, "Bad argument for '-e': %s\n", optarg);
1508 usage();
1510 break;
1512 case 'i':
1513 hdr_ip = TRUE;
1514 hdr_ip_proto = strtol(optarg, &p, 10);
1515 if (p == optarg || *p != '\0' || hdr_ip_proto < 0 ||
1516 hdr_ip_proto > 255) {
1517 fprintf(stderr, "Bad argument for '-i': %s\n", optarg);
1518 usage();
1520 hdr_ethernet = TRUE;
1521 hdr_ethernet_proto = 0x800;
1522 break;
1524 case 's':
1525 hdr_sctp = TRUE;
1526 hdr_data_chunk = FALSE;
1527 hdr_tcp = FALSE;
1528 hdr_udp = FALSE;
1529 hdr_sctp_src = (guint32)strtol(optarg, &p, 10);
1530 if (p == optarg || (*p != ',' && *p != '\0')) {
1531 fprintf(stderr, "Bad src port for '-%c'\n", c);
1532 usage();
1534 if (*p == '\0') {
1535 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1536 usage();
1538 p++;
1539 optarg = p;
1540 hdr_sctp_dest = (guint32)strtol(optarg, &p, 10);
1541 if (p == optarg || (*p != ',' && *p != '\0')) {
1542 fprintf(stderr, "Bad dest port for '-s'\n");
1543 usage();
1545 if (*p == '\0') {
1546 fprintf(stderr, "No tag specified for '-%c'\n", c);
1547 usage();
1549 p++;
1550 optarg = p;
1551 hdr_sctp_tag = (guint32)strtol(optarg, &p, 10);
1552 if (p == optarg || *p != '\0') {
1553 fprintf(stderr, "Bad tag for '-%c'\n", c);
1554 usage();
1557 hdr_ip = TRUE;
1558 hdr_ip_proto = 132;
1559 hdr_ethernet = TRUE;
1560 hdr_ethernet_proto = 0x800;
1561 break;
1562 case 'S':
1563 hdr_sctp = TRUE;
1564 hdr_data_chunk = TRUE;
1565 hdr_tcp = FALSE;
1566 hdr_udp = FALSE;
1567 hdr_sctp_src = (guint32)strtol(optarg, &p, 10);
1568 if (p == optarg || (*p != ',' && *p != '\0')) {
1569 fprintf(stderr, "Bad src port for '-%c'\n", c);
1570 usage();
1572 if (*p == '\0') {
1573 fprintf(stderr, "No dest port specified for '-%c'\n", c);
1574 usage();
1576 p++;
1577 optarg = p;
1578 hdr_sctp_dest = (guint32)strtol(optarg, &p, 10);
1579 if (p == optarg || (*p != ',' && *p != '\0')) {
1580 fprintf(stderr, "Bad dest port for '-s'\n");
1581 usage();
1583 if (*p == '\0') {
1584 fprintf(stderr, "No ppi specified for '-%c'\n", c);
1585 usage();
1587 p++;
1588 optarg = p;
1589 hdr_data_chunk_ppid = (guint32)strtoul(optarg, &p, 10);
1590 if (p == optarg || *p != '\0') {
1591 fprintf(stderr, "Bad ppi for '-%c'\n", c);
1592 usage();
1595 hdr_ip = TRUE;
1596 hdr_ip_proto = 132;
1597 hdr_ethernet = TRUE;
1598 hdr_ethernet_proto = 0x800;
1599 break;
1601 case 't':
1602 ts_fmt = optarg;
1603 break;
1605 case 'u':
1606 hdr_udp = TRUE;
1607 hdr_tcp = FALSE;
1608 hdr_sctp = FALSE;
1609 hdr_data_chunk = FALSE;
1610 hdr_src_port = (guint32)strtol(optarg, &p, 10);
1611 if (p == optarg || (*p != ',' && *p != '\0')) {
1612 fprintf(stderr, "Bad src port for '-u'\n");
1613 usage();
1615 if (*p == '\0') {
1616 fprintf(stderr, "No dest port specified for '-u'\n");
1617 usage();
1619 p++;
1620 optarg = p;
1621 hdr_dest_port = (guint32)strtol(optarg, &p, 10);
1622 if (p == optarg || *p != '\0') {
1623 fprintf(stderr, "Bad dest port for '-u'\n");
1624 usage();
1626 hdr_ip = TRUE;
1627 hdr_ip_proto = 17;
1628 hdr_ethernet = TRUE;
1629 hdr_ethernet_proto = 0x800;
1630 break;
1632 case 'T':
1633 hdr_tcp = TRUE;
1634 hdr_udp = FALSE;
1635 hdr_sctp = FALSE;
1636 hdr_data_chunk = FALSE;
1637 hdr_src_port = (guint32)strtol(optarg, &p, 10);
1638 if (p == optarg || (*p != ',' && *p != '\0')) {
1639 fprintf(stderr, "Bad src port for '-T'\n");
1640 usage();
1642 if (*p == '\0') {
1643 fprintf(stderr, "No dest port specified for '-u'\n");
1644 usage();
1646 p++;
1647 optarg = p;
1648 hdr_dest_port = (guint32)strtol(optarg, &p, 10);
1649 if (p == optarg || *p != '\0') {
1650 fprintf(stderr, "Bad dest port for '-T'\n");
1651 usage();
1653 hdr_ip = TRUE;
1654 hdr_ip_proto = 6;
1655 hdr_ethernet = TRUE;
1656 hdr_ethernet_proto = 0x800;
1657 break;
1659 case 'a':
1660 identify_ascii = TRUE;
1661 break;
1663 case '4':
1664 case '6':
1665 p = strchr(optarg, ',');
1667 if (!p) {
1668 fprintf(stderr, "Bad source param addr for '-%c'\n", c);
1669 usage();
1672 *p = '\0';
1673 if(c == '6')
1675 hdr_ipv6 = TRUE;
1676 hdr_ethernet_proto = 0x86DD;
1678 else
1680 hdr_ip = TRUE;
1681 hdr_ethernet_proto = 0x800;
1683 hdr_ethernet = TRUE;
1685 if (hdr_ipv6 == TRUE) {
1686 if(inet_pton( AF_INET6, optarg, hdr_ipv6_src_addr) <= 0) {
1687 fprintf(stderr, "Bad src addr -%c '%s'\n", c, p);
1688 usage();
1690 } else {
1691 if(inet_pton( AF_INET, optarg, &hdr_ip_src_addr) <= 0) {
1692 fprintf(stderr, "Bad src addr -%c '%s'\n", c, p);
1693 usage();
1697 p++;
1698 if (*p == '\0') {
1699 fprintf(stderr, "No dest addr specified for '-%c'\n", c);
1700 usage();
1703 if (hdr_ipv6 == TRUE) {
1704 if(inet_pton( AF_INET6, p, hdr_ipv6_dest_addr) <= 0) {
1705 fprintf(stderr, "Bad dest addr for -%c '%s'\n", c, p);
1706 usage();
1708 } else {
1709 if(inet_pton( AF_INET, p, &hdr_ip_dest_addr) <= 0) {
1710 fprintf(stderr, "Bad dest addr for -%c '%s'\n", c, p);
1711 usage();
1714 break;
1717 default:
1718 usage();
1722 if (optind >= argc || argc-optind < 2) {
1723 fprintf(stderr, "Must specify input and output filename\n");
1724 usage();
1727 if (strcmp(argv[optind], "-")) {
1728 input_filename = g_strdup(argv[optind]);
1729 input_file = ws_fopen(input_filename, "rb");
1730 if (!input_file) {
1731 fprintf(stderr, "Cannot open file [%s] for reading: %s\n",
1732 input_filename, g_strerror(errno));
1733 exit(-1);
1735 } else {
1736 input_filename = "Standard input";
1737 input_file = stdin;
1740 if (strcmp(argv[optind+1], "-")) {
1741 output_filename = g_strdup(argv[optind+1]);
1742 output_file = ws_fopen(output_filename, "wb");
1743 if (!output_file) {
1744 fprintf(stderr, "Cannot open file [%s] for writing: %s\n",
1745 output_filename, g_strerror(errno));
1746 exit(-1);
1748 } else {
1749 output_filename = "Standard output";
1750 output_file = stdout;
1753 /* Some validation */
1754 if (pcap_link_type != 1 && hdr_ethernet) {
1755 fprintf(stderr, "Dummy headers (-e, -i, -u, -s, -S -T) cannot be specified with link type override (-l)\n");
1756 exit(-1);
1759 /* Set up our variables */
1760 if (!input_file) {
1761 input_file = stdin;
1762 input_filename = "Standard input";
1764 if (!output_file) {
1765 output_file = stdout;
1766 output_filename = "Standard output";
1769 ts_sec = time(0); /* initialize to current time */
1770 timecode_default = *localtime(&ts_sec);
1771 timecode_default.tm_isdst = -1; /* Unknown for now, depends on time given to the strptime() function */
1773 /* Display summary of our state */
1774 if (!quiet) {
1775 fprintf(stderr, "Input from: %s\n", input_filename);
1776 fprintf(stderr, "Output to: %s\n", output_filename);
1777 fprintf(stderr, "Output format: %s\n", use_pcapng ? "PCAP-NG" : "PCAP");
1779 if (hdr_ethernet) fprintf(stderr, "Generate dummy Ethernet header: Protocol: 0x%0X\n",
1780 hdr_ethernet_proto);
1781 if (hdr_ip) fprintf(stderr, "Generate dummy IP header: Protocol: %ld\n",
1782 hdr_ip_proto);
1783 if (hdr_udp) fprintf(stderr, "Generate dummy UDP header: Source port: %u. Dest port: %u\n",
1784 hdr_src_port, hdr_dest_port);
1785 if (hdr_tcp) fprintf(stderr, "Generate dummy TCP header: Source port: %u. Dest port: %u\n",
1786 hdr_src_port, hdr_dest_port);
1787 if (hdr_sctp) fprintf(stderr, "Generate dummy SCTP header: Source port: %u. Dest port: %u. Tag: %u\n",
1788 hdr_sctp_src, hdr_sctp_dest, hdr_sctp_tag);
1789 if (hdr_data_chunk) fprintf(stderr, "Generate dummy DATA chunk header: TSN: %u. SID: %d. SSN: %d. PPID: %u\n",
1790 hdr_data_chunk_tsn, hdr_data_chunk_sid, hdr_data_chunk_ssn, hdr_data_chunk_ppid);
1795 main(int argc, char *argv[])
1797 parse_options(argc, argv);
1799 assert(input_file != NULL);
1800 assert(output_file != NULL);
1802 write_file_header();
1804 header_length = 0;
1805 if (hdr_ethernet) {
1806 header_length += (int)sizeof(HDR_ETHERNET);
1808 if (hdr_ip) {
1809 ip_offset = header_length;
1810 header_length += (int)sizeof(HDR_IP);
1811 } else if (hdr_ipv6) {
1812 ip_offset = header_length;
1813 header_length += (int)sizeof(HDR_IPv6);
1815 if (hdr_sctp) {
1816 header_length += (int)sizeof(HDR_SCTP);
1818 if (hdr_data_chunk) {
1819 header_length += (int)sizeof(HDR_DATA_CHUNK);
1821 if (hdr_tcp) {
1822 header_length += (int)sizeof(HDR_TCP);
1824 if (hdr_udp) {
1825 header_length += (int)sizeof(HDR_UDP);
1827 curr_offset = header_length;
1829 yyin = input_file;
1830 yylex();
1832 write_current_packet(FALSE);
1833 write_file_trailer();
1834 fclose(input_file);
1835 fclose(output_file);
1836 if (debug)
1837 fprintf(stderr, "\n-------------------------\n");
1838 if (!quiet) {
1839 fprintf(stderr, "Read %u potential packet%s, wrote %u packet%s (%" G_GINT64_MODIFIER "u byte%s).\n",
1840 num_packets_read, (num_packets_read == 1) ? "" : "s",
1841 num_packets_written, (num_packets_written == 1) ? "" : "s",
1842 bytes_written, (bytes_written == 1) ? "" : "s");
1844 return 0;
1848 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1850 * Local variables:
1851 * c-basic-offset: 4
1852 * tab-width: 4
1853 * indent-tabs-mode: nil
1854 * End:
1856 * vi: set shiftwidth=4 tabstop=4 expandtab:
1857 * :indentSize=4:tabSize=4:noTabs=true: