diff --git a/epan/Makefile.common b/epan/Makefile.common index 150140a00a..339d516345 100644 --- a/epan/Makefile.common +++ b/epan/Makefile.common @@ -49,6 +49,7 @@ LIBETHEREAL_SRC = \ emem.c \ epan.c \ except.c \ + expert.c \ filesystem.c \ follow.c \ frame_data.c \ @@ -115,6 +116,7 @@ LIBETHEREAL_INCLUDES = \ epan_dissect.h \ except.h \ exceptions.h \ + expert.h \ filesystem.h \ follow.h \ frame_data.h \ diff --git a/epan/dissectors/packet-clnp.c b/epan/dissectors/packet-clnp.c index b7c734cf32..e7501d5c6c 100644 --- a/epan/dissectors/packet-clnp.c +++ b/epan/dissectors/packet-clnp.c @@ -41,6 +41,7 @@ #include "packet-esis.h" #include "nlpid.h" #include +#include /* protocols and fields */ @@ -782,7 +783,7 @@ static int ositp_decode_DR(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu, packet_info *pinfo, proto_tree *tree) { proto_tree *cotp_tree; - proto_item *ti; + proto_item *ti = NULL; guint16 dst_ref, src_ref; guchar reason; const char *str; @@ -843,6 +844,9 @@ static int ositp_decode_DR(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu, offset += li + 1; + expert_add_info_format(pinfo, ti, PI_SEQUENCE, PI_CHAT, + "Disconnect Request(DR): 0x%x -> 0x%x", src_ref, dst_ref); + /* User data */ call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo, tree); offset += tvb_length_remaining(tvb, offset); @@ -1176,6 +1180,7 @@ static int ositp_decode_RJ(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu, { proto_tree *cotp_tree; proto_item *ti; + proto_item *item = NULL; guint16 dst_ref; guint tpdu_nr; gushort credit = 0; @@ -1206,7 +1211,7 @@ static int ositp_decode_RJ(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu, ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE); cotp_tree = proto_item_add_subtree(ti, ett_cotp); proto_tree_add_uint(cotp_tree, hf_cotp_li, tvb, offset, 1,li); - proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, tpdu); + item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset + 1, 1, tpdu); if (li == LI_NORMAL_RJ) proto_tree_add_text(cotp_tree, tvb, offset + 1, 1, "Credit: %u", cdt); @@ -1224,6 +1229,9 @@ static int ositp_decode_RJ(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu, offset += li + 1; + expert_add_info_format(pinfo, item, PI_SEQUENCE, PI_NOTE, + "Reject(RJ): -> 0x%x", dst_ref); + return offset; } /* ositp_decode_RJ */ @@ -1238,6 +1246,7 @@ static int ositp_decode_CC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu, proto_tree *cotp_tree = NULL; proto_item *ti; + proto_item *item = NULL; guint16 dst_ref, src_ref; guchar class_option; tvbuff_t *next_tvb; @@ -1266,7 +1275,7 @@ static int ositp_decode_CC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu, offset += 1; if (tree) { - proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu); + item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu); } offset += 1; li -= 1; @@ -1281,6 +1290,14 @@ static int ositp_decode_CC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu, offset += 2; li -= 2; + /* expert info, but only if not encapsulated in TCP/SMB */ + /* XXX - the best way to detect seems to be if we have a port set */ + if (pinfo->destport == 0) { + expert_add_info_format(pinfo, item, PI_SEQUENCE, PI_CHAT, + tpdu == CR_TPDU ? "Connection Request(CR): 0x%x -> 0x%x" : "Connection Confirm(CC): 0x%x -> 0x%x", + src_ref, dst_ref); + } + if (tree) { proto_tree_add_text(cotp_tree, tvb, offset, 1, "Class option: 0x%02x", class_option); @@ -1315,6 +1332,7 @@ static int ositp_decode_DC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu, { proto_tree *cotp_tree = NULL; proto_item *ti; + proto_item *item = NULL; guint16 dst_ref, src_ref; if (li > LI_MAX_DC) @@ -1339,7 +1357,7 @@ static int ositp_decode_DC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu, offset += 1; if (tree) { - proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu); + item = proto_tree_add_uint(cotp_tree, hf_cotp_type, tvb, offset, 1, tpdu); } offset += 1; li -= 1; @@ -1358,6 +1376,9 @@ static int ositp_decode_DC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu, ositp_decode_var_part(tvb, offset, li, 4, cotp_tree); offset += li; + expert_add_info_format(pinfo, item, PI_SEQUENCE, PI_CHAT, + "Disconnect Confirm(DC): 0x%x -> 0x%x", src_ref, dst_ref); + return offset; } /* ositp_decode_DC */ @@ -1684,6 +1705,7 @@ static gboolean dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo, if (!first_tpdu) { if (check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, ", "); + expert_add_info_format(pinfo, NULL, PI_SEQUENCE, PI_NOTE, "Multiple TDPUs in one packet"); } if ((li = tvb_get_guint8(tvb, offset + P_LI)) == 0) { if (check_col(pinfo->cinfo, COL_INFO)) diff --git a/epan/dissectors/packet-dcerpc.c b/epan/dissectors/packet-dcerpc.c index 9fad9ef11d..57fbbee4bf 100644 --- a/epan/dissectors/packet-dcerpc.c +++ b/epan/dissectors/packet-dcerpc.c @@ -45,6 +45,7 @@ #include #include #include +#include static int dcerpc_tap = -1; @@ -284,6 +285,29 @@ static const value_string reject_status_vals[] = { { 0x1c010013, "nca_out_args_too_big" }, { 0x1c010014, "nca_server_too_busy" }, { 0x1c010017, "nca_unsupported_type" }, + /* MS Windows specific values + * see: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes__1700-3999_.asp + * and: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/common_hresult_values.asp + * and: http://www.megos.ch/support/doserrors.txt + * + * XXX - we might need a way to dynamically add entries here, as higher layer protocols use these values too, + * at least MS protocols (like DCOM) do it that way ... */ + { 0x80004001, "E_NOTIMPL" }, + { 0x80004003, "E_POINTER" }, + { 0x80004004, "E_ABORT" }, + { 0x80010105, "RPC_E_SERVERFAULT" }, + { 0x80010108, "RPC_E_DISCONNECTED" }, + { 0x80010113, "RPC_E_INVALID_IPID" }, + { 0x80020006, "DISP_E_UNKNOWNNAME" }, + { 0x8004CB00, "CBA_E_MALFORMED" }, + { 0x8004CB01, "CBA_E_UNKNOWNOBJECT" }, + { 0x8004CB09, "CBA_E_INVALIDCOOKIE" }, + { 0x8004CB0B, "CBA_E_QOSTYPEUNSUPPORTED" }, + { 0x8004CB0C, "CBA_E_QOSVALUEUNSUPPORTED" }, + { 0x8004CB0F, "CBA_E_NOTAPPLICABLE" }, + { 0x8004CB12, "CBA_E_LIMITVIOLATION" }, + { 0x80070057, "E_INVALIDARG" }, + { 0x800706d1, "RPC_S_PROCNUM_OUT_OF_RANGE" }, { 0, NULL } }; @@ -3040,6 +3064,8 @@ dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo, col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC %s fragment]", fragment_type(hdr->flags)); } + expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT, + "%s fragment", fragment_type(hdr->flags)); pinfo->fragmented = save_fragmented; return; } @@ -3166,6 +3192,9 @@ end_cn_stub: pinfo->fragmented = FALSE; + expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT, + "%s fragment, reassembled here in #%u", fragment_type(hdr->flags), fd_head->reassembled_in); + dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb, next_tvb, hdr->drep, di, auth_info); @@ -3181,6 +3210,8 @@ end_cn_stub: col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in); } + expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT, + "%s fragment, reassembled in #%u", fragment_type(hdr->flags), fd_head->reassembled_in); } } else { /* Reassembly not complete - some fragments @@ -3189,6 +3220,8 @@ end_cn_stub: col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC %s fragment]", fragment_type(hdr->flags)); } + expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT, + "%s fragment", fragment_type(hdr->flags)); if(decrypted_tvb){ show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE); @@ -3560,7 +3593,7 @@ dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo, guint32 status; guint32 alloc_hint; dcerpc_auth_info auth_info; - proto_item *pi; + proto_item *pi = NULL; offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, hf_dcerpc_cn_alloc_hint, &alloc_hint); @@ -3573,8 +3606,19 @@ dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo, /* padding */ offset++; - offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, - hf_dcerpc_cn_status, &status); + /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_status, &status);*/ + status = ((hdr->drep[0] & 0x10) + ? tvb_get_letohl (tvb, offset) + : tvb_get_ntohl (tvb, offset)); + + if (dcerpc_tree) { + pi = proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_status, tvb, offset, 4, (hdr->drep[0] & 0x10)); + } + offset+=4; + + expert_add_info_format(pinfo, pi, PI_APPL_RESPONSE, PI_NOTE, "Fault: %s", + val_to_str(status, reject_status_vals, "Unknown (0x%08x)")); /* save context ID for use with dcerpc_add_conv_to_bind_table() */ pinfo->dcectxid = ctx_id; @@ -3910,6 +3954,11 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo, pckt_vals[hdr.ptype].strptr, hdr.call_id); } + if(pinfo->dcectxid != 0) { + /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */ + expert_add_info_format(pinfo, NULL, PI_SEQUENCE, PI_NOTE, "Multiple DCE/RPC fragments/PDU's in one packet"); + } + if (tree) { offset = start_offset; tvb_ensure_bytes_exist(tvb, offset, hdr.frag_len); @@ -3919,7 +3968,20 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo, } proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver); proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor); - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype); + tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype); + } else { + tf = NULL; + } + + /* XXX - too much "output noise", removed for now + if(hdr.ptype == PDU_BIND || hdr.ptype == PDU_ALTER || + hdr.ptype == PDU_BIND_ACK || hdr.ptype == PDU_ALTER_ACK) + expert_add_info_format(pinfo, tf, PI_SEQUENCE, PI_CHAT, "Context change: %s", + val_to_str(hdr.ptype, pckt_vals, "(0x%x)"));*/ + if(hdr.ptype == PDU_BIND_NAK) + expert_add_info_format(pinfo, tf, PI_SEQUENCE, PI_WARN, "Bind not acknowledged"); + + if (tree) { proto_item_append_text(ti, " %s, Fragment:", val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)")); tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags); diff --git a/epan/dissectors/packet-dcom.c b/epan/dissectors/packet-dcom.c index b64d1150c4..0a13d041c6 100644 --- a/epan/dissectors/packet-dcom.c +++ b/epan/dissectors/packet-dcom.c @@ -87,6 +87,7 @@ #include "packet-dcerpc.h" #include "packet-dcom.h" #include "prefs.h" +#include "expert.h" static int proto_dcom = -1; @@ -339,10 +340,12 @@ const value_string dcom_hresult_vals[] = { { 0x80070057, "E_INVALIDARG" }, { 0x80010108, "RPC_E_DISCONNECTED" }, + { 0x80010113, "RPC_E_INVALID_IPID" }, { 0x80020004, "DISP_E_PARAMNOTFOUND" }, { 0x80040154, "REGDB_E_CLASSNOTREG" }, + { 0x80040201, "CO_E_FAILEDTOGETSECCTX" }, /* following are CBA application specific values */ { 0x0004CA00, "CBA_S_PERSISTPENDING" }, @@ -391,6 +394,9 @@ const value_string dcom_hresult_vals[] = { { 0x8004CB23, "CBA_E_FRAMECOUNTUNSUPPORTED" }, { 0x8004CB24, "CBA_E_LINKFAILURE" }, { 0x8004CB25, "CBA_E_MODECHANGE" }, + + { 0x80080004, "CO_E_BAD_PATH" }, + { 0, NULL } }; @@ -730,11 +736,14 @@ extern int dissect_dcom_tobedone_data(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, guint8 *drep _U_, int length) { + proto_item *item; proto_tree_add_uint(tree, hf_dcom_tobedone_len, tvb, offset, length, length); - proto_tree_add_bytes(tree, hf_dcom_tobedone, tvb, offset, length, + item = proto_tree_add_bytes(tree, hf_dcom_tobedone, tvb, offset, length, tvb_get_ptr(tvb, offset, length)); + expert_add_info_format(pinfo, item, PI_UNDECODED, PI_WARN, "%u bytes still undecoded", length); + offset += length; return offset; @@ -807,8 +816,26 @@ dissect_dcom_HRESULT(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, guint32 * pu32HResult) { - offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, drep, - hf_dcom_hresult, pu32HResult); + guint32 u32HResult; + proto_item *item = NULL; + + /* dissect the DWORD, but don't add to tree */ + offset = dissect_dcom_DWORD(tvb, offset, pinfo, NULL /*tree*/, drep, + hf_dcom_hresult, &u32HResult); + + if (tree) { + /* special formatted output of indexed value */ + item = proto_tree_add_item (tree, hf_dcom_hresult, tvb, offset-4, 4, (drep[0] & 0x10)); + } + + /* expert info only if severity is set */ + /* XXX - move this to the callers of this function, to provide a more detailed error output */ + if(u32HResult & 0x80000000) { + expert_add_info_format(pinfo, item, PI_APPL_RESPONSE, PI_NOTE, "Hresult: %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%x)")); + } + if (pu32HResult) + *pu32HResult = u32HResult; return offset; } @@ -821,6 +848,7 @@ dissect_dcom_indexed_HRESULT(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 * pu32HResult, int field_index) { guint32 u32HResult; + proto_item *item = NULL; /* dissect the DWORD, but don't add to tree */ @@ -829,11 +857,17 @@ dissect_dcom_indexed_HRESULT(tvbuff_t *tvb, int offset, packet_info *pinfo, if (tree) { /* special formatted output of indexed value */ - proto_tree_add_uint_format(tree, hf_dcom_hresult, tvb, offset-4, 4, (drep[0] & 0x10), + item = proto_tree_add_uint_format(tree, hf_dcom_hresult, tvb, offset-4, 4, (drep[0] & 0x10), "HResult[%u]: %s (0x%08x)", field_index, val_to_str(u32HResult, dcom_hresult_vals, "Unknown"), u32HResult); } + /* expert info only if severity flag is set */ + /* XXX - move this to the callers of this function, to provide a more detailed error output */ + if(u32HResult & 0x80000000) { + expert_add_info_format(pinfo, item, PI_APPL_RESPONSE, PI_NOTE, "Hresult: %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%x)")); + } if (pu32HResult) *pu32HResult = u32HResult; diff --git a/epan/dissectors/packet-frame.c b/epan/dissectors/packet-frame.c index 9b581d8913..b7d35cad25 100644 --- a/epan/dissectors/packet-frame.c +++ b/epan/dissectors/packet-frame.c @@ -34,6 +34,7 @@ #include "packet-frame.h" #include #include +#include int proto_frame = -1; int hf_frame_arrival_time = -1; @@ -264,14 +265,18 @@ show_exception(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, { static const char dissector_error_nomsg[] = "Dissector writer didn't bother saying what the error was"; + proto_item *item; + switch (exception) { case BoundsError: if (check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, "[Short Frame]"); - proto_tree_add_protocol_format(tree, proto_short, tvb, 0, 0, + item = proto_tree_add_protocol_format(tree, proto_short, tvb, 0, 0, "[Short Frame: %s]", pinfo->current_proto); + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, + "Short Frame"); break; case ReportedBoundsError: @@ -285,7 +290,7 @@ show_exception(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, pinfo->current_proto, exception_message == NULL ? dissector_error_nomsg : exception_message); - proto_tree_add_protocol_format(tree, proto_malformed, tvb, 0, 0, + item = proto_tree_add_protocol_format(tree, proto_malformed, tvb, 0, 0, "[Dissector bug, protocol %s: %s]", pinfo->current_proto, exception_message == NULL ? @@ -294,6 +299,9 @@ show_exception(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, pinfo->current_proto, pinfo->fd->num, exception_message == NULL ? dissector_error_nomsg : exception_message); + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, + exception_message == NULL ? + dissector_error_nomsg : exception_message); if (exception_message != NULL) g_free(exception_message); break; @@ -307,6 +315,8 @@ show_exception(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void show_reported_bounds_error(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { + proto_item *item; + if (pinfo->fragmented) { /* * We were dissecting an unreassembled fragmented @@ -320,15 +330,17 @@ show_reported_bounds_error(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) col_append_fstr(pinfo->cinfo, COL_INFO, "[Unreassembled Packet%s]", pinfo->noreassembly_reason); - proto_tree_add_protocol_format(tree, proto_unreassembled, + item = proto_tree_add_protocol_format(tree, proto_unreassembled, tvb, 0, 0, "[Unreassembled Packet%s: %s]", pinfo->noreassembly_reason, pinfo->current_proto); + expert_add_info_format(pinfo, item, PI_REASSEMBLE, PI_WARN, "Unreassembled Packet (Exception occured)"); } else { if (check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, "[Malformed Packet]"); - proto_tree_add_protocol_format(tree, proto_malformed, + item = proto_tree_add_protocol_format(tree, proto_malformed, tvb, 0, 0, "[Malformed Packet: %s]", pinfo->current_proto); + expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, "Malformed Packet (Exception occured)"); } } diff --git a/epan/dissectors/packet-http.c b/epan/dissectors/packet-http.c index 6fb851fa93..741ee5ffa7 100644 --- a/epan/dissectors/packet-http.c +++ b/epan/dissectors/packet-http.c @@ -47,6 +47,7 @@ #include #include "packet-http.h" #include +#include typedef enum _http_type { HTTP_REQUEST, @@ -755,6 +756,8 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo, tvb_format_text(tvb, offset, next_offset - offset)); } + expert_add_info_format(pinfo, hdr_item, PI_SEQUENCE, PI_CHAT, + tvb_format_text(tvb, offset, next_offset - offset)); if (reqresp_dissector) { if (tree) req_tree = proto_item_add_subtree(hdr_item, ett_http_request); else req_tree = NULL; diff --git a/epan/dissectors/packet-tcp.c b/epan/dissectors/packet-tcp.c index 71f7351d26..6c59cb67d8 100644 --- a/epan/dissectors/packet-tcp.c +++ b/epan/dissectors/packet-tcp.c @@ -46,6 +46,7 @@ #include #include #include +#include static int tcp_tap = -1; @@ -1306,13 +1307,14 @@ tcp_print_sequence_number_analysis(packet_info *pinfo, tvbuff_t *tvb, proto_tree if( ta->flags&TCP_A_RETRANSMISSION ){ flags_item=proto_tree_add_none_format(flags_tree, hf_tcp_analysis_retransmission, tvb, 0, 0, "This frame is a (suspected) retransmission"); PROTO_ITEM_SET_GENERATED(flags_item); + expert_add_info_format(pinfo, flags_item, PI_SEQUENCE, PI_NOTE, "Retransmission (suspected)"); if(check_col(pinfo->cinfo, COL_INFO)){ col_prepend_fstr(pinfo->cinfo, COL_INFO, "[TCP Retransmission] "); } if( ta->rto_ts.secs || ta->rto_ts.nsecs ){ item = proto_tree_add_time(flags_tree, hf_tcp_analysis_rto, tvb, 0, 0, &ta->rto_ts); - PROTO_ITEM_SET_GENERATED(item); + PROTO_ITEM_SET_GENERATED(item); item=proto_tree_add_uint(flags_tree, hf_tcp_analysis_rto_frame, tvb, 0, 0, ta->rto_frame); PROTO_ITEM_SET_GENERATED(item); } @@ -1320,6 +1322,7 @@ tcp_print_sequence_number_analysis(packet_info *pinfo, tvbuff_t *tvb, proto_tree if( ta->flags&TCP_A_FAST_RETRANSMISSION ){ flags_item=proto_tree_add_none_format(flags_tree, hf_tcp_analysis_fast_retransmission, tvb, 0, 0, "This frame is a (suspected) fast retransmission"); PROTO_ITEM_SET_GENERATED(flags_item); + expert_add_info_format(pinfo, flags_item, PI_SEQUENCE, PI_WARN, "Fast retransmission (suspected)"); flags_item=proto_tree_add_none_format(flags_tree, hf_tcp_analysis_retransmission, tvb, 0, 0, "This frame is a (suspected) retransmission"); PROTO_ITEM_SET_GENERATED(flags_item); if(check_col(pinfo->cinfo, COL_INFO)){ @@ -1329,6 +1332,7 @@ tcp_print_sequence_number_analysis(packet_info *pinfo, tvbuff_t *tvb, proto_tree if( ta->flags&TCP_A_OUT_OF_ORDER ){ flags_item=proto_tree_add_none_format(flags_tree, hf_tcp_analysis_out_of_order, tvb, 0, 0, "This frame is a (suspected) out-of-order segment"); PROTO_ITEM_SET_GENERATED(flags_item); + expert_add_info_format(pinfo, flags_item, PI_SEQUENCE, PI_WARN, "Out-Of-Order segment"); if(check_col(pinfo->cinfo, COL_INFO)){ col_prepend_fstr(pinfo->cinfo, COL_INFO, "[TCP Out-Of-Order] "); } @@ -1336,6 +1340,7 @@ tcp_print_sequence_number_analysis(packet_info *pinfo, tvbuff_t *tvb, proto_tree if( ta->flags&TCP_A_LOST_PACKET ){ flags_item=proto_tree_add_none_format(flags_tree, hf_tcp_analysis_lost_packet, tvb, 0, 0, "A segment before this frame was lost"); PROTO_ITEM_SET_GENERATED(flags_item); + expert_add_info_format(pinfo, flags_item, PI_SEQUENCE, PI_WARN, "Previous segment lost (common at capture start)"); if(check_col(pinfo->cinfo, COL_INFO)){ col_prepend_fstr(pinfo->cinfo, COL_INFO, "[TCP Previous segment lost] "); } @@ -1343,6 +1348,7 @@ tcp_print_sequence_number_analysis(packet_info *pinfo, tvbuff_t *tvb, proto_tree if( ta->flags&TCP_A_ACK_LOST_PACKET ){ flags_item=proto_tree_add_none_format(flags_tree, hf_tcp_analysis_ack_lost_packet, tvb, 0, 0, "This frame ACKs a segment we have not seen (lost?)"); PROTO_ITEM_SET_GENERATED(flags_item); + expert_add_info_format(pinfo, flags_item, PI_SEQUENCE, PI_WARN, "ACKed lost segment (common at capture start)"); if(check_col(pinfo->cinfo, COL_INFO)){ col_prepend_fstr(pinfo->cinfo, COL_INFO, "[TCP ACKed lost segment] "); } @@ -1350,6 +1356,7 @@ tcp_print_sequence_number_analysis(packet_info *pinfo, tvbuff_t *tvb, proto_tree if( ta->flags&TCP_A_WINDOW_UPDATE ){ flags_item=proto_tree_add_none_format(flags_tree, hf_tcp_analysis_window_update, tvb, 0, 0, "This is a tcp window update"); PROTO_ITEM_SET_GENERATED(flags_item); + expert_add_info_format(pinfo, flags_item, PI_SEQUENCE, PI_NOTE, "Window update"); if(check_col(pinfo->cinfo, COL_INFO)){ col_prepend_fstr(pinfo->cinfo, COL_INFO, "[TCP Window Update] "); } @@ -1357,6 +1364,7 @@ tcp_print_sequence_number_analysis(packet_info *pinfo, tvbuff_t *tvb, proto_tree if( ta->flags&TCP_A_WINDOW_FULL ){ flags_item=proto_tree_add_none_format(flags_tree, hf_tcp_analysis_window_full, tvb, 0, 0, "The transmission window is now completely full"); PROTO_ITEM_SET_GENERATED(flags_item); + expert_add_info_format(pinfo, flags_item, PI_SEQUENCE, PI_NOTE, "Window is full"); if(check_col(pinfo->cinfo, COL_INFO)){ col_prepend_fstr(pinfo->cinfo, COL_INFO, "[TCP Window Full] "); } @@ -1364,6 +1372,7 @@ tcp_print_sequence_number_analysis(packet_info *pinfo, tvbuff_t *tvb, proto_tree if( ta->flags&TCP_A_KEEP_ALIVE ){ flags_item=proto_tree_add_none_format(flags_tree, hf_tcp_analysis_keep_alive, tvb, 0, 0, "This is a TCP keep-alive segment"); PROTO_ITEM_SET_GENERATED(flags_item); + expert_add_info_format(pinfo, flags_item, PI_SEQUENCE, PI_NOTE, "Keep-Alive"); if(check_col(pinfo->cinfo, COL_INFO)){ col_prepend_fstr(pinfo->cinfo, COL_INFO, "[TCP Keep-Alive] "); } @@ -1371,6 +1380,7 @@ tcp_print_sequence_number_analysis(packet_info *pinfo, tvbuff_t *tvb, proto_tree if( ta->flags&TCP_A_KEEP_ALIVE_ACK ){ flags_item=proto_tree_add_none_format(flags_tree, hf_tcp_analysis_keep_alive_ack, tvb, 0, 0, "This is an ACK to a TCP keep-alive segment"); PROTO_ITEM_SET_GENERATED(flags_item); + expert_add_info_format(pinfo, flags_item, PI_SEQUENCE, PI_NOTE, "Keep-Alive ACK"); if(check_col(pinfo->cinfo, COL_INFO)){ col_prepend_fstr(pinfo->cinfo, COL_INFO, "[TCP Keep-Alive ACK] "); } @@ -1389,10 +1399,13 @@ tcp_print_sequence_number_analysis(packet_info *pinfo, tvbuff_t *tvb, proto_tree flags_item=proto_tree_add_uint(tree, hf_tcp_analysis_duplicate_ack_frame, tvb, 0, 0, ta->dupack_frame); PROTO_ITEM_SET_GENERATED(flags_item); + expert_add_info_format(pinfo, flags_item, PI_SEQUENCE, PI_NOTE, "Duplicate ACK (#%u) to ACK in packet #%u", + ta->dupack_num, ta->dupack_frame); } if( ta->flags&TCP_A_ZERO_WINDOW_PROBE ){ flags_item=proto_tree_add_none_format(flags_tree, hf_tcp_analysis_zero_window_probe, tvb, 0, 0, "This is a TCP zero-window-probe"); PROTO_ITEM_SET_GENERATED(flags_item); + expert_add_info_format(pinfo, flags_item, PI_SEQUENCE, PI_NOTE, "Zero window probe"); if(check_col(pinfo->cinfo, COL_INFO)){ col_prepend_fstr(pinfo->cinfo, COL_INFO, "[TCP ZeroWindowProbe] "); } @@ -1400,7 +1413,7 @@ tcp_print_sequence_number_analysis(packet_info *pinfo, tvbuff_t *tvb, proto_tree if( ta->flags&TCP_A_ZERO_WINDOW ){ flags_item=proto_tree_add_none_format(flags_tree, hf_tcp_analysis_zero_window, tvb, 0, 0, "This is a ZeroWindow segment"); PROTO_ITEM_SET_GENERATED(flags_item); - PROTO_ITEM_SET_SEQUENCE_WARNING(flags_item); + expert_add_info_format(pinfo, flags_item, PI_SEQUENCE, PI_NOTE, "Zero window"); if(check_col(pinfo->cinfo, COL_INFO)){ col_prepend_fstr(pinfo->cinfo, COL_INFO, "[TCP ZeroWindow] "); } @@ -1408,6 +1421,7 @@ tcp_print_sequence_number_analysis(packet_info *pinfo, tvbuff_t *tvb, proto_tree if( ta->flags&TCP_A_ZERO_WINDOW_VIOLATION ){ flags_item=proto_tree_add_none_format(flags_tree, hf_tcp_analysis_zero_window_violation, tvb, 0, 0, "This is a ZeroWindow violation, attempts to write >1 byte of data to a zero-window"); PROTO_ITEM_SET_GENERATED(flags_item); + expert_add_info_format(pinfo, flags_item, PI_SEQUENCE, PI_NOTE, "Zero window violation"); if(check_col(pinfo->cinfo, COL_INFO)){ col_prepend_fstr(pinfo->cinfo, COL_INFO, "[TCP ZeroWindowViolation] "); } @@ -2679,6 +2693,7 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) struct tcpinfo tcpinfo; static struct tcpheader tcphstruct[4], *tcph; static int tcph_count=0; + proto_item *tf_syn = NULL, *tf_fin = NULL, *tf_rst = NULL; tcph_count++; if(tcph_count>=4){ @@ -2866,9 +2881,9 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) proto_tree_add_boolean(field_tree, hf_tcp_flags_urg, tvb, offset + 13, 1, tcph->th_flags); proto_tree_add_boolean(field_tree, hf_tcp_flags_ack, tvb, offset + 13, 1, tcph->th_flags); proto_tree_add_boolean(field_tree, hf_tcp_flags_push, tvb, offset + 13, 1, tcph->th_flags); - proto_tree_add_boolean(field_tree, hf_tcp_flags_reset, tvb, offset + 13, 1, tcph->th_flags); - proto_tree_add_boolean(field_tree, hf_tcp_flags_syn, tvb, offset + 13, 1, tcph->th_flags); - proto_tree_add_boolean(field_tree, hf_tcp_flags_fin, tvb, offset + 13, 1, tcph->th_flags); + tf_rst = proto_tree_add_boolean(field_tree, hf_tcp_flags_reset, tvb, offset + 13, 1, tcph->th_flags); + tf_syn = proto_tree_add_boolean(field_tree, hf_tcp_flags_syn, tvb, offset + 13, 1, tcph->th_flags); + tf_fin = proto_tree_add_boolean(field_tree, hf_tcp_flags_fin, tvb, offset + 13, 1, tcph->th_flags); if(tcp_relative_seq && (tcph->th_win!=real_window)){ proto_tree_add_uint_format(tcp_tree, hf_tcp_window_size, tvb, offset + 14, 2, tcph->th_win, "Window size: %u (scaled)", tcph->th_win); } else { @@ -2876,6 +2891,20 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) } } + if(tcph->th_flags & TH_SYN) + if(tcph->th_flags & TH_ACK) + expert_add_info_format(pinfo, tf_syn, PI_SEQUENCE, PI_CHAT, "Connection establish acknowledge (SYN+ACK): %s -> %s", + get_tcp_port(tcph->th_sport), get_tcp_port(tcph->th_dport)); + else + expert_add_info_format(pinfo, tf_syn, PI_SEQUENCE, PI_CHAT, "Connection establish request (SYN): %s -> %s", + get_tcp_port(tcph->th_sport), get_tcp_port(tcph->th_dport)); + if(tcph->th_flags & TH_FIN) + expert_add_info_format(pinfo, tf_fin, PI_SEQUENCE, PI_CHAT, "Connection finish (FIN): %s -> %s", + get_tcp_port(tcph->th_sport), get_tcp_port(tcph->th_dport)); + if(tcph->th_flags & TH_RST) + expert_add_info_format(pinfo, tf_rst, PI_SEQUENCE, PI_CHAT, "Connection reset (RST): %s -> %s", + get_tcp_port(tcph->th_sport), get_tcp_port(tcph->th_dport)); + /* Supply the sequence number of the first byte and of the first byte after the segment. */ tcpinfo.seq = tcph->th_seq; @@ -2937,13 +2966,15 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) } else { proto_item *item; - proto_tree_add_uint_format(tcp_tree, hf_tcp_checksum, tvb, + item = proto_tree_add_uint_format(tcp_tree, hf_tcp_checksum, tvb, offset + 16, 2, th_sum, "Checksum: 0x%04x [incorrect, should be 0x%04x]", th_sum, in_cksum_shouldbe(th_sum, computed_cksum)); + expert_add_info_format(pinfo, item, PI_CHECKSUM, PI_ERROR, "Bad checksum"); item = proto_tree_add_boolean(tcp_tree, hf_tcp_checksum_bad, tvb, offset + 16, 2, TRUE); PROTO_ITEM_SET_GENERATED(item); + /* XXX - don't use hidden fields for checksums */ PROTO_ITEM_SET_HIDDEN(item); if (check_col(pinfo->cinfo, COL_INFO)) @@ -2955,7 +2986,7 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) } } else { proto_tree_add_uint_format(tcp_tree, hf_tcp_checksum, tvb, - offset + 16, 2, th_sum, "Checksum: 0x%04x", th_sum); + offset + 16, 2, th_sum, "Checksum: 0x%04x [validation disabled]", th_sum); /* We didn't check the checksum, and don't care if it's valid, so we're willing to desegment it. */ @@ -2964,7 +2995,7 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) } else { /* We don't have all the packet data, so we can't checksum it... */ proto_tree_add_uint_format(tcp_tree, hf_tcp_checksum, tvb, - offset + 16, 2, th_sum, "Checksum: 0x%04x", th_sum); + offset + 16, 2, th_sum, "Checksum: 0x%04x [unchecked, not all data available]", th_sum); /* ...and aren't willing to desegment it. */ desegment_ok = FALSE; @@ -3201,7 +3232,7 @@ proto_register_tcp(void) { &hf_tcp_analysis_window_full, { "Window full", "tcp.analysis.window_full", FT_NONE, BASE_NONE, NULL, 0x0, - "The this segment has caused the allowed window to become 100% full", HFILL }}, + "This segment has caused the allowed window to become 100% full", HFILL }}, { &hf_tcp_analysis_keep_alive, { "Keep Alive", "tcp.analysis.keep_alive", FT_NONE, BASE_NONE, NULL, 0x0, @@ -3397,8 +3428,8 @@ proto_register_tcp(void) "Whether the TCP summary line should be shown in the protocol tree", &tcp_summary_in_tree); prefs_register_bool_preference(tcp_module, "check_checksum", - "Check the validity of the TCP checksum when possible", - "Whether to check the validity of the TCP checksum", + "Validate the TCP checksum if possible", + "Whether to validate the TCP checksum", &tcp_check_checksum); prefs_register_bool_preference(tcp_module, "desegment_tcp_streams", "Allow subdissector to reassemble TCP streams", diff --git a/epan/epan.c b/epan/epan.c index 1a289e396e..895d3faa0d 100644 --- a/epan/epan.c +++ b/epan/epan.c @@ -22,6 +22,7 @@ #include "tap.h" #include "addr_resolv.h" #include "emem.h" +#include "expert.h" static void (*report_failure_func)(const char *, va_list); static void (*report_open_failure_func)(const char *, int, gboolean); @@ -66,11 +67,13 @@ epan_init(const char *plugin_dir, void (*register_all_protocols)(void), dfilter_init(); final_registration_all_protocols(); host_name_lookup_init(); + expert_init(); } void epan_cleanup(void) { + expert_cleanup(); dfilter_cleanup(); proto_cleanup(); packet_cleanup(); diff --git a/epan/expert.c b/epan/expert.c new file mode 100644 index 0000000000..dfa585f7e2 --- /dev/null +++ b/epan/expert.c @@ -0,0 +1,117 @@ +/* expert.c + * Collecting Expert information. + * + * Implemented as a tap named "expert". + * + * $Id$ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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 "packet.h" +#include "expert.h" +#include "emem.h" +#include "tap.h" + + + +static int expert_tap = -1; + + +void +expert_init(void) +{ + if(expert_tap == -1) { + expert_tap = register_tap("expert"); + } +} + +void +expert_cleanup(void) +{ + /* memory cleanup will be done by se_... */ +} + + +/* set's the PI_ flags to a protocol item + * (and it's parent items till the toplevel) */ +static void +expert_set_item_flags(proto_item *pi, int group, int severity) +{ + + if(proto_item_set_expert_flags(pi, group, severity)) { + /* propagate till toplevel item */ + pi = proto_item_get_parent(pi); + expert_set_item_flags(pi, group, severity); + } +} + + +static void +expert_set_info_vformat( +packet_info *pinfo, proto_item *pi, int group, int severity, const char *format, va_list ap) +{ + int ret; /*tmp return value */ + char formatted[300]; + expert_info_t *ei; + + + /* if this packet isn't loaded because of a read filter, don't output anything */ + if(pinfo->fd->num == -1) { + return; + } + + /* XXX - use currently nonexistant se_vsnprintf instead */ + ret = g_vsnprintf(formatted, sizeof(formatted), format, ap); + if ((ret == -1) || (ret >= sizeof(formatted))) + formatted[sizeof(formatted) - 1] = '\0'; + + ei = se_alloc(sizeof(expert_info_t)); + ei->packet_num = pinfo ? pinfo->fd->num : -1; + ei->group = group; + ei->severity = severity; + ei->protocol = se_strdup(pinfo->current_proto); + ei->summary = se_strdup(formatted); + + /* if we have a proto_item (not a faked item), set expert attributes to it */ + if(pi != NULL && pi->finfo != NULL) { + expert_set_item_flags(pi, group, severity); + } + + tap_queue_packet(expert_tap, pinfo, ei); +} + + +void +expert_add_info_format( +packet_info *pinfo, proto_item *pi, int group, int severity, const char *format, ...) +{ + va_list ap; + + + va_start(ap, format); + expert_set_info_vformat(pinfo, pi, group, severity, format, ap); + va_end(ap); +} + + diff --git a/epan/expert.h b/epan/expert.h new file mode 100644 index 0000000000..5860121fba --- /dev/null +++ b/epan/expert.h @@ -0,0 +1,60 @@ +/* expert.h + * Collecting of Expert information. + * + * For further info, see: http://wiki.ethereal.com/Development/ExpertInfo + * + * $Id$ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifndef __EXPERT_H__ +#define __EXPERT_H__ + + +/** only for internal and display use */ +typedef struct expert_info_s { + int packet_num; + int group; + int severity; + gchar * protocol; + gchar * summary; +} expert_info_t; + + +extern void +expert_init(void); + +extern void +expert_cleanup(void); + +/** Add an expert info. + * XXX - add gcc format string check. + + @param pinfo packet info of the currently processed packet + @param pi current protocol item (or NULL) + @param group the expert group (like PI_CHECKSUM) + @param severity the expert severity (like PI_WARN) + @param format printf like format string with further infos + */ +extern void +expert_add_info_format( +packet_info *pinfo, proto_item *pi, int group, int severity, const char *format, ...); + +#endif /* __EXPERT_H__ */ diff --git a/epan/libethereal.def b/epan/libethereal.def index 91f676e935..019122a86f 100644 --- a/epan/libethereal.def +++ b/epan/libethereal.def @@ -191,7 +191,9 @@ ep_alloc se_alloc ep_alloc0 ep_strdup +se_strdup ep_strdup_printf +se_strdup_printf ep_strndup ep_strsplit ep_memdup @@ -217,6 +219,7 @@ except_throw except_throwd except_throwf except_unhandled_catcher +expert_set_info_format FacilityReason_vals DATA fc_fc4_val DATA file_open_error_message @@ -404,6 +407,7 @@ proto_item_get_parent proto_item_get_parent_nth proto_item_get_subtree proto_item_set_end +proto_item_set_expert_flags proto_item_set_len proto_item_set_text proto_register_field_array diff --git a/epan/proto.c b/epan/proto.c index 5deb8f1b18..a7996f4276 100644 --- a/epan/proto.c +++ b/epan/proto.c @@ -2465,6 +2465,32 @@ proto_item_get_len(proto_item *pi) return fi->length; } + +/** clear flags according to the mask and set new flag values */ +#define FI_REPLACE_FLAGS(fi, mask, flags_in) { \ + (fi->flags = (fi)->flags & ~(mask)); \ + (fi->flags = (fi)->flags | (flags_in)); \ +} + +gboolean +proto_item_set_expert_flags(proto_item *pi, int group, int severity) +{ + if(pi == NULL || pi->finfo == NULL) + return FALSE; + + /* only change things if severity is worse or at least equal than before */ + if(severity >= FI_GET_FLAG(pi->finfo, PI_SEVERITY_MASK)) { + FI_REPLACE_FLAGS(pi->finfo, PI_GROUP_MASK, group); + FI_REPLACE_FLAGS(pi->finfo, PI_SEVERITY_MASK, severity); + + return TRUE; + } + + return FALSE; +} + + + proto_tree* proto_tree_create_root(void) { diff --git a/epan/proto.h b/epan/proto.h index 950687810f..50618acf98 100644 --- a/epan/proto.h +++ b/epan/proto.h @@ -218,20 +218,13 @@ typedef struct field_info { /** The protocol field should be displayed as "generated by Ethereal", * used in field_info.flags. */ #define FI_GENERATED 0x0002 -/** The protocol field has a bad checksum */ -#define FI_CHECKSUM_ERROR 0x0004 -/** The protocol field has an unusual sequence (e.g. TCP window is zero) */ -#define FI_SEQUENCE_WARNING 0x0008 -/** The protocol field has a bad sequence (e.g. TCP segment is lost) */ -#define FI_SEQUENCE_ERROR 0x0010 + /** convenience macro to get field_info.flags */ #define FI_GET_FLAG(fi, flag) (fi->flags & flag) /** convenience macro to set field_info.flags */ #define FI_SET_FLAG(fi, flag) (fi->flags = fi->flags | flag) - - /** One of these exists for the entire protocol tree. Each proto_node * in the protocol tree points to the same copy. */ typedef struct { @@ -254,6 +247,38 @@ typedef proto_node proto_tree; /** A protocol item element. */ typedef proto_node proto_item; +/* expert severities */ +#define PI_SEVERITY_MASK 0x001C /* mask usually for internal use only! */ +/** Usual workflow, e.g. TCP connection establishing */ +#define PI_CHAT 0x0004 +/** Notable messages, e.g. an application returned an "usual" error code like HTTP 404 */ +#define PI_NOTE 0x0008 +/** Warning, e.g. application returned an "unusual" error code */ +#define PI_WARN 0x000C +/** Serious problems, e.g. [Malformed Packet] */ +#define PI_ERROR 0x0010 + +/* expert "event groups" */ +#define PI_GROUP_MASK 0xFF00 /* mask usually for internal use only! */ +/** The protocol field has a bad checksum, usually PI_WARN */ +#define PI_CHECKSUM 0x0100 +/** The protocol field indicates a sequence problem (e.g. TCP window is zero) */ +#define PI_SEQUENCE 0x0200 +/** The protocol field indicates a bad application response code (e.g. HTTP 404), usually PI_NOTE */ +#define PI_RESPONSE_CODE 0x0400 +/** The data is undecoded, the protocol dissection is incomplete here, usually PI_WARN */ +#define PI_UNDECODED 0x0800 +/** The protocol field indicates a reassemble (e.g. DCE/RPC defragmentation), usually PI_CHAT (or PI_ERROR) */ +#define PI_REASSEMBLE 0x1000 +/** The packet data is malformed, the dissector has "given up", usually PI_ERROR */ +#define PI_MALFORMED 0x2000 +/** A generic debugging message (shouldn't remain in production code!), usually PI_ERROR */ +#define PI_DEBUG 0x4000 +/** The protocol field indicates a security probem (e.g. unsecure implementation) */ +/*#define PI_SECURITY 0x8000*/ + +/* add more, see http://wiki.ethereal.com/Development/ExpertInfo */ + /** is this protocol field hidden from the protocol tree display (used for filtering only)? */ /* HIDING PROTOCOL FIELDS IS DEPRECATED, IT'S CONSIDERED TO BE BAD GUI DESIGN! */ @@ -269,16 +294,6 @@ typedef proto_node proto_item; /** mark this protocol field as generated by Ethereal (and not read from the packet data) */ #define PROTO_ITEM_SET_GENERATED(proto_item) \ ((proto_item) ? FI_SET_FLAG((proto_item)->finfo, FI_GENERATED) : 0) -/** mark this protocol field having a bad checksum */ -#define PROTO_ITEM_SET_CHECKSUM_ERROR(proto_item) \ - ((proto_item) ? FI_SET_FLAG((proto_item)->finfo, FI_CHECKSUM_ERROR) : 0) -/** mark this protocol field having a sequence warning */ -#define PROTO_ITEM_SET_SEQUENCE_WARNING(proto_item) \ - ((proto_item) ? FI_SET_FLAG((proto_item)->finfo, FI_SEQUENCE_WARNING) : 0) -/** mark this protocol field having a sequence error */ -#define PROTO_ITEM_SET_SEQUENCE_ERROR(proto_item) \ - ((proto_item) ? FI_SET_FLAG((proto_item)->finfo, FI_SEQUENCE_ERROR) : 0) - typedef void (*proto_tree_foreach_func)(proto_node *, gpointer); @@ -376,6 +391,16 @@ extern void proto_item_set_end(proto_item *ti, tvbuff_t *tvb, gint end); @return the current length */ extern int proto_item_get_len(proto_item *ti); +/** + * Sets an expert info to the proto_item. + @param ti the item to set the expert info + @param group the group of this info (e.g. FI_CHECKSUM) + @param severity of this info (e.g. FI_ERROR) + @return TRUE if value was written + */ +extern gboolean proto_item_set_expert_flags(proto_item *ti, int group, int severity); + + /** Creates a new proto_tree root. diff --git a/gtk/Makefile.common b/gtk/Makefile.common index da06f639d8..a6d934e1dd 100644 --- a/gtk/Makefile.common +++ b/gtk/Makefile.common @@ -122,6 +122,7 @@ ETHEREAL_TAP_SRC = \ conversations_wlan.c \ conversations_rsvp.c \ dcerpc_stat.c \ + expert_dlg.c \ fc_stat.c \ flow_graph.c \ gsm_a_stat.c \ diff --git a/gtk/expert_dlg.c b/gtk/expert_dlg.c new file mode 100644 index 0000000000..957f3cd787 --- /dev/null +++ b/gtk/expert_dlg.c @@ -0,0 +1,511 @@ +/* expert_dlg.c + * Display of Expert information. + * + * Implemented as a tap listener to the "expert" tap. + * + * $Id$ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include "compat_macros.h" +#include "epan/packet_info.h" +#include "image/clist_ascend.xpm" +#include "image/clist_descend.xpm" +#include "simple_dialog.h" +#include "globals.h" +#include "gtk/find_dlg.h" +#include "color.h" +#include "gtk/color_dlg.h" +#include "main.h" +#include "gui_utils.h" +#include "gtkglobals.h" +#include "dlg_utils.h" +#include "../stat_menu.h" +#include "gui_stat_menu.h" +#include <../tap_dfilter_dlg.h> +#include + +#include +#include "colors.h" +#include "proto_draw.h" +#include + + + +static const value_string expert_severity_vals[] = { + { PI_CHAT, "Chat" }, + { PI_NOTE, "Note" }, + { PI_WARN, "Warn" }, + { PI_ERROR, "Error" }, + { 0, NULL } +}; + +static const value_string expert_group_vals[] = { + { PI_CHECKSUM, "Checksum" }, + { PI_SEQUENCE, "Sequence" }, + { PI_APPL_RESPONSE, "Response" }, + { PI_UNDECODED, "Undecoded" }, + { PI_MALFORMED, "Malformed" }, + { PI_REASSEMBLE, "Reassemble" }, + { PI_SECURITY, "Security" }, + { 0, NULL } +}; + +typedef struct expert_tapdata_s { + GtkWidget *win; + GtkWidget *scrolled_window; + GtkCList *table; + GtkWidget *label; + GList *displayed_events; + GList *new_events; + guint32 chat_events; + guint32 note_events; + guint32 warn_events; + guint32 error_events; +} expert_tapdata_t; + + +/* the current warning severity */ +/* XXX - make this a preference setting / a setting in the dialog */ +int severity_report_level = PI_CHAT; +//int severity_report_level = PI_NOTE; + + +void expert_dlg_reset(void *tapdata) +{ + expert_tapdata_t * etd = tapdata; + gchar *title; + + g_list_free(etd->displayed_events); + etd->displayed_events = NULL; + g_list_free(etd->new_events); + etd->new_events = NULL; + etd->chat_events = 0; + etd->note_events = 0; + etd->warn_events = 0; + etd->error_events = 0; + gtk_clist_clear(etd->table); + gtk_clist_columns_autosize(etd->table); + + title = g_strdup_printf("Errors: %u Warnings: %u Notes: %u Chats: %u", + etd->error_events, etd->warn_events, etd->note_events, etd->chat_events); + gtk_label_set_text(GTK_LABEL(etd->label), "Please wait ..."); + g_free(title); + + title = g_strdup_printf("Ethereal: %u Expert Infos", + g_list_length(etd->displayed_events)); + gtk_window_set_title(GTK_WINDOW(etd->win), title); + g_free(title); +} + +int expert_dlg_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, const void *pointer) +{ + expert_info_t *ei = (expert_info_t *) pointer; + expert_tapdata_t * etd = tapdata; + + + switch(ei->severity) { + case(PI_CHAT): + etd->chat_events++; + break; + case(PI_NOTE): + etd->note_events++; + break; + case(PI_WARN): + etd->warn_events++; + break; + case(PI_ERROR): + etd->error_events++; + break; + default: + g_assert_not_reached(); + } + + if(ei->severity < severity_report_level) { + return 0; /* draw not required */ + } + + etd->new_events = g_list_append(etd->new_events, ei); + + return 1; /* draw required */ +} + +void +expert_dlg_draw(expert_tapdata_t *etd) +{ + int row; + char *strp; + expert_info_t *ei; + gchar *title; + char *entries[5] = { "", "", "", "", "" }; /**< column entries */ + + + /*g_warning("draw start: displayed:%u new:%u", + g_list_length(etd->displayed_events), g_list_length(etd->new_events));*/ + + title = g_strdup_printf("Errors: %u Warnings: %u Notes: %u Chats: %u", + etd->error_events, etd->warn_events, etd->note_events, etd->chat_events); + gtk_label_set_text(GTK_LABEL(etd->label), title); + g_free(title); + + gtk_clist_freeze(etd->table); + + /* append new events (remove from new list, append to displayed list and clist) */ + while(etd->new_events != NULL){ + ei = etd->new_events->data; + + etd->new_events = g_list_remove(etd->new_events, ei); + etd->displayed_events = g_list_append(etd->displayed_events, ei); + + row=gtk_clist_append(etd->table, entries); + gtk_clist_set_row_data(etd->table, row, ei); + + /* packet number */ + strp=se_strdup_printf("%d", ei->packet_num); + gtk_clist_set_text(etd->table, row, 0, strp); + + /* severity */ + strp=se_strdup(val_to_str(ei->severity, expert_severity_vals, "Unknown severity (%u)")); + gtk_clist_set_text(etd->table, row, 1, strp); + + /* group */ + strp=se_strdup(val_to_str(ei->group, expert_group_vals, "Unknown group (%u)")); + gtk_clist_set_text(etd->table, row, 2, strp); + + /* protocol */ + if(ei->protocol) { + gtk_clist_set_text(etd->table, row, 3, ei->protocol); + } else { + gtk_clist_set_text(etd->table, row, 3, "-"); + } + + /* summary */ + gtk_clist_set_text(etd->table, row, 4, ei->summary); + + /*gtk_clist_set_pixmap(etd->table, row, 5, ascend_pm, ascend_bm);*/ + + /* set rows background color depending on severity */ + switch(ei->severity) { + case(PI_CHAT): + gtk_clist_set_background(etd->table, row, &expert_color_chat); + break; + case(PI_NOTE): + gtk_clist_set_background(etd->table, row, &expert_color_note); + break; + case(PI_WARN): + gtk_clist_set_background(etd->table, row, &expert_color_warn); + break; + case(PI_ERROR): + gtk_clist_set_background(etd->table, row, &expert_color_error); + break; + default: + g_assert_not_reached(); + } + + } + + gtk_clist_sort(etd->table); + gtk_clist_columns_autosize(etd->table); + gtk_clist_thaw(etd->table); + + title = g_strdup_printf("Ethereal: %u Expert Infos", + g_list_length(etd->displayed_events)); + gtk_window_set_title(GTK_WINDOW(etd->win), title); + g_free(title); + + /*g_warning("draw end: displayed:%u", g_list_length(etd->displayed_events));*/ +} + + +typedef struct column_arrows { + GtkWidget *table; + GtkWidget *ascend_pm; + GtkWidget *descend_pm; +} column_arrows; + + +static gint +srt_sort_column(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2) +{ + char *text1 = NULL; + char *text2 = NULL; + int i1, i2; + + const GtkCListRow *row1 = ptr1; + const GtkCListRow *row2 = ptr2; + + text1 = GTK_CELL_TEXT (row1->cell[clist->sort_column])->text; + text2 = GTK_CELL_TEXT (row2->cell[clist->sort_column])->text; + + switch(clist->sort_column){ + case 0: + i1=atoi(text1); + i2=atoi(text2); + return i1-i2; + case 1: + case 2: + case 3: + case 4: + return strcmp (text1, text2); + } + g_assert_not_reached(); + return 0; +} + + +static void +srt_click_column_cb(GtkCList *clist, gint column, gpointer data) +{ + column_arrows *col_arrows = (column_arrows *) data; + int i; + + gtk_clist_freeze(clist); + + for (i = 0; i < 5; i++) { + gtk_widget_hide(col_arrows[i].ascend_pm); + gtk_widget_hide(col_arrows[i].descend_pm); + } + + if (column == clist->sort_column) { + if (clist->sort_type == GTK_SORT_ASCENDING) { + clist->sort_type = GTK_SORT_DESCENDING; + gtk_widget_show(col_arrows[column].descend_pm); + } else { + clist->sort_type = GTK_SORT_ASCENDING; + gtk_widget_show(col_arrows[column].ascend_pm); + } + } else { + clist->sort_type = GTK_SORT_ASCENDING; + gtk_widget_show(col_arrows[column].ascend_pm); + gtk_clist_set_sort_column(clist, column); + } + gtk_clist_sort(clist); + + gtk_clist_thaw(clist); +} + + +static void +select_row_cb(GtkCList *clist, gint row, gint column, GdkEventButton *event, gpointer user_data) +{ + expert_info_t *ei; + + + ei = (expert_info_t *) gtk_clist_get_row_data(clist, row); + + cf_goto_frame(&cfile, ei->packet_num); +} + + +void +expert_dlg_init_table(expert_tapdata_t * etd, GtkWidget *vbox) +{ + int i; + column_arrows *col_arrows; + GtkStyle *win_style; + GtkWidget *column_lb; + GdkBitmap *ascend_bm, *descend_bm; + GdkPixmap *ascend_pm, *descend_pm; + const char *default_titles[] = { "No.", "Sever.", "Group", "Protocol", "Summary" }; + + + etd->scrolled_window=scrolled_window_new(NULL, NULL); + gtk_box_pack_start(GTK_BOX(vbox), etd->scrolled_window, TRUE, TRUE, 0); + + etd->table=(GtkCList *)gtk_clist_new(5); + SIGNAL_CONNECT(etd->table, "select-row", select_row_cb, etd); + + gtk_widget_show(GTK_WIDGET(etd->table)); + gtk_widget_show(etd->scrolled_window); + + col_arrows = (column_arrows *) g_malloc(sizeof(column_arrows) * 5); + win_style = gtk_widget_get_style(etd->scrolled_window); + ascend_pm = gdk_pixmap_create_from_xpm_d(etd->scrolled_window->window, + &ascend_bm, + &win_style->bg[GTK_STATE_NORMAL], + (gchar **)clist_ascend_xpm); + descend_pm = gdk_pixmap_create_from_xpm_d(etd->scrolled_window->window, + &descend_bm, + &win_style->bg[GTK_STATE_NORMAL], + (gchar **)clist_descend_xpm); + for (i = 0; i < 5; i++) { + col_arrows[i].table = gtk_table_new(2, 2, FALSE); + gtk_table_set_col_spacings(GTK_TABLE(col_arrows[i].table), 5); + column_lb = gtk_label_new(default_titles[i]); + gtk_table_attach(GTK_TABLE(col_arrows[i].table), column_lb, 0, 1, 0, 2, GTK_SHRINK, GTK_SHRINK, 0, 0); + gtk_widget_show(column_lb); + + col_arrows[i].ascend_pm = gtk_pixmap_new(ascend_pm, ascend_bm); + gtk_table_attach(GTK_TABLE(col_arrows[i].table), col_arrows[i].ascend_pm, 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0, 0); + col_arrows[i].descend_pm = gtk_pixmap_new(descend_pm, descend_bm); + gtk_table_attach(GTK_TABLE(col_arrows[i].table), col_arrows[i].descend_pm, 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0); + if (i == 0) { + gtk_widget_show(col_arrows[i].ascend_pm); + } + gtk_clist_set_column_widget(GTK_CLIST(etd->table), i, col_arrows[i].table); + gtk_widget_show(col_arrows[i].table); + } + gtk_clist_column_titles_show(GTK_CLIST(etd->table)); + + gtk_clist_set_compare_func(etd->table, srt_sort_column); + gtk_clist_set_sort_column(etd->table, 0); + gtk_clist_set_sort_type(etd->table, GTK_SORT_ASCENDING); + + gtk_clist_set_column_justification(etd->table, 0, GTK_JUSTIFY_RIGHT); + gtk_clist_set_column_justification(etd->table, 3, GTK_JUSTIFY_RIGHT); + gtk_clist_set_shadow_type(etd->table, GTK_SHADOW_IN); + gtk_clist_column_titles_show(etd->table); + gtk_clist_columns_autosize(etd->table); +// gtk_clist_set_selection_mode(etd->table, GTK_SELECTION_SINGLE); +// gtk_list_set_selection_mode(GTK_LIST(etd->table), GTK_SELECTION_BROWSE); +// gtk_list_select_item(GTK_LIST(value_list), 0); + gtk_container_add(GTK_CONTAINER(etd->scrolled_window), (GtkWidget *)etd->table); + + SIGNAL_CONNECT(etd->table, "click-column", srt_click_column_cb, col_arrows); + + gtk_widget_show(GTK_WIDGET(etd->table)); + gtk_widget_show(etd->scrolled_window); + + /* create popup menu for this table */ + /*if(etd->filter_string){ + srt_create_popup_menu(etd); + }*/ +} + +void protect_thread_critical_region(void); +void unprotect_thread_critical_region(void); +static void +expert_dlg_destroy_cb(GtkWindow *win _U_, gpointer data) +{ + expert_tapdata_t *etd=(expert_tapdata_t *)data; + + protect_thread_critical_region(); + remove_tap_listener(etd); + unprotect_thread_critical_region(); + + //free_srt_table_data(&etd->afp_srt_table); + g_free(etd); +} + + + +static void +expert_dlg_init(const char *optarg) +{ + expert_tapdata_t * etd; + const char *filter=NULL; + GString *error_string; + GtkWidget *vbox; + GtkWidget *bbox; + GtkWidget *close_bt; + + if(!strncmp(optarg,"afp,srt,",8)){ + filter=optarg+8; + } else { + filter=NULL; + } + + proto_draw_colors_init(); + + etd=g_malloc(sizeof(expert_tapdata_t)); + etd->displayed_events = NULL; + etd->new_events = NULL; + etd->chat_events = 0; + etd->note_events = 0; + etd->warn_events = 0; + etd->error_events = 0; + + etd->win=window_new(GTK_WINDOW_TOPLEVEL, "Ethereal: Expert Info"); + gtk_window_set_default_size(GTK_WINDOW(etd->win), 650, 600); + + vbox=gtk_vbox_new(FALSE, 3); + gtk_container_add(GTK_CONTAINER(etd->win), vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 12); + + etd->label=gtk_label_new("Please wait ..."); + gtk_box_pack_start(GTK_BOX(vbox), etd->label, FALSE, FALSE, 0); + + /* We must display TOP LEVEL Widget before calling init_srt_table() */ + gtk_widget_show_all(etd->win); + + expert_dlg_init_table(etd, vbox); + /*for(i=0;i<256;i++){ + init_srt_table_row(&etd->afp_srt_table, i, val_to_str(i, CommandCode_vals, "Unknown(%u)")); + }*/ + + error_string=register_tap_listener("expert", etd, NULL /* fstring */, + expert_dlg_reset, + expert_dlg_packet, + expert_dlg_draw); + if(error_string){ + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, error_string->str); + g_string_free(error_string, TRUE); + g_free(etd); + return; + } + + /* Button row. */ + bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL); + gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); + + close_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CLOSE); + window_set_cancel_button(etd->win, close_bt, window_cancel_button_cb); + + SIGNAL_CONNECT(etd->win, "delete_event", window_delete_event_cb, NULL); + SIGNAL_CONNECT(etd->win, "destroy", expert_dlg_destroy_cb, etd); + + gtk_widget_show_all(etd->win); + window_present(etd->win); + + cf_retap_packets(&cfile); +} + + +static void +expert_dlg_cb(GtkWidget *w _U_, gpointer d _U_) +{ + expert_dlg_init(""); +} + + + + +void +register_tap_listener_expert(void) +{ + register_stat_cmd_arg("expert", expert_dlg_init); + + register_stat_menu_item("_Expert Info", REGISTER_STAT_GROUP_GENERIC, + expert_dlg_cb, NULL, NULL, NULL); +} diff --git a/gtk/proto_draw.c b/gtk/proto_draw.c index b2fd2340b3..f1ece58795 100644 --- a/gtk/proto_draw.c +++ b/gtk/proto_draw.c @@ -1602,6 +1602,27 @@ set_ptree_font_all(FONT_TYPE *font) } +gboolean colors_ok = FALSE; +GdkColor expert_color_chat = { 0, 0xcc00, 0xcc00, 0xe000 }; /* a pale bluegrey */ +GdkColor expert_color_note = { 0, 0xa000, 0xff00, 0xff00 }; /* a bright turquoise */ +GdkColor expert_color_warn = { 0, 0xff00, 0xff00, 0 }; /* yellow */ +GdkColor expert_color_error = { 0, 0xff00, 0x5c00, 0x5c00 }; /* pale red */ + +void proto_draw_colors_init(void) +{ + if(colors_ok) { + return; + } + + get_color(&expert_color_chat); + get_color(&expert_color_note); + get_color(&expert_color_warn); + get_color(&expert_color_error); + + colors_ok = TRUE; +} + + #if GTK_MAJOR_VERSION >= 2 static void tree_cell_renderer(GtkTreeViewColumn *tree_column _U_, GtkCellRenderer *cell, @@ -1613,11 +1634,16 @@ static void tree_cell_renderer(GtkTreeViewColumn *tree_column _U_, gtk_tree_model_get(tree_model, iter, 1, &fi, -1); + if(!colors_ok) { + proto_draw_colors_init(); + } + /* for the various possible attributes, see: * http://developer.gnome.org/doc/API/2.0/gtk/GtkCellRendererText.html * * color definitions can be found at: * http://cvs.gnome.org/viewcvs/gtk+/gdk-pixbuf/io-xpm.c?rev=1.42 + * (a good color overview: http://www.computerhope.com/htmcolor.htm) * * some experiences: * background-gdk: doesn't seem to work (probably the GdkColor must be allocated) @@ -1639,22 +1665,9 @@ static void tree_cell_renderer(GtkTreeViewColumn *tree_column _U_, /*g_object_set (cell, "weight", PANGO_WEIGHT_NORMAL, NULL); g_object_set (cell, "weight-set", FALSE, NULL);*/ - if(FI_GET_FLAG(fi, FI_CHECKSUM_ERROR)) { - g_object_set (cell, "background", "red", NULL); - g_object_set (cell, "background-set", TRUE, NULL); - } - - if(FI_GET_FLAG(fi, FI_SEQUENCE_WARNING)) { - g_object_set (cell, "background", "yellow", NULL); - g_object_set (cell, "background-set", TRUE, NULL); - } - - if(FI_GET_FLAG(fi, FI_SEQUENCE_ERROR)) { - g_object_set (cell, "background", "red", NULL); - g_object_set (cell, "background-set", TRUE, NULL); - } - if(FI_GET_FLAG(fi, FI_GENERATED)) { + /* we use "[...]" to mark generated items, no need to change things here */ + /* as some fonts don't support italic, don't use this */ /*g_object_set (cell, "style", PANGO_STYLE_ITALIC, NULL); g_object_set (cell, "style-set", TRUE, NULL); @@ -1677,6 +1690,29 @@ static void tree_cell_renderer(GtkTreeViewColumn *tree_column _U_, g_object_set (cell, "underline", PANGO_UNDERLINE_SINGLE, NULL); g_object_set (cell, "underline-set", TRUE, NULL); } + + if(FI_GET_FLAG(fi, PI_SEVERITY_MASK)) { + switch(FI_GET_FLAG(fi, PI_SEVERITY_MASK)) { + case(PI_CHAT): + g_object_set (cell, "background-gdk", &expert_color_chat, NULL); + g_object_set (cell, "background-set", TRUE, NULL); + break; + case(PI_NOTE): + g_object_set (cell, "background-gdk", &expert_color_note, NULL); + g_object_set (cell, "background-set", TRUE, NULL); + break; + case(PI_WARN): + g_object_set (cell, "background-gdk", &expert_color_warn, NULL); + g_object_set (cell, "background-set", TRUE, NULL); + break; + case(PI_ERROR): + g_object_set (cell, "background-gdk", &expert_color_error, NULL); + g_object_set (cell, "background-set", TRUE, NULL); + break; + default: + g_assert_not_reached(); + } + } } #endif diff --git a/gtk/proto_draw.h b/gtk/proto_draw.h index 740161df58..54b5868985 100644 --- a/gtk/proto_draw.h +++ b/gtk/proto_draw.h @@ -206,4 +206,14 @@ extern gboolean tree_view_select(GtkWidget *widget, GdkEventButton *event); */ extern void set_ptree_sel_browse_all(gboolean val); + +/** init the expert colors */ +extern void proto_draw_colors_init(void); + +/** the expert colors */ +extern GdkColor expert_color_chat; +extern GdkColor expert_color_note; +extern GdkColor expert_color_warn; +extern GdkColor expert_color_error; + #endif