2 * Routines for pop packet dissection
4 * Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * Copied from packet-tftp.c
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
35 #include <epan/packet.h>
36 #include <epan/strutil.h>
37 #include <epan/conversation.h>
38 #include <epan/prefs.h>
39 #include <epan/reassemble.h>
40 #include <epan/wmem/wmem.h>
41 #include "packet-ssl.h"
43 static int proto_pop
= -1;
45 static int hf_pop_response
= -1;
46 static int hf_pop_response_indicator
= -1;
47 static int hf_pop_response_description
= -1;
48 static int hf_pop_response_data
= -1;
50 static int hf_pop_request
= -1;
51 static int hf_pop_request_command
= -1;
52 static int hf_pop_request_parameter
= -1;
53 static int hf_pop_request_data
= -1;
55 static int hf_pop_data_fragments
= -1;
56 static int hf_pop_data_fragment
= -1;
57 static int hf_pop_data_fragment_overlap
= -1;
58 static int hf_pop_data_fragment_overlap_conflicts
= -1;
59 static int hf_pop_data_fragment_multiple_tails
= -1;
60 static int hf_pop_data_fragment_too_long_fragment
= -1;
61 static int hf_pop_data_fragment_error
= -1;
62 static int hf_pop_data_fragment_count
= -1;
63 static int hf_pop_data_reassembled_in
= -1;
64 static int hf_pop_data_reassembled_length
= -1;
66 static gint ett_pop
= -1;
67 static gint ett_pop_reqresp
= -1;
69 static gint ett_pop_data_fragment
= -1;
70 static gint ett_pop_data_fragments
= -1;
72 static dissector_handle_t data_handle
;
73 static dissector_handle_t imf_handle
= NULL
;
74 static dissector_handle_t ssl_handle
= NULL
;
76 #define TCP_PORT_POP 110
77 #define TCP_PORT_SSL_POP 995
79 /* desegmentation of POP command and response lines */
80 static gboolean pop_data_desegment
= TRUE
;
82 static reassembly_table pop_data_reassembly_table
;
84 static const fragment_items pop_data_frag_items
= {
85 /* Fragment subtrees */
86 &ett_pop_data_fragment
,
87 &ett_pop_data_fragments
,
89 &hf_pop_data_fragments
,
90 &hf_pop_data_fragment
,
91 &hf_pop_data_fragment_overlap
,
92 &hf_pop_data_fragment_overlap_conflicts
,
93 &hf_pop_data_fragment_multiple_tails
,
94 &hf_pop_data_fragment_too_long_fragment
,
95 &hf_pop_data_fragment_error
,
96 &hf_pop_data_fragment_count
,
97 /* Reassembled in field */
98 &hf_pop_data_reassembled_in
,
99 /* Reassembled length field */
100 &hf_pop_data_reassembled_length
,
101 /* Reassembled data field */
107 struct pop_proto_data
{
108 guint16 conversation_id
;
112 struct pop_data_val
{
113 gboolean msg_request
;
114 guint32 msg_read_len
; /* Length of RETR message read so far */
115 guint32 msg_tot_len
; /* Total length of RETR message */
116 gboolean stls_request
; /* Received STLS request */
117 guint32 last_nontls_frame
; /* last non-TLS frame; 0 if not known or no TLS */
122 static gboolean
response_is_continuation(const guchar
*data
);
125 dissect_pop(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
127 struct pop_proto_data
*frame_data_p
;
129 gboolean is_continuation
;
130 proto_tree
*pop_tree
, *reqresp_tree
;
137 const guchar
*next_token
;
138 fragment_head
*frag_msg
= NULL
;
139 tvbuff_t
*next_tvb
= NULL
;
140 conversation_t
*conversation
= NULL
;
141 struct pop_data_val
*data_val
= NULL
;
142 gint length_remaining
;
144 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "POP");
146 frame_data_p
= (struct pop_proto_data
*)p_get_proto_data(pinfo
->fd
, proto_pop
, 0);
148 conversation
= find_or_create_conversation(pinfo
);
149 data_val
= (struct pop_data_val
*)conversation_get_proto_data(conversation
, proto_pop
);
153 * No conversation - create one and attach it.
155 data_val
= wmem_new0(wmem_file_scope(), struct pop_data_val
);
157 conversation_add_proto_data(conversation
, proto_pop
, data_val
);
160 /* Are we doing TLS? */
161 if (data_val
->last_nontls_frame
!= 0 && pinfo
->fd
->num
> data_val
->last_nontls_frame
) {
162 guint16 save_can_desegment
;
163 guint32 save_last_nontls_frame
;
165 /* This is TLS, not raw POP/IMF. TLS can desegment */
166 save_can_desegment
= pinfo
->can_desegment
;
167 pinfo
->can_desegment
= pinfo
->saved_can_desegment
;
169 /* Make sure the SSL dissector will not be called again after decryption */
170 save_last_nontls_frame
= data_val
->last_nontls_frame
;
171 data_val
->last_nontls_frame
= 0;
173 call_dissector(ssl_handle
, tvb
, pinfo
, tree
);
175 pinfo
->can_desegment
= save_can_desegment
;
176 data_val
->last_nontls_frame
= save_last_nontls_frame
;
181 * Find the end of the first line.
183 * Note that "tvb_find_line_end()" will return a value that is
184 * not longer than what's in the buffer, so the "tvb_get_ptr()"
185 * call won't throw an exception.
187 linelen
= tvb_find_line_end(tvb
, offset
, -1, &next_offset
, FALSE
);
188 line
= tvb_get_ptr(tvb
, offset
, linelen
);
190 if (pinfo
->match_uint
== pinfo
->destport
) {
192 is_continuation
= FALSE
;
195 is_continuation
= response_is_continuation(line
);
199 * Put the first line from the buffer into the summary
200 * if it's a POP request or reply (but leave out the
202 * Otherwise, just call it a continuation.
204 if (is_continuation
) {
205 length_remaining
= tvb_length_remaining(tvb
, offset
);
206 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "S: DATA fragment, %d byte%s",
207 length_remaining
, plurality (length_remaining
, "", "s"));
210 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s: %s", is_request
? "C" : "S",
211 format_text(line
, linelen
));
213 ti
= proto_tree_add_item(tree
, proto_pop
, tvb
, offset
, -1, ENC_NA
);
214 pop_tree
= proto_item_add_subtree(ti
, ett_pop
);
216 if (is_continuation
) {
218 if (pop_data_desegment
) {
222 data_val
->msg_read_len
+= tvb_length(tvb
);
224 frame_data_p
= wmem_new(wmem_file_scope(), struct pop_proto_data
);
226 frame_data_p
->conversation_id
= conversation
->index
;
227 frame_data_p
->more_frags
= data_val
->msg_read_len
< data_val
->msg_tot_len
;
229 p_add_proto_data(pinfo
->fd
, proto_pop
, 0, frame_data_p
);
232 frag_msg
= fragment_add_seq_next(&pop_data_reassembly_table
, tvb
, 0,
234 frame_data_p
->conversation_id
,
237 frame_data_p
->more_frags
);
239 next_tvb
= process_reassembled_data(tvb
, offset
, pinfo
,
241 frag_msg
, &pop_data_frag_items
,
247 call_dissector(imf_handle
, next_tvb
, pinfo
, tree
);
250 /* we have read everything - reset */
252 data_val
->msg_read_len
= 0;
253 data_val
->msg_tot_len
= 0;
255 pinfo
->fragmented
= FALSE
;
257 pinfo
->fragmented
= TRUE
;
263 * Put the whole packet into the tree as data.
265 call_dissector(data_handle
,tvb
, pinfo
, pop_tree
);
272 * Put the line into the protocol tree.
274 ti
= proto_tree_add_string_format(pop_tree
,
279 next_offset
- offset
,
281 tvb_format_text(tvb
, offset
, next_offset
- offset
));
282 reqresp_tree
= proto_item_add_subtree(ti
, ett_pop_reqresp
);
285 * Extract the first token, and, if there is a first
286 * token, add it as the request or reply code.
288 tokenlen
= get_token_len(line
, line
+ linelen
, &next_token
);
290 proto_tree_add_item(reqresp_tree
,
292 hf_pop_request_command
:
293 hf_pop_response_indicator
,
294 tvb
, offset
, tokenlen
, ENC_ASCII
|ENC_NA
);
298 /* see if this is RETR or TOP command */
299 if (g_ascii_strncasecmp(line
, "RETR", 4) == 0 ||
300 g_ascii_strncasecmp(line
, "TOP", 3) == 0)
301 /* the next response will tell us how many bytes */
302 data_val
->msg_request
= TRUE
;
304 if (g_ascii_strncasecmp(line
, "STLS", 4) == 0) {
305 data_val
->stls_request
= TRUE
;
308 if (data_val
->msg_request
) {
309 /* this is a response to a RETR or TOP command */
311 if (g_ascii_strncasecmp(line
, "+OK ", 4) == 0) {
312 /* the message will be sent - work out how many bytes */
313 data_val
->msg_read_len
= 0;
314 data_val
->msg_tot_len
= atoi(line
+ 4);
316 data_val
->msg_request
= FALSE
;
319 if (data_val
->stls_request
) {
320 if (g_ascii_strncasecmp(line
, "+OK ", 4) == 0) {
321 /* This is the last non-TLS frame. */
322 data_val
->last_nontls_frame
= pinfo
->fd
->num
;
324 data_val
->stls_request
= FALSE
;
329 offset
+= (gint
) (next_token
- line
);
330 linelen
-= (int) (next_token
- line
);
336 * Add the rest of the first line as request or
337 * reply param/description.
340 proto_tree_add_item(reqresp_tree
,
342 hf_pop_request_parameter
:
343 hf_pop_response_description
,
344 tvb
, offset
, linelen
, ENC_ASCII
|ENC_NA
);
346 offset
= next_offset
;
349 * Show the rest of the request or response as text,
352 while (tvb_offset_exists(tvb
, offset
)) {
354 * Find the end of the line.
356 tvb_find_line_end(tvb
, offset
, -1, &next_offset
, FALSE
);
361 proto_tree_add_string_format(pop_tree
,
363 hf_pop_request_data
:
364 hf_pop_response_data
,
366 next_offset
- offset
,
368 tvb_format_text(tvb
, offset
, next_offset
- offset
));
369 offset
= next_offset
;
374 static gboolean
response_is_continuation(const guchar
*data
)
376 if (strncmp(data
, "+OK", strlen("+OK")) == 0)
379 if (strncmp(data
, "-ERR", strlen("-ERR")) == 0)
385 static void pop_data_reassemble_init (void)
387 reassembly_table_init (&pop_data_reassembly_table
,
388 &addresses_ports_reassembly_table_functions
);
392 proto_register_pop(void)
394 static hf_register_info hf
[] = {
396 { "Response", "pop.response",
397 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
398 { &hf_pop_response_indicator
,
399 { "Response indicator", "pop.response.indicator",
400 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
401 { &hf_pop_response_description
,
402 { "Response description", "pop.response.description",
403 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
404 { &hf_pop_response_data
,
405 { "Data", "pop.response.data",
406 FT_STRING
, BASE_NONE
, NULL
, 0x0, "Response Data", HFILL
}},
408 { "Request", "pop.request",
409 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
410 { &hf_pop_request_command
,
411 { "Request command", "pop.request.command",
412 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
413 { &hf_pop_request_parameter
,
414 { "Request parameter", "pop.request.parameter",
415 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
416 { &hf_pop_request_data
,
417 { "Data", "pop.request.data",
418 FT_STRING
, BASE_NONE
, NULL
, 0x0, "Request data", HFILL
}},
419 /* Fragment entries */
420 { &hf_pop_data_fragments
,
421 { "DATA fragments", "pop.data.fragments", FT_NONE
, BASE_NONE
,
422 NULL
, 0x00, "Message fragments", HFILL
} },
423 { &hf_pop_data_fragment
,
424 { "DATA fragment", "pop.data.fragment", FT_FRAMENUM
, BASE_NONE
,
425 NULL
, 0x00, "Message fragment", HFILL
} },
426 { &hf_pop_data_fragment_overlap
,
427 { "DATA fragment overlap", "pop.data.fragment.overlap", FT_BOOLEAN
,
428 BASE_NONE
, NULL
, 0x0, "Message fragment overlap", HFILL
} },
429 { &hf_pop_data_fragment_overlap_conflicts
,
430 { "DATA fragment overlapping with conflicting data",
431 "pop.data.fragment.overlap.conflicts", FT_BOOLEAN
, BASE_NONE
, NULL
,
432 0x0, "Message fragment overlapping with conflicting data", HFILL
} },
433 { &hf_pop_data_fragment_multiple_tails
,
434 { "DATA has multiple tail fragments",
435 "pop.data.fragment.multiple_tails", FT_BOOLEAN
, BASE_NONE
,
436 NULL
, 0x0, "Message has multiple tail fragments", HFILL
} },
437 { &hf_pop_data_fragment_too_long_fragment
,
438 { "DATA fragment too long", "pop.data.fragment.too_long_fragment",
439 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, "Message fragment too long",
441 { &hf_pop_data_fragment_error
,
442 { "DATA defragmentation error", "pop.data.fragment.error", FT_FRAMENUM
,
443 BASE_NONE
, NULL
, 0x00, "Message defragmentation error", HFILL
} },
444 { &hf_pop_data_fragment_count
,
445 { "DATA fragment count", "pop.data.fragment.count", FT_UINT32
, BASE_DEC
,
446 NULL
, 0x00, NULL
, HFILL
} },
447 { &hf_pop_data_reassembled_in
,
448 { "Reassembled DATA in frame", "pop.data.reassembled.in", FT_FRAMENUM
, BASE_NONE
,
449 NULL
, 0x00, "This DATA fragment is reassembled in this frame", HFILL
} },
450 { &hf_pop_data_reassembled_length
,
451 { "Reassembled DATA length", "pop.data.reassembled.length", FT_UINT32
, BASE_DEC
,
452 NULL
, 0x00, "The total length of the reassembled payload", HFILL
} },
455 static gint
*ett
[] = {
458 &ett_pop_data_fragment
,
459 &ett_pop_data_fragments
461 module_t
*pop_module
;
464 proto_pop
= proto_register_protocol("Post Office Protocol", "POP", "pop");
465 register_dissector("pop", dissect_pop
, proto_pop
);
466 proto_register_field_array(proto_pop
, hf
, array_length(hf
));
467 proto_register_subtree_array(ett
, array_length(ett
));
468 register_init_routine (&pop_data_reassemble_init
);
471 pop_module
= prefs_register_protocol(proto_pop
, NULL
);
473 prefs_register_bool_preference(pop_module
, "desegment_data",
474 "Reassemble POP RETR and TOP responses spanning multiple TCP segments",
475 "Whether the POP dissector should reassemble RETR and TOP responses and spanning multiple TCP segments."
476 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
477 &pop_data_desegment
);
481 proto_reg_handoff_pop(void)
483 dissector_handle_t pop_handle
;
485 pop_handle
= find_dissector("pop");
486 dissector_add_uint("tcp.port", TCP_PORT_POP
, pop_handle
);
487 ssl_dissector_add(TCP_PORT_SSL_POP
, "pop", TRUE
);
488 data_handle
= find_dissector("data");
490 /* find the IMF dissector */
491 imf_handle
= find_dissector("imf");
493 /* find the SSL dissector */
494 ssl_handle
= find_dissector("ssl");