2 * Routines for imap packet dissection
3 * Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * Copied from packet-tftp.c
11 * SPDX-License-Identifier: GPL-2.0-or-later
17 #include <epan/packet.h>
18 #include <epan/strutil.h>
19 #include <wsutil/strtoi.h>
20 #include "packet-tls.h"
21 #include "packet-tls-utils.h"
22 #include <ui/tap-credentials.h>
25 void proto_register_imap(void);
26 void proto_reg_handoff_imap(void);
28 static int proto_imap
;
29 static int hf_imap_isrequest
;
30 static int hf_imap_line
;
31 static int hf_imap_request
;
32 static int hf_imap_request_tag
;
33 static int hf_imap_response
;
34 static int hf_imap_response_tag
;
35 static int hf_imap_request_command
;
36 static int hf_imap_response_command
;
37 static int hf_imap_tag
;
38 static int hf_imap_command
;
39 static int hf_imap_response_status
;
40 static int hf_imap_request_folder
;
41 static int hf_imap_request_username
;
42 static int hf_imap_request_password
;
43 static int hf_imap_request_uid
;
44 static int hf_imap_response_in
;
45 static int hf_imap_response_to
;
46 static int hf_imap_time
;
49 static int ett_imap_reqresp
;
51 static int credentials_tap
;
53 static dissector_handle_t imap_handle
;
54 static dissector_handle_t tls_handle
;
55 static dissector_handle_t imf_handle
;
57 static bool imap_ssl_heuristic
= true;
59 /* patterns used for tvb_ws_mempbrk_pattern_uint8 */
60 static ws_mempbrk_pattern pbrk_whitespace
;
62 #define TCP_PORT_IMAP 143
63 #define TCP_PORT_SSL_IMAP 993
64 #define IMAP_HEUR_LEN 5
65 #define NUM_LOOKAHEAD_TOKENS 3
67 struct simple_token_info
70 int token_start_offset
;
74 typedef struct imap_state
{
76 int ssl_heur_tries_left
;
79 typedef struct imap_request_key
{
81 uint32_t conversation
;
84 typedef struct imap_request_val
{
92 } imap_request_info_t
;
94 static wmem_map_t
*imap_requests
;
97 imap_request_equal(const void *v
, const void *w
)
99 const imap_request_key_t
*v1
= (const imap_request_key_t
*)v
;
100 const imap_request_key_t
*v2
= (const imap_request_key_t
*)w
;
102 if ((v1
->conversation
== v2
->conversation
) &&
103 (!strcmp(v1
->tag
, v2
->tag
)))
110 imap_request_hash(const void *v
)
112 const imap_request_key_t
*key
= (const imap_request_key_t
*)v
;
115 val
= (unsigned)(wmem_str_hash(key
->tag
) * 37 + key
->conversation
* 765);
121 imap_match_request(packet_info
*pinfo
, proto_tree
*tree
, imap_request_key_t
*request_key
, bool is_request
)
123 imap_request_key_t
*new_request_key
;
124 imap_request_val_t
*request_val
;
125 imap_request_info_t
*request_info
= NULL
;
128 request_val
= (imap_request_val_t
*)wmem_map_lookup(imap_requests
, request_key
);
129 if (!pinfo
->fd
->visited
)
133 if (request_val
== NULL
)
135 new_request_key
= (imap_request_key_t
*)wmem_memdup(wmem_file_scope(), request_key
, sizeof(imap_request_key_t
));
136 new_request_key
->tag
= wmem_strdup(wmem_file_scope(), request_key
->tag
);
138 request_val
= wmem_new(wmem_file_scope(), imap_request_val_t
);
139 request_val
->frames
= wmem_tree_new(wmem_file_scope());
141 wmem_map_insert(imap_requests
, new_request_key
, request_val
);
144 request_info
= wmem_new(wmem_file_scope(), imap_request_info_t
);
145 request_info
->req_num
= pinfo
->num
;
146 request_info
->rep_num
= 0;
147 request_info
->req_time
= pinfo
->abs_ts
;
148 wmem_tree_insert32(request_val
->frames
, pinfo
->num
, (void *)request_info
);
150 if (request_val
&& !is_request
)
152 request_info
= (imap_request_info_t
*)wmem_tree_lookup32_le(request_val
->frames
, pinfo
->num
);
155 request_info
->rep_num
= pinfo
->num
;
162 request_info
= (imap_request_info_t
*)wmem_tree_lookup32_le(request_val
->frames
, pinfo
->num
);
165 if (tree
&& request_info
)
169 /* print request/response tracking in the tree */
172 /* This is a request */
173 if (request_info
->rep_num
)
176 it
= proto_tree_add_uint(tree
, hf_imap_response_in
, NULL
, 0, 0, request_info
->rep_num
);
177 proto_item_set_generated(it
);
182 /* This is a reply */
183 if (request_info
->req_num
)
187 it
= proto_tree_add_uint(tree
, hf_imap_response_to
, NULL
, 0, 0, request_info
->req_num
);
188 proto_item_set_generated(it
);
190 nstime_delta(&ns
, &pinfo
->abs_ts
, &request_info
->req_time
);
191 it
= proto_tree_add_time(tree
, hf_imap_time
, NULL
, 0, 0, &ns
);
192 proto_item_set_generated(it
);
200 dissect_imap_fetch(tvbuff_t
*tvb
, packet_info
*pinfo
,
201 proto_tree
* main_tree
, proto_tree
* imap_tree
, proto_tree
** reqresp_tree
,
202 int fetch_offset
, int offset
, int* next_offset
, bool* first_line
)
205 bool need_more
= true;
207 //All information in encapsulated in () so make sure there are existing and matching parenthesis
208 int first_parenthesis
= tvb_find_uint8(tvb
, fetch_offset
, -1, '(');
209 if (first_parenthesis
>= 0)
211 int remaining_size
= tvb_reported_length_remaining(tvb
, first_parenthesis
+ 1);
212 if (remaining_size
> 0)
214 //look for the size field
215 int size_start
= tvb_find_uint8(tvb
, first_parenthesis
, remaining_size
, '{');
218 int size_end
= tvb_find_uint8(tvb
, size_start
+ 1, remaining_size
- (size_start
- first_parenthesis
), '}');
221 //Have a size field, convert it to an integer to see how long the contents are
223 const char* size_str
= (const char *)tvb_get_string_enc(pinfo
->pool
, tvb
, size_start
+ 1, size_end
- size_start
- 1, ENC_ASCII
);
224 if (ws_strtou32(size_str
, NULL
, &size
))
226 int remaining
= tvb_reported_length_remaining(tvb
, size_end
+ size
);
229 //Look for the ) after the size field
230 int parenthesis_end
= tvb_find_uint8(tvb
, size_end
+ size
, remaining
, ')');
231 if (parenthesis_end
>= 0)
235 // Put the line into the protocol tree.
236 proto_item
*ti
= proto_tree_add_item(imap_tree
, hf_imap_line
, tvb
, offset
, *next_offset
- offset
, ENC_ASCII
| ENC_NA
);
237 *reqresp_tree
= proto_item_add_subtree(ti
, ett_imap_reqresp
);
239 //no need to overwrite column information since subdissector was called
242 next_tvb
= tvb_new_subset_length(tvb
, *next_offset
, size
);
243 call_dissector(imf_handle
, next_tvb
, pinfo
, main_tree
);
244 if ((int)(*next_offset
+ size
) > *next_offset
)
245 (*next_offset
) += size
;
253 //See if there is no size field, just and end of line
254 int linelen
= tvb_find_line_end(tvb
, first_parenthesis
, -1, next_offset
, true);
259 // Put the line into the protocol tree.
260 proto_item
*ti
= proto_tree_add_item(imap_tree
, hf_imap_line
, tvb
, offset
, *next_offset
- offset
, ENC_ASCII
| ENC_NA
);
261 *reqresp_tree
= proto_item_add_subtree(ti
, ett_imap_reqresp
);
270 /* Heuristic to detect plaintext or TLS ciphertext IMAP */
272 check_imap_heur(tvbuff_t
*tvb
)
274 if (!tvb_bytes_exist(tvb
, 0, IMAP_HEUR_LEN
)) {
278 if (!tvb_ascii_isprint(tvb
, 0, IMAP_HEUR_LEN
))
285 dissect_imap(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
288 proto_tree
*imap_tree
, *reqresp_tree
;
289 proto_item
*ti
, *hidden_item
;
292 int folder_offset
= 0;
294 int linelen
, tokenlen
, uidlen
, uid_tokenlen
, folderlen
, folder_tokenlen
;
295 int next_token
, uid_next_token
, folder_next_token
;
296 const char *tokenbuf
= NULL
;
297 const char *command_token
;
299 bool first_line
= true;
300 imap_request_key_t request_key
;
302 conversation_t
*conversation
;
303 imap_state_t
*session_state
;
305 conversation
= find_or_create_conversation(pinfo
);
306 session_state
= (imap_state_t
*)conversation_get_proto_data(conversation
, proto_imap
);
307 if (!session_state
) {
308 session_state
= wmem_new0(wmem_file_scope(), imap_state_t
);
309 session_state
->ssl_requested
= false;
310 if (imap_ssl_heuristic
)
311 session_state
->ssl_heur_tries_left
= 2;
313 session_state
->ssl_heur_tries_left
= -1; /* Disabled */
314 conversation_add_proto_data(conversation
, proto_imap
, session_state
);
317 request_key
.tag
= NULL
;
318 request_key
.conversation
= conversation
->conv_index
;
320 if (imap_ssl_heuristic
&& session_state
->ssl_heur_tries_left
< 0) {
321 /* Preference changed to enabled */
322 session_state
->ssl_heur_tries_left
= 2;
324 else if (!imap_ssl_heuristic
&& session_state
->ssl_heur_tries_left
>= 0) {
325 /* Preference changed to disabled */
326 session_state
->ssl_heur_tries_left
= -1;
330 * It is possible the IMAP session is already running over TLS and the
331 * STARTTLS request/response happened before the capture began. Don't assume
332 * we have plaintext without performing some heuristic checks first.
333 * We have three cases:
334 * 1. capture includes STARTTLS command: no need for heuristics
335 * 2. capture starts with STARTTLS OK response: next frame will be TLS (need to retry heuristic)
336 * 3. capture start after STARTTLS negotiation: current frame is TLS
338 if (session_state
->ssl_heur_tries_left
> 0) {
339 session_state
->ssl_heur_tries_left
--;
340 if (!check_imap_heur(tvb
)) {
341 ssl_starttls_post_ack(tls_handle
, pinfo
, imap_handle
);
342 session_state
->ssl_heur_tries_left
= 0;
343 return call_dissector(tls_handle
, tvb
, pinfo
, tree
);
347 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "IMAP");
349 if (pinfo
->match_uint
== pinfo
->destport
)
355 * Put the first line from the buffer into the summary
356 * (but leave out the line terminator).
358 linelen
= tvb_find_line_end(tvb
, offset
, -1, &next_offset
, true);
361 pinfo
->desegment_offset
= 0;
362 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
363 return tvb_captured_length(tvb
);
366 ti
= proto_tree_add_item(tree
, proto_imap
, tvb
, offset
, -1, ENC_NA
);
367 imap_tree
= proto_item_add_subtree(ti
, ett_imap
);
369 hidden_item
= proto_tree_add_boolean(imap_tree
, hf_imap_isrequest
, tvb
, 0, 0, is_request
);
370 proto_item_set_hidden(hidden_item
);
372 while(tvb_offset_exists(tvb
, offset
)) {
379 * Find the end of each line
381 * Note that "tvb_find_line_end()" will return a value that is
382 * not longer than what's in the buffer, so the "tvb_get_ptr()"
383 * call won't throw an exception.
385 linelen
= tvb_find_line_end(tvb
, offset
, -1, &next_offset
, true);
388 pinfo
->desegment_offset
= offset
;
389 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
390 return tvb_captured_length(tvb
);
394 * Check that the line doesn't begin with '*', because that's a continuation line.
395 * Otherwise if a tag is present then extract tokens.
397 if (tvb_get_uint8(tvb
, offset
) == '*') {
398 bool show_line
= true;
400 //find up to NUM_LOOKAHEAD_TOKENS tokens
402 int next_pattern
= offset
, token_count
= 0;
403 struct simple_token_info tokens
[NUM_LOOKAHEAD_TOKENS
];
406 start_offset
= next_pattern
+1;
407 next_pattern
= tvb_ws_mempbrk_pattern_uint8(tvb
, start_offset
, next_offset
- start_offset
, &pbrk_whitespace
, NULL
);
408 if (next_pattern
> start_offset
)
410 tokens
[token_count
].token
= tvb_get_string_enc(pinfo
->pool
, tvb
, start_offset
, next_pattern
-start_offset
, ENC_ASCII
);
411 tokens
[token_count
].token_start_offset
= start_offset
;
412 tokens
[token_count
].token_end_offset
= next_pattern
;
415 } while ((next_pattern
!= -1) && (token_count
< NUM_LOOKAHEAD_TOKENS
));
417 if (token_count
>= 2)
419 bool need_more
= false;
420 for (int token
= 0; token
< token_count
; token
++)
422 if (!tvb_strncaseeql(tvb
, tokens
[token
].token_start_offset
, "FETCH", tokens
[token
].token_end_offset
- tokens
[token
].token_start_offset
))
424 //FETCH command. Presume we need more data until we find a complete command
425 need_more
= dissect_imap_fetch(tvb
, pinfo
, tree
, imap_tree
, &reqresp_tree
,
426 tokens
[token
].token_end_offset
, offset
, &next_offset
, &first_line
);
437 pinfo
->desegment_offset
= offset
;
438 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
439 return tvb_captured_length(tvb
);
444 proto_tree_add_item(imap_tree
, hf_imap_line
, tvb
, offset
, next_offset
- offset
, ENC_ASCII
| ENC_NA
);
449 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s: %s", is_request
? "Request" : "Response", tvb_format_text(pinfo
->pool
, tvb
, offset
, linelen
));
453 // Put the line into the protocol tree.
454 ti
= proto_tree_add_item(imap_tree
, hf_imap_line
, tvb
, offset
, next_offset
- offset
, ENC_ASCII
| ENC_NA
);
455 reqresp_tree
= proto_item_add_subtree(ti
, ett_imap_reqresp
);
458 * Show each line as requests or replies + tags.
462 * Add the line as request or reply data.
465 proto_tree_add_item(reqresp_tree
, (is_request
) ? hf_imap_request
: hf_imap_response
, tvb
, offset
, linelen
, ENC_ASCII
|ENC_NA
);
469 * Extract the first token, and, if there is a first
470 * token, add it as the request or reply tag.
472 tokenlen
= tvb_get_token_len(tvb
, offset
, linelen
, &next_token
, false);
474 const char* tag
= (const char*)tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, tokenlen
, ENC_ASCII
);
475 request_key
.tag
= wmem_ascii_strdown(pinfo
->pool
, tag
, strlen(tag
));
477 proto_tree_add_string(reqresp_tree
, (is_request
) ? hf_imap_request_tag
: hf_imap_response_tag
, tvb
, offset
, tokenlen
, tag
);
478 hidden_item
= proto_tree_add_string(reqresp_tree
, hf_imap_tag
, tvb
, offset
, tokenlen
, tag
);
479 proto_item_set_hidden(hidden_item
);
481 linelen
-= (next_token
-offset
);
486 * Extract second token, and, if there is a second
487 * token, and it's not uid, add it as the request or reply command.
489 tokenlen
= tvb_get_token_len(tvb
, offset
, linelen
, &next_token
, false);
492 tokenbuf
= (const char*)tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, tokenlen
, ENC_ASCII
);
493 tokenbuf
= wmem_ascii_strdown(pinfo
->pool
, tokenbuf
, tokenlen
);
495 if (is_request
&& !tvb_strncaseeql(tvb
, offset
, "UID", tokenlen
)) {
496 proto_tree_add_item(reqresp_tree
, hf_imap_request_uid
, tvb
, offset
, tokenlen
, ENC_ASCII
|ENC_NA
);
498 * UID is a precursor to a command, if following the tag,
499 * so move to next token to grab the actual command.
501 uidlen
= linelen
- (next_token
- offset
);
502 uid_offset
= next_token
;
503 uid_tokenlen
= tvb_get_token_len(tvb
, next_token
, uidlen
, &uid_next_token
, false);
504 if (uid_tokenlen
!= 0) {
505 proto_tree_add_item(reqresp_tree
, hf_imap_request_command
, tvb
, uid_offset
, uid_tokenlen
, ENC_ASCII
);
506 hidden_item
= proto_tree_add_item(reqresp_tree
, hf_imap_command
, tvb
, offset
, tokenlen
, ENC_ASCII
| ENC_NA
);
507 proto_item_set_hidden(hidden_item
);
510 * Save command string to do specialized processing.
512 commandlen
= uid_tokenlen
;
513 command_token
= (const char*)tvb_get_string_enc(pinfo
->pool
, tvb
, next_token
, commandlen
, ENC_ASCII
);
514 command_token
= wmem_ascii_strdown(pinfo
->pool
, command_token
, commandlen
);
516 folderlen
= linelen
- (uid_next_token
- offset
);
517 folder_offset
= uid_next_token
;
518 folder_tokenlen
= tvb_get_token_len(tvb
, uid_next_token
, folderlen
, &folder_next_token
, false);
522 * Not a UID request so perform normal parsing.
524 proto_tree_add_item(reqresp_tree
, (is_request
) ? hf_imap_request_command
: hf_imap_response_status
, tvb
, offset
, tokenlen
, ENC_ASCII
|ENC_NA
);
526 hidden_item
= proto_tree_add_item(reqresp_tree
, hf_imap_command
, tvb
, offset
, tokenlen
, ENC_ASCII
| ENC_NA
);
527 proto_item_set_hidden(hidden_item
);
530 * Save command string to do specialized processing.
532 commandlen
= tokenlen
;
533 command_token
= (const char*)tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, commandlen
, ENC_ASCII
);
534 command_token
= wmem_ascii_strdown(pinfo
->pool
, command_token
, commandlen
);
536 folderlen
= linelen
- (next_token
- offset
);
537 folder_offset
= next_token
;
538 folder_tokenlen
= tvb_get_token_len(tvb
, next_token
, folderlen
, &folder_next_token
, false);
542 if (commandlen
> 0) { // implies is_request (i.e. can be true only if is_request but is not equivalent)
543 if (strncmp(command_token
, "select", commandlen
) == 0 ||
544 strncmp(command_token
, "examine", commandlen
) == 0 ||
545 strncmp(command_token
, "create", commandlen
) == 0 ||
546 strncmp(command_token
, "delete", commandlen
) == 0 ||
547 strncmp(command_token
, "rename", commandlen
) == 0 ||
548 strncmp(command_token
, "subscribe", commandlen
) == 0 ||
549 strncmp(command_token
, "unsubscribe", commandlen
) == 0 ||
550 strncmp(command_token
, "status", commandlen
) == 0 ||
551 strncmp(command_token
, "append", commandlen
) == 0 ||
552 strncmp(command_token
, "search", commandlen
) == 0) {
555 * These commands support folder as an argument,
556 * so parse out the folder name.
558 if (folder_tokenlen
!= 0)
559 proto_tree_add_item(reqresp_tree
, hf_imap_request_folder
, tvb
, folder_offset
, folder_tokenlen
, ENC_ASCII
| ENC_NA
);
561 else if ((linelen
> 0) && strncmp(command_token
, "copy", commandlen
) == 0) {
563 * Handle the copy command separately since folder
564 * is the second argument for this command.
566 folderlen
= linelen
- (folder_next_token
- offset
);
567 folder_offset
= folder_next_token
;
568 folder_tokenlen
= tvb_get_token_len(tvb
, folder_offset
, folderlen
, &folder_next_token
, false);
570 if (folder_tokenlen
!= 0)
571 proto_tree_add_item(reqresp_tree
, hf_imap_request_folder
, tvb
, folder_offset
, folder_tokenlen
, ENC_ASCII
| ENC_NA
);
573 else if (strncmp(command_token
, "starttls", commandlen
) == 0) {
574 /* If next response is OK, then TLS should be commenced. */
575 session_state
->ssl_requested
= true;
577 else if (strncmp(command_token
, "login", commandlen
) == 0) {
578 int usernamelen
= linelen
- (next_token
- offset
);
579 int username_offset
= next_token
;
580 int username_next_token
;
581 int username_tokenlen
= tvb_get_token_len(tvb
, next_token
, usernamelen
, &username_next_token
, false);
582 char *username
= (char*)tvb_get_string_enc(pinfo
->pool
, tvb
, username_offset
, username_tokenlen
, ENC_ASCII
| ENC_NA
);
583 proto_tree_add_string(reqresp_tree
, hf_imap_request_username
, tvb
, username_offset
, username_tokenlen
, username
);
585 int passwordlen
= linelen
- (username_next_token
- offset
);
586 int password_offset
= username_next_token
;
587 int password_tokenlen
= tvb_get_token_len(tvb
, username_next_token
, passwordlen
, NULL
, false);
588 const char* password
= tvb_get_string_enc(pinfo
->pool
, tvb
, password_offset
+ 1, password_tokenlen
- 2, ENC_ASCII
| ENC_NA
);
589 proto_tree_add_string(reqresp_tree
, hf_imap_request_password
, tvb
, password_offset
, password_tokenlen
, password
);
591 tap_credential_t
* auth
= wmem_new0(pinfo
->pool
, tap_credential_t
);
592 auth
->num
= auth
->username_num
= pinfo
->num
;
593 auth
->password_hf_id
= hf_imap_request_password
;
594 auth
->username
= username
;
595 auth
->proto
= "IMAP";
596 tap_queue_packet(credentials_tap
, pinfo
, auth
);
601 //See if there is the response command
602 int command_next_token
;
603 int command_offset
= next_token
;
604 commandlen
= linelen
- (next_token
-offset
);
605 commandlen
= tvb_get_token_len(tvb
, next_token
, commandlen
, &command_next_token
, false);
606 if (commandlen
> 0) {
607 proto_tree_add_item(reqresp_tree
, hf_imap_response_command
, tvb
, command_offset
, commandlen
, ENC_ASCII
| ENC_NA
);
608 hidden_item
= proto_tree_add_item(reqresp_tree
, hf_imap_command
, tvb
, command_offset
, commandlen
, ENC_ASCII
| ENC_NA
);
609 proto_item_set_hidden(hidden_item
);
613 /* If not yet switched to TLS, check for STARTTLS. */
614 if (session_state
->ssl_requested
) {
615 if (!is_request
&& (tokenbuf
!= NULL
) && strncmp(tokenbuf
, "ok", tokenlen
) == 0) {
616 /* STARTTLS accepted, next reply will be TLS. */
617 ssl_starttls_ack(tls_handle
, pinfo
, imap_handle
);
618 if (session_state
->ssl_heur_tries_left
> 0) {
619 session_state
->ssl_heur_tries_left
= 0;
621 session_state
->ssl_requested
= false;
626 /* Add request/response statistics */
627 if (request_key
.tag
!= NULL
)
629 imap_match_request(pinfo
, reqresp_tree
, &request_key
, is_request
);
633 offset
= next_offset
; /* Skip over last line and \r\n at the end of it */
636 // If there is only lines that begin with *, at least show the first one
638 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s: %s", is_request
? "Request" : "Response", tvb_format_text(pinfo
->pool
, tvb
, 0, linelen
));
641 return tvb_captured_length(tvb
);
645 proto_register_imap(void)
647 static hf_register_info hf
[] = {
649 { &hf_imap_isrequest
,
650 { "Request", "imap.isrequest",
651 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
652 "true if IMAP request, false otherwise", HFILL
}
655 { "Line", "imap.line",
656 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
657 "A line of an IMAP message", HFILL
}
660 { "Request", "imap.request",
661 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
662 "Remainder of request line", HFILL
}
664 { &hf_imap_request_tag
,
665 { "Request Tag", "imap.request_tag",
666 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
667 "First token of request line", HFILL
}
670 { "Response", "imap.response",
671 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
672 "Remainder of response line", HFILL
}
674 { &hf_imap_response_tag
,
675 { "Response Tag", "imap.response_tag",
676 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
677 "First token of response line", HFILL
}
679 { &hf_imap_request_command
,
680 { "Request Command", "imap.request.command",
681 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
682 "Request command name", HFILL
}
684 { &hf_imap_response_command
,
685 { "Response Command", "imap.response.command",
686 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
687 "Response command name", HFILL
}
689 { &hf_imap_response_status
,
690 { "Response Status", "imap.response.status",
691 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
692 "Response status code", HFILL
}
696 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
697 "First token of line", HFILL
}
700 { "Command", "imap.command",
701 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
702 "Request or Response command name", HFILL
}
704 { &hf_imap_request_folder
,
705 { "Request Folder", "imap.request.folder",
706 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
707 "Request command folder", HFILL
}
709 { &hf_imap_request_uid
,
710 { "Request isUID", "imap.request.command.uid",
711 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
712 "Request command uid", HFILL
}
714 { &hf_imap_request_username
,
715 { "Request Username", "imap.request.username",
716 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
717 "Request command username", HFILL
}
719 { &hf_imap_request_password
,
720 { "Request Password", "imap.request.password",
721 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
722 "Request command password", HFILL
}
725 /* Request/Response Matching */
726 { &hf_imap_response_in
,
727 { "Response In", "imap.response_in",
728 FT_FRAMENUM
, BASE_NONE
, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE
), 0x0,
729 "The response to this IMAP request is in this frame", HFILL
}
731 { &hf_imap_response_to
,
732 { "Request In", "imap.response_to",
733 FT_FRAMENUM
, BASE_NONE
, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST
), 0x0,
734 "This is a response to the IMAP request in this frame", HFILL
}
737 { "Response Time", "imap.time",
738 FT_RELATIVE_TIME
, BASE_NONE
, NULL
, 0x0,
739 "The time between the request and response", HFILL
}
743 static int *ett
[] = {
748 module_t
*imap_module
;
750 proto_imap
= proto_register_protocol("Internet Message Access Protocol", "IMAP", "imap");
752 imap_handle
= register_dissector("imap", dissect_imap
, proto_imap
);
754 proto_register_field_array(proto_imap
, hf
, array_length(hf
));
755 proto_register_subtree_array(ett
, array_length(ett
));
757 imap_module
= prefs_register_protocol(proto_imap
, NULL
);
758 prefs_register_bool_preference(imap_module
, "ssl_heuristic",
759 "Use heuristic detection for TLS",
760 "Whether to use heuristics for post-STARTTLS detection of encrypted IMAP conversations",
761 &imap_ssl_heuristic
);
763 imap_requests
= wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), imap_request_hash
, imap_request_equal
);
765 /* compile patterns */
766 ws_mempbrk_compile(&pbrk_whitespace
, " \t\r\n");
768 credentials_tap
= register_tap("credentials");
772 proto_reg_handoff_imap(void)
774 dissector_add_uint_with_preference("tcp.port", TCP_PORT_IMAP
, imap_handle
);
775 ssl_dissector_add(TCP_PORT_SSL_IMAP
, imap_handle
);
776 tls_handle
= find_dissector("tls");
777 imf_handle
= find_dissector("imf");
780 * Editor modelines - https://www.wireshark.org/tools/modelines.html
785 * indent-tabs-mode: nil
788 * vi: set shiftwidth=2 tabstop=8 expandtab:
789 * :indentSize=2:tabSize=8:noTabs=true