The "file types" we have are actually combinations of types and
[metze/wireshark/wip.git] / epan / wslua / wslua_dumper.c
1 /*
2  *  wslua_dumper.c
3  *
4  * Wireshark's interface to the Lua Programming Language
5  *
6  * (c) 2006, Luis E. Garcia Ontanon <luis@ontanon.org>
7  *
8  * $Id$
9  *
10  * Wireshark - Network traffic analyzer
11  * By Gerald Combs <gerald@wireshark.org>
12  * Copyright 1998 Gerald Combs
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27  */
28
29 #include "config.h"
30
31 #include <epan/emem.h>
32
33 /* WSLUA_MODULE Dumper Saving capture files */
34
35 #include "wslua.h"
36 #include <math.h>
37
38 WSLUA_CLASS_DEFINE(PseudoHeader,NOP,NOP);
39 /*
40  A pseudoheader to be used to save captured frames.
41  */
42
43 enum lua_pseudoheader_type {
44     PHDR_NONE,
45     PHDR_ETH,
46     PHDR_X25,
47     PHDR_ISDN,
48     PHDR_ATM,
49     PHDR_ASCEND,
50     PHDR_P2P,
51     PHDR_WIFI,
52     PHDR_COSINE,
53     PHDR_IRDA,
54     PHDR_NETTL,
55     PHDR_MTP2,
56     PHDR_K12
57 };
58
59 struct lua_pseudo_header {
60     enum lua_pseudoheader_type type;
61     union wtap_pseudo_header* wph;
62 };
63
64 WSLUA_CONSTRUCTOR PseudoHeader_none(lua_State* L) {
65     /*
66      Creates a "no" pseudoheader.
67
68     */
69     PseudoHeader ph = (PseudoHeader)g_malloc(sizeof(struct lua_pseudo_header));
70     ph->type = PHDR_NONE;
71     ph->wph = NULL;
72
73     pushPseudoHeader(L,ph);
74
75     WSLUA_RETURN(1);
76     /* A null pseudoheader */
77 }
78
79 WSLUA_CONSTRUCTOR PseudoHeader_eth(lua_State* L) {
80     /*
81      Creates an ethernet pseudoheader
82      */
83
84 #define WSLUA_OPTARG_PseudoHeader_eth_FCSLEN 1 /* The fcs length */
85
86     PseudoHeader ph = (PseudoHeader)g_malloc(sizeof(struct lua_pseudo_header));
87     ph->type = PHDR_ETH;
88     ph->wph = (union wtap_pseudo_header *)g_malloc(sizeof(union wtap_pseudo_header));
89     ph->wph->eth.fcs_len = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_eth_FCSLEN,-1);
90
91     pushPseudoHeader(L,ph);
92
93     WSLUA_RETURN(1); /* The ethernet pseudoheader */
94 }
95
96 WSLUA_CONSTRUCTOR PseudoHeader_atm(lua_State* L) {
97     /*
98      Creates an ATM pseudoheader
99      */
100 #define WSLUA_OPTARG_PseudoHeader_atm_AAL 1 /* AAL number */
101 #define WSLUA_OPTARG_PseudoHeader_atm_VPI 2 /* VPI */
102 #define WSLUA_OPTARG_PseudoHeader_atm_VCI 3 /* VCI */
103 #define WSLUA_OPTARG_PseudoHeader_atm_CHANNEL 4 /* Channel */
104 #define WSLUA_OPTARG_PseudoHeader_atm_CELLS 5 /* Number of cells in the PDU */
105 #define WSLUA_OPTARG_PseudoHeader_atm_AAL5U2U 6 /* AAL5 User to User indicator */
106 #define WSLUA_OPTARG_PseudoHeader_atm_AAL5LEN 7 /* AAL5 Len */
107
108     PseudoHeader ph = (PseudoHeader)g_malloc(sizeof(struct lua_pseudo_header));
109     ph->type = PHDR_ATM;
110     ph->wph = (union wtap_pseudo_header *)g_malloc(sizeof(union wtap_pseudo_header));
111     ph->wph->atm.aal = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_AAL,5);
112     ph->wph->atm.vpi = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_VPI,1);
113     ph->wph->atm.vci = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_VCI,1);
114     ph->wph->atm.channel = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_CHANNEL,0);
115     ph->wph->atm.cells = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_CELLS,1);
116     ph->wph->atm.aal5t_u2u = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_AAL5U2U,1);
117     ph->wph->atm.aal5t_len = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_AAL5LEN,0);
118
119     pushPseudoHeader(L,ph);
120     WSLUA_RETURN(1);
121     /* The ATM pseudoheader */
122 }
123
124 WSLUA_CONSTRUCTOR PseudoHeader_mtp2(lua_State* L) {
125     /* Creates an MTP2 PseudoHeader */
126 #define WSLUA_OPTARG_PseudoHeader_mtp2_SENT 1 /* True if the packet is sent, False if received. */
127 #define WSLUA_OPTARG_PseudoHeader_mtp2_ANNEXA 2 /* True if annex A is used  */
128 #define WSLUA_OPTARG_PseudoHeader_mtp2_LINKNUM 3 /* Link Number */
129     PseudoHeader ph = (PseudoHeader)g_malloc(sizeof(struct lua_pseudo_header));
130     ph->type = PHDR_MTP2;
131     ph->wph = (union wtap_pseudo_header *)g_malloc(sizeof(union wtap_pseudo_header));
132     ph->wph->mtp2.sent = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_mtp2_SENT,0);
133     ph->wph->mtp2.annex_a_used = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_mtp2_ANNEXA,0);
134     ph->wph->mtp2.link_number = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_mtp2_LINKNUM,0);
135
136     pushPseudoHeader(L,ph);
137     WSLUA_RETURN(1); /* The MTP2 pseudoheader */
138 }
139
140 #if 0
141 static int PseudoHeader_x25(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
142 static int PseudoHeader_isdn(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
143 static int PseudoHeader_ascend(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
144 static int PseudoHeader_wifi(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
145 static int PseudoHeader_cosine(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
146 static int PseudoHeader_irda(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
147 static int PseudoHeader_nettl(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
148 static int PseudoHeader_k12(lua_State* L) { luaL_error(L,"not implemented"); return 0; }
149 #endif
150
151 /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */
152 static int PseudoHeader__gc(lua_State* L _U_) {
153     /* do NOT free PseudoHeader */
154     return 0;
155 }
156
157 WSLUA_METHODS PseudoHeader_methods[] = {
158     WSLUA_CLASS_FNREG(PseudoHeader,mtp2),
159     WSLUA_CLASS_FNREG(PseudoHeader,atm),
160     WSLUA_CLASS_FNREG(PseudoHeader,eth),
161     WSLUA_CLASS_FNREG(PseudoHeader,none),
162     {0,0}
163 };
164
165 WSLUA_META PseudoHeader_meta[] = {
166     {0,0}
167 };
168
169 int PseudoHeader_register(lua_State* L) {
170     WSLUA_REGISTER_CLASS(PseudoHeader)
171     return 0;
172 }
173
174
175 WSLUA_CLASS_DEFINE(Dumper,FAIL_ON_NULL("Dumper already closed"),NOP);
176
177 static GHashTable* dumper_encaps = NULL;
178 #define DUMPER_ENCAP(d) GPOINTER_TO_INT(g_hash_table_lookup(dumper_encaps,d))
179
180 static const char* cross_plat_fname(const char* fname) {
181     static char fname_clean[256];
182     char* f;
183
184     g_strlcpy(fname_clean,fname,255);
185     fname_clean[255] = '\0';
186
187     for(f = fname_clean; *f; f++) {
188         switch(*f) {
189             case '/': case '\\':
190                 *f = *(G_DIR_SEPARATOR_S);
191                 break;
192             default:
193                 break;
194         }
195     }
196
197     return fname_clean;
198 }
199
200 WSLUA_CONSTRUCTOR Dumper_new(lua_State* L) {
201     /*
202      Creates a file to write packets.
203      Dumper:new_for_current() will probably be a better choice.
204     */
205 #define WSLUA_ARG_Dumper_new_FILENAME 1 /* The name of the capture file to be created */
206 #define WSLUA_OPTARG_Dumper_new_FILETYPE 2 /* The type of the file to be created */
207 #define WSLUA_OPTARG_Dumper_new_ENCAP 3 /* The encapsulation to be used in the file to be created */
208     Dumper d;
209     const char* fname = luaL_checkstring(L,WSLUA_ARG_Dumper_new_FILENAME);
210     int filetype = luaL_optint(L,WSLUA_OPTARG_Dumper_new_FILETYPE,WTAP_FILE_TYPE_SUBTYPE_PCAP);
211     int encap  = luaL_optint(L,WSLUA_OPTARG_Dumper_new_ENCAP,WTAP_ENCAP_ETHERNET);
212     int err = 0;
213     const char* filename;
214
215     if (! fname) return 0;
216
217     filename = cross_plat_fname(fname);
218
219     d = wtap_dump_open(filename, filetype, encap, 0, FALSE, &err);
220
221     if (! d ) {
222         /* WSLUA_ERROR("Error while opening file for writing"); */
223         switch (err) {
224         case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
225             luaL_error(L,"Files of file type %s cannot be written",
226                        wtap_file_type_subtype_string(filetype));
227             break;
228
229         case WTAP_ERR_UNSUPPORTED_ENCAP:
230             luaL_error(L,"Files of file type %s don't support encapsulation %s",
231                        wtap_file_type_subtype_string(filetype),
232                        wtap_encap_short_string(encap));
233             break;
234
235         default:
236             luaL_error(L,"error while opening `%s': %s",
237                        filename,
238                        wtap_strerror(err));
239             break;
240         }
241         return 0;
242     }
243
244     g_hash_table_insert(dumper_encaps,d,GINT_TO_POINTER(encap));
245
246     pushDumper(L,d);
247     WSLUA_RETURN(1);
248     /* The newly created Dumper object */
249 }
250
251 WSLUA_METHOD Dumper_close(lua_State* L) {
252     /* Closes a dumper */
253     Dumper* dp = (Dumper*)luaL_checkudata(L, 1, "Dumper");
254     int err;
255
256     if (! *dp)
257         WSLUA_ERROR(Dumper_close,"Cannot operate on a closed dumper");
258
259     g_hash_table_remove(dumper_encaps,*dp);
260
261     if (!wtap_dump_close(*dp, &err)) {
262         luaL_error(L,"error closing: %s",
263                    wtap_strerror(err));
264     }
265
266     /* this way if we close a dumper any attempt to use it (for everything but GC) will yield an error */
267     *dp = NULL;
268
269     return 0;
270 }
271
272 WSLUA_METHOD Dumper_flush(lua_State* L) {
273     /*
274      Writes all unsaved data of a dumper to the disk.
275      */
276     Dumper d = checkDumper(L,1);
277
278     if (!d) return 0;
279
280     wtap_dump_flush(d);
281
282     return 0;
283 }
284
285 WSLUA_METHOD Dumper_dump(lua_State* L) {
286     /*
287      Dumps an arbitrary packet.
288      Note: Dumper:dump_current() will fit best in most cases.
289      */
290 #define WSLUA_ARG_Dumper_dump_TIMESTAMP 2 /* The absolute timestamp the packet will have */
291 #define WSLUA_ARG_Dumper_dump_PSEUDOHEADER 3 /* The Pseudoheader to use. */
292 #define WSLUA_ARG_Dumper_dump_BYTEARRAY 4 /* the data to be saved */
293
294     Dumper d = checkDumper(L,1);
295     PseudoHeader ph;
296     ByteArray ba;
297     struct wtap_pkthdr pkthdr;
298     double ts;
299     int err;
300
301     if (!d) return 0;
302
303     ts = luaL_checknumber(L,WSLUA_ARG_Dumper_dump_TIMESTAMP);
304     ph = checkPseudoHeader(L,WSLUA_ARG_Dumper_dump_PSEUDOHEADER);
305
306     if (!ph) WSLUA_ARG_ERROR(Dumper_dump,TIMESTAMP,"need a PseudoHeader");
307
308     ba = checkByteArray(L,WSLUA_ARG_Dumper_dump_BYTEARRAY);
309
310     if (! ba) WSLUA_ARG_ERROR(Dumper_dump,BYTEARRAY,"must be a ByteArray");
311
312     memset(&pkthdr, 0, sizeof(pkthdr));
313
314     pkthdr.ts.secs  = (unsigned)floor(ts);
315     pkthdr.ts.nsecs = (unsigned)floor((ts - (double)pkthdr.ts.secs) * 1000000000);
316
317     pkthdr.len       = ba->len;
318     pkthdr.caplen    = ba->len;
319     pkthdr.pkt_encap = DUMPER_ENCAP(d);
320     pkthdr.pseudo_header = *ph->wph;
321
322     /* TODO: Can we get access to pinfo->pkt_comment here somehow? We
323      * should be copying it to pkthdr.opt_comment if we can. */
324
325     if (! wtap_dump(d, &pkthdr, ba->data, &err)) {
326         luaL_error(L,"error while dumping: %s",
327                    wtap_strerror(err));
328     }
329
330     return 0;
331
332 }
333
334 WSLUA_METHOD Dumper_new_for_current(lua_State* L) {
335     /*
336      Creates a capture file using the same encapsulation as the one of the cuurrent packet
337      */
338 #define WSLUA_OPTARG_Dumper_new_for_current_FILETYPE 2 /* The file type. Defaults to pcap. */
339     Dumper d;
340     const char* fname = luaL_checkstring(L,1);
341     int filetype = luaL_optint(L,WSLUA_OPTARG_Dumper_new_for_current_FILETYPE,WTAP_FILE_TYPE_SUBTYPE_PCAP);
342     int encap;
343     int err = 0;
344     const char* filename;
345
346     if (! fname) return 0;
347
348     filename = cross_plat_fname(fname);
349
350     if (! lua_pinfo )
351         WSLUA_ERROR(Dumper_new_for_current,"Cannot be used outside a tap or a dissector");
352
353     encap = lua_pinfo->fd->lnk_t;
354
355     d = wtap_dump_open(filename, filetype, encap, 0, FALSE, &err);
356
357     if (! d ) {
358         switch (err) {
359         case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
360             luaL_error(L,"Files of file type %s cannot be written",
361                        wtap_file_type_subtype_string(filetype));
362             break;
363
364         case WTAP_ERR_UNSUPPORTED_ENCAP:
365             luaL_error(L,"Files of file type %s don't support encapsulation %s",
366                        wtap_file_type_subtype_string(filetype),
367                        wtap_encap_short_string(encap));
368             break;
369
370         default:
371             luaL_error(L,"error while opening `%s': %s",
372                        filename,
373                        wtap_strerror(err));
374             break;
375         }
376         return 0;
377     }
378
379     pushDumper(L,d);
380     WSLUA_RETURN(1); /* The newly created Dumper Object */
381
382 }
383
384 WSLUA_METHOD Dumper_dump_current(lua_State* L) {
385     /*
386      Dumps the current packet as it is.
387      */
388     Dumper d = checkDumper(L,1);
389     struct wtap_pkthdr pkthdr;
390     const guchar* data;
391     tvbuff_t* tvb;
392     struct data_source *data_src;
393     int err = 0;
394
395     if (!d) return 0;
396
397     if (! lua_pinfo ) WSLUA_ERROR(Dumper_new_for_current,"Cannot be used outside a tap or a dissector");
398
399     data_src = (struct data_source*) (lua_pinfo->data_src->data);
400     if (!data_src)
401         return 0;
402
403     tvb = get_data_source_tvb(data_src);
404
405     memset(&pkthdr, 0, sizeof(pkthdr));
406
407     pkthdr.ts.secs   = lua_pinfo->fd->abs_ts.secs;
408     pkthdr.ts.nsecs  = lua_pinfo->fd->abs_ts.nsecs;
409     pkthdr.len       = tvb_reported_length(tvb);
410     pkthdr.caplen    = tvb_length(tvb);
411     pkthdr.pkt_encap = lua_pinfo->fd->lnk_t;
412     pkthdr.pseudo_header = *lua_pinfo->pseudo_header;
413
414     if (lua_pinfo->pkt_comment)
415         pkthdr.opt_comment = ep_strdup(lua_pinfo->pkt_comment);
416
417     data = (const guchar *)tvb_memdup(wmem_packet_scope(),tvb,0,pkthdr.caplen);
418
419     if (! wtap_dump(d, &pkthdr, data, &err)) {
420         luaL_error(L,"error while dumping: %s",
421                    wtap_strerror(err));
422     }
423
424     return 0;
425 }
426
427 /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */
428 static int Dumper__gc(lua_State* L) {
429     Dumper* dp = (Dumper*)luaL_checkudata(L, 1, "Dumper");
430     int err;
431
432     /* If we are Garbage Collected it means the Dumper is no longer usable. Close it */
433
434     if (! *dp)
435         return 0; /* already closed, nothing to do! */
436
437     g_hash_table_remove(dumper_encaps,*dp);
438
439     if (!wtap_dump_close(*dp, &err)) {
440         luaL_error(L,"error closing: %s",
441                    wtap_strerror(err));
442     }
443
444     return 0;
445 }
446
447
448 WSLUA_METHODS Dumper_methods[] = {
449     WSLUA_CLASS_FNREG(Dumper,new),
450     WSLUA_CLASS_FNREG(Dumper,new_for_current),
451     WSLUA_CLASS_FNREG(Dumper,close),
452     WSLUA_CLASS_FNREG(Dumper,flush),
453     WSLUA_CLASS_FNREG(Dumper,dump),
454     WSLUA_CLASS_FNREG(Dumper,dump_current),
455     {0, 0}
456 };
457
458 WSLUA_META Dumper_meta[] = {
459     {0, 0}
460 };
461
462 int Dumper_register(lua_State* L) {
463     dumper_encaps = g_hash_table_new(g_direct_hash,g_direct_equal);
464     WSLUA_REGISTER_CLASS(Dumper);
465     return 1;
466 }
467