forked from osmocom/wireshark
Erlang Port Mapper Daemon protocol updated and Erlang Distribution Protocol implemented
svn path=/trunk/; revision=35819
This commit is contained in:
parent
da9d25c9eb
commit
e3808393e1
|
@ -519,6 +519,7 @@ set(DISSECTOR_SRC
|
|||
dissectors/packet-eapol.c
|
||||
dissectors/packet-echo.c
|
||||
dissectors/packet-edonkey.c
|
||||
dissectors/packet-erldp.c
|
||||
dissectors/packet-egd.c
|
||||
dissectors/packet-ehs.c
|
||||
dissectors/packet-eigrp.c
|
||||
|
|
|
@ -430,6 +430,7 @@ DISSECTOR_SRC = \
|
|||
packet-eapol.c \
|
||||
packet-echo.c \
|
||||
packet-edonkey.c \
|
||||
packet-erldp.c \
|
||||
packet-egd.c \
|
||||
packet-ehs.c \
|
||||
packet-eigrp.c \
|
||||
|
@ -1094,6 +1095,7 @@ DISSECTOR_INCLUDES = \
|
|||
packet-enc.h \
|
||||
packet-epl.h \
|
||||
packet-epl_v1.h \
|
||||
packet-epmd.h \
|
||||
packet-esis.h \
|
||||
packet-ess.h \
|
||||
packet-eth.h \
|
||||
|
|
|
@ -36,12 +36,18 @@
|
|||
#endif
|
||||
|
||||
#include <epan/packet.h>
|
||||
#include <epan/ptvcursor.h>
|
||||
#include <epan/conversation.h>
|
||||
|
||||
#define PNAME "Erlang Port Mapper Daemon"
|
||||
#define PSNAME "EPMD"
|
||||
#define PFNAME "epmd"
|
||||
|
||||
static int proto_epmd = -1;
|
||||
static int hf_epmd_len = -1;
|
||||
static int hf_epmd_type = -1;
|
||||
static int hf_epmd_tcp_port = -1;
|
||||
static int hf_epmd_port_no = -1;
|
||||
static int hf_epmd_node_type = -1;
|
||||
static int hf_epmd_protocol = -1;
|
||||
static int hf_epmd_dist_high = -1;
|
||||
static int hf_epmd_dist_low = -1;
|
||||
static int hf_epmd_name_len = -1;
|
||||
|
@ -54,133 +60,216 @@ static int hf_epmd_creation = -1;
|
|||
|
||||
static gint ett_epmd = -1;
|
||||
|
||||
/* Other dissectors */
|
||||
static dissector_handle_t edp_handle = NULL;
|
||||
|
||||
#define EPMD_PORT 4369
|
||||
|
||||
/* requests */
|
||||
#define EPMD_ALIVE2 'x'
|
||||
#define EPMD_PORT_PLEASE 'p'
|
||||
#define EPMD_PORT_PLEASE2 'z'
|
||||
#define EPMD_NAMES 'n'
|
||||
#define EPMD_ALIVE 'a'
|
||||
/* Definitions of message codes */
|
||||
#define EPMD_ALIVE_REQ 'a'
|
||||
#define EPMD_ALIVE_OK_RESP 'Y'
|
||||
#define EPMD_PORT_REQ 'p'
|
||||
#define EPMD_NAMES_REQ 'n'
|
||||
#define EPMD_DUMP_REQ 'd'
|
||||
#define EPMD_KILL_REQ 'k'
|
||||
#define EPMD_STOP_REQ 's'
|
||||
/* New epmd messages */
|
||||
#define EPMD_ALIVE2_REQ 'x' /* 120 */
|
||||
#define EPMD_PORT2_REQ 'z' /* 122 */
|
||||
#define EPMD_ALIVE2_RESP 'y' /* 121 */
|
||||
#define EPMD_PORT2_RESP 'w' /* 119 */
|
||||
|
||||
/* responses */
|
||||
#define EPMD_ALIVE_OK 'Y'
|
||||
#define EPMD_ALIVE2_OK 'y'
|
||||
#define EPMD_PORT_PLEASE2_OK 'w'
|
||||
static const value_string message_types[] = {
|
||||
{ EPMD_ALIVE_REQ , "EPMD_ALIVE_REQ" },
|
||||
{ EPMD_ALIVE_OK_RESP, "EPMD_ALIVE_OK_RESP" },
|
||||
{ EPMD_PORT_REQ , "EPMD_PORT_REQ" },
|
||||
{ EPMD_NAMES_REQ , "EPMD_NAMES_REQ" },
|
||||
{ EPMD_DUMP_REQ , "EPMD_DUMP_REQ" },
|
||||
{ EPMD_KILL_REQ , "EPMD_KILL_REQ" },
|
||||
{ EPMD_STOP_REQ , "EPMD_STOP_REQ" },
|
||||
{ EPMD_ALIVE2_REQ , "EPMD_ALIVE2_REQ" },
|
||||
{ EPMD_PORT2_REQ , "EPMD_PORT2_REQ" },
|
||||
{ EPMD_ALIVE2_RESP , "EPMD_ALIVE2_RESP" },
|
||||
{ EPMD_PORT2_RESP , "EPMD_PORT2_RESP" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/* unknown; currently not implemented */
|
||||
#define EPMD_DUMP 'd'
|
||||
#define EPMD_KILL 'k'
|
||||
#define EPMD_STOP 's'
|
||||
static const value_string node_type_vals[] = {
|
||||
{ 72 , "R3 hidden node" },
|
||||
{ 77 , "R3 erlang node" },
|
||||
{ 104 , "R4 hidden node" },
|
||||
{ 109 , "R4 erlang node" },
|
||||
{ 110 , "R6 nodes" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const value_string message_types[] =
|
||||
{
|
||||
{ EPMD_ALIVE, "Alive" },
|
||||
{ EPMD_PORT_PLEASE, "Port Please" },
|
||||
{ EPMD_NAMES, "Names" },
|
||||
{ EPMD_DUMP, "Dump" },
|
||||
{ EPMD_KILL, "Kill" },
|
||||
{ EPMD_STOP, "Stop" },
|
||||
{ EPMD_ALIVE_OK, "Alive Ok" },
|
||||
{ EPMD_ALIVE2, "Alive 2" },
|
||||
{ EPMD_PORT_PLEASE2, "Port Please 2" },
|
||||
{ EPMD_ALIVE2_OK, "Alive 2 Ok" },
|
||||
{ EPMD_PORT_PLEASE2_OK, "Port Please 2 Ok" },
|
||||
{ 0, NULL }
|
||||
static const value_string protocol_vals[] = {
|
||||
{ 0 , "tcp/ip-v4" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
const value_string epmd_version_vals[] = {
|
||||
{ 0 , "R3" },
|
||||
{ 1 , "R4" },
|
||||
{ 2 , "R5" },
|
||||
{ 3 , "R5C" },
|
||||
{ 4 , "R6 dev" },
|
||||
{ 5 , "R6" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
dissect_epmd_request(ptvcursor_t *cursor)
|
||||
{
|
||||
tvbuff_t *tvb;
|
||||
guint8 type;
|
||||
dissect_epmd_request(packet_info *pinfo, tvbuff_t *tvb, gint offset, proto_tree *tree) {
|
||||
guint8 type;
|
||||
guint16 name_length = 0;
|
||||
const gchar *name = NULL;
|
||||
|
||||
tvb = ptvcursor_tvbuff(cursor);
|
||||
ptvcursor_add(cursor, hf_epmd_len, 2, FALSE);
|
||||
proto_tree_add_item(tree, hf_epmd_len, tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
offset += 2;
|
||||
type = tvb_get_guint8(tvb, offset);
|
||||
proto_tree_add_item(tree, hf_epmd_type, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset++;
|
||||
col_add_str(pinfo->cinfo, COL_INFO, val_to_str(type, VALS(message_types), "unknown (0x%02X)"));
|
||||
|
||||
type = tvb_get_guint8(tvb, ptvcursor_current_offset(cursor));
|
||||
ptvcursor_add(cursor, hf_epmd_type, 1, FALSE);
|
||||
switch (type) {
|
||||
case EPMD_ALIVE2: {
|
||||
guint16 name_length, elen;
|
||||
ptvcursor_add(cursor, hf_epmd_tcp_port, 2, FALSE);
|
||||
ptvcursor_advance(cursor,2); /* 'M', 0 */
|
||||
ptvcursor_add(cursor, hf_epmd_dist_high, 2, FALSE);
|
||||
ptvcursor_add(cursor, hf_epmd_dist_low, 2, FALSE);
|
||||
name_length = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor));
|
||||
ptvcursor_add(cursor, hf_epmd_name_len, 2, FALSE);
|
||||
ptvcursor_add(cursor, hf_epmd_name, name_length, FALSE);
|
||||
elen = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor));
|
||||
ptvcursor_add(cursor, hf_epmd_elen, 2, FALSE);
|
||||
if (elen > 0)
|
||||
ptvcursor_add(cursor, hf_epmd_edata, elen, FALSE);
|
||||
break;
|
||||
}
|
||||
case EPMD_PORT_PLEASE:
|
||||
case EPMD_PORT_PLEASE2:
|
||||
/*ptvcursor_add(cursor, hf_epmd_name, tvb_length(tvb)-3, FALSE);*/
|
||||
ptvcursor_add(cursor, hf_epmd_name, -1, FALSE);
|
||||
break;
|
||||
case EPMD_ALIVE: {
|
||||
ptvcursor_add(cursor, hf_epmd_tcp_port, 2, FALSE);
|
||||
/*ptvcursor_add(cursor, hf_epmd_name, tvb_length(tvb)-3, FALSE);*/
|
||||
ptvcursor_add(cursor, hf_epmd_name, -1, FALSE);
|
||||
break;
|
||||
}
|
||||
case EPMD_NAMES:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (type) {
|
||||
case EPMD_ALIVE2_REQ:
|
||||
proto_tree_add_item(tree, hf_epmd_port_no, tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
offset += 2;
|
||||
proto_tree_add_item(tree, hf_epmd_node_type, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset++;
|
||||
proto_tree_add_item(tree, hf_epmd_protocol, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset++;
|
||||
proto_tree_add_item(tree, hf_epmd_dist_high, tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
offset += 2;
|
||||
proto_tree_add_item(tree, hf_epmd_dist_low, tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
offset += 2;
|
||||
name_length = tvb_get_ntohs(tvb, offset);
|
||||
proto_tree_add_item(tree, hf_epmd_name_len, tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
proto_tree_add_item(tree, hf_epmd_name, tvb, offset + 2, name_length, ENC_NA);
|
||||
name = tvb_get_ephemeral_string(tvb, offset + 2, name_length);
|
||||
offset += 2 + name_length;
|
||||
if (tvb_length_remaining(tvb, offset) >= 2) {
|
||||
guint16 elen=0;
|
||||
elen = tvb_get_ntohs(tvb, offset);
|
||||
proto_tree_add_item(tree, hf_epmd_elen, tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
if (elen > 0)
|
||||
proto_tree_add_item(tree, hf_epmd_edata, tvb, offset + 2, elen, ENC_NA);
|
||||
offset += 2 + elen;
|
||||
}
|
||||
break;
|
||||
|
||||
case EPMD_PORT_REQ:
|
||||
case EPMD_PORT2_REQ:
|
||||
name_length = tvb_length_remaining(tvb, offset);
|
||||
proto_tree_add_item(tree, hf_epmd_name, tvb, offset, name_length, ENC_NA);
|
||||
name = tvb_get_ephemeral_string(tvb, offset, name_length);
|
||||
break;
|
||||
|
||||
case EPMD_ALIVE_REQ:
|
||||
proto_tree_add_item(tree, hf_epmd_port_no, tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
offset += 2;
|
||||
name_length = tvb_length_remaining(tvb, offset);
|
||||
proto_tree_add_item(tree, hf_epmd_name, tvb, offset, name_length, ENC_NA);
|
||||
name = tvb_get_ephemeral_string(tvb, offset, name_length);
|
||||
break;
|
||||
|
||||
case EPMD_NAMES_REQ:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (name) {
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, " %s", name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
dissect_epmd_response_names(ptvcursor_t *cursor)
|
||||
{
|
||||
ptvcursor_add(cursor, hf_epmd_tcp_port, 2, FALSE);
|
||||
ptvcursor_add(cursor, hf_epmd_names, -1, FALSE);
|
||||
/* TODO: parse names */
|
||||
dissect_epmd_response_names(packet_info *pinfo, tvbuff_t *tvb, gint offset, proto_tree *tree) {
|
||||
proto_tree_add_item(tree, hf_epmd_port_no, tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
offset += 2;
|
||||
proto_tree_add_item(tree, hf_epmd_names, tvb, offset, -1, ENC_NA);
|
||||
}
|
||||
|
||||
static void
|
||||
dissect_epmd_response(ptvcursor_t *cursor)
|
||||
{
|
||||
tvbuff_t *tvb;
|
||||
guint32 port;
|
||||
guint8 type;
|
||||
dissect_epmd_response(packet_info *pinfo, tvbuff_t *tvb, gint offset, proto_tree *tree) {
|
||||
guint8 type, result;
|
||||
guint32 port;
|
||||
guint16 name_length = 0;
|
||||
const gchar *name = NULL;
|
||||
conversation_t *conv = NULL;
|
||||
|
||||
tvb = ptvcursor_tvbuff(cursor);
|
||||
port = tvb_get_ntohl(tvb, 0);
|
||||
if (port == EPMD_PORT) {
|
||||
dissect_epmd_response_names(cursor);
|
||||
return;
|
||||
}
|
||||
port = tvb_get_ntohl(tvb, offset);
|
||||
if (port == EPMD_PORT) {
|
||||
dissect_epmd_response_names(pinfo, tvb, offset, tree);
|
||||
return;
|
||||
}
|
||||
|
||||
type = tvb_get_guint8(tvb, 0);
|
||||
ptvcursor_add(cursor, hf_epmd_type, 1, FALSE);
|
||||
switch (type) {
|
||||
case EPMD_PORT_PLEASE2_OK: {
|
||||
ptvcursor_advance(cursor, 1);
|
||||
/* 'w', 0, Port(16), Type(8), Proto(8), High(16), Low(16), NLen(16), Name(x) */
|
||||
ptvcursor_add(cursor, hf_epmd_tcp_port, 2, FALSE);
|
||||
ptvcursor_advance(cursor, 2); /* 'M', 0 */
|
||||
ptvcursor_add(cursor, hf_epmd_dist_high, 2, FALSE);
|
||||
ptvcursor_add(cursor, hf_epmd_dist_low, 2, FALSE);
|
||||
ptvcursor_add(cursor, hf_epmd_name_len, 2, FALSE);
|
||||
ptvcursor_add(cursor, hf_epmd_name, -1, FALSE);
|
||||
}
|
||||
case EPMD_ALIVE_OK:
|
||||
case EPMD_ALIVE2_OK: {
|
||||
ptvcursor_add(cursor, hf_epmd_result, 1, FALSE);
|
||||
ptvcursor_add(cursor, hf_epmd_creation, 2, FALSE);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
type = tvb_get_guint8(tvb, offset);
|
||||
proto_tree_add_item(tree, hf_epmd_type, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset++;
|
||||
col_add_str(pinfo->cinfo, COL_INFO, val_to_str(type, VALS(message_types), "unknown (0x%02X)"));
|
||||
|
||||
switch (type) {
|
||||
case EPMD_ALIVE_OK_RESP:
|
||||
case EPMD_ALIVE2_RESP:
|
||||
result = tvb_get_guint8(tvb, offset);
|
||||
proto_tree_add_item(tree, hf_epmd_result, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset++;
|
||||
proto_tree_add_item(tree, hf_epmd_creation, tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
offset += 2;
|
||||
if (!result) {
|
||||
col_append_str(pinfo->cinfo, COL_INFO, " OK");
|
||||
} else {
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, " ERROR 0x%02X", result);
|
||||
}
|
||||
break;
|
||||
|
||||
case EPMD_PORT2_RESP:
|
||||
result = tvb_get_guint8(tvb, offset);
|
||||
proto_tree_add_item(tree, hf_epmd_result, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset++;
|
||||
if (!result) {
|
||||
col_append_str(pinfo->cinfo, COL_INFO, " OK");
|
||||
} else {
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, " ERROR 0x%02X", result);
|
||||
break;
|
||||
}
|
||||
port = tvb_get_ntohs(tvb, offset);
|
||||
proto_tree_add_item(tree, hf_epmd_port_no, tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
offset += 2;
|
||||
proto_tree_add_item(tree, hf_epmd_node_type, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset++;
|
||||
proto_tree_add_item(tree, hf_epmd_protocol, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset++;
|
||||
proto_tree_add_item(tree, hf_epmd_dist_high, tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
offset += 2;
|
||||
proto_tree_add_item(tree, hf_epmd_dist_low, tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
offset += 2;
|
||||
name_length = tvb_get_ntohs(tvb, offset);
|
||||
proto_tree_add_item(tree, hf_epmd_name_len, tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
proto_tree_add_item(tree, hf_epmd_name, tvb, offset + 2, name_length, ENC_NA);
|
||||
name = tvb_get_ephemeral_string(tvb, offset + 2, name_length);
|
||||
offset += 2 + name_length;
|
||||
if (tvb_length_remaining(tvb, offset) >= 2) {
|
||||
guint16 elen=0;
|
||||
elen = tvb_get_ntohs(tvb, offset);
|
||||
proto_tree_add_item(tree, hf_epmd_elen, tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
if (elen > 0)
|
||||
proto_tree_add_item(tree, hf_epmd_edata, tvb, offset + 2, elen, ENC_NA);
|
||||
offset += 2 + elen;
|
||||
}
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, " %s port=%d", name, port);
|
||||
if (!pinfo->fd->flags.visited) {
|
||||
conv = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_TCP, port, 0, NO_PORT2);
|
||||
conversation_set_dissector(conv, edp_handle);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_epmd(tvbuff_t *tvb)
|
||||
{
|
||||
check_epmd(tvbuff_t *tvb) {
|
||||
guint8 type;
|
||||
|
||||
/* simple heuristic:
|
||||
|
@ -196,9 +285,9 @@ check_epmd(tvbuff_t *tvb)
|
|||
|
||||
type = tvb_get_guint8(tvb, 0);
|
||||
switch (type) {
|
||||
case EPMD_ALIVE_OK:
|
||||
case EPMD_ALIVE2_OK:
|
||||
case EPMD_PORT_PLEASE2_OK:
|
||||
case EPMD_ALIVE_OK_RESP:
|
||||
case EPMD_ALIVE2_RESP:
|
||||
case EPMD_PORT2_RESP:
|
||||
return(TRUE);
|
||||
default:
|
||||
break;
|
||||
|
@ -206,11 +295,11 @@ check_epmd(tvbuff_t *tvb)
|
|||
|
||||
type = tvb_get_guint8(tvb, 2);
|
||||
switch (type) {
|
||||
case EPMD_ALIVE2:
|
||||
case EPMD_PORT_PLEASE:
|
||||
case EPMD_PORT_PLEASE2:
|
||||
case EPMD_NAMES:
|
||||
case EPMD_ALIVE:
|
||||
case EPMD_ALIVE_REQ:
|
||||
case EPMD_ALIVE2_REQ:
|
||||
case EPMD_PORT_REQ:
|
||||
case EPMD_PORT2_REQ:
|
||||
case EPMD_NAMES_REQ:
|
||||
return( TRUE);
|
||||
default:
|
||||
break;
|
||||
|
@ -220,32 +309,25 @@ check_epmd(tvbuff_t *tvb)
|
|||
}
|
||||
|
||||
static int
|
||||
dissect_epmd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
||||
{
|
||||
proto_tree *epmd_tree;
|
||||
proto_item *ti;
|
||||
ptvcursor_t *cursor;
|
||||
dissect_epmd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
|
||||
proto_tree *epmd_tree;
|
||||
proto_item *ti;
|
||||
|
||||
if (!check_epmd(tvb))
|
||||
return(0);
|
||||
if (!check_epmd(tvb))
|
||||
return(0);
|
||||
|
||||
col_set_str(pinfo->cinfo, COL_PROTOCOL, "EPMD");
|
||||
col_set_str(pinfo->cinfo, COL_PROTOCOL, PSNAME);
|
||||
|
||||
if (tree) {
|
||||
ti = proto_tree_add_item(tree, proto_epmd, tvb, 0, -1, FALSE);
|
||||
epmd_tree = proto_item_add_subtree(ti, ett_epmd);
|
||||
cursor = ptvcursor_new(epmd_tree, tvb, 0);
|
||||
ti = proto_tree_add_item(tree, proto_epmd, tvb, 0, -1, FALSE);
|
||||
epmd_tree = proto_item_add_subtree(ti, ett_epmd);
|
||||
|
||||
if (pinfo->srcport==EPMD_PORT) {
|
||||
dissect_epmd_response(cursor);
|
||||
} else {
|
||||
dissect_epmd_request(cursor);
|
||||
}
|
||||
if (pinfo->match_port == pinfo->destport) {
|
||||
dissect_epmd_request(pinfo, tvb, 0, epmd_tree);
|
||||
} else {
|
||||
dissect_epmd_response(pinfo, tvb, 0, epmd_tree);
|
||||
}
|
||||
|
||||
ptvcursor_free(cursor);
|
||||
}
|
||||
|
||||
return(tvb_length(tvb));
|
||||
return(tvb_length(tvb));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -264,30 +346,38 @@ proto_register_epmd(void)
|
|||
{ "Result", "epmd.result",
|
||||
FT_UINT8, BASE_DEC, NULL, 0x0,
|
||||
NULL, HFILL }},
|
||||
{ &hf_epmd_tcp_port,
|
||||
{ "TCP Port", "epmd.tcp_port",
|
||||
{ &hf_epmd_port_no,
|
||||
{ "Port No", "epmd.port_no",
|
||||
FT_UINT16, BASE_DEC, NULL, 0x0,
|
||||
NULL, HFILL }},
|
||||
{ &hf_epmd_node_type,
|
||||
{ "Node Type", "epmd.node_type",
|
||||
FT_UINT8, BASE_DEC, VALS(node_type_vals), 0x0,
|
||||
"Node Type", HFILL }},
|
||||
{ &hf_epmd_protocol,
|
||||
{ "Protocol", "epmd.protocol",
|
||||
FT_UINT8, BASE_DEC, VALS(protocol_vals), 0x0,
|
||||
"Protocol", HFILL }},
|
||||
{ &hf_epmd_creation,
|
||||
{ "Creation", "epmd.creation",
|
||||
FT_UINT16, BASE_DEC, NULL, 0x0,
|
||||
NULL, HFILL }},
|
||||
{ &hf_epmd_dist_high,
|
||||
{ "Dist High", "epmd.dist_high",
|
||||
FT_UINT16, BASE_DEC, NULL, 0x0,
|
||||
{ "Highest Version", "epmd.dist_high",
|
||||
FT_UINT16, BASE_DEC, VALS(epmd_version_vals), 0x0,
|
||||
NULL, HFILL }},
|
||||
{ &hf_epmd_dist_low,
|
||||
{ "Dist Low", "epmd.dist_low",
|
||||
FT_UINT16, BASE_DEC, NULL, 0x0,
|
||||
{ "Lowest Version", "epmd.dist_low",
|
||||
FT_UINT16, BASE_DEC, VALS(epmd_version_vals), 0x0,
|
||||
NULL, HFILL }},
|
||||
{ &hf_epmd_name_len,
|
||||
{ "Name Length", "epmd.name_len",
|
||||
FT_UINT16, BASE_DEC, NULL, 0x0,
|
||||
NULL, HFILL }},
|
||||
{ &hf_epmd_name,
|
||||
{ "Name", "epmd.name",
|
||||
{ "Node Name", "epmd.name",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0,
|
||||
NULL, HFILL }},
|
||||
"Node Name", HFILL }},
|
||||
{ &hf_epmd_elen,
|
||||
{ "Elen", "epmd.elen",
|
||||
FT_UINT16, BASE_DEC, NULL, 0x0,
|
||||
|
@ -305,16 +395,18 @@ proto_register_epmd(void)
|
|||
&ett_epmd,
|
||||
};
|
||||
|
||||
proto_epmd = proto_register_protocol("EPMD Protocol", "EPMD", "epmd");
|
||||
proto_epmd = proto_register_protocol(PNAME, PSNAME, PFNAME);
|
||||
proto_register_field_array(proto_epmd, hf, array_length(hf));
|
||||
proto_register_subtree_array(ett, array_length(ett));
|
||||
new_register_dissector("epmd", dissect_epmd, proto_epmd);
|
||||
new_register_dissector(PFNAME, dissect_epmd, proto_epmd);
|
||||
}
|
||||
|
||||
void
|
||||
proto_reg_handoff_epmd(void)
|
||||
{
|
||||
dissector_handle_t epmd_handle;
|
||||
epmd_handle = find_dissector("epmd");
|
||||
dissector_add_uint("tcp.port", EPMD_PORT, epmd_handle);
|
||||
proto_reg_handoff_epmd(void) {
|
||||
dissector_handle_t epmd_handle;
|
||||
|
||||
epmd_handle = find_dissector("epmd");
|
||||
edp_handle = find_dissector("erldp");
|
||||
|
||||
dissector_add_uint("tcp.port", EPMD_PORT, epmd_handle);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/* packet-epmd.h
|
||||
* Definitions for EPMD (Erlang Port Mapper Daemon) messages
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __PACKET_EPMD_H__
|
||||
#define __PACKET_EPMD_H__
|
||||
|
||||
extern const value_string epmd_version_vals[];
|
||||
|
||||
#endif
|
|
@ -0,0 +1,592 @@
|
|||
/* packet-erldp.c
|
||||
* Erlang Distribution Protocol
|
||||
* http://www.erlang.org/doc/apps/erts/erl_dist_protocol.html
|
||||
*
|
||||
* 2010 Tomas Kukosa
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <epan/packet.h>
|
||||
#include <epan/strutil.h>
|
||||
#include <epan/emem.h>
|
||||
|
||||
#include <epan/dissectors/packet-tcp.h>
|
||||
#include <epan/dissectors/packet-epmd.h>
|
||||
|
||||
#define ERL_PASS_THROUGH 'p'
|
||||
|
||||
#define VERSION_MAGIC 131 /* 130 in erlang 4.2 */
|
||||
|
||||
#define SMALL_INTEGER_EXT 'a'
|
||||
#define INTEGER_EXT 'b'
|
||||
#define FLOAT_EXT 'c'
|
||||
#define ATOM_EXT 'd'
|
||||
#define SMALL_ATOM_EXT 's'
|
||||
#define REFERENCE_EXT 'e'
|
||||
#define NEW_REFERENCE_EXT 'r'
|
||||
#define PORT_EXT 'f'
|
||||
#define NEW_FLOAT_EXT 'F'
|
||||
#define PID_EXT 'g'
|
||||
#define SMALL_TUPLE_EXT 'h'
|
||||
#define LARGE_TUPLE_EXT 'i'
|
||||
#define NIL_EXT 'j'
|
||||
#define STRING_EXT 'k'
|
||||
#define LIST_EXT 'l'
|
||||
#define BINARY_EXT 'm'
|
||||
#define BIT_BINARY_EXT 'M'
|
||||
#define SMALL_BIG_EXT 'n'
|
||||
#define LARGE_BIG_EXT 'o'
|
||||
#define NEW_FUN_EXT 'p'
|
||||
#define EXPORT_EXT 'q'
|
||||
#define FUN_EXT 'u'
|
||||
|
||||
#define DIST_HEADER 'D'
|
||||
#define ATOM_CACHE_REF 'R'
|
||||
#define COMPRESSED 'P'
|
||||
|
||||
#define PNAME "Erlang Distribution Protocol"
|
||||
#define PSNAME "ErlDP"
|
||||
#define PFNAME "erldp"
|
||||
|
||||
static const value_string etf_tag_vals[] = {
|
||||
{ SMALL_INTEGER_EXT , "SMALL_INTEGER_EXT" },
|
||||
{ INTEGER_EXT , "INTEGER_EXT" },
|
||||
{ FLOAT_EXT , "FLOAT_EXT" },
|
||||
{ ATOM_EXT , "ATOM_EXT" },
|
||||
{ SMALL_ATOM_EXT , "SMALL_ATOM_EXT" },
|
||||
{ REFERENCE_EXT , "REFERENCE_EXT" },
|
||||
{ NEW_REFERENCE_EXT , "NEW_REFERENCE_EXT" },
|
||||
{ PORT_EXT , "PORT_EXT" },
|
||||
{ NEW_FLOAT_EXT , "NEW_FLOAT_EXT" },
|
||||
{ PID_EXT , "PID_EXT" },
|
||||
{ SMALL_TUPLE_EXT , "SMALL_TUPLE_EXT" },
|
||||
{ LARGE_TUPLE_EXT , "LARGE_TUPLE_EXT" },
|
||||
{ NIL_EXT , "NIL_EXT" },
|
||||
{ STRING_EXT , "STRING_EXT" },
|
||||
{ LIST_EXT , "LIST_EXT" },
|
||||
{ BINARY_EXT , "BINARY_EXT" },
|
||||
{ BIT_BINARY_EXT , "BIT_BINARY_EXT" },
|
||||
{ SMALL_BIG_EXT , "SMALL_BIG_EXT" },
|
||||
{ LARGE_BIG_EXT , "LARGE_BIG_EXT" },
|
||||
{ NEW_FUN_EXT , "NEW_FUN_EXT" },
|
||||
{ EXPORT_EXT , "EXPORT_EXT" },
|
||||
{ FUN_EXT , "FUN_EXT" },
|
||||
{ DIST_HEADER , "DIST_HEADER" },
|
||||
{ ATOM_CACHE_REF , "ATOM_CACHE_REF" },
|
||||
{ COMPRESSED , "COMPRESSED" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const value_string erldp_ctlmsg_vals[] = {
|
||||
{ 1, "LINK" },
|
||||
{ 2, "SEND" },
|
||||
{ 3, "EXIT" },
|
||||
{ 4, "UNLINK" },
|
||||
{ 5, "NODE_LINK" },
|
||||
{ 6, "REG_SEND" },
|
||||
{ 7, "GROUP_LEADER" },
|
||||
{ 8, "EXIT2" },
|
||||
{ 12, "SEND_TT" },
|
||||
{ 13, "EXIT_TT" },
|
||||
{ 16, "REG_SEND_TT" },
|
||||
{ 18, "EXIT2_TT" },
|
||||
{ 19, "MONITOR_P" },
|
||||
{ 20, "DEMONITOR_P" },
|
||||
{ 21, "MONITOR_P_EXIT" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/* Initialize the protocol and registered fields */
|
||||
int proto_erldp = -1;
|
||||
static int hf_erldp_length_2 = -1;
|
||||
static int hf_erldp_length_4 = -1;
|
||||
static int hf_erldp_tag = -1;
|
||||
static int hf_erldp_tagd = -1;
|
||||
static int hf_erldp_type = -1;
|
||||
static int hf_erldp_version = -1;
|
||||
static int hf_erldp_flags = -1;
|
||||
static int hf_erldp_challenge = -1;
|
||||
static int hf_erldp_digest = -1;
|
||||
static int hf_erldp_name = -1;
|
||||
static int hf_erldp_status = -1;
|
||||
|
||||
static int hf_etf_tag = -1;
|
||||
|
||||
/* Initialize the subtree pointers */
|
||||
static gint ett_erldp = -1;
|
||||
|
||||
static gint ett_etf = -1;
|
||||
static gint ett_etf_flags = -1;
|
||||
static gint ett_etf_acrs = -1;
|
||||
static gint ett_etf_acr = -1;
|
||||
static gint ett_etf_tmp = -1;
|
||||
|
||||
/* Preferences */
|
||||
static gboolean erldp_desegment = TRUE;
|
||||
|
||||
/* Dissectors */
|
||||
static dissector_handle_t erldp_handle = NULL;
|
||||
|
||||
/* Subdissectors */
|
||||
dissector_handle_t data_handle;
|
||||
|
||||
/*--- External Term Format ---*/
|
||||
|
||||
static gint dissect_etf_type(const gchar *label, packet_info *pinfo, tvbuff_t *tvb, gint offset, proto_tree *tree);
|
||||
|
||||
static gint dissect_etf_dist_header(packet_info *pinfo, tvbuff_t *tvb, gint offset, proto_tree *tree) {
|
||||
guint8 num, flen, i, flg, isi;
|
||||
gint flg_offset, acrs_offset, acr_offset;
|
||||
guint32 atom_txt_len;
|
||||
gboolean new_entry, long_atom;
|
||||
proto_item *ti_acrs, *ti_acr, *ti_tmp;
|
||||
proto_tree *flags_tree, *acrs_tree, *acr_tree;
|
||||
const gchar *str;
|
||||
|
||||
num = tvb_get_guint8(tvb, offset);
|
||||
proto_tree_add_text(tree, tvb, offset, 1, "NumberOfAtomCacheRefs: %d", num);
|
||||
offset++;
|
||||
|
||||
if (num == 0)
|
||||
return offset;
|
||||
|
||||
flg_offset = offset;
|
||||
flen = num / 2 + 1;
|
||||
ti_tmp = proto_tree_add_text(tree, tvb, offset, flen, "Flags: %s", tvb_bytes_to_str(tvb, offset, flen));
|
||||
flags_tree = proto_item_add_subtree(ti_tmp, ett_etf_flags);
|
||||
for (i=0; i<num; i++) {
|
||||
flg = tvb_get_guint8(tvb, offset + i / 2);
|
||||
proto_tree_add_text(flags_tree, tvb, offset + i / 2, 1,
|
||||
decode_boolean_bitfield(flg, 0x08 << 4*(i%2), 8,
|
||||
ep_strdup_printf("NewCacheEntryFlag[%2d]: SET", i),
|
||||
ep_strdup_printf("NewCacheEntryFlag[%2d]: ---", i)));
|
||||
proto_tree_add_text(flags_tree, tvb, offset + i / 2, 1,
|
||||
decode_numeric_bitfield(flg, 0x07 << 4*(i%2), 8, ep_strdup_printf("SegmentIndex [%2d]: %%u", i)));
|
||||
}
|
||||
flg = tvb_get_guint8(tvb, offset + num / 2);
|
||||
proto_tree_add_text(flags_tree, tvb, offset + num / 2, 1,
|
||||
decode_boolean_bitfield(flg, 0x01 << 4*(num%2), 8,
|
||||
"LongAtoms: YES",
|
||||
"LongAtoms: NO"));
|
||||
long_atom = flg & (0x01 << 4*(num%2));
|
||||
offset += flen;
|
||||
|
||||
acrs_offset = offset;
|
||||
ti_acrs = proto_tree_add_text(tree, tvb, offset, 0, "AtomCacheRefs");
|
||||
acrs_tree = proto_item_add_subtree(ti_acrs, ett_etf_acrs);
|
||||
for (i=0; i<num; i++) {
|
||||
flg = tvb_get_guint8(tvb, flg_offset + i / 2);
|
||||
new_entry = flg & (0x08 << 4*(i%2));
|
||||
acr_offset = offset;
|
||||
ti_acr = proto_tree_add_text(acrs_tree, tvb, offset, 0, "AtomCacheRef[%2d]:", i);
|
||||
acr_tree = proto_item_add_subtree(ti_acr, ett_etf_acr);
|
||||
isi = tvb_get_guint8(tvb, offset);
|
||||
proto_tree_add_text(acr_tree, tvb, offset, 1, "InternalSegmentIndex: %d", isi);
|
||||
proto_item_append_text(ti_acr, " %3d", isi);
|
||||
offset++;
|
||||
if (!new_entry)
|
||||
continue;
|
||||
atom_txt_len = (long_atom) ? tvb_get_ntohs(tvb, offset) : tvb_get_guint8(tvb, offset);
|
||||
proto_tree_add_text(acr_tree, tvb, offset, (long_atom) ? 2 : 1, "Length: %d", atom_txt_len);
|
||||
offset += (long_atom) ? 2 : 1;
|
||||
str = tvb_get_ephemeral_string(tvb, offset, atom_txt_len);
|
||||
proto_tree_add_text(acr_tree, tvb, offset, atom_txt_len, "AtomText: %s", str);
|
||||
proto_item_append_text(ti_acr, " - '%s'", str);
|
||||
offset += atom_txt_len;
|
||||
proto_item_set_len(ti_acr, offset - acr_offset);
|
||||
}
|
||||
proto_item_set_len(ti_acrs, offset - acrs_offset);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static gint dissect_etf_tuple_content(gboolean large, packet_info *pinfo, tvbuff_t *tvb, gint offset, proto_tree *tree, gchar **value_str) {
|
||||
guint32 arity, i;
|
||||
|
||||
arity = (large) ? tvb_get_ntohl(tvb, offset) : tvb_get_guint8(tvb, offset);
|
||||
proto_tree_add_text(tree, tvb, offset, (large) ? 4 : 1, "Arity: %u", arity);
|
||||
offset += (large) ? 4 : 1;
|
||||
for (i=0; i<arity; i++) {
|
||||
offset = dissect_etf_type(NULL, pinfo, tvb, offset, tree);
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static gint dissect_etf_type_content(guint8 tag, packet_info *pinfo, tvbuff_t *tvb, gint offset, proto_tree *tree, gchar **value_str) {
|
||||
gint32 len, int_val, i;
|
||||
|
||||
switch (tag) {
|
||||
case DIST_HEADER:
|
||||
offset = dissect_etf_dist_header(pinfo, tvb, offset, tree);
|
||||
break;
|
||||
|
||||
case ATOM_CACHE_REF:
|
||||
int_val = tvb_get_guint8(tvb, offset);
|
||||
proto_tree_add_text(tree, tvb, offset, 1, "AtomCacheReferenceIndex: %d", int_val);
|
||||
offset += 1;
|
||||
if (value_str)
|
||||
*value_str = ep_strdup_printf("%d", int_val);
|
||||
break;
|
||||
|
||||
case SMALL_INTEGER_EXT:
|
||||
int_val = tvb_get_guint8(tvb, offset);
|
||||
proto_tree_add_text(tree, tvb, offset, 1, "Int: %d", int_val);
|
||||
offset += 1;
|
||||
if (value_str)
|
||||
*value_str = ep_strdup_printf("%d", int_val);
|
||||
break;
|
||||
|
||||
case INTEGER_EXT:
|
||||
int_val = tvb_get_ntohl(tvb, offset);
|
||||
proto_tree_add_text(tree, tvb, offset, 4, "Int: %d", int_val);
|
||||
offset += 4;
|
||||
if (value_str)
|
||||
*value_str = ep_strdup_printf("%d", int_val);
|
||||
break;
|
||||
|
||||
case PID_EXT:
|
||||
offset = dissect_etf_type("Node", pinfo, tvb, offset, tree);
|
||||
proto_tree_add_text(tree, tvb, offset, 4, "ID: 0x%08X", tvb_get_ntohl(tvb, offset));
|
||||
offset += 4;
|
||||
proto_tree_add_text(tree, tvb, offset, 4, "Serial: %u", tvb_get_ntohl(tvb, offset));
|
||||
offset += 4;
|
||||
proto_tree_add_text(tree, tvb, offset, 1, "Creation: %u", tvb_get_guint8(tvb, offset));
|
||||
offset++;
|
||||
break;
|
||||
|
||||
case SMALL_TUPLE_EXT:
|
||||
offset = dissect_etf_tuple_content(FALSE, pinfo, tvb, offset, tree, value_str);
|
||||
break;
|
||||
|
||||
case LARGE_TUPLE_EXT:
|
||||
offset = dissect_etf_tuple_content(TRUE, pinfo, tvb, offset, tree, value_str);
|
||||
break;
|
||||
|
||||
case NIL_EXT:
|
||||
break;
|
||||
|
||||
case LIST_EXT:
|
||||
len = tvb_get_ntohl(tvb, offset);
|
||||
proto_tree_add_text(tree, tvb, offset, 4, "Len: %d", len);
|
||||
offset += 4;
|
||||
for (i=0; i<len; i++) {
|
||||
offset = dissect_etf_type(NULL, pinfo, tvb, offset, tree);
|
||||
}
|
||||
offset = dissect_etf_type("Tail", pinfo, tvb, offset, tree);
|
||||
break;
|
||||
|
||||
case NEW_REFERENCE_EXT:
|
||||
len = tvb_get_ntohs(tvb, offset);
|
||||
proto_tree_add_text(tree, tvb, offset, 2, "Len: %d", len);
|
||||
offset += 2;
|
||||
offset = dissect_etf_type("Node", pinfo, tvb, offset, tree);
|
||||
proto_tree_add_text(tree, tvb, offset, 1, "Creation: %u", tvb_get_guint8(tvb, offset));
|
||||
offset++;
|
||||
for (i=0; i<len; i++) {
|
||||
proto_tree_add_text(tree, tvb, offset, 4, "ID[%d]: 0x%08X", i, tvb_get_ntohl(tvb, offset));
|
||||
offset += 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static gint dissect_etf_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const gchar *label) {
|
||||
gint offset = 0;
|
||||
guint8 mag, tag;
|
||||
proto_item *ti;
|
||||
proto_tree *etf_tree;
|
||||
|
||||
mag = tvb_get_guint8(tvb, offset);
|
||||
if (mag != VERSION_MAGIC) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ti = proto_tree_add_text(tree, tvb, offset, -1, (label) ? label : "External Term Format");
|
||||
etf_tree = proto_item_add_subtree(ti, ett_etf);
|
||||
|
||||
proto_tree_add_text(etf_tree, tvb, offset, 1, "VERSION_MAGIC: %d", mag);
|
||||
offset++;
|
||||
|
||||
tag = tvb_get_guint8(tvb, offset);
|
||||
proto_tree_add_item(etf_tree, hf_etf_tag, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset++;
|
||||
|
||||
if (!label)
|
||||
proto_item_set_text(ti, "%s", val_to_str(tag, VALS(etf_tag_vals), "unknown tag (%d)"));
|
||||
|
||||
offset = dissect_etf_type_content(tag, pinfo, tvb, offset, etf_tree, NULL);
|
||||
|
||||
proto_item_set_len(ti, offset);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static gint dissect_etf_type(const gchar *label, packet_info *pinfo, tvbuff_t *tvb, gint offset, proto_tree *tree) {
|
||||
gint begin = offset;
|
||||
guint8 tag;
|
||||
proto_item *ti;
|
||||
proto_tree *etf_tree;
|
||||
gchar *value_str = NULL;
|
||||
|
||||
ti = proto_tree_add_text(tree, tvb, offset, -1, (label) ? label : "External Term Format");
|
||||
etf_tree = proto_item_add_subtree(ti, ett_etf);
|
||||
|
||||
tag = tvb_get_guint8(tvb, offset);
|
||||
proto_tree_add_item(etf_tree, hf_etf_tag, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset++;
|
||||
|
||||
if (!label)
|
||||
proto_item_set_text(ti, "%s", val_to_str(tag, VALS(etf_tag_vals), "unknown tag (%d)"));
|
||||
|
||||
offset = dissect_etf_type_content(tag, pinfo, tvb, offset, etf_tree, &value_str);
|
||||
if (value_str)
|
||||
proto_item_append_text(ti, ": %s", value_str);
|
||||
|
||||
proto_item_set_len(ti, offset - begin);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static gboolean is_handshake(tvbuff_t *tvb, int offset) {
|
||||
guint32 len = tvb_get_ntohs(tvb, offset);
|
||||
guint8 tag = tvb_get_guint8(tvb, offset + 2);
|
||||
return ((len > 0) && strchr("nras", tag) && (len == tvb_length_remaining(tvb, offset + 2)));
|
||||
}
|
||||
|
||||
/*--- dissect_erldp_handshake -------------------------------------------------*/
|
||||
static void dissect_erldp_handshake(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
|
||||
gint offset = 0;
|
||||
guint8 tag;
|
||||
gint i;
|
||||
gboolean is_challenge = FALSE;
|
||||
guint32 str_len;
|
||||
const gchar *str;
|
||||
|
||||
proto_tree_add_item(tree, hf_erldp_length_2, tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
offset += 2;
|
||||
tag = tvb_get_guint8(tvb, offset);
|
||||
proto_tree_add_item(tree, hf_erldp_tag, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset++;
|
||||
|
||||
switch (tag) {
|
||||
case 'n' :
|
||||
proto_tree_add_item(tree, hf_erldp_version, tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
offset += 2;
|
||||
proto_tree_add_item(tree, hf_erldp_flags, tvb, offset, 4, ENC_BIG_ENDIAN);
|
||||
offset += 4;
|
||||
if (tvb_bytes_exist(tvb, offset, 4)) {
|
||||
for (i=0; i<4; i++)
|
||||
if(!g_ascii_isprint(tvb_get_guint8(tvb, offset + i))) {
|
||||
is_challenge = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_challenge) {
|
||||
proto_tree_add_item(tree, hf_erldp_challenge, tvb, offset, 4, ENC_BIG_ENDIAN);
|
||||
offset += 4;
|
||||
}
|
||||
str_len = tvb_length_remaining(tvb, offset);
|
||||
str = tvb_get_ephemeral_string(tvb, offset, str_len);
|
||||
proto_tree_add_item(tree, hf_erldp_name, tvb, offset, str_len, ENC_NA);
|
||||
col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s", (is_challenge) ? "SEND_CHALLENGE" : "SEND_NAME", str);
|
||||
break;
|
||||
|
||||
case 'r' :
|
||||
proto_tree_add_item(tree, hf_erldp_challenge, tvb, offset, 4, ENC_BIG_ENDIAN);
|
||||
offset += 4;
|
||||
proto_tree_add_item(tree, hf_erldp_digest, tvb, offset, 16, ENC_NA);
|
||||
offset += 16;
|
||||
col_add_str(pinfo->cinfo, COL_INFO, "SEND_CHALLENGE_REPLY");
|
||||
break;
|
||||
|
||||
case 'a' :
|
||||
proto_tree_add_item(tree, hf_erldp_digest, tvb, offset, 16, ENC_NA);
|
||||
offset += 16;
|
||||
col_add_str(pinfo->cinfo, COL_INFO, "SEND_CHALLENGE_ACK");
|
||||
break;
|
||||
|
||||
case 's' :
|
||||
str_len = tvb_length_remaining(tvb, offset);
|
||||
str = tvb_get_ephemeral_string(tvb, offset, str_len);
|
||||
proto_tree_add_item(tree, hf_erldp_status, tvb, offset, str_len, ENC_NA);
|
||||
col_add_fstr(pinfo->cinfo, COL_INFO, "SEND_STATUS %s", str);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*--- dissect_erldp_pdu -------------------------------------------------*/
|
||||
static void dissect_erldp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
|
||||
gint offset;
|
||||
guint32 msg_len;
|
||||
guint8 type, ctl_op;
|
||||
proto_tree *erldp_tree;
|
||||
proto_item *ti;
|
||||
tvbuff_t *next_tvb = NULL;
|
||||
|
||||
col_set_str(pinfo->cinfo, COL_PROTOCOL, PSNAME);
|
||||
|
||||
ti = proto_tree_add_item(tree, proto_erldp, tvb, 0, -1, FALSE);
|
||||
erldp_tree = proto_item_add_subtree(ti, ett_erldp);
|
||||
|
||||
if (is_handshake(tvb, 0)) {
|
||||
dissect_erldp_handshake(tvb, pinfo, erldp_tree);
|
||||
return;
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
|
||||
msg_len = tvb_get_ntohl(tvb, offset);
|
||||
proto_tree_add_item(erldp_tree, hf_erldp_length_4, tvb, offset, 4, ENC_BIG_ENDIAN);
|
||||
offset += 4;
|
||||
|
||||
if (msg_len == 0) {
|
||||
col_add_str(pinfo->cinfo, COL_INFO, "KEEP_ALIVE");
|
||||
return;
|
||||
}
|
||||
|
||||
type = tvb_get_guint8(tvb, offset);
|
||||
switch (type) {
|
||||
case ERL_PASS_THROUGH:
|
||||
proto_tree_add_item(erldp_tree, hf_erldp_type, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset++;
|
||||
break;
|
||||
|
||||
case VERSION_MAGIC:
|
||||
next_tvb = tvb_new_subset(tvb, offset, -1, 4 + msg_len - offset);
|
||||
offset += dissect_etf_pdu(next_tvb, pinfo, erldp_tree, "DistributionHeader");
|
||||
if ((tvb_get_guint8(tvb, offset) == SMALL_TUPLE_EXT) && (tvb_get_guint8(tvb, offset + 2) == SMALL_INTEGER_EXT)) {
|
||||
ctl_op = tvb_get_guint8(tvb, offset + 3);
|
||||
col_add_str(pinfo->cinfo, COL_INFO, val_to_str(ctl_op, VALS(erldp_ctlmsg_vals), "unknown ControlMessage operation (%d)"));
|
||||
}
|
||||
offset = dissect_etf_type("ControlMessage", pinfo, tvb, offset, erldp_tree);
|
||||
if (tvb_length_remaining(tvb, offset) > 0)
|
||||
offset = dissect_etf_type("Message", pinfo, tvb, offset, erldp_tree);
|
||||
break;
|
||||
|
||||
default:
|
||||
proto_tree_add_item(erldp_tree, hf_erldp_type, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset++;
|
||||
col_add_str(pinfo->cinfo, COL_INFO, "unknown header format");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*--- get_erldp_pdu_len -------------------------------------------------*/
|
||||
static guint get_erldp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset) {
|
||||
return (is_handshake(tvb, offset)) ? 2 + tvb_get_ntohs(tvb, offset) : 4 + tvb_get_ntohl(tvb, offset);
|
||||
}
|
||||
|
||||
/*--- dissect_erldp -------------------------------------------------*/
|
||||
static void
|
||||
dissect_erldp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
|
||||
tcp_dissect_pdus(tvb, pinfo, tree,
|
||||
erldp_desegment, /* desegment or not */
|
||||
4, /* fixed-length part of the PDU */
|
||||
get_erldp_pdu_len, /* routine to get the length of the PDU */
|
||||
dissect_erldp_pdu); /* routine to dissect a PDU */
|
||||
}
|
||||
|
||||
/*--- proto_register_erldp ----------------------------------------------*/
|
||||
void proto_register_erldp(void) {
|
||||
/* module_t *erldp_module; */
|
||||
|
||||
/* List of fields */
|
||||
static hf_register_info hf[] = {
|
||||
/*--- Handshake fields ---*/
|
||||
{ &hf_erldp_length_2, { "Length", "erldp.len",
|
||||
FT_UINT16, BASE_DEC, NULL, 0x0,
|
||||
"Message Length", HFILL}},
|
||||
{ &hf_erldp_tag, { "Tag", "erldp.tag",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0,
|
||||
"Tag", HFILL}},
|
||||
{ &hf_erldp_tagd, { "Tag", "erldp.tag",
|
||||
FT_UINT8, BASE_DEC, NULL, 0x0,
|
||||
"Tag", HFILL}},
|
||||
{ &hf_erldp_type, { "Type", "erldp.type",
|
||||
FT_UINT8, BASE_DEC, NULL, 0x0,
|
||||
"Type", HFILL}},
|
||||
{ &hf_erldp_version, { "Version", "erldp.version",
|
||||
FT_UINT16, BASE_DEC, VALS(epmd_version_vals), 0x0,
|
||||
"Version", HFILL}},
|
||||
{ &hf_erldp_flags, { "Flags", "erldp.flags",
|
||||
FT_UINT32, BASE_HEX, NULL, 0x0,
|
||||
"Flags", HFILL}},
|
||||
{ &hf_erldp_challenge, { "Challenge", "erldp.challenge",
|
||||
FT_UINT32, BASE_HEX, NULL, 0x0,
|
||||
"Challenge", HFILL}},
|
||||
{ &hf_erldp_digest, { "Digest", "erldp.digest",
|
||||
FT_BYTES, BASE_NONE, NULL, 0x0,
|
||||
"Digest", HFILL}},
|
||||
{ &hf_erldp_name, { "Name", "erldp.name",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0,
|
||||
"Name", HFILL}},
|
||||
{ &hf_erldp_status, { "Status", "erldp.status",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0,
|
||||
"Status", HFILL}},
|
||||
/*--- ---*/
|
||||
{ &hf_erldp_length_4, { "Length", "erldp.len",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0,
|
||||
"Message Length", HFILL}},
|
||||
|
||||
/*--- ETF ---*/
|
||||
{ &hf_etf_tag, { "Tag", "etf.tag",
|
||||
FT_UINT8, BASE_DEC, VALS(etf_tag_vals), 0x0,
|
||||
"Tag", HFILL}},
|
||||
};
|
||||
|
||||
/* List of subtrees */
|
||||
static gint *ett[] = {
|
||||
&ett_erldp,
|
||||
&ett_etf,
|
||||
&ett_etf_flags,
|
||||
&ett_etf_acrs,
|
||||
&ett_etf_acr,
|
||||
&ett_etf_tmp,
|
||||
};
|
||||
|
||||
/* Register protocol and dissector */
|
||||
proto_erldp = proto_register_protocol(PNAME, PSNAME, PFNAME);
|
||||
register_dissector(PFNAME, dissect_erldp, proto_erldp);
|
||||
erldp_handle = find_dissector(PFNAME);
|
||||
|
||||
/* Register fields and subtrees */
|
||||
proto_register_field_array(proto_erldp, hf, array_length(hf));
|
||||
proto_register_subtree_array(ett, array_length(ett));
|
||||
|
||||
}
|
||||
|
||||
/*--- proto_reg_handoff_erldp -------------------------------------------*/
|
||||
void proto_reg_handoff_erldp(void) {
|
||||
|
||||
dissector_add_handle("tcp.port", erldp_handle);
|
||||
|
||||
data_handle = find_dissector("data");
|
||||
}
|
Loading…
Reference in New Issue