Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-gopher.c
blob35440d6fb40d8750c67077242c074177b7790d42
1 /* packet-gopher.c
2 * Routines for RFC 1436 Gopher protocol dissection
3 * Copyright 2010, Gerald Combs <gerald@wireshark.org>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * Copied from packet-banana.c
11 * SPDX-License-Identifier: GPL-2.0-or-later
15 * RFC 1436: https://tools.ietf.org/html/rfc1436
16 * http://en.wikipedia.org/wiki/Gopher_%28protocol%29
19 #include "config.h"
21 #include <epan/packet.h>
22 #include <epan/prefs.h>
24 void proto_register_gopher(void);
25 void proto_reg_handoff_gopher(void);
27 /* Initialize the protocol and registered fields */
28 static int proto_gopher;
29 static int hf_gopher_request;
30 static int hf_gopher_dir_item;
31 static int hf_gopher_di_type;
32 static int hf_gopher_di_name;
33 static int hf_gopher_di_selector;
34 static int hf_gopher_di_host;
35 static int hf_gopher_di_port;
36 static int hf_gopher_unknown;
38 /* Initialize the subtree pointers */
39 static int ett_gopher;
40 static int ett_dir_item;
42 static dissector_handle_t gopher_handle;
44 /* RFC 1436 section 3.8 */
45 static const value_string item_types[] = {
46 { '+', "Redundant server" },
47 { '0', "Text file" },
48 { '1', "Menu" },
49 { '2', "CSO phone book entity" },
50 { '3', "Error" },
51 { '4', "BinHexed Macintosh file" },
52 { '5', "DOS binary file" },
53 { '6', "Uuencoded file" },
54 { '7', "Index server" },
55 { '8', "Telnet session" },
56 { '9', "Binary file" },
57 { 'g', "GIF file" },
58 { 'h', "HTML file" }, /* Not in RFC 1436 */
59 { 'i', "Informational message"}, /* Not in RFC 1436 */
60 { 'I', "Image file" },
61 { 's', "Audio file" }, /* Not in RFC 1436 */
62 { 'T', "Tn3270 session" },
63 { 0, NULL }
66 #define TCP_DEFAULT_RANGE "70"
68 static range_t *gopher_tcp_range;
70 /* Returns true if the packet is from a client */
71 static bool
72 is_client(packet_info *pinfo) {
73 return value_is_in_range(gopher_tcp_range, pinfo->destport);
76 /* Name + Tab + Selector + Tab + Host + Tab + Port */
77 #define MAX_DIR_LINE_LEN (70 + 1 + 255 + 1 + 255 + 1 + 5)
78 #define MIN_DIR_LINE_LEN (0 + 1 + 0 + 1 + 1 + 1 + 1)
79 static bool
80 find_dir_tokens(tvbuff_t *tvb, int name_start, int *sel_start, int *host_start, int *port_start, int *line_len, int *next_offset) {
81 int remain;
83 if (tvb_captured_length_remaining(tvb, name_start) < MIN_DIR_LINE_LEN)
84 return false;
86 if (! (sel_start && host_start && port_start && line_len && next_offset) )
87 return false;
89 *line_len = tvb_find_line_end(tvb, name_start, MAX_DIR_LINE_LEN, next_offset, false);
90 if (*line_len < MIN_DIR_LINE_LEN)
91 return false;
93 remain = *line_len;
94 *sel_start = tvb_find_uint8(tvb, name_start, remain, '\t') + 1;
95 if (*sel_start < name_start + 1)
96 return false;
98 remain -= *sel_start - name_start;
99 *host_start = tvb_find_uint8(tvb, *sel_start, remain, '\t') + 1;
100 if (*host_start < *sel_start + 1)
101 return false;
103 remain -= *host_start - *sel_start;
104 *port_start = tvb_find_uint8(tvb, *host_start, remain, '\t') + 1;
105 if (*port_start < *host_start + 1)
106 return false;
108 return true;
111 /* Dissect the packets */
113 static int
114 dissect_gopher(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
115 proto_item *ti;
116 proto_tree *gopher_tree, *dir_tree = NULL;
117 bool client = is_client(pinfo);
118 int line_len;
119 const char *request = "[Invalid request]";
120 bool is_dir = false;
121 int offset = 0, next_offset;
122 int sel_start, host_start, port_start;
123 char *name;
125 /* Fill in our protocol and info columns */
126 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Gopher");
128 if (client) {
129 line_len = tvb_find_line_end(tvb, 0, -1, NULL, false);
130 if (line_len == 0) {
131 request = "[Directory list]";
132 } else if (line_len > 0) {
133 request = tvb_get_string_enc(pinfo->pool, tvb, 0, line_len, ENC_ASCII);
135 col_add_fstr(pinfo->cinfo, COL_INFO, "Request: %s", request);
136 } else {
137 col_set_str(pinfo->cinfo, COL_INFO, "Response");
140 if (tree) {
141 /* Create display subtree for the protocol */
142 ti = proto_tree_add_item(tree, proto_gopher, tvb, 0, -1, ENC_NA);
143 gopher_tree = proto_item_add_subtree(ti, ett_gopher);
145 if (client) {
146 proto_item_append_text(ti, " request: %s", request);
147 proto_tree_add_string(gopher_tree, hf_gopher_request, tvb,
148 0, -1, request);
149 } else {
150 proto_item_append_text(ti, " response: ");
152 while (find_dir_tokens(tvb, offset + 1, &sel_start, &host_start, &port_start, &line_len, &next_offset)) {
153 if (!is_dir) { /* First time */
154 proto_item_append_text(ti, "[Directory list]");
155 col_append_str(pinfo->cinfo, COL_INFO, ": [Directory list]");
158 name = tvb_get_string_enc(pinfo->pool, tvb, offset + 1, sel_start - offset - 2, ENC_ASCII);
159 ti = proto_tree_add_string(gopher_tree, hf_gopher_dir_item, tvb,
160 offset, line_len + 1, name);
161 dir_tree = proto_item_add_subtree(ti, ett_dir_item);
162 proto_tree_add_item(dir_tree, hf_gopher_di_type, tvb, offset, 1, ENC_ASCII|ENC_NA);
163 proto_tree_add_item(dir_tree, hf_gopher_di_name, tvb, offset + 1,
164 sel_start - offset - 2, ENC_ASCII);
165 proto_tree_add_item(dir_tree, hf_gopher_di_selector, tvb, sel_start,
166 host_start - sel_start - 1, ENC_ASCII);
167 proto_tree_add_item(dir_tree, hf_gopher_di_host, tvb, host_start,
168 port_start - host_start - 1, ENC_ASCII);
169 proto_tree_add_item(dir_tree, hf_gopher_di_port, tvb, port_start,
170 line_len - (port_start - offset - 1), ENC_ASCII);
171 is_dir = true;
172 offset = next_offset;
175 if (!is_dir) {
176 proto_item_append_text(ti, "[Unknown]");
177 proto_tree_add_item(gopher_tree, hf_gopher_unknown, tvb, 0, -1, ENC_ASCII);
183 /* Return the amount of data this dissector was able to dissect */
184 return tvb_captured_length(tvb);
187 /* Preference callbacks */
188 static void
189 gopher_prefs_apply(void) {
191 gopher_tcp_range = prefs_get_range_value("gopher", "tcp.port");
194 /* Register the protocol with Wireshark */
196 void
197 proto_register_gopher(void)
199 static hf_register_info hf[] = {
200 { &hf_gopher_request,
201 { "Gopher client request", "gopher.request",
202 FT_STRING, BASE_NONE, NULL, 0,
203 NULL, HFILL }
206 { &hf_gopher_dir_item,
207 { "Directory item", "gopher.directory",
208 FT_STRING, BASE_NONE, NULL, 0,
209 NULL, HFILL }
211 { &hf_gopher_di_type,
212 { "Type", "gopher.directory.type",
213 FT_CHAR, BASE_HEX, VALS(item_types), 0,
214 NULL, HFILL }
216 { &hf_gopher_di_name,
217 { "Name", "gopher.directory.name",
218 FT_STRING, BASE_NONE, NULL, 0,
219 NULL, HFILL }
221 { &hf_gopher_di_selector,
222 { "Selector", "gopher.directory.selector",
223 FT_STRING, BASE_NONE, NULL, 0,
224 NULL, HFILL }
226 { &hf_gopher_di_host,
227 { "Host", "gopher.directory.host",
228 FT_STRING, BASE_NONE, NULL, 0,
229 NULL, HFILL }
231 { &hf_gopher_di_port,
232 { "Port", "gopher.directory.port",
233 FT_STRING, BASE_NONE, NULL, 0,
234 NULL, HFILL }
237 { &hf_gopher_unknown,
238 { "Unknown Gopher transaction data", "gopher.unknown",
239 FT_STRING, BASE_NONE, NULL, 0,
240 NULL, HFILL }
244 /* Setup protocol subtree array */
245 static int *ett[] = {
246 &ett_gopher,
247 &ett_dir_item
250 /* Register the protocol name and description */
251 proto_gopher = proto_register_protocol("Gopher", "Gopher", "gopher");
253 /* Register the dissector handle */
254 gopher_handle = register_dissector("gopher", dissect_gopher, proto_gopher);
256 /* Required function calls to register the header fields and subtrees used */
257 proto_register_field_array(proto_gopher, hf, array_length(hf));
258 proto_register_subtree_array(ett, array_length(ett));
260 /* Preferences for this module are generated when registering with
261 dissector tables and need the callback function to get the
262 port range values
264 prefs_register_protocol(proto_gopher, gopher_prefs_apply);
267 void
268 proto_reg_handoff_gopher(void)
270 dissector_add_uint_range_with_preference("tcp.port", TCP_DEFAULT_RANGE, gopher_handle);
271 gopher_prefs_apply();
275 * Editor modelines - https://www.wireshark.org/tools/modelines.html
277 * Local variables:
278 * c-basic-offset: 4
279 * tab-width: 8
280 * indent-tabs-mode: nil
281 * End:
283 * vi: set shiftwidth=4 tabstop=8 expandtab:
284 * :indentSize=4:tabSize=8:noTabs=true: