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
|
/* packet-ipmi-session.c
* Routines for dissection of IPMI session wrapper (v1.5 and v2.0)
* Copyright 2007-2008, Alexey Neyman, Pigeon Point Systems <avn@pigeonpoint.com>
* Copyright Duncan Laurie <duncan@sun.com>
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* Partially copied from packet-ipmi.c.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
#include <epan/packet.h>
void proto_register_ipmi_session(void);
void proto_reg_handoff_ipmi_session(void);
static dissector_handle_t ipmi_session_handle;
#define RMCP_CLASS_IPMI 0x07
static int proto_ipmi_session = -1;
static gint ett_ipmi_session = -1;
static gint ett_ipmi_session_payloadtype = -1;
/* IPMI session header */
static int hf_ipmi_session_id = -1;
static int hf_ipmi_session_authtype = -1;
static int hf_ipmi_session_payloadtype = -1;
static int hf_ipmi_session_payloadtype_auth = -1;
static int hf_ipmi_session_payloadtype_enc = -1;
static int hf_ipmi_session_oem_iana = -1;
static int hf_ipmi_session_oem_payload_id = -1;
static int hf_ipmi_session_sequence = -1;
static int hf_ipmi_session_authcode = -1;
static int hf_ipmi_session_msg_len_1b = -1;
static int hf_ipmi_session_msg_len_2b = -1;
static int hf_ipmi_session_trailer = -1;
static dissector_handle_t ipmi_handle;
#define IPMI_AUTH_NONE 0x00
#define IPMI_AUTH_MD2 0x01
#define IPMI_AUTH_MD5 0x02
#define IPMI_AUTH_PASSWORD 0x04
#define IPMI_AUTH_OEM 0x05
#define IPMI_AUTH_RMCPP 0x06
static const value_string ipmi_authtype_vals[] = {
{ IPMI_AUTH_NONE, "NONE" },
{ IPMI_AUTH_MD2, "MD2" },
{ IPMI_AUTH_MD5, "MD5" },
{ IPMI_AUTH_PASSWORD, "PASSWORD" },
{ IPMI_AUTH_OEM, "OEM" },
{ IPMI_AUTH_RMCPP, "RMCP+"},
{ 0x00, NULL }
};
#define IPMI_IPMI_MESSAGE 0
#define IPMI_OEM_EXPLICIT 2
static const value_string ipmi_payload_vals[] = {
{ IPMI_IPMI_MESSAGE, "IPMI Message" },
{ 0x01, "SOL (serial over LAN)" },
{ IPMI_OEM_EXPLICIT, "OEM Explicit" },
/* Session Setup Payload Types */
{ 0x10, "RMCP+ Open Session Request" },
{ 0x11, "RMCP+ Open Session Response" },
{ 0x12, "RAKP Message 1" },
{ 0x13, "RAKP Message 2" },
{ 0x14, "RAKP Message 3" },
{ 0x15, "RAKP Message 4" },
/* OEM Payload Type Handles */
{ 0x20, "OEM0 (OEM Payload)" },
{ 0x21, "OEM1 (OEM Payload)" },
{ 0x22, "OEM2 (OEM Payload)" },
{ 0x23, "OEM3 (OEM Payload)" },
{ 0x24, "OEM4 (OEM Payload)" },
{ 0x25, "OEM5 (OEM Payload)" },
{ 0x26, "OEM6 (OEM Payload)" },
{ 0x27, "OEM7 (OEM Payload)" },
{ 0x00, NULL }
};
static const true_false_string ipmi_payload_aut_val = {
"Payload is authenticated",
"Payload is unauthenticated"
};
static const true_false_string ipmi_payload_enc_val = {
"Payload is encrypted",
"Payload is unencrypted"
};
static int
dissect_ipmi_session(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
proto_tree *sess_tree = NULL, *s_tree;
proto_item *ti;
tvbuff_t *next_tvb;
guint32 session_id;
guint8 authtype, payloadtype = 0;
guint32 msg_start, msg_len, offset = 0;
gboolean payloadtype_auth = 0, payloadtype_enc = 0;
/* session authtype, 0=no authcode present, 6=RMCP+ */
authtype = tvb_get_guint8(tvb, 0);
if (authtype == IPMI_AUTH_RMCPP) {
/* Fetch additional info before trying to interpret
the packet. It may not be IPMI at all! */
payloadtype = tvb_get_guint8(tvb, 1);
payloadtype_auth = (payloadtype >> 6) & 1;
payloadtype_enc = (payloadtype >> 7);
payloadtype &= 0x3f;
/* IPMI v2.0 packets have session ID BEFORE the session
sequence number; just after authentication and payload
types. The OEM Explicit payload type has 6 more bytes
(IANA + Payload ID) before the session ID. */
if (payloadtype == IPMI_OEM_EXPLICIT) {
session_id = tvb_get_letohl(tvb, 8);
msg_start = 18;
msg_len = tvb_get_letohs(tvb, 16);
} else {
session_id = tvb_get_letohl(tvb, 2);
msg_start = 12;
msg_len = tvb_get_letohs(tvb, 10);
}
} else {
/* IPMI v1.5 packets have session ID AFTER the session
sequence number. They also have 1 byte for payload
message length. */
session_id = tvb_get_letohl(tvb, 5);
if (authtype == IPMI_AUTH_NONE) {
msg_start = 10;
msg_len = tvb_get_guint8(tvb, 9);
} else {
msg_start = 26;
msg_len = tvb_get_guint8(tvb, 25);
}
}
/* Later it will be overridden with sub-dissector, if any */
if (authtype == IPMI_AUTH_RMCPP) {
col_set_str(pinfo->cinfo, COL_PROTOCOL, "RMCP+");
} else {
col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPMI");
}
col_add_fstr(pinfo->cinfo, COL_INFO, "Session ID 0x%x", session_id);
if (authtype == IPMI_AUTH_RMCPP) {
col_append_fstr(pinfo->cinfo, COL_INFO, ", payload type: %s",
val_to_str_const(payloadtype, ipmi_payload_vals, "Unknown"));
}
if (tree) {
offset = 0;
ti = proto_tree_add_protocol_format(tree, proto_ipmi_session,
tvb, 0, -1,
"IPMI v%s Session Wrapper, session ID 0x%x",
authtype == IPMI_AUTH_RMCPP ? "2.0+" : "1.5",
session_id);
sess_tree = proto_item_add_subtree(ti, ett_ipmi_session);
proto_tree_add_item(sess_tree, hf_ipmi_session_authtype, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset++;
if (authtype == IPMI_AUTH_RMCPP) {
/* IPMI v2.0+ */
s_tree = proto_tree_add_subtree_format(sess_tree, tvb, offset, 1,
ett_ipmi_session_payloadtype, NULL,
"Payload type: %s (0x%02x), %sencrypted, %sauthenticated",
val_to_str_const(payloadtype, ipmi_payload_vals, "Unknown"),
payloadtype,
payloadtype_enc ? "" : "not ",
payloadtype_auth ? "" : "not ");
proto_tree_add_item(s_tree, hf_ipmi_session_payloadtype_enc, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(s_tree, hf_ipmi_session_payloadtype_auth, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(s_tree, hf_ipmi_session_payloadtype, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset++;
if (payloadtype == IPMI_OEM_EXPLICIT) {
proto_tree_add_item(sess_tree, hf_ipmi_session_oem_iana, tvb, offset, 4, ENC_NA);
offset += 4;
proto_tree_add_item(sess_tree, hf_ipmi_session_oem_payload_id, tvb, offset, 2, ENC_NA);
offset += 2;
}
proto_tree_add_item(sess_tree, hf_ipmi_session_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
offset += 4;
proto_tree_add_item(sess_tree, hf_ipmi_session_sequence, tvb, offset, 4, ENC_LITTLE_ENDIAN);
offset += 4;
proto_tree_add_item(sess_tree, hf_ipmi_session_msg_len_2b, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
} else {
/* IPMI v1.5 */
proto_tree_add_item(sess_tree, hf_ipmi_session_sequence, tvb, offset, 4, ENC_LITTLE_ENDIAN);
offset += 4;
proto_tree_add_item(sess_tree, hf_ipmi_session_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
offset += 4;
if (authtype != IPMI_AUTH_NONE) {
proto_tree_add_item(sess_tree, hf_ipmi_session_authcode,
tvb, offset, 16, ENC_NA);
offset += 16;
}
proto_tree_add_item(sess_tree, hf_ipmi_session_msg_len_1b, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset++;
}
}
/* If we can parse the embedded message, do so */
next_tvb = tvb_new_subset_length_caplen(tvb, msg_start, msg_len, -1);
if (payloadtype_enc) {
/* This is RMCP+, and payload is encrypted. In this case,
there is a 'confidentiality header/trailer', whose lengths
are unknown to us. These lengths are negotiated during
session open process and are retained over a session.
Since we are stateless (and more, we may have no session
open packet in the capture we parse), we cannot even
decipher where a message starts. Just print them as data.
*/
call_data_dissector(next_tvb, pinfo, tree);
} else if (authtype != IPMI_AUTH_RMCPP || payloadtype == IPMI_IPMI_MESSAGE) {
/* This is an IPMI message, either v1.5 or v2.0+. For now,
we don't need to distinguish these kinds. */
call_dissector(ipmi_handle, next_tvb, pinfo, tree);
} else {
/* All other RMCP+ payload types fall here: session open/close
requests, RAKP messages, SOL. We cannot parse them yet, thus
just output as data. */
call_data_dissector(next_tvb, pinfo, tree);
}
if (tree) {
/* Account for the message we just parsed. */
offset += msg_len;
/* Show the rest of the session wrapper as binary data */
if (offset < tvb_captured_length(tvb)) {
proto_tree_add_item(sess_tree, hf_ipmi_session_trailer,
tvb, offset, -1, ENC_NA);
}
}
return tvb_captured_length(tvb);
}
void
proto_register_ipmi_session(void)
{
static hf_register_info hf[] = {
{ &hf_ipmi_session_authtype, {
"Authentication Type", "ipmi_session.authtype",
FT_UINT8, BASE_HEX, VALS(ipmi_authtype_vals), 0, NULL, HFILL }},
{ &hf_ipmi_session_payloadtype,{
"Payload Type", "ipmi_session.payloadtype",
FT_UINT8, BASE_HEX, VALS(ipmi_payload_vals), 0x3f, NULL, HFILL }},
{ &hf_ipmi_session_payloadtype_auth,{
"Authenticated","ipmi_session.payloadtype.auth",
FT_BOOLEAN,8, TFS(&ipmi_payload_aut_val), 0x40, NULL, HFILL }},
{ &hf_ipmi_session_payloadtype_enc,{
"Encryption","ipmi_session.payloadtype.enc",
FT_BOOLEAN,8, TFS(&ipmi_payload_enc_val), 0x80, NULL, HFILL }},
{ &hf_ipmi_session_oem_iana, {
"OEM IANA", "ipmi_session.oem.iana",
FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
{ &hf_ipmi_session_oem_payload_id, {
"OEM Payload ID", "ipmi_session.oem.payloadid",
FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
{ &hf_ipmi_session_sequence, {
"Session Sequence Number", "ipmi_session.sequence",
FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_ipmi_session_id, {
"Session ID", "ipmi_session.id",
FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_ipmi_session_authcode, {
"Authentication Code", "ipmi_session.authcode",
FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
{ &hf_ipmi_session_msg_len_1b, {
"Message Length", "ipmi_session.msg.len",
FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_ipmi_session_msg_len_2b, {
"Message Length", "ipmi_session.msg.len",
FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_ipmi_session_trailer, {
"IPMI Session Wrapper (trailer)", "ipmi_session.trailer",
FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
};
static gint *ett[] = { &ett_ipmi_session, &ett_ipmi_session_payloadtype };
proto_ipmi_session = proto_register_protocol("Intelligent Platform Management Interface (Session Wrapper)", "IPMI Session", "ipmi_session");
proto_register_field_array(proto_ipmi_session, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
ipmi_session_handle = register_dissector("ipmi_session", dissect_ipmi_session, proto_ipmi_session);
}
void
proto_reg_handoff_ipmi_session(void)
{
dissector_add_uint("rmcp.class", RMCP_CLASS_IPMI, ipmi_session_handle);
ipmi_handle = find_dissector_add_dependency("ipmi", proto_ipmi_session);
}
/*
* 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:
*/
|