Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-icap.c
blob09020e4926210c61524bba8f2141018f2092c015
1 /* packet-icap.c
2 * Routines for ICAP packet disassembly
3 * RFC 3507
5 * Srishylam Simharajan simha@netapp.com
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include "config.h"
17 #include <epan/packet.h>
18 #include <epan/strutil.h>
19 #include "packet-tls.h"
21 void proto_register_icap(void);
22 void proto_reg_handoff_icap(void);
24 typedef enum _icap_type {
25 ICAP_OPTIONS,
26 ICAP_REQMOD,
27 ICAP_RESPMOD,
28 ICAP_RESPONSE,
29 ICAP_OTHER
30 } icap_type_t;
32 static int proto_icap;
33 static int hf_icap_response;
34 static int hf_icap_reqmod;
35 static int hf_icap_respmod;
36 static int hf_icap_options;
37 /* static int hf_icap_other; */
39 static int ett_icap;
41 static dissector_handle_t http_handle;
43 #define TCP_PORT_ICAP 1344
44 static int is_icap_message(const unsigned char *data, int linelen, icap_type_t *type);
45 static int
46 dissect_icap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
48 proto_tree *icap_tree = NULL;
49 proto_item *ti = NULL;
50 proto_item *hidden_item;
51 tvbuff_t *new_tvb;
52 int offset = 0;
53 const unsigned char *line;
54 int next_offset;
55 const unsigned char *linep, *lineend;
56 int linelen;
57 unsigned char c;
58 icap_type_t icap_type;
59 int datalen;
61 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICAP");
64 * Put the first line from the buffer into the summary
65 * if it's an ICAP header (but leave out the
66 * line terminator).
67 * Otherwise, just call it a continuation.
69 * Note that "tvb_find_line_end()" will return a value that
70 * is not longer than what's in the buffer, so the
71 * "tvb_get_ptr()" call won't throw an exception.
73 linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, false);
74 line = tvb_get_ptr(tvb, offset, linelen);
75 icap_type = ICAP_OTHER; /* type not known yet */
76 if (is_icap_message(line, linelen, &icap_type))
77 col_add_str(pinfo->cinfo, COL_INFO,
78 format_text(pinfo->pool, line, linelen));
79 else
80 col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
82 if (tree) {
83 ti = proto_tree_add_item(tree, proto_icap, tvb, offset, -1,
84 ENC_NA);
85 icap_tree = proto_item_add_subtree(ti, ett_icap);
89 * Process the packet data, a line at a time.
91 icap_type = ICAP_OTHER; /* type not known yet */
92 while (tvb_offset_exists(tvb, offset)) {
93 bool is_icap = false;
94 bool loop_done = false;
96 * Find the end of the line.
98 linelen = tvb_find_line_end(tvb, offset, -1, &next_offset,
99 false);
102 * Get a buffer that refers to the line.
104 line = tvb_get_ptr(tvb, offset, linelen);
105 lineend = line + linelen;
108 * find header format
110 if (is_icap_message(line, linelen, &icap_type)) {
111 goto is_icap_header;
115 * if it looks like a blank line, end of header perhaps?
117 if (linelen == 0) {
118 goto is_icap_header;
122 * No. Does it look like a header?
124 linep = line;
125 loop_done = false;
126 while (linep < lineend && (!loop_done)) {
127 c = *linep++;
130 * This must be a CHAR, and must not be a CTL, to be part
131 * of a token; that means it must be printable ASCII.
133 * XXX - what about leading LWS on continuation
134 * lines of a header?
136 if (!g_ascii_isprint(c)) {
137 is_icap = false;
138 break;
141 switch (c) {
143 case '(':
144 case ')':
145 case '<':
146 case '>':
147 case '@':
148 case ',':
149 case ';':
150 case '\\':
151 case '"':
152 case '/':
153 case '[':
154 case ']':
155 case '?':
156 case '=':
157 case '{':
158 case '}':
160 * It's a separator, so it's not part of a
161 * token, so it's not a field name for the
162 * beginning of a header.
164 * (We don't have to check for HT; that's
165 * already been ruled out by "iscntrl()".)
167 * XXX - what about ' '? HTTP's checks
168 * check for that.
170 is_icap = false;
171 loop_done = true;
172 break;
174 case ':':
176 * This ends the token; we consider this
177 * to be a header.
179 goto is_icap_header;
184 * We don't consider this part of an ICAP message,
185 * so we don't display it.
186 * (Yeah, that means we don't display, say, a text/icap
187 * page, but you can get that from the data pane.)
189 if (!is_icap)
190 break;
191 is_icap_header:
192 proto_tree_add_format_text(icap_tree, tvb, offset, next_offset - offset);
193 offset = next_offset;
196 if (tree) {
197 switch (icap_type) {
199 case ICAP_OPTIONS:
200 hidden_item = proto_tree_add_boolean(icap_tree,
201 hf_icap_options, tvb, 0, 0, 1);
202 proto_item_set_hidden(hidden_item);
203 break;
205 case ICAP_REQMOD:
206 hidden_item = proto_tree_add_boolean(icap_tree,
207 hf_icap_reqmod, tvb, 0, 0, 1);
208 proto_item_set_hidden(hidden_item);
209 break;
211 case ICAP_RESPMOD:
212 hidden_item = proto_tree_add_boolean(icap_tree,
213 hf_icap_respmod, tvb, 0, 0, 1);
214 proto_item_set_hidden(hidden_item);
215 break;
217 case ICAP_RESPONSE:
218 hidden_item = proto_tree_add_boolean(icap_tree,
219 hf_icap_response, tvb, 0, 0, 1);
220 proto_item_set_hidden(hidden_item);
221 break;
223 case ICAP_OTHER:
224 default:
225 break;
229 datalen = tvb_reported_length_remaining(tvb, offset);
230 if (datalen > 0) {
231 if(http_handle){
232 new_tvb = tvb_new_subset_remaining(tvb, offset);
233 call_dissector(http_handle, new_tvb, pinfo, icap_tree);
237 return tvb_captured_length(tvb);
241 static int
242 is_icap_message(const unsigned char *data, int linelen, icap_type_t *type)
244 #define ICAP_COMPARE(string, length, msgtype) { \
245 if (strncmp(data, string, length) == 0) { \
246 if (*type == ICAP_OTHER) \
247 *type = msgtype; \
248 return true; \
252 * From draft-elson-opes-icap-01(72).txt
254 if (linelen >= 5) {
255 ICAP_COMPARE("ICAP/", 5, ICAP_RESPONSE); /* response */
257 if (linelen >= 7) {
258 ICAP_COMPARE("REQMOD ", 7, ICAP_REQMOD); /* request mod */
260 if (linelen >= 8) {
261 ICAP_COMPARE("OPTIONS ", 8, ICAP_OPTIONS); /* options */
262 ICAP_COMPARE("RESPMOD ", 8, ICAP_RESPMOD); /* response mod */
264 return false;
265 #undef ICAP_COMPARE
268 void
269 proto_register_icap(void)
271 static hf_register_info hf[] = {
272 { &hf_icap_response,
273 { "Response", "icap.response",
274 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
275 "true if ICAP response", HFILL }},
276 { &hf_icap_reqmod,
277 { "Reqmod", "icap.reqmod",
278 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
279 "true if ICAP reqmod", HFILL }},
280 { &hf_icap_respmod,
281 { "Respmod", "icap.respmod",
282 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
283 "true if ICAP respmod", HFILL }},
284 { &hf_icap_options,
285 { "Options", "icap.options",
286 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
287 "true if ICAP options", HFILL }},
288 #if 0
289 { &hf_icap_other,
290 { "Other", "icap.other",
291 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
292 "true if ICAP other", HFILL }},
293 #endif
295 static int *ett[] = {
296 &ett_icap,
299 proto_icap = proto_register_protocol("Internet Content Adaptation Protocol", "ICAP", "icap");
300 proto_register_field_array(proto_icap, hf, array_length(hf));
301 proto_register_subtree_array(ett, array_length(ett));
305 void
306 proto_reg_handoff_icap(void)
308 dissector_handle_t icap_handle;
310 http_handle = find_dissector_add_dependency("http", proto_icap);
312 icap_handle = register_dissector("icap", dissect_icap, proto_icap);
313 dissector_add_uint_with_preference("tcp.port", TCP_PORT_ICAP, icap_handle);
315 /* As ICAPS port is not officially assigned by IANA
316 * (de facto standard is 11344), we default to 0
317 * to have "decode as" available */
318 ssl_dissector_add(0, icap_handle);
322 * Editor modelines - https://www.wireshark.org/tools/modelines.html
324 * Local variables:
325 * c-basic-offset: 4
326 * tab-width: 8
327 * indent-tabs-mode: nil
328 * End:
330 * vi: set shiftwidth=4 tabstop=8 expandtab:
331 * :indentSize=4:tabSize=8:noTabs=true: