1 /* radcom.c
2  *
3  * Wiretap Library
4  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
5  *
6  * SPDX-License-Identifier: GPL-2.0-or-later
7  */
8 
9 #include "config.h"
10 
11 #include <errno.h>
12 #include <string.h>
13 #include "wtap-int.h"
14 #include "file_wrappers.h"
15 #include "radcom.h"
16 
17 struct frame_date {
18 	guint16	year;
19 	guint8	month;
20 	guint8	day;
21 	guint32	sec;		/* seconds since midnight */
22 	guint32	usec;
23 };
24 
25 struct unaligned_frame_date {
26 	char	year[2];
27 	char	month;
28 	char	day;
29 	char	sec[4];		/* seconds since midnight */
30 	char	usec[4];
31 };
32 
33 /* Found at the beginning of the file. Bytes 2 and 3 (D2:00) seem to be
34  * different in some captures */
35 static const guint8 radcom_magic[8] = {
36 	0x42, 0xD2, 0x00, 0x34, 0x12, 0x66, 0x22, 0x88
37 };
38 
39 static const guint8 encap_magic[4] = {
40 	0x00, 0x42, 0x43, 0x09
41 };
42 
43 static const guint8 active_time_magic[11] = {
44 	'A', 'c', 't', 'i', 'v', 'e', ' ', 'T', 'i', 'm', 'e'
45 };
46 
47 /* RADCOM record header - followed by frame data (perhaps including FCS).
48 
49    "data_length" appears to be the length of packet data following
50    the record header.  It's 0 in the last record.
51 
52    "length" appears to be the amount of captured packet data, and
53    "real_length" might be the actual length of the frame on the wire -
54    in some captures, it's the same as "length", and, in others,
55    it's greater than "length".  In the last record, however, those
56    may have bogus values (or is that some kind of trailer record?).
57 
58    "xxx" appears to be all-zero in all but the last record in one
59    capture; if so, perhaps this indicates that the last record is,
60    in fact, a trailer of some sort, and some field in the header
61    is a record type. */
62 struct radcomrec_hdr {
63 	char	xxx[4];		/* unknown */
64 	char	data_length[2];	/* packet length? */
65 	char	xxy[5];		/* unknown */
66 	struct unaligned_frame_date date; /* date/time stamp of packet */
67 	char	real_length[2];	/* actual length of packet */
68 	char	length[2];	/* captured length of packet */
69 	char	xxz[2];		/* unknown */
70 	char	dce;		/* DCE/DTE flag (and other flags?) */
71 	char	xxw[9];		/* unknown */
72 };
73 
74 static gboolean radcom_read(wtap *wth, wtap_rec *rec, Buffer *buf,
75 	int *err, gchar **err_info, gint64 *data_offset);
76 static gboolean radcom_seek_read(wtap *wth, gint64 seek_off,
77 	wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
78 static gboolean radcom_read_rec(wtap *wth, FILE_T fh, wtap_rec *rec,
79 	Buffer *buf, int *err, gchar **err_info);
80 
81 static int radcom_file_type_subtype = -1;
82 
83 void register_radcom(void);
84 
radcom_open(wtap * wth,int * err,gchar ** err_info)85 wtap_open_return_val radcom_open(wtap *wth, int *err, gchar **err_info)
86 {
87 	guint8 r_magic[8], t_magic[11], search_encap[7];
88 	struct frame_date start_date;
89 #if 0
90 	guint32 sec;
91 	struct tm tm;
92 #endif
93 
94 	/* Read in the string that should be at the start of a RADCOM file */
95 	if (!wtap_read_bytes(wth->fh, r_magic, 8, err, err_info)) {
96 		if (*err != WTAP_ERR_SHORT_READ)
97 			return WTAP_OPEN_ERROR;
98 		return WTAP_OPEN_NOT_MINE;
99 	}
100 
101 	/* XXX: bytes 2 and 3 of the "magic" header seem to be different in some
102 	 * captures. We force them to our standard value so that the test
103 	 * succeeds (until we find if they have a special meaning, perhaps a
104 	 * version number ?) */
105 	r_magic[1] = 0xD2;
106 	r_magic[2] = 0x00;
107 	if (memcmp(r_magic, radcom_magic, 8) != 0) {
108 		return WTAP_OPEN_NOT_MINE;
109 	}
110 
111 	/* Look for the "Active Time" string. The "frame_date" structure should
112 	 * be located 32 bytes before the beginning of this string */
113 	if (!wtap_read_bytes(wth->fh, t_magic, 11, err, err_info)) {
114 		if (*err != WTAP_ERR_SHORT_READ)
115 			return WTAP_OPEN_ERROR;
116 		return WTAP_OPEN_NOT_MINE;
117 	}
118 	while (memcmp(t_magic, active_time_magic, 11) != 0)
119 	{
120 		if (file_seek(wth->fh, -10, SEEK_CUR, err) == -1)
121 			return WTAP_OPEN_ERROR;
122 		if (!wtap_read_bytes(wth->fh, t_magic, 11, err, err_info)) {
123 			if (*err != WTAP_ERR_SHORT_READ)
124 				return WTAP_OPEN_ERROR;
125 			return WTAP_OPEN_NOT_MINE;
126 		}
127 	}
128 	if (file_seek(wth->fh, -43, SEEK_CUR, err) == -1)
129 		return WTAP_OPEN_ERROR;
130 
131 	/* Get capture start time */
132 	if (!wtap_read_bytes(wth->fh, &start_date, sizeof(struct frame_date),
133 	    err, err_info)) {
134 		if (*err != WTAP_ERR_SHORT_READ)
135 			return WTAP_OPEN_ERROR;
136 		return WTAP_OPEN_NOT_MINE;
137 	}
138 
139 	/* So what time is this? */
140 	if (!wtap_read_bytes(wth->fh, NULL, sizeof(struct frame_date),
141 	    err, err_info)) {
142 		if (*err != WTAP_ERR_SHORT_READ)
143 			return WTAP_OPEN_ERROR;
144 		return WTAP_OPEN_NOT_MINE;
145 	}
146 
147 	for (;;) {
148 		if (!wtap_read_bytes(wth->fh, search_encap, 4,
149 		    err, err_info)) {
150 			if (*err != WTAP_ERR_SHORT_READ)
151 				return WTAP_OPEN_ERROR;
152 			return WTAP_OPEN_NOT_MINE;
153 		}
154 
155 		if (memcmp(encap_magic, search_encap, 4) == 0)
156 			break;
157 
158 		/*
159 		 * OK, that's not it, go forward 1 byte - reading
160 		 * the magic moved us forward 4 bytes, so seeking
161 		 * backward 3 bytes moves forward 1 byte - and
162 		 * try the 4 bytes at that offset.
163 		 */
164 		if (file_seek(wth->fh, -3, SEEK_CUR, err) == -1)
165 			return WTAP_OPEN_ERROR;
166 	}
167 	if (!wtap_read_bytes(wth->fh, NULL, 12, err, err_info)) {
168 		if (*err != WTAP_ERR_SHORT_READ)
169 			return WTAP_OPEN_ERROR;
170 		return WTAP_OPEN_NOT_MINE;
171 	}
172 	if (!wtap_read_bytes(wth->fh, search_encap, 4, err, err_info)) {
173 		if (*err != WTAP_ERR_SHORT_READ)
174 			return WTAP_OPEN_ERROR;
175 		return WTAP_OPEN_NOT_MINE;
176 	}
177 
178 	/* This is a radcom file */
179 	wth->file_type_subtype = radcom_file_type_subtype;
180 	wth->subtype_read = radcom_read;
181 	wth->subtype_seek_read = radcom_seek_read;
182 	wth->snapshot_length = 0; /* not available in header, only in frame */
183 	wth->file_tsprec = WTAP_TSPREC_USEC;
184 
185 #if 0
186 	tm.tm_year = pletoh16(&start_date.year)-1900;
187 	tm.tm_mon = start_date.month-1;
188 	tm.tm_mday = start_date.day;
189 	sec = pletoh32(&start_date.sec);
190 	tm.tm_hour = sec/3600;
191 	tm.tm_min = (sec%3600)/60;
192 	tm.tm_sec = sec%60;
193 	tm.tm_isdst = -1;
194 #endif
195 
196 	if (memcmp(search_encap, "LAPB", 4) == 0)
197 		wth->file_encap = WTAP_ENCAP_LAPB;
198 	else if (memcmp(search_encap, "Ethe", 4) == 0)
199 		wth->file_encap = WTAP_ENCAP_ETHERNET;
200 	else if (memcmp(search_encap, "ATM/", 4) == 0)
201 		wth->file_encap = WTAP_ENCAP_ATM_RFC1483;
202 	else {
203 		*err = WTAP_ERR_UNSUPPORTED;
204 		*err_info = g_strdup_printf("radcom: network type \"%.4s\" unknown", search_encap);
205 		return WTAP_OPEN_ERROR;
206 	}
207 
208 #if 0
209 	if (!wtap_read_bytes(wth->fh, &next_date, sizeof(struct frame_date),
210 	    err, err_info))
211 		return WTAP_OPEN_ERROR;
212 
213 	while (memcmp(&start_date, &next_date, 4)) {
214 		if (file_seek(wth->fh, 1-sizeof(struct frame_date), SEEK_CUR, err) == -1)
215 			return WTAP_OPEN_ERROR;
216 		if (!wtap_read_bytes(wth->fh, &next_date, sizeof(struct frame_date),
217 		    err, err_info))
218 			return WTAP_OPEN_ERROR;
219 	}
220 #endif
221 
222 	if (wth->file_encap == WTAP_ENCAP_ETHERNET) {
223 		if (!wtap_read_bytes(wth->fh, NULL, 294, err, err_info))
224 			return WTAP_OPEN_ERROR;
225 	} else if (wth->file_encap == WTAP_ENCAP_LAPB) {
226 		if (!wtap_read_bytes(wth->fh, NULL, 297, err, err_info))
227 			return WTAP_OPEN_ERROR;
228 	} else if (wth->file_encap == WTAP_ENCAP_ATM_RFC1483) {
229 		if (!wtap_read_bytes(wth->fh, NULL, 504, err, err_info))
230 			return WTAP_OPEN_ERROR;
231 	}
232 
233 	/*
234 	 * Add an IDB; we don't know how many interfaces were involved,
235 	 * so we just say one interface, about which we only know
236 	 * the link-layer type, snapshot length, and time stamp
237 	 * resolution.
238 	 */
239 	wtap_add_generated_idb(wth);
240 
241 	return WTAP_OPEN_MINE;
242 }
243 
244 /* Read the next packet */
radcom_read(wtap * wth,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info,gint64 * data_offset)245 static gboolean radcom_read(wtap *wth, wtap_rec *rec, Buffer *buf,
246 			    int *err, gchar **err_info, gint64 *data_offset)
247 {
248 	char	fcs[2];
249 
250 	*data_offset = file_tell(wth->fh);
251 
252 	/* Read record. */
253 	if (!radcom_read_rec(wth, wth->fh, rec, buf, err, err_info)) {
254 		/* Read error or EOF */
255 		return FALSE;
256 	}
257 
258 	if (wth->file_encap == WTAP_ENCAP_LAPB) {
259 		/* Read the FCS.
260 		   XXX - should we have some way of indicating the
261 		   presence and size of an FCS to our caller?
262 		   That'd let us handle other file types as well. */
263 		if (!wtap_read_bytes(wth->fh, &fcs, sizeof fcs, err, err_info))
264 			return FALSE;
265 	}
266 
267 	return TRUE;
268 }
269 
270 static gboolean
radcom_seek_read(wtap * wth,gint64 seek_off,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info)271 radcom_seek_read(wtap *wth, gint64 seek_off,
272 		 wtap_rec *rec, Buffer *buf,
273 		 int *err, gchar **err_info)
274 {
275 	if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
276 		return FALSE;
277 
278 	/* Read record. */
279 	if (!radcom_read_rec(wth, wth->random_fh, rec, buf, err,
280 	    err_info)) {
281 		/* Read error or EOF */
282 		if (*err == 0) {
283 			/* EOF means "short read" in random-access mode */
284 			*err = WTAP_ERR_SHORT_READ;
285 		}
286 		return FALSE;
287 	}
288 	return TRUE;
289 }
290 
291 static gboolean
radcom_read_rec(wtap * wth,FILE_T fh,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info)292 radcom_read_rec(wtap *wth, FILE_T fh, wtap_rec *rec, Buffer *buf,
293 		int *err, gchar **err_info)
294 {
295 	struct radcomrec_hdr hdr;
296 	guint16 data_length, real_length, length;
297 	guint32 sec;
298 	struct tm tm;
299 	guint8	atmhdr[8];
300 
301 	if (!wtap_read_bytes_or_eof(fh, &hdr, sizeof hdr, err, err_info))
302 		return FALSE;
303 
304 	data_length = pletoh16(&hdr.data_length);
305 	if (data_length == 0) {
306 		/*
307 		 * The last record appears to have 0 in its "data_length"
308 		 * field, but non-zero values in other fields, so we
309 		 * check for that and treat it as an EOF indication.
310 		 */
311 		*err = 0;
312 		return FALSE;
313 	}
314 	length = pletoh16(&hdr.length);
315 	real_length = pletoh16(&hdr.real_length);
316 	/*
317 	 * The maximum value of length is 65535, which is less than
318 	 * WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need to check
319 	 * it.
320 	 */
321 
322 	rec->rec_type = REC_TYPE_PACKET;
323 	rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
324 	rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
325 
326 	tm.tm_year = pletoh16(&hdr.date.year)-1900;
327 	tm.tm_mon = (hdr.date.month&0x0f)-1;
328 	tm.tm_mday = hdr.date.day;
329 	sec = pletoh32(&hdr.date.sec);
330 	tm.tm_hour = sec/3600;
331 	tm.tm_min = (sec%3600)/60;
332 	tm.tm_sec = sec%60;
333 	tm.tm_isdst = -1;
334 	rec->ts.secs = mktime(&tm);
335 	rec->ts.nsecs = pletoh32(&hdr.date.usec) * 1000;
336 
337 	switch (wth->file_encap) {
338 
339 	case WTAP_ENCAP_ETHERNET:
340 		/* XXX - is there an FCS? */
341 		rec->rec_header.packet_header.pseudo_header.eth.fcs_len = -1;
342 		break;
343 
344 	case WTAP_ENCAP_LAPB:
345 		rec->rec_header.packet_header.pseudo_header.dte_dce.flags = (hdr.dce & 0x1) ?
346 		    0x00 : FROM_DCE;
347 		length -= 2; /* FCS */
348 		real_length -= 2;
349 		break;
350 
351 	case WTAP_ENCAP_ATM_RFC1483:
352 		/*
353 		 * XXX - is this stuff a pseudo-header?
354 		 * The direction appears to be in the "hdr.dce" field.
355 		 */
356 		if (!wtap_read_bytes(fh, atmhdr, sizeof atmhdr, err,
357 		    err_info))
358 			return FALSE;	/* Read error */
359 		length -= 8;
360 		real_length -= 8;
361 		break;
362 	}
363 
364 	rec->rec_header.packet_header.len = real_length;
365 	rec->rec_header.packet_header.caplen = length;
366 
367 	/*
368 	 * Read the packet data.
369 	 */
370 	if (!wtap_read_packet_bytes(fh, buf, length, err, err_info))
371 		return FALSE;	/* Read error */
372 
373 	return TRUE;
374 }
375 
376 static const struct supported_block_type radcom_blocks_supported[] = {
377 	/*
378 	 * We support packet blocks, with no comments or other options.
379 	 */
380 	{ WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
381 };
382 
383 static const struct file_type_subtype_info radcom_info = {
384 	"RADCOM WAN/LAN analyzer", "radcom", NULL, NULL,
385 	FALSE, BLOCKS_SUPPORTED(radcom_blocks_supported),
386 	NULL, NULL, NULL
387 };
388 
register_radcom(void)389 void register_radcom(void)
390 {
391 	radcom_file_type_subtype = wtap_register_file_type_subtype(&radcom_info);
392 
393 	/*
394 	 * Register name for backwards compatibility with the
395 	 * wtap_filetypes table in Lua.
396 	 */
397 	wtap_register_backwards_compatibility_lua_name("RADCOM",
398 	    radcom_file_type_subtype);
399 }
400 
401 /*
402  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
403  *
404  * Local variables:
405  * c-basic-offset: 8
406  * tab-width: 8
407  * indent-tabs-mode: t
408  * End:
409  *
410  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
411  * :indentSize=8:tabSize=8:noTabs=false:
412  */
413