diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-whois.c | |
parent | Initial commit. (diff) | |
download | wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip |
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/dissectors/packet-whois.c')
-rw-r--r-- | epan/dissectors/packet-whois.c | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/epan/dissectors/packet-whois.c b/epan/dissectors/packet-whois.c new file mode 100644 index 00000000..527f20d9 --- /dev/null +++ b/epan/dissectors/packet-whois.c @@ -0,0 +1,265 @@ +/* packet-whois.c + * Routines for whois dissection (see https://tools.ietf.org/html/rfc3912) + * Copyright 2013, Christopher Maynard <Christopher.Maynard@gtech.com> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" +#include <epan/packet.h> +#include <epan/conversation.h> +#include <epan/expert.h> + +#include "packet-tcp.h" + +#define WHOIS_PORT 43 /* This is the registered IANA port (nicname) */ + +void proto_register_whois(void); +void proto_reg_handoff_whois(void); + +static dissector_handle_t whois_handle; + +static int proto_whois = -1; +static int hf_whois_query = -1; +static int hf_whois_answer = -1; +static int hf_whois_answer_in = -1; +static int hf_whois_answer_to = -1; +static int hf_whois_response_time = -1; + +static expert_field ei_whois_nocrlf = EI_INIT; +static expert_field ei_whois_encoding = EI_INIT; + +static gint ett_whois = -1; + +typedef struct _whois_transaction_t { + guint32 req_frame; + guint32 rep_frame; + nstime_t req_time; + guint8* query; +} whois_transaction_t; + +static int +dissect_whois(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + void *data) +{ + proto_item *ti, *expert_ti; + proto_tree *whois_tree; + conversation_t *conversation; + whois_transaction_t *whois_trans; + gboolean is_query; + guint len; + struct tcpinfo *tcpinfo = (struct tcpinfo*)data; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "WHOIS"); + + if (pinfo->destport == WHOIS_PORT) { + is_query = TRUE; + col_set_str(pinfo->cinfo, COL_INFO, "Query"); + } else { + is_query = FALSE; + col_set_str(pinfo->cinfo, COL_INFO, "Answer"); + } + + conversation = find_or_create_conversation(pinfo); + whois_trans = (whois_transaction_t *)conversation_get_proto_data(conversation, proto_whois); + if (whois_trans == NULL) { + gint linelen; + whois_trans = wmem_new0(wmem_file_scope(), whois_transaction_t); + + /* + * Find the end of the first line. + */ + linelen = tvb_find_line_end(tvb, 0, -1, NULL, FALSE); + if (linelen != -1) + whois_trans->query = tvb_get_string_enc(wmem_file_scope(), tvb, 0, linelen, ENC_ASCII|ENC_NA); + conversation_add_proto_data(conversation, proto_whois, whois_trans); + } + + if (whois_trans->query) { + col_append_str(pinfo->cinfo, COL_INFO, ": "); + col_append_str(pinfo->cinfo, COL_INFO, whois_trans->query); + } + + len = tvb_reported_length(tvb); + if (!PINFO_FD_VISITED(pinfo)) { + if (pinfo->can_desegment) { + if (is_query) { + if ((len < 2) || (tvb_memeql(tvb, len - 2, (const guint8*)"\r\n", 2))) { + pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT; + pinfo->desegment_offset = 0; + return -1; + } else { + whois_trans->req_frame = pinfo->num; + whois_trans->req_time = pinfo->abs_ts; + } + } else if (!(tcpinfo && (IS_TH_FIN(tcpinfo->flags) || tcpinfo->is_reassembled))) { + /* If this is the FIN (or already desegmented, as with an out + * of order segment received after FIN) go ahead and dissect + * on the first pass. + */ + pinfo->desegment_len = DESEGMENT_UNTIL_FIN; + pinfo->desegment_offset = 0; + return -1; + } + } + } else if (is_query && (whois_trans->req_frame == 0)) { + whois_trans->req_frame = pinfo->num; + whois_trans->req_time = pinfo->abs_ts; + } + + if (!is_query && (whois_trans->rep_frame == 0)) { + /* By comparing whois_trans->rep_frame to 0, if reassembly is turned + * on, whois_trans->rep_frame will be assigned to the reassembled frame + * number, and if reassembly is turned off, whois_trans->rep_frame will + * be assigned to the first frame number of the response. This seems + * to match other protocols' behavior. The alternative is: + * if (pinfo->num > whois_trans->rep_frame) + * which will give us the same frame number either way. + */ + whois_trans->rep_frame = pinfo->num; + } + + ti = proto_tree_add_protocol_format(tree, proto_whois, tvb, 0, -1, + "WHOIS: %s", is_query ? "Query" : "Answer"); + whois_tree = proto_item_add_subtree(ti, ett_whois); + + /* + * XXX - WHOIS, as RFC 3912 says, "has no mechanism for indicating + * the character set in use." We assume UTF-8, which is backwards + * compatible with ASCII; if somebody wants to support WHOIS requests + * or responses in other encodings, they should add a preference. + * (Show Packet Bytes works well enough for many use cases.) + * Some servers do use other character encodings; + * e.g., in 2022 RIPE still uses ISO-8859-1. + */ + if (is_query) { + expert_ti = proto_tree_add_item(whois_tree, hf_whois_query, tvb, 0, -1, ENC_ASCII); + if ((len < 2) || (tvb_memeql(tvb, len - 2, (const guint8*)"\r\n", 2))) { + /* + * From RFC3912, section 2: + * All requests are terminated with ASCII CR and then ASCII LF. + */ + expert_add_info(pinfo, expert_ti, &ei_whois_nocrlf); + } + if (tree && whois_trans->rep_frame) { + ti = proto_tree_add_uint(whois_tree, hf_whois_answer_in, + tvb, 0, 0, whois_trans->rep_frame); + proto_item_set_generated(ti); + } + } else if (tree && whois_trans->rep_frame) { + /* + * If we know the request frame, show it and the time delta between + * the request and the response. + */ + if (whois_trans->req_frame) { + nstime_t ns; + + ti = proto_tree_add_uint(whois_tree, hf_whois_answer_to, + tvb, 0, 0, whois_trans->req_frame); + proto_item_set_generated(ti); + + if (pinfo->num == whois_trans->rep_frame) { + nstime_delta(&ns, &pinfo->abs_ts, &whois_trans->req_time); + ti = proto_tree_add_time(whois_tree, hf_whois_response_time, tvb, 0, 0, &ns); + proto_item_set_generated(ti); + } + } + + /* + * Show the response as text, a line at a time. + */ + int offset = 0, next_offset; + while (tvb_offset_exists(tvb, offset)) { + /* + * Find the end of the line. + */ + tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); + + /* + * Put this line. + */ + proto_tree_add_item(whois_tree, hf_whois_answer, tvb, offset, + next_offset - offset, ENC_UTF_8); + offset = next_offset; + } + proto_tree_add_expert(whois_tree, pinfo, &ei_whois_encoding, tvb, 0, -1); + } + + return tvb_captured_length(tvb); +} + +void +proto_register_whois(void) +{ + expert_module_t *expert_whois; + + static hf_register_info hf[] = { + { &hf_whois_query, + { "Query", "whois.query", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_whois_answer, + { "Answer", "whois.answer", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_whois_answer_in, + { "Answer In", "whois.answer_in", FT_FRAMENUM, BASE_NONE, NULL, + 0x0, "The answer to this WHOIS query is in this frame", + HFILL } + }, + { &hf_whois_answer_to, + { "Query In", "whois.answer_to", FT_FRAMENUM, BASE_NONE, NULL, + 0x0, "This is the answer to the WHOIS query in this frame", + HFILL } + }, + { &hf_whois_response_time, + { "Response Time", "whois.response_time", FT_RELATIVE_TIME, + BASE_NONE, NULL, 0x0, + "The time between the Query and the Answer", HFILL } + } + }; + + static gint *ett[] = { + &ett_whois + }; + + static ei_register_info ei[] = { + { &ei_whois_nocrlf, + { "whois.nocrlf", PI_MALFORMED, PI_WARN, "Missing <CR><LF>", EXPFILL} + }, + { &ei_whois_encoding, + { "whois.encoding", PI_ASSUMPTION, PI_CHAT, "WHOIS has no mechanism to indicate encoding (RFC 3912), assuming UTF-8", EXPFILL} + } + }; + + proto_whois = proto_register_protocol("whois", "WHOIS", "whois"); + proto_register_field_array(proto_whois, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + expert_whois = expert_register_protocol(proto_whois); + expert_register_field_array(expert_whois, ei, array_length(ei)); + whois_handle = register_dissector("whois", dissect_whois, proto_whois); +} + +void +proto_reg_handoff_whois(void) +{ + dissector_add_uint_with_preference("tcp.port", WHOIS_PORT, whois_handle); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ + |