Coverage Report

Created: 2025-07-23 07:29

/src/suricata7/rust/src/smb/dcerpc.rs
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2017 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
18
// written by Victor Julien
19
20
use uuid;
21
use crate::smb::smb::*;
22
use crate::smb::smb2::*;
23
use crate::smb::dcerpc_records::*;
24
use crate::smb::events::*;
25
use crate::dcerpc::dcerpc::*;
26
use crate::smb::smb_status::*;
27
28
impl SMBCommonHdr {
29
    /// helper for DCERPC tx tracking. Check if we need
30
    /// to use the msg_id/multiplex_id in TX tracking.
31
    ///
32
633k
    pub fn to_dcerpc(&self, vercmd: &SMBVerCmdStat) -> SMBCommonHdr {
33
633k
        // only use the msg id for IOCTL, not for READ/WRITE
34
633k
        // as there request/response are different transactions
35
633k
        let mut use_msg_id = self.msg_id;
36
633k
        match vercmd.get_version() {
37
            2 => {
38
374k
                let (_, cmd2) = vercmd.get_smb2_cmd();
39
374k
                let x = match cmd2 {
40
122k
                    SMB2_COMMAND_READ => { 0 },
41
245k
                    SMB2_COMMAND_WRITE => { 0 },
42
6.88k
                    SMB2_COMMAND_IOCTL => { self.msg_id },
43
0
                    _ => { self.msg_id },
44
                };
45
374k
                use_msg_id = x;
46
            },
47
258k
            1 => {
48
258k
                SCLogDebug!("FIXME TODO");
49
258k
                //let (_, cmd1) = vercmd.get_smb1_cmd();
50
258k
                //if cmd1 != SMB1_COMMAND_IOCTL {
51
258k
                use_msg_id = 0;
52
258k
                //}
53
258k
            },
54
0
            _ => { },
55
        }
56
633k
        SMBCommonHdr {
57
633k
            ssn_id: self.ssn_id,
58
633k
            tree_id: self.tree_id,
59
633k
            msg_id: use_msg_id,
60
633k
            rec_type: SMBHDR_TYPE_DCERPCTX,
61
633k
        }
62
633k
    }
63
}
64
65
#[derive(Default, Debug)]
66
pub struct DCERPCIface {
67
    pub uuid: Vec<u8>,
68
    pub ver: u16,
69
    pub ver_min: u16,
70
    pub ack_result: u16,
71
    pub ack_reason: u16,
72
    pub acked: bool,
73
    pub context_id: u16,
74
}
75
76
impl DCERPCIface {
77
22.0k
    pub fn new(uuid: Vec<u8>, ver: u16, ver_min: u16) -> Self {
78
22.0k
        Self {
79
22.0k
            uuid,
80
22.0k
            ver,
81
22.0k
            ver_min,
82
22.0k
            ..Default::default()
83
22.0k
        }
84
22.0k
    }
85
}
86
87
#[derive(Default, Debug)]
88
pub struct SMBTransactionDCERPC {
89
    pub opnum: u16,
90
    pub context_id: u16,
91
    pub req_cmd: u8,
92
    pub req_set: bool,
93
    pub res_cmd: u8,
94
    pub res_set: bool,
95
    pub call_id: u32,
96
    pub frag_cnt_ts: u16,
97
    pub frag_cnt_tc: u16,
98
    pub stub_data_ts: Vec<u8>,
99
    pub stub_data_tc: Vec<u8>,
100
}
101
102
impl SMBTransactionDCERPC {
103
43.7k
    fn new_request(req: u8, call_id: u32) -> Self {
104
43.7k
        return Self {
105
43.7k
            opnum: 0,
106
43.7k
            context_id: 0,
107
43.7k
            req_cmd: req,
108
43.7k
            req_set: true,
109
43.7k
            call_id,
110
43.7k
            ..Default::default()
111
43.7k
        }
112
43.7k
    }
113
4.89k
    fn new_response(call_id: u32) -> Self {
114
4.89k
       return  Self {
115
4.89k
            call_id,
116
4.89k
            ..Default::default()
117
4.89k
        };
118
4.89k
    }
119
7.03k
    pub fn set_result(&mut self, res: u8) {
120
7.03k
        self.res_set = true;
121
7.03k
        self.res_cmd = res;
122
7.03k
    }
123
}
124
125
impl SMBState {
126
43.7k
    fn new_dcerpc_tx(&mut self, hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, cmd: u8, call_id: u32)
127
43.7k
        -> &mut SMBTransaction
128
43.7k
    {
129
43.7k
        let mut tx = self.new_tx();
130
43.7k
        tx.hdr = hdr;
131
43.7k
        tx.vercmd = vercmd;
132
43.7k
        tx.type_data = Some(SMBTransactionTypeData::DCERPC(
133
43.7k
                    SMBTransactionDCERPC::new_request(cmd, call_id)));
134
43.7k
135
43.7k
        SCLogDebug!("SMB: TX DCERPC created: ID {} hdr {:?}", tx.id, tx.hdr);
136
43.7k
        self.transactions.push_back(tx);
137
43.7k
        let tx_ref = self.transactions.back_mut();
138
43.7k
        return tx_ref.unwrap();
139
43.7k
    }
140
141
4.89k
    fn new_dcerpc_tx_for_response(&mut self, hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, call_id: u32)
142
4.89k
        -> &mut SMBTransaction
143
4.89k
    {
144
4.89k
        let mut tx = self.new_tx();
145
4.89k
        tx.hdr = hdr;
146
4.89k
        tx.vercmd = vercmd;
147
4.89k
        tx.type_data = Some(SMBTransactionTypeData::DCERPC(
148
4.89k
                    SMBTransactionDCERPC::new_response(call_id)));
149
4.89k
150
4.89k
        SCLogDebug!("SMB: TX DCERPC created: ID {} hdr {:?}", tx.id, tx.hdr);
151
4.89k
        self.transactions.push_back(tx);
152
4.89k
        let tx_ref = self.transactions.back_mut();
153
4.89k
        return tx_ref.unwrap();
154
4.89k
    }
155
156
25.5k
    fn get_dcerpc_tx(&mut self, hdr: &SMBCommonHdr, vercmd: &SMBVerCmdStat, call_id: u32)
157
25.5k
        -> Option<&mut SMBTransaction>
158
25.5k
    {
159
25.5k
        let dce_hdr = hdr.to_dcerpc(vercmd);
160
161
        SCLogDebug!("looking for {:?}", dce_hdr);
162
617k
        for tx in &mut self.transactions {
163
608k
            let found = dce_hdr.compare(&tx.hdr.to_dcerpc(vercmd)) &&
164
43.8k
                match tx.type_data {
165
39.5k
                Some(SMBTransactionTypeData::DCERPC(ref x)) => {
166
39.5k
                    x.call_id == call_id
167
                },
168
196k
                _ => { false },
169
            };
170
608k
            if found {
171
15.7k
                tx.tx_data.updated_tc = true;
172
15.7k
                tx.tx_data.updated_ts = true;
173
15.7k
                return Some(tx);
174
592k
            }
175
        }
176
9.82k
        return None;
177
25.5k
    }
178
}
179
180
/// Handle DCERPC request data from a WRITE, IOCTL or TRANS record.
181
/// return bool indicating whether an tx has been created/updated.
182
///
183
73.2k
pub fn smb_write_dcerpc_record(state: &mut SMBState,
184
73.2k
        vercmd: SMBVerCmdStat,
185
73.2k
        hdr: SMBCommonHdr,
186
73.2k
        data: &[u8]) -> bool
187
73.2k
{
188
73.2k
    let mut bind_ifaces : Option<Vec<DCERPCIface>> = None;
189
73.2k
    let mut is_bind = false;
190
73.2k
191
73.2k
    SCLogDebug!("called for {} bytes of data", data.len());
192
73.2k
    match parse_dcerpc_record(data) {
193
67.3k
        Ok((_, dcer)) => {
194
67.3k
            SCLogDebug!("DCERPC: version {}.{} write data {} => {:?}",
195
67.3k
                    dcer.version_major, dcer.version_minor, dcer.data.len(), dcer);
196
67.3k
197
67.3k
            /* if this isn't the first frag, simply update the existing
198
67.3k
             * tx with the additional stub data */
199
67.3k
            if dcer.packet_type == DCERPC_TYPE_REQUEST && !dcer.first_frag {
200
                SCLogDebug!("NOT the first frag. Need to find an existing TX");
201
23.6k
                match parse_dcerpc_request_record(dcer.data, dcer.frag_len, dcer.little_endian) {
202
10.2k
                    Ok((_, recr)) => {
203
10.2k
                        let found = match state.get_dcerpc_tx(&hdr, &vercmd, dcer.call_id) {
204
6.47k
                            Some(tx) => {
205
                                SCLogDebug!("previous CMD {} found at tx {} => {:?}",
206
                                        dcer.packet_type, tx.id, tx);
207
6.47k
                                if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data {
208
6.47k
                                    SCLogDebug!("additional frag of size {}", recr.data.len());
209
6.47k
                                    tdn.stub_data_ts.extend_from_slice(recr.data);
210
6.47k
                                    tdn.frag_cnt_ts += 1;
211
6.47k
                                    SCLogDebug!("stub_data now {}", tdn.stub_data_ts.len());
212
6.47k
                                }
213
6.47k
                                if dcer.last_frag {
214
3.81k
                                    SCLogDebug!("last frag set, so request side of DCERPC closed");
215
3.81k
                                    tx.request_done = true;
216
3.81k
                                } else {
217
2.66k
                                    SCLogDebug!("NOT last frag, so request side of DCERPC remains open");
218
2.66k
                                }
219
6.47k
                                true
220
                            },
221
                            None => {
222
                                SCLogDebug!("NO previous CMD {} found", dcer.packet_type);
223
3.72k
                                false
224
                            },
225
                        };
226
10.2k
                        return found;
227
                    },
228
                    _ => {
229
13.4k
                        state.set_event(SMBEvent::MalformedData);
230
13.4k
                        return false;
231
                    },
232
                }
233
43.7k
            }
234
43.7k
235
43.7k
            let tx = state.new_dcerpc_tx(hdr, vercmd, dcer.packet_type, dcer.call_id);
236
43.7k
            match dcer.packet_type {
237
                DCERPC_TYPE_REQUEST => {
238
10.5k
                    match parse_dcerpc_request_record(dcer.data, dcer.frag_len, dcer.little_endian) {
239
5.62k
                        Ok((_, recr)) => {
240
                            SCLogDebug!("DCERPC: REQUEST {:?}", recr);
241
5.62k
                            if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data {
242
5.62k
                                SCLogDebug!("first frag size {}", recr.data.len());
243
5.62k
                                tdn.stub_data_ts.extend_from_slice(recr.data);
244
5.62k
                                tdn.opnum = recr.opnum;
245
5.62k
                                tdn.context_id = recr.context_id;
246
5.62k
                                tdn.frag_cnt_ts += 1;
247
5.62k
                                SCLogDebug!("DCERPC: REQUEST opnum {} stub data len {}",
248
5.62k
                                        tdn.opnum, tdn.stub_data_ts.len());
249
5.62k
                            }
250
5.62k
                            if dcer.last_frag {
251
823
                                tx.request_done = true;
252
4.80k
                            } else {
253
4.80k
                                SCLogDebug!("NOT last frag, so request side of DCERPC remains open");
254
4.80k
                            }
255
                        },
256
4.88k
                        _ => {
257
4.88k
                            tx.set_event(SMBEvent::MalformedData);
258
4.88k
                            tx.request_done = true;
259
4.88k
                        },
260
                    }
261
                },
262
                DCERPC_TYPE_BIND => {
263
28.9k
                    let brec = if dcer.little_endian {
264
19.1k
                        parse_dcerpc_bind_record(dcer.data)
265
                    } else {
266
9.77k
                        parse_dcerpc_bind_record_big(dcer.data)
267
                    };
268
28.9k
                    match brec {
269
2.93k
                        Ok((_, bindr)) => {
270
2.93k
                            is_bind = true;
271
2.93k
                            SCLogDebug!("SMB DCERPC {:?} BIND {:?}", dcer, bindr);
272
2.93k
273
2.93k
                            if !bindr.ifaces.is_empty() {
274
1.51k
                                let mut ifaces: Vec<DCERPCIface> = Vec::new();
275
23.5k
                                for i in bindr.ifaces {
276
22.0k
                                    let x = if dcer.little_endian {
277
14.2k
                                        vec![i.iface[3],  i.iface[2],  i.iface[1],  i.iface[0],
278
14.2k
                                             i.iface[5],  i.iface[4],  i.iface[7],  i.iface[6],
279
14.2k
                                             i.iface[8],  i.iface[9],  i.iface[10], i.iface[11],
280
14.2k
                                             i.iface[12], i.iface[13], i.iface[14], i.iface[15]]
281
                                    } else {
282
7.80k
                                        i.iface.to_vec()
283
                                    };
284
22.0k
                                    let uuid_str = uuid::Uuid::from_slice(&x.clone());
285
22.0k
                                    let _uuid_str = uuid_str.map(|uuid_str| uuid_str.to_hyphenated().to_string()).unwrap();
286
22.0k
                                    let d = DCERPCIface::new(x,i.ver,i.ver_min);
287
22.0k
                                    SCLogDebug!("UUID {} version {}/{} bytes {:?}",
288
22.0k
                                            _uuid_str,
289
22.0k
                                            i.ver, i.ver_min,i.iface);
290
22.0k
                                    ifaces.push(d);
291
22.0k
                                }
292
1.51k
                                bind_ifaces = Some(ifaces);
293
1.42k
                            }
294
                        },
295
25.9k
                        _ => {
296
25.9k
                            tx.set_event(SMBEvent::MalformedData);
297
25.9k
                        },
298
                    }
299
28.9k
                    tx.request_done = true;
300
                }
301
2.39k
                21..=255 => {
302
2.39k
                    tx.set_event(SMBEvent::MalformedData);
303
2.39k
                    tx.request_done = true;
304
2.39k
                },
305
1.88k
                _ => {
306
1.88k
                    // valid type w/o special processing
307
1.88k
                    tx.request_done = true;
308
1.88k
                },
309
            }
310
        },
311
5.92k
        _ => {
312
5.92k
            state.set_event(SMBEvent::MalformedData);
313
5.92k
        },
314
    }
315
316
49.6k
    if is_bind {
317
2.93k
        // We have to write here the interfaces
318
2.93k
        // rather than in the BIND block
319
2.93k
        // due to borrow issues with the tx mutable reference
320
2.93k
        // that is part of the state
321
2.93k
        state.dcerpc_ifaces = bind_ifaces; // TODO store per ssn
322
46.7k
    }
323
49.6k
    return true;
324
73.2k
}
325
326
/// Update TX for bind ack. Needs to update both tx and state.
327
///
328
6.16k
fn smb_dcerpc_response_bindack(
329
6.16k
        state: &mut SMBState,
330
6.16k
        vercmd: SMBVerCmdStat,
331
6.16k
        hdr: SMBCommonHdr,
332
6.16k
        dcer: &DceRpcRecord,
333
6.16k
        ntstatus: u32)
334
6.16k
{
335
6.16k
    match parse_dcerpc_bindack_record(dcer.data) {
336
2.10k
        Ok((_, bindackr)) => {
337
            SCLogDebug!("SMB READ BINDACK {:?}", bindackr);
338
339
2.10k
            let found = match state.get_dcerpc_tx(&hdr, &vercmd, dcer.call_id) {
340
904
                Some(tx) => {
341
904
                    if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data {
342
904
                        tdn.set_result(DCERPC_TYPE_BINDACK);
343
904
                    }
344
904
                    tx.vercmd.set_ntstatus(ntstatus);
345
904
                    tx.response_done = true;
346
904
                    true
347
                },
348
1.20k
                None => false,
349
            };
350
2.10k
            if found {
351
904
                if let Some(ref mut ifaces) = state.dcerpc_ifaces {
352
1.73k
                    for (i, r) in bindackr.results.into_iter().enumerate() {
353
1.73k
                        if i >= ifaces.len() {
354
                            // TODO set event: more acks that requests
355
202
                            break;
356
1.53k
                        }
357
1.53k
                        ifaces[i].ack_result = r.ack_result;
358
1.53k
                        ifaces[i].acked = true;
359
                    }
360
252
                }
361
1.20k
            }
362
        },
363
4.05k
        _ => {
364
4.05k
            state.set_event(SMBEvent::MalformedData);
365
4.05k
        },
366
    }
367
6.16k
}
368
369
2.32k
fn smb_read_dcerpc_record_error(state: &mut SMBState,
370
2.32k
        hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, ntstatus: u32)
371
2.32k
    -> bool
372
2.32k
{
373
2.32k
    let ver = vercmd.get_version();
374
2.32k
    let cmd = if ver == 2 {
375
2.32k
        let (_, c) = vercmd.get_smb2_cmd();
376
2.32k
        c
377
    } else {
378
0
        let (_, c) = vercmd.get_smb1_cmd();
379
0
        c as u16
380
    };
381
382
2.32k
    let found = match state.get_generic_tx(ver, cmd, &hdr) {
383
907
        Some(tx) => {
384
907
            SCLogDebug!("found");
385
907
            tx.set_status(ntstatus, false);
386
907
            tx.response_done = true;
387
907
            true
388
        },
389
        None => {
390
            SCLogDebug!("NOT found");
391
1.41k
            false
392
        },
393
    };
394
2.32k
    return found;
395
2.32k
}
396
397
13.2k
fn dcerpc_response_handle(tx: &mut SMBTransaction,
398
13.2k
        vercmd: SMBVerCmdStat,
399
13.2k
        dcer: &DceRpcRecord)
400
13.2k
{
401
13.2k
    let (_, ntstatus) = vercmd.get_ntstatus();
402
13.2k
    match dcer.packet_type {
403
        DCERPC_TYPE_RESPONSE => {
404
8.47k
            match parse_dcerpc_response_record(dcer.data, dcer.frag_len) {
405
1.36k
                Ok((_, respr)) => {
406
                    SCLogDebug!("SMBv1 READ RESPONSE {:?}", respr);
407
1.36k
                    if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data {
408
1.36k
                        SCLogDebug!("CMD 11 found at tx {}", tx.id);
409
1.36k
                        tdn.set_result(DCERPC_TYPE_RESPONSE);
410
1.36k
                        tdn.stub_data_tc.extend_from_slice(respr.data);
411
1.36k
                        tdn.frag_cnt_tc += 1;
412
1.36k
                    }
413
1.36k
                    tx.vercmd.set_ntstatus(ntstatus);
414
1.36k
                    tx.response_done = dcer.last_frag;
415
                },
416
7.11k
                _ => {
417
7.11k
                    tx.set_event(SMBEvent::MalformedData);
418
7.11k
                },
419
            }
420
        },
421
0
        DCERPC_TYPE_BINDACK => {
422
0
            // handled elsewhere
423
0
        },
424
1.89k
        21..=255 => {
425
1.89k
            if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data {
426
1.89k
                tdn.set_result(dcer.packet_type);
427
1.89k
            }
428
1.89k
            tx.vercmd.set_ntstatus(ntstatus);
429
1.89k
            tx.response_done = true;
430
1.89k
            tx.set_event(SMBEvent::MalformedData);
431
        }
432
        _ => { // valid type w/o special processing
433
2.86k
            if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data {
434
2.86k
                tdn.set_result(dcer.packet_type);
435
2.86k
            }
436
2.86k
            tx.vercmd.set_ntstatus(ntstatus);
437
2.86k
            tx.response_done = true;
438
        },
439
    }
440
13.2k
}
441
442
/// Handle DCERPC reply record. Called for READ, TRANS, IOCTL
443
///
444
34.2k
pub fn smb_read_dcerpc_record(state: &mut SMBState,
445
34.2k
        vercmd: SMBVerCmdStat,
446
34.2k
        hdr: SMBCommonHdr,
447
34.2k
        guid: &[u8],
448
34.2k
        indata: &[u8]) -> bool
449
34.2k
{
450
34.2k
    let (_, ntstatus) = vercmd.get_ntstatus();
451
34.2k
452
34.2k
    if ntstatus != SMB_NTSTATUS_SUCCESS && ntstatus != SMB_NTSTATUS_BUFFER_OVERFLOW {
453
2.32k
        return smb_read_dcerpc_record_error(state, hdr, vercmd, ntstatus);
454
31.9k
    }
455
31.9k
456
31.9k
    SCLogDebug!("lets first see if we have prior data");
457
31.9k
    // msg_id 0 as this data crosses cmd/reply pairs
458
31.9k
    let ehdr = SMBHashKeyHdrGuid::new(SMBCommonHdr::new(SMBHDR_TYPE_TRANS_FRAG,
459
31.9k
            hdr.ssn_id, hdr.tree_id, 0_u64), guid.to_vec());
460
31.9k
    let mut prevdata = state.ssnguid2vec_map.remove(&ehdr).unwrap_or_default();
461
31.9k
    SCLogDebug!("indata {} prevdata {}", indata.len(), prevdata.len());
462
31.9k
    prevdata.extend_from_slice(indata);
463
31.9k
    let data = prevdata;
464
31.9k
465
31.9k
    let mut malformed = false;
466
31.9k
467
31.9k
    if data.is_empty() {
468
        SCLogDebug!("weird: no DCERPC data"); // TODO
469
        // TODO set event?
470
565
        return false;
471
472
    } else {
473
31.3k
        match parse_dcerpc_record(&data) {
474
28.5k
            Ok((_, dcer)) => {
475
28.5k
                SCLogDebug!("DCERPC: version {}.{} read data {} => {:?}",
476
28.5k
                        dcer.version_major, dcer.version_minor, dcer.data.len(), dcer);
477
28.5k
478
28.5k
                if ntstatus == SMB_NTSTATUS_BUFFER_OVERFLOW && data.len() < dcer.frag_len as usize {
479
                    SCLogDebug!("short record {} < {}: storing partial data in state",
480
                            data.len(), dcer.frag_len);
481
9.10k
                    state.ssnguid2vec_map.insert(ehdr, data.to_vec());
482
9.10k
                    return true; // TODO review
483
19.4k
                }
484
19.4k
485
19.4k
                if dcer.packet_type == DCERPC_TYPE_BINDACK {
486
6.16k
                    smb_dcerpc_response_bindack(state, vercmd, hdr, &dcer, ntstatus);
487
6.16k
                    return true;
488
13.2k
                }
489
490
13.2k
                let found = match state.get_dcerpc_tx(&hdr, &vercmd, dcer.call_id) {
491
8.34k
                    Some(tx) => {
492
8.34k
                        dcerpc_response_handle(tx, vercmd.clone(), &dcer);
493
8.34k
                        true
494
                    },
495
                    None => {
496
                        SCLogDebug!("no tx");
497
4.89k
                        false
498
                    },
499
                };
500
13.2k
                if !found {
501
4.89k
                    // pick up DCERPC tx even if we missed the request
502
4.89k
                    let tx = state.new_dcerpc_tx_for_response(hdr, vercmd.clone(), dcer.call_id);
503
4.89k
                    dcerpc_response_handle(tx, vercmd, &dcer);
504
8.34k
                }
505
            },
506
2.88k
            _ => {
507
2.88k
                malformed = true;
508
2.88k
            },
509
        }
510
    }
511
512
16.1k
    if malformed {
513
2.88k
        state.set_event(SMBEvent::MalformedData);
514
13.2k
    }
515
516
16.1k
    return true;
517
34.2k
}
518
519
/// Try to find out if the input data looks like DCERPC
520
34.4k
pub fn smb_dcerpc_probe(data: &[u8]) -> bool
521
34.4k
{
522
34.4k
    if let Ok((_, recr)) = parse_dcerpc_record(data) {
523
        SCLogDebug!("SMB: could be DCERPC {:?}", recr);
524
23.2k
        if recr.version_major == 5 && recr.version_minor < 3 &&
525
17.9k
            recr.frag_len > 0 && recr.packet_type <= 20
526
            {
527
                SCLogDebug!("SMB: looks like we have dcerpc");
528
17.6k
                return true;
529
5.56k
            }
530
11.2k
    }
531
16.7k
    return false;
532
34.4k
}