Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

detect: add ldap operation keywords - draft v2 #12343

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

AkakiAlice
Copy link
Contributor

@AkakiAlice AkakiAlice commented Jan 6, 2025

Ticket: #7453

Contribution style:

Our Contribution agreements:

Changes (if applicable):

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

Description:

  • Implement ldap.request.operation and ldap.responses.operation keywords.

detect.rs changes:

  • Add constants for any and all: line 32, line 33
  • Create structure DetectLdapRespData to store ldap.responses.operation data: line 36
  • Create function to parse ldap.responses.operation values: line 59
  • Implement switch case to check index value: line 169

ldap-keywords.rst changes:

SV_BRANCH=OISF/suricata-verify#2216
Previous PR= #12321

ldap.request.operation matches on Lightweight Directory Access Protocol request operations
ldap.responses.operation matches on Lightweight Directory Access Protocol response operations
Both are unsigned 8-bit integer
Don't support prefiltering

Ticket: OISF#7453
@AkakiAlice
Copy link
Contributor Author

I'm not quite sure about these values I used for the constants. Should I approach it differently to be able to handle negative indexes, just like vlan.id?

Copy link

codecov bot commented Jan 6, 2025

Codecov Report

Attention: Patch coverage is 77.01149% with 40 lines in your changes missing coverage. Please review.

Project coverage is 83.23%. Comparing base (def22fa) to head (061a50a).

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #12343      +/-   ##
==========================================
- Coverage   83.23%   83.23%   -0.01%     
==========================================
  Files         912      913       +1     
  Lines      257647   257821     +174     
==========================================
+ Hits       214450   214588     +138     
- Misses      43197    43233      +36     
Flag Coverage Δ
fuzzcorpus 61.15% <20.11%> (-0.07%) ⬇️
livemode 19.39% <20.11%> (-0.01%) ⬇️
pcap 44.41% <20.11%> (+0.01%) ⬆️
suricata-verify 62.90% <77.01%> (+0.03%) ⬆️
unittests 59.16% <20.11%> (-0.03%) ⬇️

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

3 search_request
4 search_result_entry
5 search_result_done
19 search_result_reference
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we should keep the code ordered... @jufajardini ?


.. container:: example-rule

alert tcp any any -> any any (msg:"Test LDAP bind request"; :example-rule-emphasis:`ldap.request.operation:0;` sid:1;)
Copy link
Contributor

Choose a reason for hiding this comment

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

You should also say somewhere that you can use the strings...

ldap.responses.operation uses :ref:`unsigned 8-bit integer <rules-integer-keywords>`.

An LDAP request operation can receive multiple responses. By default, the ldap.responses.operation
keyword matches all indices, but it is possible to specify a particular index for matching
Copy link
Contributor

Choose a reason for hiding this comment

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

By default, should be any, not all

[default] Match all indexes
all Match only if all indexes match
any Match all indexes
0>= Match specific index
Copy link
Contributor

Choose a reason for hiding this comment

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

Need also negative indexes


.. container:: example-rule

alert tcp any any -> any any (msg:"Test LDAP search response"; :example-rule-emphasis:`ldap.responses.operation:search_result_entry,all;` sid:1;)
Copy link
Contributor

Choose a reason for hiding this comment

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

Also need a ldap.responses.count keyword :-)

ModDnRequest = 12,
ModDnResponse = 13,
CompareRequest = 14,
CompareResponse = 15,
Copy link
Contributor

Choose a reason for hiding this comment

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

AbandonRequest is also needed...
Can you at least put a comment about it ?

#[derive(Debug, PartialEq)]
pub struct DetectLdapRespData {
pub response: DetectUintData<u8>, //ldap response code
pub index: i8,
Copy link
Contributor

Choose a reason for hiding this comment

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

May we should support indexes bigger than 255==u8::MAX

Let's try i32

Copy link
Contributor

Choose a reason for hiding this comment

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

And if we can do pure rust here, you can have the struct not public, and having the index have a type that is an enum that is either Any, All, or Index(i32)

use std::os::raw::{c_int, c_void};
use std::str::FromStr;

pub const DETECT_LDAP_RESP_ANY: i8 = -1;
Copy link
Contributor

Choose a reason for hiding this comment

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

These values -1 and -2 should mean last and before last index...

return std::ptr::null_mut();
}

pub fn aux_ldap_parse_protocol_resp_op(s: &str) -> Option<DetectLdapRespData> {
Copy link
Contributor

Choose a reason for hiding this comment

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

This function does not need to be pub

let tx = cast_pointer!(tx, LdapTransaction);
let ctx = cast_pointer!(ctx, DetectUintData<u8>);
if let Some(request) = &tx.request {
let option: u8 = request.protocol_op.to_u8();
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need the : u8 here ?

}
let response: &LdapMessage = &tx.responses[index];
let option: u8 = response.protocol_op.to_u8();
if rs_detect_u8_match(option, &ctx.response) == 1 {
Copy link
Contributor

Choose a reason for hiding this comment

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

return rs_detect_u8_match(option, &ctx.response) saves 2 lines ;-)

as *const libc::c_char,
AppLayerTxMatch: Some(ldap_detect_responses_operation_match),
Setup: ldap_detect_responses_operation_setup,
Free: Some(ldap_detect_operation_free),
Copy link
Contributor

Choose a reason for hiding this comment

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

ldap_detect_operation_free frees a DetectUintData<u8>when it should free a DetectLdapRespData

I am afraid you need 2 different free functions

Copy link
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 Alice, nice work

Main things that remain to do

  • negative indices
  • AbandonRequest support
  • ldap.reponses.count keyword

CI : 🟢
Code : cool
Commits segmentation : ok
Commit messages : nice
Git ID set : looks fine for me
CLA : you already contributed
Doc update : good
Redmine ticket : ok
Rustfmt : ok
Tests : ok, I left some remarks in SV
Dependencies added: none

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

Successfully merging this pull request may close these issues.

2 participants