diff options
Diffstat (limited to 'epan/dissectors/packet-epmd.c')
-rw-r--r-- | epan/dissectors/packet-epmd.c | 396 |
1 files changed, 244 insertions, 152 deletions
diff --git a/epan/dissectors/packet-epmd.c b/epan/dissectors/packet-epmd.c index 5fe2430208..8f572da80f 100644 --- a/epan/dissectors/packet-epmd.c +++ b/epan/dissectors/packet-epmd.c @@ -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); } |