summaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-aol.c
blob: 74b347222292b1bd73d9f18348011dcd44ac75d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
/* packet-aol.c
 *
 * Routines for dissecting the America Online protocol
 * Copyright (C) 2012 Tim Hentenaar <tim at hentenaar dot com>
 *
 * More information on the P3 frame protocol can be found on page 66 of:
 * http://koin.org/files/aol.aim/aol/fdo/manuals/WAOL.doc
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#include "config.h"

#include <epan/packet.h>
#include <epan/prefs.h>
#include <epan/expert.h>

#include "packet-tcp.h"

void proto_register_aol(void);
void proto_reg_handoff_aol(void);

static dissector_handle_t aol_handle;

/* AOL's port */
#define AOL_PORT 5190

/* Frame markers */
#define AOL_P3_FRAME_START 0x5a
#define AOL_P3_FRAME_END   0x0d

/* Frame types */
#define AOL_P3_TYPE_DATA      0x20
#define AOL_P3_TYPE_SS        0x21
#define AOL_P3_TYPE_SSR       0x22
#define AOL_P3_TYPE_INIT      0x23
#define AOL_P3_TYPE_ACK       0x24
#define AOL_P3_TYPE_NAK       0x25
#define AOL_P3_TYPE_HEARTBEAT 0x26

static const value_string aol_p3_types[] = {
	{ AOL_P3_TYPE_DATA,      "Data"        },
	{ AOL_P3_TYPE_SS,        "SS Request"  },
	{ AOL_P3_TYPE_SSR,       "SS Response" },
	{ AOL_P3_TYPE_INIT,      "Init"        },
	{ AOL_P3_TYPE_ACK,       "ACK"         },
	{ AOL_P3_TYPE_NAK,       "NAK"         },
	{ AOL_P3_TYPE_HEARTBEAT, "Heartbeat"   },
	{ 0,                     NULL          }
};

/* Platforms */
#define AOL_PLATFORM_WINDOWS 0x03
#define AOL_PLATFORM_MAC     0x0c

static const value_string aol_platforms[] = {
	{ AOL_PLATFORM_WINDOWS,  "Microsoft Windows" },
	{ AOL_PLATFORM_MAC,      "Macintosh"         },
	{ 0,                     NULL                }
};

/* Windows Memory Mode */
static const value_string aol_wmem_mode[] = {
	{ 0, "Standard" },
	{ 1, "Enhanced" },
	{ 0, NULL       }
};

/* Protocol */
static int proto_aol;

/* Special fields */
static int hf_aol_udata;
static int hf_aol_init;

/* Header fields */
static int hf_aol_start;
static int hf_aol_crc;
static int hf_aol_len;
static int hf_aol_tx_seq;
static int hf_aol_rx_seq;
static int hf_aol_type;
static int hf_aol_token;
static int hf_aol_data;
static int hf_aol_end;

/* 'INIT' PDU Fields */
static int hf_aol_platform;
static int hf_aol_version;
static int hf_aol_subversion;
static int hf_aol_unused;
static int hf_aol_machine_mem;
static int hf_aol_app_mem;
static int hf_aol_pc_type;
static int hf_aol_rel_month;
static int hf_aol_rel_day;
static int hf_aol_cust_class;
static int hf_aol_udo_timestamp;
static int hf_aol_dos_ver;
static int hf_aol_sess_flags;
static int hf_aol_video_type;
static int hf_aol_cpu_type;
static int hf_aol_media_type;
static int hf_aol_win_ver;
static int hf_aol_wmem_mode;
static int hf_aol_horiz_res;
static int hf_aol_vert_res;
static int hf_aol_num_colors;
static int hf_aol_filler;
static int hf_aol_region;
static int hf_aol_lang;
static int hf_aol_conn_spd;

/* Subtrees */
static int ett_aol;
static int ett_aol_data;

static expert_field ei_aol_pdu_length_bad;
static expert_field ei_aol_end_missing;

/* Prefs */
static bool aol_desegment  = true;

/**
 * Dissect the 'INIT' PDU.
 */
static unsigned dissect_aol_init(tvbuff_t *tvb, packet_info *pinfo _U_, unsigned offset, proto_tree *tree) {
	proto_item *data_item;
	proto_tree *data_tree;
	uint16_t    dos_ver   = 0;
	uint16_t    win_ver   = 0;

	/* Add the Data subtree */
	data_item = proto_tree_add_item(tree,hf_aol_init,tvb,offset,tvb_reported_length_remaining(tvb,offset)-1,ENC_NA);
	data_tree = proto_item_add_subtree(data_item,ett_aol_data);

	/* Now, parse the structure */
	proto_tree_add_item(data_tree,hf_aol_platform,     tvb,offset,1,ENC_NA);            offset += 1;
	proto_tree_add_item(data_tree,hf_aol_version,      tvb,offset,1,ENC_NA);            offset += 1;
	proto_tree_add_item(data_tree,hf_aol_subversion,   tvb,offset,1,ENC_NA);            offset += 1;
	proto_tree_add_item(data_tree,hf_aol_unused,       tvb,offset,1,ENC_NA);            offset += 1;
	proto_tree_add_item(data_tree,hf_aol_machine_mem,  tvb,offset,1,ENC_NA);            offset += 1;
	proto_tree_add_item(data_tree,hf_aol_app_mem,      tvb,offset,1,ENC_NA);            offset += 1;
	proto_tree_add_item(data_tree,hf_aol_pc_type,      tvb,offset,2,ENC_LITTLE_ENDIAN); offset += 2;
	proto_tree_add_item(data_tree,hf_aol_rel_month,    tvb,offset,1,ENC_NA);            offset += 1;
	proto_tree_add_item(data_tree,hf_aol_rel_day,      tvb,offset,1,ENC_NA);            offset += 1;
	proto_tree_add_item(data_tree,hf_aol_cust_class,   tvb,offset,2,ENC_LITTLE_ENDIAN); offset += 2;
	proto_tree_add_item(data_tree,hf_aol_udo_timestamp,tvb,offset,4,ENC_LITTLE_ENDIAN); offset += 4;

	dos_ver = tvb_get_ntohs(tvb,offset);
	proto_tree_add_uint_format_value(data_tree,hf_aol_dos_ver,tvb,offset,2,dos_ver,"%d.%d",(dos_ver & 0xFF00) >> 8,dos_ver & 0xFF);
	offset += 2;

	proto_tree_add_item(data_tree,hf_aol_sess_flags,   tvb,offset,2,ENC_LITTLE_ENDIAN); offset += 2;
	proto_tree_add_item(data_tree,hf_aol_video_type,   tvb,offset,1,ENC_NA);            offset += 1;
	proto_tree_add_item(data_tree,hf_aol_cpu_type,     tvb,offset,1,ENC_NA);            offset += 1;
	proto_tree_add_item(data_tree,hf_aol_media_type,   tvb,offset,4,ENC_LITTLE_ENDIAN); offset += 4;

	/* Windows version is a 32-bit value, but only the lower 16 bits are populated */
	win_ver = tvb_get_ntohs(tvb,offset);
	proto_tree_add_uint_format_value(data_tree,hf_aol_win_ver,tvb,offset,2,dos_ver,"%d.%d",(win_ver & 0xFF00) >> 8,win_ver & 0xFF);
	offset += 4;

	proto_tree_add_item(data_tree,hf_aol_wmem_mode,    tvb,offset,1,ENC_NA);            offset += 1;
	proto_tree_add_item(data_tree,hf_aol_horiz_res,    tvb,offset,2,ENC_LITTLE_ENDIAN); offset += 2;
	proto_tree_add_item(data_tree,hf_aol_vert_res,     tvb,offset,2,ENC_LITTLE_ENDIAN); offset += 2;
	proto_tree_add_item(data_tree,hf_aol_num_colors,   tvb,offset,2,ENC_LITTLE_ENDIAN); offset += 2; /* 37b */

	/* WAOL 1.5 (48b), >= 2.5 (49b) */
	if (tvb_reported_length_remaining(tvb,offset) <= 13) { /* WAOL 1.5 - 3.0 */
		if (tvb_reported_length_remaining(tvb,offset) == 13) { /* WAOL > 1.5 */
			proto_tree_add_item(data_tree,hf_aol_filler,tvb,offset,1,ENC_BIG_ENDIAN); offset += 1;
		}

		proto_tree_add_item(data_tree,hf_aol_region,  tvb,offset,2,ENC_LITTLE_ENDIAN); offset += 2;
		proto_tree_add_item(data_tree,hf_aol_lang,    tvb,offset,8,ENC_LITTLE_ENDIAN); offset += 8;
		proto_tree_add_item(data_tree,hf_aol_conn_spd,tvb,offset,1,ENC_NA);            offset += 1;
	} else { /* WAOL >= 4.0 - ??? (52b) */
		;
	}

	return offset;
}

/**
 * Get the length of a particular PDU (+6 bytes for the frame)
 */
static unsigned get_aol_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb,
                             int offset, void *data _U_)
{
	uint16_t plen;

	/* Get the PDU length */
	plen = tvb_get_ntohs(tvb,offset+3);
	return plen + 6;
}

/**
 * Dissect a PDU
 */
static int dissect_aol_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) {
	proto_item    *ti;
	proto_tree    *aol_tree;
	unsigned       offset     = 0;
	uint16_t       pdu_len;
	uint8_t        pdu_type   = 0;

	/* Set the protocol name, and info column text. */
	col_set_str(pinfo->cinfo,COL_PROTOCOL,"AOL");
	col_set_str(pinfo->cinfo,COL_INFO,"America Online");

	/* Add our tree item, and tree */
	ti       = proto_tree_add_item(tree,proto_aol,tvb,0,-1,ENC_NA);
	aol_tree = proto_item_add_subtree(ti,ett_aol);
	pdu_len  = tvb_get_ntohs(tvb,3);

	/* Add the first few P3 fields */
	proto_tree_add_item(aol_tree,hf_aol_start,tvb,offset,1,ENC_NA);         offset += 1;
	proto_tree_add_checksum(aol_tree, tvb, offset, hf_aol_crc, -1, NULL, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS); offset += 2;
	proto_tree_add_item(aol_tree,hf_aol_len,  tvb,offset,2,ENC_BIG_ENDIAN); offset += 2;

	/* Add sequence fields */
	if (pdu_len >= 2) {
		proto_tree_add_item(aol_tree,hf_aol_tx_seq,tvb,offset,1,ENC_NA); offset += 1;
		proto_tree_add_item(aol_tree,hf_aol_rx_seq,tvb,offset,1,ENC_NA); offset += 1;
		pdu_len -= 2;
	}

	/* Add type (and add it to the tree item / info column) */
	if (pdu_len >= 1) {
		pdu_type = tvb_get_uint8(tvb,offset) & 0x3f;
		col_append_fstr(pinfo->cinfo,COL_INFO," [Type: %s]",val_to_str_const(pdu_type,aol_p3_types,"Unknown"));
		proto_item_append_text(ti," [Type: %s]",val_to_str_const(pdu_type,aol_p3_types,"Unknown"));
		proto_tree_add_uint(aol_tree,hf_aol_type,tvb,offset,1,pdu_type);
		offset += 1; pdu_len -= 1;
	}

	/* Now for the data... */
	if (pdu_len > 0) {
		unsigned old_offset = offset;

		if (tvb_reported_length_remaining(tvb,offset) > pdu_len) {
			/* Init packets are a special case */
			if (pdu_type == AOL_P3_TYPE_INIT) {
				offset = dissect_aol_init(tvb,pinfo,offset,aol_tree);
			} else {
				if (pdu_len >= 2) {
					const uint8_t* token;
					/* Get the token */
					proto_tree_add_item_ret_string(aol_tree,hf_aol_token,tvb,offset,2,ENC_ASCII,pinfo->pool,&token);
					/* Add it */
					col_append_fstr(pinfo->cinfo,COL_INFO," [Token: '%s']", token);
					proto_item_append_text(ti," [Token: '%s']", token);
					offset += 2; pdu_len -= 2;
				}

				/* Add the data */
				if (pdu_len > 0) {
					proto_tree_add_item(aol_tree,hf_aol_data,tvb,offset,pdu_len,ENC_NA);
					offset += pdu_len;
				}
			}

			if (offset < (old_offset + pdu_len)) {
				/* We didn't parse the entire pdu... */
				proto_tree_add_item(aol_tree,hf_aol_udata,tvb,offset,(old_offset+pdu_len)-offset,ENC_NA);
				offset = old_offset + pdu_len;
			}
		} else {
			/* Malformed packet */
			expert_add_info(pinfo,ti,&ei_aol_pdu_length_bad);
		}
	}

	/* End-of-Frame Marker */
	if (tvb_reported_length_remaining(tvb,offset) >= 1) {
		proto_tree_add_item(aol_tree,hf_aol_end,tvb,offset,1,ENC_NA);/* offset += 1;*/
	} else {
		/* Malformed Packet */
		expert_add_info(pinfo,ti,&ei_aol_end_missing);
	}

	return tvb_reported_length(tvb);
}

/**
 * Dissect a packet
 */
static int dissect_aol(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
	/* Ensure this really is an AOL packet */
	if (tvb_reported_length(tvb) >= 1 && tvb_get_uint8(tvb,0) != AOL_P3_FRAME_START) return 0;

	/* Dissect PDUs */
	tcp_dissect_pdus(tvb,pinfo,tree,aol_desegment,9,get_aol_pdu_len,dissect_aol_pdu,data);
	return tvb_reported_length(tvb);
}

/**
 * Protocol Registration Routine
 *
 * Registers our protocol.
 */
void proto_register_aol(void) {
	/* Header fields */
	static hf_register_info hf[] = {
		/* Special Stuff */
		{ &hf_aol_udata, { "Unparsed Data",   "aol.udata",    FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }},
		{ &hf_aol_init,  { "AOL 'INIT' Data", "aol.init_data",FT_NONE,  BASE_NONE, NULL, 0x00, NULL, HFILL }},

		/* P3 Frame */
		{ &hf_aol_start,  { "Start of Frame", "aol.start",    FT_UINT8,  BASE_HEX,  NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_crc,    { "Checksum",       "aol.checksum", FT_UINT16, BASE_HEX,  NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_len,    { "Length",         "aol.len",      FT_UINT16, BASE_DEC,  NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_tx_seq, { "Tx Sequence",    "aol.tx_seq",   FT_UINT8,  BASE_HEX,  NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_rx_seq, { "Rx Sequence",    "aol.rx_seq",   FT_UINT8,  BASE_HEX,  NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_type,   { "Type",           "aol.type",     FT_UINT8,  BASE_HEX,  VALS(aol_p3_types), 0x00, NULL, HFILL }},
		{ &hf_aol_token,  { "Token",          "aol.token",    FT_STRING, BASE_NONE, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_data,   { "Data",           "aol.data",     FT_BYTES,  BASE_NONE, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_end,    { "End of Frame",   "aol.end",      FT_UINT8,  BASE_HEX,  NULL,               0x00, NULL, HFILL }},

		/* Init packet */
		{ &hf_aol_platform,     { "Platform",         "aol.init.platform",   FT_UINT8,  BASE_HEX, VALS(aol_platforms),0x00, NULL, HFILL }},
		{ &hf_aol_version,      { "Client Version",   "aol.init.version",    FT_UINT8,  BASE_DEC, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_subversion,   { "Client Subversion","aol.init.subversion", FT_UINT8,  BASE_DEC, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_unused,       { "Unused",           "aol.init.unused",     FT_UINT8,  BASE_HEX, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_machine_mem,  { "Machine Memory",   "aol.init.memory",     FT_UINT8,  BASE_DEC, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_app_mem,      { "App Memory",       "aol.init.app_memory", FT_UINT8,  BASE_DEC, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_pc_type,      { "PC Type",          "aol.init.pc_type",    FT_UINT16, BASE_HEX, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_rel_month,    { "Release Month",    "aol.init.rel_month",  FT_UINT8,  BASE_DEC, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_rel_day,      { "Release Day",      "aol.init.rel_day",    FT_UINT8,  BASE_DEC, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_cust_class,   { "Customer Class",   "aol.init.cust_class", FT_UINT16, BASE_HEX, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_udo_timestamp,{ "UDO Timestamp",    "aol.init.udo_ts",     FT_UINT32, BASE_DEC, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_dos_ver,      { "DOS Version",      "aol.init.dos_ver",    FT_UINT16, BASE_HEX, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_sess_flags,   { "Session Flags",    "aol.init.sess_flags", FT_UINT16, BASE_HEX, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_video_type,   { "Video Type",       "aol.init.video_type", FT_UINT8,  BASE_DEC, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_cpu_type,     { "CPU Type",         "aol.init.cpu_type",   FT_UINT8,  BASE_DEC, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_media_type,   { "Media Type",       "aol.init.media_type", FT_UINT32, BASE_HEX, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_win_ver,      { "Windows Version",  "aol.init.win_ver",    FT_UINT32, BASE_HEX, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_wmem_mode,    { "Windows Mem Type", "aol.init.wmem_mode",  FT_UINT8,  BASE_DEC, VALS(aol_wmem_mode),0x00, NULL, HFILL }},
		{ &hf_aol_horiz_res,    { "Horizontal Res",   "aol.init.horiz_res",  FT_UINT16, BASE_DEC, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_vert_res,     { "Vertical Res",     "aol.init.vert_res",   FT_UINT16, BASE_DEC, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_num_colors,   { "Colors",           "aol.init.colors",     FT_UINT16, BASE_DEC, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_filler,       { "Filler Byte",      "aol.init.filler",     FT_UINT8,  BASE_HEX, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_region,       { "AOL Region",       "aol.init.region",     FT_UINT16, BASE_HEX, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_lang,         { "AOL Language(s)",  "aol.init.langs",      FT_UINT64, BASE_HEX, NULL,               0x00, NULL, HFILL }},
		{ &hf_aol_conn_spd,     { "Connection Speed", "aol.init.conn_spd",   FT_UINT8,  BASE_HEX, NULL,               0x00, NULL, HFILL }},
	};

	/* Trees */
	static int *ett[] = {
		&ett_aol,
		&ett_aol_data
	};

	static ei_register_info ei[] = {
		{ &ei_aol_pdu_length_bad, { "aol.pdu_length_bad", PI_MALFORMED, PI_ERROR, "pdu length > tvb length", EXPFILL }},
		{ &ei_aol_end_missing, { "aol.end_missing", PI_PROTOCOL, PI_WARN, "End of frame marker expected", EXPFILL }},
	};

	/* Module (for prefs) */
	module_t *aol_module;
	expert_module_t* expert_aol;

	/* Register the protocol and header fields */
	proto_aol = proto_register_protocol("America Online","AOL","aol");
	proto_register_field_array(proto_aol,hf,array_length(hf));
	proto_register_subtree_array(ett,array_length(ett));

	expert_aol = expert_register_protocol(proto_aol);
	expert_register_field_array(expert_aol, ei, array_length(ei));

	/* Register prefs */
	aol_module = prefs_register_protocol(proto_aol,NULL);
	prefs_register_bool_preference(aol_module,"desegment",
	    "Reassemble AOL messages spanning multiple TCP segments",
	    "Whether the AOL dissector should reassemble messages spanning multiple TCP segments. "
	    "To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" "
	    "in the TCP protocol settings.",&aol_desegment);

	/* Register the dissector */
	aol_handle = register_dissector("aol", dissect_aol,proto_aol);
}

/**
 * Dissector Handoff Routine
 *
 * Initialize the dissector.
 */
void proto_reg_handoff_aol(void) {
	dissector_add_uint_with_preference("tcp.port",AOL_PORT,aol_handle);
}

/* vi:set ts=4: */

/*
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
 *
 * Local variables:
 * c-basic-offset: 8
 * tab-width: 8
 * indent-tabs-mode: t
 * End:
 *
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
 * :indentSize=8:tabSize=8:noTabs=false:
 */