4 * Wireshark's interface to the Lua Programming Language
6 * (c) 2006, Luis E. Garcia Ontanon <luis@ontanon.org>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * SPDX-License-Identifier: GPL-2.0-or-later
17 #include <wiretap/wtap_opttypes.h>
18 #include <epan/wmem_scopes.h>
20 /* WSLUA_MODULE Dumper Saving Capture Files
22 The classes/functions defined in this module are for using a `Dumper` object to
23 make Wireshark save a capture file to disk. `Dumper` represents Wireshark's built-in
24 file format writers (see the `wtap_name_to_file_type_subtype` function).
26 (The `wtap_filetypes` table is deprecated, and should
27 only be used in code that must run on Wireshark 3.4.3 and earlier 3.4
28 releases or in Wireshark 3.2.11 and earlier 3.2.x releases.)
30 To have a Lua script create its own file format writer, see the chapter titled
31 "Custom file format reading/writing".
37 WSLUA_CLASS_DEFINE(PseudoHeader
,NOP
);
39 A pseudoheader to be used to save captured frames.
42 enum lua_pseudoheader_type
{
58 struct lua_pseudo_header
{
59 enum lua_pseudoheader_type type
;
60 union wtap_pseudo_header
* wph
;
63 WSLUA_CONSTRUCTOR
PseudoHeader_none(lua_State
* L
) {
65 Creates a "no" pseudoheader.
68 PseudoHeader ph
= (PseudoHeader
)g_malloc(sizeof(struct lua_pseudo_header
));
72 pushPseudoHeader(L
,ph
);
75 /* A null pseudoheader */
78 WSLUA_CONSTRUCTOR
PseudoHeader_eth(lua_State
* L
) {
80 Creates an ethernet pseudoheader.
83 #define WSLUA_OPTARG_PseudoHeader_eth_FCSLEN 1 /* The fcs length */
85 PseudoHeader ph
= (PseudoHeader
)g_malloc(sizeof(struct lua_pseudo_header
));
87 ph
->wph
= (union wtap_pseudo_header
*)g_malloc(sizeof(union wtap_pseudo_header
));
88 ph
->wph
->eth
.fcs_len
= (int)luaL_optinteger(L
,WSLUA_OPTARG_PseudoHeader_eth_FCSLEN
,-1);
90 pushPseudoHeader(L
,ph
);
92 WSLUA_RETURN(1); /* The ethernet pseudoheader */
95 WSLUA_CONSTRUCTOR
PseudoHeader_atm(lua_State
* L
) {
97 Creates an ATM pseudoheader.
99 #define WSLUA_OPTARG_PseudoHeader_atm_AAL 1 /* AAL number */
100 #define WSLUA_OPTARG_PseudoHeader_atm_VPI 2 /* VPI */
101 #define WSLUA_OPTARG_PseudoHeader_atm_VCI 3 /* VCI */
102 #define WSLUA_OPTARG_PseudoHeader_atm_CHANNEL 4 /* Channel */
103 #define WSLUA_OPTARG_PseudoHeader_atm_CELLS 5 /* Number of cells in the PDU */
104 #define WSLUA_OPTARG_PseudoHeader_atm_AAL5U2U 6 /* AAL5 User to User indicator */
105 #define WSLUA_OPTARG_PseudoHeader_atm_AAL5LEN 7 /* AAL5 Len */
107 PseudoHeader ph
= (PseudoHeader
)g_malloc(sizeof(struct lua_pseudo_header
));
109 ph
->wph
= (union wtap_pseudo_header
*)g_malloc(sizeof(union wtap_pseudo_header
));
110 ph
->wph
->atm
.aal
= (uint8_t)luaL_optinteger(L
,WSLUA_OPTARG_PseudoHeader_atm_AAL
,5);
111 ph
->wph
->atm
.vpi
= (uint16_t)luaL_optinteger(L
,WSLUA_OPTARG_PseudoHeader_atm_VPI
,1);
112 ph
->wph
->atm
.vci
= (uint16_t)luaL_optinteger(L
,WSLUA_OPTARG_PseudoHeader_atm_VCI
,1);
113 ph
->wph
->atm
.channel
= (uint16_t)luaL_optinteger(L
,WSLUA_OPTARG_PseudoHeader_atm_CHANNEL
,0);
114 ph
->wph
->atm
.cells
= (uint16_t)luaL_optinteger(L
,WSLUA_OPTARG_PseudoHeader_atm_CELLS
,1);
115 ph
->wph
->atm
.aal5t_u2u
= (uint16_t)luaL_optinteger(L
,WSLUA_OPTARG_PseudoHeader_atm_AAL5U2U
,1);
116 ph
->wph
->atm
.aal5t_len
= (uint16_t)luaL_optinteger(L
,WSLUA_OPTARG_PseudoHeader_atm_AAL5LEN
,0);
118 pushPseudoHeader(L
,ph
);
120 /* The ATM pseudoheader */
123 WSLUA_CONSTRUCTOR
PseudoHeader_mtp2(lua_State
* L
) {
124 /* Creates an MTP2 PseudoHeader. */
125 #define WSLUA_OPTARG_PseudoHeader_mtp2_SENT 1 /* True if the packet is sent, False if received. */
126 #define WSLUA_OPTARG_PseudoHeader_mtp2_ANNEXA 2 /* True if annex A is used. */
127 #define WSLUA_OPTARG_PseudoHeader_mtp2_LINKNUM 3 /* Link Number. */
128 PseudoHeader ph
= (PseudoHeader
)g_malloc(sizeof(struct lua_pseudo_header
));
129 ph
->type
= PHDR_MTP2
;
130 ph
->wph
= (union wtap_pseudo_header
*)g_malloc(sizeof(union wtap_pseudo_header
));
131 ph
->wph
->mtp2
.sent
= (uint8_t)luaL_optinteger(L
,WSLUA_OPTARG_PseudoHeader_mtp2_SENT
,0);
132 ph
->wph
->mtp2
.annex_a_used
= (uint8_t)luaL_optinteger(L
,WSLUA_OPTARG_PseudoHeader_mtp2_ANNEXA
,0);
133 ph
->wph
->mtp2
.link_number
= (uint16_t)luaL_optinteger(L
,WSLUA_OPTARG_PseudoHeader_mtp2_LINKNUM
,0);
135 pushPseudoHeader(L
,ph
);
136 WSLUA_RETURN(1); /* The MTP2 pseudoheader */
140 static int PseudoHeader_x25(lua_State
* L
) { luaL_error(L
,"not implemented"); return 0; }
141 static int PseudoHeader_isdn(lua_State
* L
) { luaL_error(L
,"not implemented"); return 0; }
142 static int PseudoHeader_ascend(lua_State
* L
) { luaL_error(L
,"not implemented"); return 0; }
143 static int PseudoHeader_wifi(lua_State
* L
) { luaL_error(L
,"not implemented"); return 0; }
144 static int PseudoHeader_cosine(lua_State
* L
) { luaL_error(L
,"not implemented"); return 0; }
145 static int PseudoHeader_irda(lua_State
* L
) { luaL_error(L
,"not implemented"); return 0; }
146 static int PseudoHeader_nettl(lua_State
* L
) { luaL_error(L
,"not implemented"); return 0; }
147 static int PseudoHeader_k12(lua_State
* L
) { luaL_error(L
,"not implemented"); return 0; }
150 /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */
151 static int PseudoHeader__gc(lua_State
* L _U_
) {
152 /* do NOT free PseudoHeader */
156 WSLUA_METHODS PseudoHeader_methods
[] = {
157 WSLUA_CLASS_FNREG(PseudoHeader
,mtp2
),
158 WSLUA_CLASS_FNREG(PseudoHeader
,atm
),
159 WSLUA_CLASS_FNREG(PseudoHeader
,eth
),
160 WSLUA_CLASS_FNREG(PseudoHeader
,none
),
164 WSLUA_META PseudoHeader_meta
[] = {
168 int PseudoHeader_register(lua_State
* L
) {
169 WSLUA_REGISTER_CLASS(PseudoHeader
)
174 WSLUA_CLASS_DEFINE(Dumper
,FAIL_ON_NULL("Dumper already closed"));
176 static GHashTable
* dumper_encaps
;
177 #define DUMPER_ENCAP(d) GPOINTER_TO_INT(g_hash_table_lookup(dumper_encaps,d))
179 static const char* cross_plat_fname(const char* fname
) {
180 static char fname_clean
[256];
183 (void) g_strlcpy(fname_clean
,fname
,255);
184 fname_clean
[255] = '\0';
186 for(f
= fname_clean
; *f
; f
++) {
189 *f
= *(G_DIR_SEPARATOR_S
);
199 WSLUA_CONSTRUCTOR
Dumper_new(lua_State
* L
) {
201 Creates a file to write packets.
202 `Dumper:new_for_current()` will probably be a better choice, especially for file types other than pcapng.
204 #define WSLUA_ARG_Dumper_new_FILENAME 1 /* The name of the capture file to be created. */
205 #define WSLUA_OPTARG_Dumper_new_FILETYPE 2 /* The type of the file to be created - a number returned by `wtap_name_to_file_type_subtype()`. Defaults to pcapng.
206 (The `wtap_filetypes` table
207 is deprecated, and should only be used
208 in code that must run on Wireshark 3.4.3 and earlier 3.4.x releases
209 or in Wireshark 3.2.11 and earlier
211 #define WSLUA_OPTARG_Dumper_new_ENCAP 3 /* The encapsulation to be used in the file to be created - a number entry from the `wtap_encaps` table.
212 Defaults to per-packet encapsulation for pcapng
213 (which doesn't have file-level encapsulation;
214 this will create IDBs on demand as necessary)
215 and Ethernet encapsulation for other file types. */
217 const char* fname
= luaL_checkstring(L
,WSLUA_ARG_Dumper_new_FILENAME
);
218 int filetype
= (int)luaL_optinteger(L
,WSLUA_OPTARG_Dumper_new_FILETYPE
,wtap_pcapng_file_type_subtype());
219 /* If we're writing pcapng, then WTAP_ENCAP_NONE and WTAP_ENCAP_PER_PACKET
220 * generate a fake IDB on demand when the first packet for an encapsulation
221 * type is written. Specifying any other encapsulation will generate a fake
222 * IDB for that encapsulation upon opening even if there are no packets of
224 * XXX - Default to PER_PACKET for any file type that supports it? */
225 int encap
= (int)luaL_optinteger(L
,WSLUA_OPTARG_Dumper_new_ENCAP
, filetype
== wtap_pcapng_file_type_subtype() ? WTAP_ENCAP_PER_PACKET
: WTAP_ENCAP_ETHERNET
);
227 char *err_info
= NULL
;
228 const char* filename
= cross_plat_fname(fname
);
229 wtap_dump_params params
= WTAP_DUMP_PARAMS_INIT
;
231 params
.encap
= encap
;
232 /* XXX - Check for an existing file, or the same file name as the current
235 d
= wtap_dump_open(filename
, filetype
, WTAP_UNCOMPRESSED
, ¶ms
, &err
,
239 /* WSLUA_ERROR("Error while opening file for writing"); */
241 case WTAP_ERR_NOT_REGULAR_FILE
:
242 luaL_error(L
,"The file \"%s\" is a \"special file\" or socket or other non-regular file",
246 case WTAP_ERR_CANT_WRITE_TO_PIPE
:
247 luaL_error(L
,"The file \"%s\" is a pipe, and %s capture files can't be written to a pipe",
248 filename
, wtap_file_type_subtype_description(filetype
));
251 case WTAP_ERR_UNWRITABLE_FILE_TYPE
:
252 luaL_error(L
,"Files of file type %s cannot be written",
253 wtap_file_type_subtype_description(filetype
));
256 case WTAP_ERR_UNWRITABLE_ENCAP
:
257 luaL_error(L
,"Files of file type %s don't support encapsulation %s",
258 wtap_file_type_subtype_description(filetype
),
259 wtap_encap_name(encap
));
262 case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED
:
263 luaL_error(L
,"Files of file type %s don't support per-packet encapsulation",
264 wtap_file_type_subtype_description(filetype
));
267 case WTAP_ERR_CANT_OPEN
:
268 luaL_error(L
,"The file \"%s\" could not be created for some unknown reason",
272 case WTAP_ERR_SHORT_WRITE
:
273 luaL_error(L
,"A full header couldn't be written to the file \"%s\".",
277 case WTAP_ERR_COMPRESSION_NOT_SUPPORTED
:
278 luaL_error(L
,"Files of file type %s cannot be written as a compressed file",
279 wtap_file_type_subtype_description(filetype
));
282 case WTAP_ERR_INTERNAL
:
283 luaL_error(L
,"An internal error occurred creating the file \"%s\" (%s)",
285 err_info
!= NULL
? err_info
: "no information supplied");
290 luaL_error(L
,"error while opening \"%s\": %s",
298 g_hash_table_insert(dumper_encaps
,d
,GINT_TO_POINTER(encap
));
302 /* The newly created Dumper object */
305 WSLUA_METHOD
Dumper_close(lua_State
* L
) {
306 /* Closes a dumper. */
307 Dumper
* dp
= (Dumper
*)luaL_checkudata(L
, 1, "Dumper");
312 WSLUA_ERROR(Dumper_close
,"Cannot operate on a closed dumper");
316 g_hash_table_remove(dumper_encaps
,*dp
);
318 if (!wtap_dump_close(*dp
, NULL
, &err
, &err_info
)) {
319 if (err_info
!= NULL
) {
320 luaL_error(L
,"error closing: %s (%s)",
321 wtap_strerror(err
), err_info
);
324 luaL_error(L
,"error closing: %s",
329 /* this way if we close a dumper any attempt to use it (for everything but GC) will yield an error */
335 WSLUA_METHOD
Dumper_flush(lua_State
* L
) {
337 Writes all unsaved data of a dumper to the disk.
339 Dumper d
= checkDumper(L
,1);
344 if (!wtap_dump_flush(d
, &err
)) {
345 luaL_error(L
,"error while dumping: %s",
352 WSLUA_METHOD
Dumper_dump(lua_State
* L
) {
354 Dumps an arbitrary packet.
355 Note: Dumper:dump_current() will fit best in most cases.
357 #define WSLUA_ARG_Dumper_dump_TIMESTAMP 2 /* The absolute timestamp the packet will have. */
358 #define WSLUA_ARG_Dumper_dump_PSEUDOHEADER 3 /* The `PseudoHeader` to use. */
359 #define WSLUA_ARG_Dumper_dump_BYTEARRAY 4 /* The data to be saved */
361 Dumper d
= checkDumper(L
,1);
371 ts
= luaL_checknumber(L
,WSLUA_ARG_Dumper_dump_TIMESTAMP
);
372 ph
= checkPseudoHeader(L
,WSLUA_ARG_Dumper_dump_PSEUDOHEADER
);
375 WSLUA_ARG_ERROR(Dumper_dump
,PSEUDOHEADER
,"need a PseudoHeader");
379 ba
= checkByteArray(L
,WSLUA_ARG_Dumper_dump_BYTEARRAY
);
382 WSLUA_ARG_ERROR(Dumper_dump
,BYTEARRAY
,"must be a ByteArray");
386 memset(&rec
, 0, sizeof rec
);
388 rec
.rec_type
= REC_TYPE_PACKET
;
390 rec
.presence_flags
= WTAP_HAS_TS
;
391 rec
.ts
.secs
= (unsigned int)(floor(ts
));
392 rec
.ts
.nsecs
= (unsigned int)(floor((ts
- (double)rec
.ts
.secs
) * 1000000000));
394 rec
.rec_header
.packet_header
.len
= ba
->len
;
395 rec
.rec_header
.packet_header
.caplen
= ba
->len
;
396 rec
.rec_header
.packet_header
.pkt_encap
= DUMPER_ENCAP(d
);
398 rec
.rec_header
.packet_header
.pseudo_header
= *ph
->wph
;
401 /* TODO: Can we get access to pinfo->rec->block here somehow? We
402 * should be copying it to pkthdr.pkt_block if we can. */
404 if (! wtap_dump(d
, &rec
, ba
->data
, &err
, &err_info
)) {
407 case WTAP_ERR_UNWRITABLE_REC_DATA
:
408 luaL_error(L
,"error while dumping: %s (%s)",
409 wtap_strerror(err
), err_info
);
414 luaL_error(L
,"error while dumping: %s",
424 WSLUA_METHOD
Dumper_new_for_current(lua_State
* L
) {
426 Creates a capture file using the same encapsulation as the one of the current packet.
428 #define WSLUA_OPTARG_Dumper_new_for_current_FILETYPE 2 /* The file type. Defaults to pcapng. */
430 const char* fname
= luaL_checkstring(L
,1);
431 int filetype
= (int)luaL_optinteger(L
,WSLUA_OPTARG_Dumper_new_for_current_FILETYPE
,wtap_pcapng_file_type_subtype());
434 char *err_info
= NULL
;
435 const char* filename
= cross_plat_fname(fname
);
436 wtap_dump_params params
= WTAP_DUMP_PARAMS_INIT
;
439 WSLUA_ERROR(Dumper_new_for_current
,"Cannot be used outside a tap or a dissector");
443 if (lua_pinfo
->rec
->rec_type
!= REC_TYPE_PACKET
) {
447 encap
= lua_pinfo
->rec
->rec_header
.packet_header
.pkt_encap
;
448 params
.encap
= encap
;
449 d
= wtap_dump_open(filename
, filetype
, WTAP_UNCOMPRESSED
, ¶ms
, &err
,
454 case WTAP_ERR_NOT_REGULAR_FILE
:
455 luaL_error(L
,"The file \"%s\" is a \"special file\" or socket or other non-regular file",
459 case WTAP_ERR_CANT_WRITE_TO_PIPE
:
460 luaL_error(L
,"The file \"%s\" is a pipe, and %s capture files can't be written to a pipe",
461 filename
, wtap_file_type_subtype_description(filetype
));
464 case WTAP_ERR_UNWRITABLE_FILE_TYPE
:
465 luaL_error(L
,"Files of file type %s cannot be written",
466 wtap_file_type_subtype_description(filetype
));
469 case WTAP_ERR_UNWRITABLE_ENCAP
:
470 luaL_error(L
,"Files of file type %s don't support encapsulation %s",
471 wtap_file_type_subtype_description(filetype
),
472 wtap_encap_name(encap
));
475 case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED
:
476 luaL_error(L
,"Files of file type %s don't support per-packet encapsulation",
477 wtap_file_type_subtype_description(filetype
));
480 case WTAP_ERR_CANT_OPEN
:
481 luaL_error(L
,"The file \"%s\" could not be created for some unknown reason",
485 case WTAP_ERR_SHORT_WRITE
:
486 luaL_error(L
,"A full header couldn't be written to the file \"%s\".",
490 case WTAP_ERR_COMPRESSION_NOT_SUPPORTED
:
491 luaL_error(L
,"Files of file type %s cannot be written as a compressed file",
492 wtap_file_type_subtype_description(filetype
));
495 case WTAP_ERR_INTERNAL
:
496 luaL_error(L
,"An internal error occurred creating the file \"%s\" (%s)",
498 err_info
!= NULL
? err_info
: "no information supplied");
503 luaL_error(L
,"error while opening \"%s\": %s",
512 WSLUA_RETURN(1); /* The newly created Dumper Object */
516 WSLUA_METHOD
Dumper_dump_current(lua_State
* L
) {
518 Dumps the current packet as it is.
520 Dumper d
= checkDumper(L
,1);
522 const unsigned char* data
;
524 struct data_source
*data_src
;
531 WSLUA_ERROR(Dumper_new_for_current
,"Cannot be used outside a tap or a dissector");
535 if (lua_pinfo
->rec
->rec_type
!= REC_TYPE_PACKET
) {
539 data_src
= (struct data_source
*) (lua_pinfo
->data_src
->data
);
543 tvb
= get_data_source_tvb(data_src
);
545 memset(&rec
, 0, sizeof rec
);
547 rec
.rec_type
= REC_TYPE_PACKET
;
548 rec
.presence_flags
= WTAP_HAS_TS
|WTAP_HAS_CAP_LEN
;
549 rec
.ts
= lua_pinfo
->abs_ts
;
550 rec
.rec_header
.packet_header
.len
= tvb_reported_length(tvb
);
551 rec
.rec_header
.packet_header
.caplen
= tvb_captured_length(tvb
);
552 rec
.rec_header
.packet_header
.pkt_encap
= lua_pinfo
->rec
->rec_header
.packet_header
.pkt_encap
;
553 rec
.rec_header
.packet_header
.pseudo_header
= *lua_pinfo
->pseudo_header
;
556 * wtap_dump does not modify rec.block, so it should be possible to
557 * pass epan_get_modified_block() or lua_pinfo->rec->block directly.
558 * Temporarily duplicating the memory should not hurt though.
560 if (lua_pinfo
->fd
->has_modified_block
) {
561 rec
.block
= epan_get_modified_block(lua_pinfo
->epan
, lua_pinfo
->fd
);
562 rec
.block_was_modified
= true;
564 rec
.block
= lua_pinfo
->rec
->block
;
567 data
= (const unsigned char *)tvb_memdup(lua_pinfo
->pool
,tvb
,0,rec
.rec_header
.packet_header
.caplen
);
569 if (! wtap_dump(d
, &rec
, data
, &err
, &err_info
)) {
572 case WTAP_ERR_UNWRITABLE_REC_DATA
:
573 luaL_error(L
,"error while dumping: %s (%s)",
574 wtap_strerror(err
), err_info
);
579 luaL_error(L
,"error while dumping: %s",
588 /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */
589 static int Dumper__gc(lua_State
* L
) {
590 Dumper
* dp
= (Dumper
*)luaL_checkudata(L
, 1, "Dumper");
594 /* If we are Garbage Collected it means the Dumper is no longer usable. Close it */
597 return 0; /* already closed, nothing to do! */
599 g_hash_table_remove(dumper_encaps
,*dp
);
601 if (!wtap_dump_close(*dp
, NULL
, &err
, &err_info
)) {
602 if (err_info
!= NULL
) {
603 luaL_error(L
,"error closing: %s (%s)",
604 wtap_strerror(err
), err_info
);
607 luaL_error(L
,"error closing: %s",
616 WSLUA_METHODS Dumper_methods
[] = {
617 WSLUA_CLASS_FNREG(Dumper
,new),
618 WSLUA_CLASS_FNREG(Dumper
,new_for_current
),
619 WSLUA_CLASS_FNREG(Dumper
,close
),
620 WSLUA_CLASS_FNREG(Dumper
,flush
),
621 WSLUA_CLASS_FNREG(Dumper
,dump
),
622 WSLUA_CLASS_FNREG(Dumper
,dump_current
),
626 WSLUA_META Dumper_meta
[] = {
630 int Dumper_register(lua_State
* L
) {
631 if (dumper_encaps
!= NULL
) {
632 g_hash_table_unref(dumper_encaps
);
634 dumper_encaps
= g_hash_table_new(g_direct_hash
,g_direct_equal
);
635 WSLUA_REGISTER_CLASS(Dumper
);
640 * Editor modelines - https://www.wireshark.org/tools/modelines.html
645 * indent-tabs-mode: nil
648 * vi: set shiftwidth=4 tabstop=8 expandtab:
649 * :indentSize=4:tabSize=8:noTabs=true: