2 * Routines for exporting PDUs to file
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include <epan/exported_pdu.h>
15 #include <epan/epan_dissect.h>
16 #include <wiretap/wtap.h>
17 #include <wiretap/wtap_opttypes.h>
18 #include <wsutil/os_version_info.h>
19 #include <wsutil/report_message.h>
20 #include "wsutil/version_info.h"
22 #include "tap_export_pdu.h"
24 /* Main entry point to the tap */
25 static tap_packet_status
26 export_pdu_packet(void *tapdata
, packet_info
*pinfo
, epan_dissect_t
*edt
, const void *data
, tap_flags_t flags _U_
)
28 const exp_pdu_data_t
*exp_pdu_data
= (const exp_pdu_data_t
*)data
;
29 exp_pdu_t
*exp_pdu_tap_data
= (exp_pdu_t
*)tapdata
;
35 tap_packet_status status
= TAP_PACKET_DONT_REDRAW
; /* no GUI, nothing to redraw */
40 exp_pdu_tap_data
->framenum
++;
42 memset(&rec
, 0, sizeof rec
);
43 buffer_len
= exp_pdu_data
->tvb_captured_length
+ exp_pdu_data
->tlv_buffer_len
;
44 packet_buf
= (uint8_t *)g_malloc(buffer_len
);
46 if(exp_pdu_data
->tlv_buffer_len
> 0){
47 memcpy(packet_buf
, exp_pdu_data
->tlv_buffer
, exp_pdu_data
->tlv_buffer_len
);
49 if(exp_pdu_data
->tvb_captured_length
> 0){
50 tvb_memcpy(exp_pdu_data
->pdu_tvb
, packet_buf
+exp_pdu_data
->tlv_buffer_len
, 0, exp_pdu_data
->tvb_captured_length
);
52 rec
.rec_type
= REC_TYPE_PACKET
;
53 rec
.presence_flags
= WTAP_HAS_CAP_LEN
|WTAP_HAS_INTERFACE_ID
|WTAP_HAS_TS
;
54 rec
.ts
.secs
= pinfo
->abs_ts
.secs
;
55 rec
.ts
.nsecs
= pinfo
->abs_ts
.nsecs
;
56 rec
.rec_header
.packet_header
.caplen
= buffer_len
;
57 rec
.rec_header
.packet_header
.len
= exp_pdu_data
->tvb_reported_length
+ exp_pdu_data
->tlv_buffer_len
;
59 rec
.rec_header
.packet_header
.pkt_encap
= exp_pdu_tap_data
->pkt_encap
;
61 /* rec.opt_block is not modified by wtap_dump, but if for some reason the
62 * epan_get_modified_block() or pinfo->rec->block are invalidated,
63 * copying it here does not hurt. (Can invalidation really happen?) */
64 if (pinfo
->fd
->has_modified_block
) {
65 rec
.block
= epan_get_modified_block(edt
->session
, pinfo
->fd
);
66 rec
.block_was_modified
= true;
68 rec
.block
= pinfo
->rec
->block
;
71 /* XXX: should the rec.rec_header.packet_header.pseudo_header be set to the pinfo's pseudo-header? */
72 if (!wtap_dump(exp_pdu_tap_data
->wdh
, &rec
, packet_buf
, &err
, &err_info
)) {
73 report_cfile_write_failure(NULL
, exp_pdu_tap_data
->pathname
,
74 err
, err_info
, exp_pdu_tap_data
->framenum
,
75 wtap_dump_file_type_subtype(exp_pdu_tap_data
->wdh
));
76 status
= TAP_PACKET_FAILED
;
85 exp_pdu_open(exp_pdu_t
*exp_pdu_tap_data
, char *pathname
,
86 int file_type_subtype
, int fd
, const char *comment
,
87 int *err
, char **err_info
)
91 wtap_block_t int_data
;
92 wtapng_if_descr_mandatory_t
*int_data_mand
;
98 * If the file format supports a section block, and the section
99 * block supports comments, create data for it.
101 if (wtap_file_type_subtype_supports_block(file_type_subtype
,
102 WTAP_BLOCK_SECTION
) != BLOCK_NOT_SUPPORTED
&&
103 wtap_file_type_subtype_supports_option(file_type_subtype
,
105 OPT_COMMENT
) != OPTION_NOT_SUPPORTED
) {
106 os_info_str
= g_string_new("");
107 get_os_version_info(os_info_str
);
109 shb_hdr
= wtap_block_create(WTAP_BLOCK_SECTION
);
112 wtap_block_add_string_option(shb_hdr
, OPT_COMMENT
, comment
, strlen(comment
));
115 * UTF-8 string containing the name of the operating system used to
116 * create this section.
118 opt_len
= os_info_str
->len
;
119 opt_str
= g_string_free(os_info_str
, FALSE
);
121 wtap_block_add_string_option(shb_hdr
, OPT_SHB_OS
, opt_str
, opt_len
);
125 * UTF-8 string containing the name of the application used to create
128 wtap_block_add_string_option_format(shb_hdr
, OPT_SHB_USERAPPL
, "%s",
129 get_appname_and_version());
131 exp_pdu_tap_data
->shb_hdrs
= g_array_new(false, false, sizeof(wtap_block_t
));
132 g_array_append_val(exp_pdu_tap_data
->shb_hdrs
, shb_hdr
);
134 exp_pdu_tap_data
->shb_hdrs
= NULL
;
138 * Create fake interface information for files that support (meaning
139 * "require") interface information and per-packet interface IDs.
141 if (wtap_file_type_subtype_supports_block(file_type_subtype
,
142 WTAP_BLOCK_IF_ID_AND_INFO
) != BLOCK_NOT_SUPPORTED
) {
143 exp_pdu_tap_data
->idb_inf
= g_new(wtapng_iface_descriptions_t
,1);
144 exp_pdu_tap_data
->idb_inf
->interface_data
= g_array_new(false, false, sizeof(wtap_block_t
));
146 /* create the fake interface data */
147 int_data
= wtap_block_create(WTAP_BLOCK_IF_ID_AND_INFO
);
148 int_data_mand
= (wtapng_if_descr_mandatory_t
*)wtap_block_get_mandatory_data(int_data
);
149 int_data_mand
->wtap_encap
= exp_pdu_tap_data
->pkt_encap
;
150 int_data_mand
->time_units_per_second
= 1000000000; /* default nanosecond resolution */
151 int_data_mand
->snap_len
= WTAP_MAX_PACKET_SIZE_STANDARD
;
153 wtap_block_add_string_option(int_data
, OPT_IDB_NAME
, "Fake IF, PDU->Export", strlen("Fake IF, PDU->Export"));
154 wtap_block_add_uint8_option(int_data
, OPT_IDB_TSRESOL
, 9);
156 g_array_append_val(exp_pdu_tap_data
->idb_inf
->interface_data
, int_data
);
158 exp_pdu_tap_data
->idb_inf
= NULL
;
161 const wtap_dump_params params
= {
162 .encap
= exp_pdu_tap_data
->pkt_encap
,
163 .snaplen
= WTAP_MAX_PACKET_SIZE_STANDARD
,
164 .shb_hdrs
= exp_pdu_tap_data
->shb_hdrs
,
165 .idb_inf
= exp_pdu_tap_data
->idb_inf
,
168 exp_pdu_tap_data
->wdh
= wtap_dump_open_stdout(file_type_subtype
,
169 WTAP_UNCOMPRESSED
, ¶ms
, err
, err_info
);
171 exp_pdu_tap_data
->wdh
= wtap_dump_fdopen(fd
, file_type_subtype
,
172 WTAP_UNCOMPRESSED
, ¶ms
, err
, err_info
);
174 if (exp_pdu_tap_data
->wdh
== NULL
)
177 exp_pdu_tap_data
->pathname
= pathname
;
178 exp_pdu_tap_data
->framenum
= 0; /* No frames written yet */
183 exp_pdu_close(exp_pdu_t
*exp_pdu_tap_data
, int *err
, char **err_info
)
187 status
= wtap_dump_close(exp_pdu_tap_data
->wdh
, NULL
, err
, err_info
);
189 wtap_block_array_free(exp_pdu_tap_data
->shb_hdrs
);
190 wtap_free_idb_info(exp_pdu_tap_data
->idb_inf
);
192 remove_tap_listener(exp_pdu_tap_data
);
198 exp_pdu_pre_open(const char *tap_name
, const char *filter
, exp_pdu_t
*exp_pdu_tap_data
)
200 GString
*error_string
;
202 /* Make sure tap is suitable for exported PDUs */
204 for (GSList
*export_pdu_tap_name_list
= get_export_pdu_tap_list();
205 export_pdu_tap_name_list
!= NULL
;
206 export_pdu_tap_name_list
= g_slist_next(export_pdu_tap_name_list
)) {
207 if (strcmp((const char*)(export_pdu_tap_name_list
->data
), tap_name
) == 0) {
213 return g_strdup("unsuitable for PDU export");
216 /* Register this tap listener now */
217 error_string
= register_tap_listener(tap_name
, /* The name of the tap we want to listen to */
218 exp_pdu_tap_data
, /* instance identifier/pointer to a struct holding
219 * all state variables */
220 filter
, /* pointer to a filter string */
221 TL_REQUIRES_PROTO_TREE
, /* flags for the tap listener */
226 if (error_string
!= NULL
)
227 return g_string_free(error_string
, FALSE
);
229 exp_pdu_tap_data
->pkt_encap
= export_pdu_tap_get_encap(tap_name
);