Skip to content

IMAP protocol parser, logger and sticky buffers v6#15400

Open
glongo wants to merge 4 commits into
OISF:mainfrom
glongo:dev-imap-proto-v6
Open

IMAP protocol parser, logger and sticky buffers v6#15400
glongo wants to merge 4 commits into
OISF:mainfrom
glongo:dev-imap-proto-v6

Conversation

@glongo
Copy link
Copy Markdown
Contributor

@glongo glongo commented May 16, 2026

Changes:

  • email object inside imap event is no longer logged. Existing email code will be refactored after this PR is merged in order to introduce a dedicated email event.
  • Updated SID range
  • Bounded missing request/response.

Link to ticket: https://redmine.openinfosecfoundation.org/issues/8276

Previous PR: #15209

SV_BRANCH=OISF/suricata-verify#2908

glongo added 4 commits May 16, 2026 10:40
This introduces a parser for IMAP protocol.

Ticket OISF#8276
This introduces a logger for IMAP protocol.

Ticket OISF#8276
This implements the following sticky buffers for IMAP protocol:
- imap.request
- imap.response

The following frames have been added:
- imap.body
- imap.headers
- imap.pdu

The following email sticky buffers have been updated to work with IMAP:
- email.from
- email.subject
- email.to
- email.cc
- email.date
- email.message_id
- email.x_mailer

The following email sticky buffers have been added and are supported
only for IMAP:
- email.command
- email.body
- email.header
- email.header.name
- email.header.value

Ticket OISF#8276
@codecov
Copy link
Copy Markdown

codecov Bot commented May 16, 2026

Codecov Report

❌ Patch coverage is 81.85373% with 464 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.61%. Comparing base (bb4e79c) to head (e6cca48).
⚠️ Report is 86 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #15400      +/-   ##
==========================================
- Coverage   82.65%   82.61%   -0.04%     
==========================================
  Files         996      999       +3     
  Lines      271109   273624    +2515     
==========================================
+ Hits       224076   226057    +1981     
- Misses      47033    47567     +534     
Flag Coverage Δ
fuzzcorpus 60.50% <15.04%> (-0.52%) ⬇️
livemode 18.28% <11.91%> (-0.09%) ⬇️
netns 22.45% <11.91%> (-0.17%) ⬇️
pcap 45.37% <63.00%> (+0.16%) ⬆️
suricata-verify 66.46% <74.97%> (+0.05%) ⬆️
unittests 58.51% <53.46%> (-0.05%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@suricata-qa
Copy link
Copy Markdown

Information: QA ran without warnings.

Pipeline = 31514

@catenacyber catenacyber added the needs rebase Needs rebase to main label May 21, 2026
@catenacyber
Copy link
Copy Markdown
Contributor

Needs a rebase now

Copy link
Copy Markdown
Contributor

@catenacyber catenacyber left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the work, needs a rebase

CI/QA : ✅
Git ID set : looks fine for me
CLA : you already contributed
Doc update : nice :-)
Redmine ticket : ok, should https://redmine.openinfosecfoundation.org/issues/3244 be closed as duplicate ?
Rustfmt : 🟡 please add the check in CI see .github/workflows/builds.yml: - run: rustfmt --check rust/src/dns/*.rs
Tests : some unanswered questions on SV PR like OISF/suricata-verify#2908 (comment)
Dependencies added: none
Code : looking
Commits segmentation : I would squash parser and logger but ok
Commit messages : cool

@victorjulien
Copy link
Copy Markdown
Member

In the new PR, please add a explanation of the transaction state machine(s) and life cycle, including how transactions and other data structures are bounded.

Comment thread rust/src/imap/imap.rs
pub direction: u8,
}

pub fn extract_command_from_requests(requests: &[ImapMessage]) -> Vec<u8> {
Copy link
Copy Markdown
Contributor

@catenacyber catenacyber May 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be pub ? (I do not think so)

Comment thread rust/src/imap/imap.rs
pub fn extract_command_from_requests(requests: &[ImapMessage]) -> Vec<u8> {
for req in requests {
if let ImapMessageType::Command { command, arguments } = &req.message {
return if matches!(command, ImapCommand::Uid) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is uid different ? please comment in the code ;-)

Comment thread rust/src/imap/imap.rs
return if matches!(command, ImapCommand::Uid) {
arguments
.first()
.map(|a| String::from_utf8_lossy(a).to_lowercase().into_bytes())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why converting to string and then back to Vec with loss on the way ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ops, forgot to remove the string part.

Comment thread rust/src/imap/imap.rs
.map(|a| String::from_utf8_lossy(a).to_lowercase().into_bytes())
.unwrap_or_default()
} else {
command.to_string().to_lowercase().into_bytes()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why lowercasing ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because in that way the sticky buffer can match with a single case.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should preserve casing, and let rule writers use to_lowercase transform if they want

Comment thread rust/src/imap/imap.rs
}

impl ImapTransaction {
pub fn new() -> ImapTransaction {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not just derive Default ?

Comment thread rust/src/imap/logger.rs
.iter()
.map(|a| String::from_utf8_lossy(a))
.collect();
js.append_string(&format!("{} {} {}", tag, cmd, args.join(" ")))?;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still feels strange to recompute what we have seen on the wire...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I can just log the raw_line directly.

Comment thread rust/src/imap/logger.rs
} = &response.message
{
if let Some(merged) = fetch.get_email() {
let _message_email = Some(merged);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this unused code ?

Comment thread rust/src/imap/detect.rs
}
let hname = CStr::from_ptr(hname);
if let Ok(hname_str) = hname.to_str() {
let normalized = hname_str.to_lowercase().replace('-', "_");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this normalization from message-id to message_id ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I do not see SV tests for this normlaization for x-mailer for example

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following the same convention used by SMTP to log email events.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this is not logging, this is detection

Is IMAP using x_mailer when SMTP is using x-mailer in the network traffic ?

Comment thread rust/src/imap/detect.rs
}
let hname = CStr::from_ptr(hname);
if let Ok(hname_str) = hname.to_str() {
let normalized = hname_str.to_lowercase().replace('-', "_");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused, right ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

used in line 201.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean you can use hname_str straight away as the only caller of SCDetectImapEmailGetDataArray passes a string that is already "normalized"


email.body_md5
--------------

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works only for SMTP, right ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, please add it as you did for the other keywords ;-)

email.body
----------

Matches on the body content of an email transferred over IMAP.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a limit of the size of the body we inspect, right ?
So, I think it should be mentioned in the docs

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the limit is applied when an email is parsed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs rebase Needs rebase to main

Development

Successfully merging this pull request may close these issues.

4 participants