Coverage Report

Created: 2026-11-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/rust/src/dcerpc/log.rs
Line
Count
Source
1
/* Copyright (C) 2020 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
use uuid::Uuid;
18
19
use crate::dcerpc::dcerpc::*;
20
use crate::dcerpc::dcerpc_udp::*;
21
use crate::jsonbuilder::{JsonBuilder, JsonError};
22
23
0
fn log_dcerpc_header_tcp(
24
0
    jsb: &mut JsonBuilder, state: &DCERPCState, tx: &DCERPCTransaction,
25
0
) -> Result<(), JsonError> {
26
0
    if tx.req_done && !tx.req_lost {
27
0
        jsb.set_string("request", &dcerpc_type_string(tx.req_cmd))?;
28
0
        match tx.req_cmd {
29
            DCERPC_TYPE_REQUEST => {
30
0
                jsb.open_object("req")?;
31
0
                jsb.set_uint("opnum", tx.opnum as u64)?;
32
0
                jsb.set_uint("frag_cnt", tx.frag_cnt_ts as u64)?;
33
0
                jsb.set_uint("stub_data_size", tx.stub_data_buffer_ts.len() as u64)?;
34
0
                jsb.close()?;
35
36
0
                let mut found = false;
37
0
                let mark = jsb.get_mark();
38
0
                jsb.open_array("interfaces")?;
39
0
                for uuid in &state.interface_uuids {
40
0
                    if tx.ctxid == uuid.ctxid {
41
0
                        found = true;
42
0
                        jsb.start_object()?;
43
0
                        let ifstr = Uuid::from_slice(uuid.uuid.as_slice());
44
0
                        let ifstr = ifstr.map(|uuid| uuid.to_hyphenated().to_string()).unwrap();
45
0
                        jsb.set_string("uuid", &ifstr)?;
46
0
                        let vstr = format!("{}.{}", uuid.version, uuid.versionminor);
47
0
                        jsb.set_string("version", &vstr)?;
48
0
                        if uuid.acked {
49
0
                            jsb.set_uint("ack_result", uuid.result as u64)?;
50
0
                        }
51
0
                        jsb.close()?;
52
0
                    }
53
                }
54
0
                if !found {
55
0
                    jsb.restore_mark(&mark)?;
56
                } else {
57
0
                    jsb.close()?;
58
                }
59
            }
60
            DCERPC_TYPE_BIND => {
61
0
                let mut found = false;
62
0
                let mark = jsb.get_mark();
63
0
                jsb.open_array("interfaces")?;
64
0
                for uuid in &state.interface_uuids {
65
0
                    if tx.call_id == uuid.call_id {
66
0
                        found = true;
67
0
                        jsb.start_object()?;
68
0
                        let ifstr = Uuid::from_slice(uuid.uuid.as_slice());
69
0
                        let ifstr = ifstr.map(|uuid| uuid.to_hyphenated().to_string()).unwrap();
70
0
                        jsb.set_string("uuid", &ifstr)?;
71
0
                        let vstr = format!("{}.{}", uuid.version, uuid.versionminor);
72
0
                        jsb.set_string("version", &vstr)?;
73
0
                        if uuid.acked {
74
0
                            jsb.set_uint("ack_result", uuid.result as u64)?;
75
0
                        }
76
0
                        jsb.close()?;
77
0
                    }
78
                }
79
0
                if !found {
80
0
                    jsb.restore_mark(&mark)?;
81
                } else {
82
0
                    jsb.close()?;
83
                }
84
            }
85
0
            _ => {}
86
        }
87
    } else {
88
0
        jsb.set_string("request", "REQUEST_LOST")?;
89
    }
90
91
0
    if tx.resp_done && !tx.resp_lost {
92
0
        jsb.set_string("response", &dcerpc_type_string(tx.resp_cmd))?;
93
        #[allow(clippy::single_match)]
94
0
        match tx.resp_cmd {
95
            DCERPC_TYPE_RESPONSE => {
96
0
                jsb.open_object("res")?;
97
0
                jsb.set_uint("frag_cnt", tx.frag_cnt_tc as u64)?;
98
0
                jsb.set_uint("stub_data_size", tx.stub_data_buffer_tc.len() as u64)?;
99
0
                jsb.close()?;
100
            }
101
0
            _ => {} // replicating behavior from smb
102
        }
103
    } else {
104
0
        jsb.set_string("response", "UNREPLIED")?;
105
    }
106
107
0
    jsb.set_uint("call_id", tx.call_id as u64)?;
108
0
    let vstr = format!("5.{}", tx.min_version);
109
0
    jsb.set_string("rpc_version", &vstr)?;
110
111
0
    return Ok(());
112
0
}
113
114
0
fn log_dcerpc_header_udp(
115
0
    jsb: &mut JsonBuilder, _state: &DCERPCUDPState, tx: &DCERPCTransaction,
116
0
) -> Result<(), JsonError> {
117
0
    if tx.req_done && !tx.req_lost {
118
0
        jsb.set_string("request", &dcerpc_type_string(tx.req_cmd))?;
119
        #[allow(clippy::single_match)]
120
0
        match tx.req_cmd {
121
            DCERPC_TYPE_REQUEST => {
122
0
                jsb.open_object("req")?;
123
0
                jsb.set_uint("opnum", tx.opnum as u64)?;
124
0
                jsb.set_uint("frag_cnt", tx.frag_cnt_ts as u64)?;
125
0
                jsb.set_uint("stub_data_size", tx.stub_data_buffer_ts.len() as u64)?;
126
0
                jsb.close()?;
127
            }
128
0
            _ => {}
129
        }
130
    } else {
131
0
        jsb.set_string("request", "REQUEST_LOST")?;
132
    }
133
134
0
    if tx.resp_done && !tx.resp_lost {
135
0
        jsb.set_string("response", &dcerpc_type_string(tx.resp_cmd))?;
136
        #[allow(clippy::single_match)]
137
0
        match tx.resp_cmd {
138
            DCERPC_TYPE_RESPONSE => {
139
0
                jsb.open_object("res")?;
140
0
                jsb.set_uint("frag_cnt", tx.frag_cnt_tc as u64)?;
141
0
                jsb.set_uint("stub_data_size", tx.stub_data_buffer_tc.len() as u64)?;
142
0
                jsb.close()?;
143
            }
144
0
            _ => {} // replicating behavior from smb
145
        }
146
    } else {
147
0
        jsb.set_string("response", "UNREPLIED")?;
148
    }
149
0
    let activityuuid = Uuid::from_slice(tx.activityuuid.as_slice());
150
0
    let activityuuid = activityuuid
151
0
        .map(|uuid| uuid.to_hyphenated().to_string())
152
0
        .unwrap();
153
0
    jsb.set_string("activityuuid", &activityuuid)?;
154
0
    jsb.set_uint("seqnum", tx.seqnum as u64)?;
155
0
    jsb.set_string("rpc_version", "4.0")?;
156
0
    return Ok(());
157
0
}
158
159
#[no_mangle]
160
0
pub extern "C" fn SCDcerpcLogJsonRecordTcp(
161
0
    state: &DCERPCState, tx: &DCERPCTransaction, jsb: &mut JsonBuilder,
162
0
) -> bool {
163
0
    log_dcerpc_header_tcp(jsb, state, tx).is_ok()
164
0
}
165
166
#[no_mangle]
167
0
pub extern "C" fn SCDcerpcLogJsonRecordUdp(
168
0
    state: &DCERPCUDPState, tx: &DCERPCTransaction, jsb: &mut JsonBuilder,
169
0
) -> bool {
170
0
    log_dcerpc_header_udp(jsb, state, tx).is_ok()
171
0
}