Coverage Report

Created: 2026-07-12 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/wiretap/mime_file.c
Line
Count
Source
1
/* mime_file.c
2
 *
3
 * MIME file format decoder for the Wiretap library.
4
 *
5
 * This is for use with Wireshark dissectors that handle file
6
 * formats (e.g., because they handle a particular MIME media type).
7
 * It breaks the file into chunks of at most WTAP_MAX_PACKET_SIZE_STANDARD,
8
 * each of which is reported as a packet, so that files larger than
9
 * WTAP_MAX_PACKET_SIZE_STANDARD can be handled by reassembly.
10
 *
11
 * The "MIME file" dissector does the reassembly, and hands the result
12
 * off to heuristic dissectors to try to identify the file's contents.
13
 *
14
 * Wiretap Library
15
 *
16
 * SPDX-License-Identifier: GPL-2.0-or-later
17
 */
18
19
#include "config.h"
20
#include "mime_file.h"
21
22
#include <sys/types.h>
23
24
#ifdef HAVE_UNISTD_H
25
#include <unistd.h>
26
#endif
27
28
#include <stdlib.h>
29
#include <string.h>
30
#include <time.h>
31
32
#include "wtap_module.h"
33
#include "file_wrappers.h"
34
#include <wsutil/array.h>
35
#include <wsutil/buffer.h>
36
37
typedef struct {
38
  const uint8_t *magic;
39
  unsigned magic_len;
40
} mime_files_t;
41
42
/*
43
 * Written by Marton Nemeth <nm127@freemail.hu>
44
 * Copyright 2009 Marton Nemeth
45
 * The JPEG specification can be found at:
46
 *
47
 * https://www.w3.org/Graphics/JPEG/itu-t81.pdf
48
 * https://www.itu.int/rec/T-REC-T.81/en (but you have to pay for it)
49
 *
50
 * and the JFIF specification can be found at:
51
 *
52
 * https://www.itu.int/rec/T-REC-T.871-201105-I/en
53
 * https://www.w3.org/Graphics/JPEG/jfif3.pdf
54
 */
55
static const uint8_t jpeg_jfif_magic[] = { 0xFF, 0xD8, /* SOF */
56
            0xFF        /* start of the next marker */
57
          };
58
59
/* <?xml */
60
static const uint8_t xml_magic[]    = { '<', '?', 'x', 'm', 'l' };
61
static const uint8_t png_magic[]    = { 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A, '\n' };
62
static const uint8_t gif87a_magic[] = { 'G', 'I', 'F', '8', '7', 'a'};
63
static const uint8_t gif89a_magic[] = { 'G', 'I', 'F', '8', '9', 'a'};
64
static const uint8_t elf_magic[]    = { 0x7F, 'E', 'L', 'F'};
65
static const uint8_t tiff_le_magic[]    = { 'I', 'I', 42, 0 };
66
static const uint8_t tiff_be_magic[]    = { 'M', 'M', 0, 42 };
67
static const uint8_t riff_magic[]    = { 'R', 'I', 'F', 'F' };
68
static const uint8_t btsnoop_magic[]    = { 'b', 't', 's', 'n', 'o', 'o', 'p', 0};
69
static const uint8_t pcap_magic[]           = { 0xA1, 0xB2, 0xC3, 0xD4 };
70
static const uint8_t pcap_swapped_magic[]   = { 0xD4, 0xC3, 0xB2, 0xA1 };
71
static const uint8_t pcap_nsec_magic[]           = { 0xA1, 0xB2, 0x3C, 0x4D };
72
static const uint8_t pcap_nsec_swapped_magic[]   = { 0x4D, 0x3C, 0xB2, 0xA1 };
73
static const uint8_t pcapng_premagic[]      = { 0x0A, 0x0D, 0x0D, 0x0A };
74
static const uint8_t blf_magic[]                 = { 'L', 'O', 'G', 'G' };
75
static const uint8_t autosar_dlt_magic[]         = { 'D', 'L', 'T', 0x01 };
76
static const uint8_t ttl_magic[]     = { 'T', 'T', 'L', ' ' };
77
static const uint8_t zip_magic[]     = { 'P', 'K', 0x03, 0x04 };
78
static const uint8_t rtpdump_magic[]         = { '#', '!', 'r', 't', 'p', 'p', 'l', 'a', 'y', '1', '.', '0', ' ' };
79
80
/* File does not start with it */
81
static const uint8_t pcapng_xmagic[]         = { 0x1A, 0x2B, 0x3C, 0x4D };
82
static const uint8_t pcapng_swapped_xmagic[] = { 0x4D, 0x3C, 0x2B, 0x1A };
83
84
static const mime_files_t magic_files[] = {
85
  { jpeg_jfif_magic, sizeof(jpeg_jfif_magic) },
86
  { xml_magic, sizeof(xml_magic) },
87
  { png_magic, sizeof(png_magic) },
88
  { gif87a_magic, sizeof(gif87a_magic) },
89
  { gif89a_magic, sizeof(gif89a_magic) },
90
  { elf_magic, sizeof(elf_magic) },
91
  { tiff_le_magic, sizeof(tiff_le_magic) },
92
  { tiff_be_magic, sizeof(tiff_be_magic) },
93
  { riff_magic, sizeof(riff_magic) },
94
  { btsnoop_magic, sizeof(btsnoop_magic) },
95
  { pcap_magic, sizeof(pcap_magic) },
96
  { pcap_swapped_magic, sizeof(pcap_swapped_magic) },
97
  { pcap_nsec_magic, sizeof(pcap_nsec_magic) },
98
  { pcap_nsec_swapped_magic, sizeof(pcap_nsec_swapped_magic) },
99
  { pcapng_premagic, sizeof(pcapng_premagic) },
100
  { blf_magic, sizeof(blf_magic) },
101
  { autosar_dlt_magic, sizeof(autosar_dlt_magic) },
102
  { ttl_magic, sizeof(ttl_magic) },
103
  { zip_magic, sizeof(zip_magic) },
104
  { rtpdump_magic, sizeof(rtpdump_magic) },
105
};
106
107
0
#define N_MAGIC_TYPES array_length(magic_files)
108
109
static int mime_file_type_subtype = -1;
110
111
void register_mime(void);
112
113
wtap_open_return_val
114
mime_file_open(wtap *wth, int *err, char **err_info)
115
0
{
116
0
  char magic_buf[128]; /* increase buffer size when needed */
117
0
  int bytes_read;
118
0
  bool found_file;
119
  /* unsigned file_ok; */
120
0
  unsigned i;
121
122
0
  unsigned read_bytes = 12;
123
124
0
  for (i = 0; i < N_MAGIC_TYPES; i++)
125
0
    read_bytes = MAX(read_bytes, magic_files[i].magic_len);
126
127
0
  read_bytes = (unsigned)MIN(read_bytes, sizeof(magic_buf));
128
0
  bytes_read = file_read(magic_buf, read_bytes, wth->fh);
129
130
0
  if (bytes_read < 0) {
131
0
    *err = file_error(wth->fh, err_info);
132
0
    return WTAP_OPEN_ERROR;
133
0
  }
134
0
  if (bytes_read == 0)
135
0
    return WTAP_OPEN_NOT_MINE;
136
137
0
  found_file = false;
138
0
  for (i = 0; i < N_MAGIC_TYPES; i++) {
139
0
    if ((unsigned) bytes_read >= magic_files[i].magic_len && !memcmp(magic_buf, magic_files[i].magic, MIN(magic_files[i].magic_len, (unsigned) bytes_read))) {
140
0
      if (!found_file) {
141
0
        if (magic_files[i].magic == pcapng_premagic) {
142
0
          if (memcmp(magic_buf + 8, pcapng_xmagic, sizeof(pcapng_xmagic)) &&
143
0
              memcmp(magic_buf + 8, pcapng_swapped_xmagic, sizeof(pcapng_swapped_xmagic)))
144
0
            continue;
145
0
        }
146
0
        found_file = true;
147
0
      } else
148
0
        return WTAP_OPEN_NOT_MINE; /* many files matched, bad file */
149
0
    }
150
0
  }
151
152
0
  if (!found_file)
153
0
    return WTAP_OPEN_NOT_MINE;
154
155
0
  if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
156
0
    return WTAP_OPEN_ERROR;
157
158
0
  wth->file_type_subtype = mime_file_type_subtype;
159
0
  wth->file_encap = WTAP_ENCAP_MIME;
160
0
  wth->file_tsprec = WTAP_TSPREC_SEC;
161
0
  wth->subtype_read = wtap_full_file_read;
162
0
  wth->subtype_seek_read = wtap_full_file_seek_read;
163
0
  wth->snapshot_length = 0;
164
165
0
  return WTAP_OPEN_MINE;
166
0
}
167
168
static const struct supported_block_type mime_blocks_supported[] = {
169
  /*
170
   * This is a file format that we dissect, so we provide
171
   * only one "packet" with the file's contents, and don't
172
   * support any options.
173
   */
174
  { WTAP_BLOCK_PACKET, ONE_BLOCK_SUPPORTED, NO_OPTIONS_SUPPORTED }
175
};
176
177
static const struct file_type_subtype_info mime_info = {
178
  "MIME File Format", "mime", NULL, NULL,
179
  false, BLOCKS_SUPPORTED(mime_blocks_supported),
180
  NULL, NULL, NULL
181
};
182
183
/*
184
 * XXX - registered solely for the benefit of Lua scripts that
185
 * look for the file type "JPEG_JFIF"; it may be removed once
186
 * we get rid of wtap_filetypes.
187
 */
188
static const struct supported_block_type jpeg_jfif_blocks_supported[] = {
189
  /*
190
   * This is a file format that we dissect, so we provide
191
   * only one "packet" with the file's contents, and don't
192
   * support any options.
193
   */
194
  { WTAP_BLOCK_PACKET, ONE_BLOCK_SUPPORTED, NO_OPTIONS_SUPPORTED }
195
};
196
197
static const struct file_type_subtype_info jpeg_jfif_info = {
198
  "JPEG/JFIF", "jpeg", "jpg", "jpeg;jfif",
199
  false, BLOCKS_SUPPORTED(jpeg_jfif_blocks_supported),
200
  NULL, NULL, NULL
201
};
202
203
void register_mime(void)
204
15
{
205
15
  int jpeg_jfif_file_type_subtype;
206
207
15
  mime_file_type_subtype = wtap_register_file_type_subtype(&mime_info);
208
209
  /*
210
   * Obsoleted by "mime", but we want it for the backwards-
211
   * compatibility table for Lua.
212
   */
213
15
  jpeg_jfif_file_type_subtype = wtap_register_file_type_subtype(&jpeg_jfif_info);
214
215
  /*
216
   * Register names for backwards compatibility with the
217
   * wtap_filetypes table in Lua.
218
   */
219
15
  wtap_register_backwards_compatibility_lua_name("MIME",
220
15
      mime_file_type_subtype);
221
15
  wtap_register_backwards_compatibility_lua_name("JPEG_JFIF",
222
15
      jpeg_jfif_file_type_subtype);
223
15
}
224
225
/*
226
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
227
 *
228
 * Local variables:
229
 * c-basic-offset: 8
230
 * tab-width: 8
231
 * indent-tabs-mode: t
232
 * End:
233
 *
234
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
235
 * :indentSize=8:tabSize=8:noTabs=false:
236
 */